回到首页

🧩九宫格拼图的最少步骤解法|Bing必应拼图游戏

七月 28, 2025

最近使用Edge浏览器,目前有各种攒积分的任务,其中就有拼图游戏,就像这样:

玩过几次后我就思考有没有最优的解法,也就是步骤最少的复原方法。通过网上搜索,发现使用 A*(A-star)搜索算法 来找最短路径,是最常用的 8-puzzle 解法。

借助chatgpt,我这个编程入门选手也可以很快得到一个可执行的程序代码。

from heapq import heappush, heappop

# 目标状态
goal = "12345678_"

# 空格移动方向及其索引变化量
moves = {
    'U': -3,
    'D': 3,
    'L': -1,
    'R': 1,
}

# 特殊情况:哪些位置不能向左/右/上/下移动
invalid_moves = {
    'L': [0, 3, 6],
    'R': [2, 5, 8],
    'U': [0, 1, 2],
    'D': [6, 7, 8],
}

# 启发函数:曼哈顿距离
def manhattan(state):
    distance = 0
    for idx, val in enumerate(state):
        if val != "_":
            goal_idx = goal.index(val)
            distance += abs(idx // 3 - goal_idx // 3) + abs(idx % 3 - goal_idx % 3)
    return distance

# A* 求解函数
def solve_puzzle(start):
    visited = set()
    heap = []
    heappush(heap, (manhattan(start), 0, start, ""))  # (估值, 步数, 状态, 路径)

    while heap:
        priority, steps, state, path = heappop(heap)
        if state == goal:
            return steps, path

        if state in visited:
            continue
        visited.add(state)

        empty_idx = state.index("_")

        for move, delta in moves.items():
            new_idx = empty_idx + delta
            if empty_idx in invalid_moves[move] or not (0 <= new_idx < 9):
                continue
            # 交换空格与相邻数字
            state_list = list(state)
            state_list[empty_idx], state_list[new_idx] = state_list[new_idx], state_list[empty_idx]
            new_state = ''.join(state_list)
            if new_state not in visited:
                heappush(heap, (steps + 1 + manhattan(new_state), steps + 1, new_state, path + move))

    return -1, ""  # 无解

# 示例用法
if __name__ == "__main__":
    initial_state = "3754182_6"
    steps, solution = solve_puzzle(initial_state)
    print(f"最少步数: {steps}")
    print(f"操作路径: {solution}")

得到输出如下:

最少步数: 21
操作路径: ULDRUULDDRURULLDDRURD

🔁 操作说明(空格的移动方向)

每个字母代表一次点击使空格与相邻数字交换:

  • L:空格向左移(即点击其左边的数字)
  • R:空格向右移
  • U:空格向上移
  • D:空格向下移
  • 最近文章