问题
这一次的编程作业是完成一个类似于“华容道”的游戏——8 puzzle:
给定一个 N × N N\times N N×N 的网格图,其中有一个网格被挖空,其余网格标记为 1 , 2 , 3 , ⋯ , N × N − 1 1,2,3,\cdots, N\times N-1 1,2,3,⋯,N×N−1。每次可以将被挖空的网格与相邻被标记数字的网格交换,目标是移至成 1 , 2 , 3 , 4 ⋯ , N × N − 1 1,2,3,4\cdots, N\times N-1 1,2,3,4⋯,N×N−1 依次排列,最后一个网格被挖空的情况。
思路
首先定义一个数据类型 Board,储存 N × N N\times N N×N 的二维数组,用 0 表示被挖空的网格,找出其相邻的 Board。定义每一个 Board 与目标 Board 之间的 Hamming 距离和 Manhattan 距离。定义一个新的数据类型 State,用来储存 Board、移动步数、前一个State。
接下来可以利用 A* search algorithm 来解决这个问题:先把初始 State 加入优先队列,然后每次删去 Manhattan 最小的 State,加入其相邻的 State(如果该 State 不曾在优先队列中出现过),直至删去的 State 的 Manhattan 距离为 0。
注意到,任意给定一个初始状态,未必能达到目标状态。可以利用逆序数来判断:当且仅当原初始状态在一维数组下是偶排列时,该问题是可行的。
代码
# -*- coding: utf-8 -*-
"""
Created on Thu Dec 10 16:34:21 2020
@author: zxw
"""
import numpy as np
import time
N = 3
goal = [i+1 for i in range(N*N)]
goal[N*N-1] = 0
class Board:
#construct a board from an N-by-N array of tiles
def __init__(self, tiles):
self.Array = np.array(tiles).reshape(N,N)
# return number of blocks out of place
def hamming(self):
temp = N*N-1-sum(sum(self.Array == Board(goal).Array))