此代码的目标是解决N拼图(请参阅此处:https://en.wikipedia.org/wiki/15_puzzle)
该函数用于获取整数0到(N ** 2-1)的加扰列表,并返回移动列表以达到求解状态,其中移动是x和y坐标的列表(例如[2,2]表示在3x3拼图中移动右下角)。我知道只有某些电路板可以解决,我测试代码的电路板绝对是可以解决的。
我尝试实现A *搜索,但似乎有一些问题,因为对于许多电路板我正在堆栈溢出。我在下面的代码中使用的板导致堆栈溢出,但是这个板将在大约20秒后返回正确的移动序列(这似乎太长了): [7,2,8,1,5,6,0,3,4]
基本思路是从一系列移动路径开始,然后找到尚未扩展的最低成本路径(成本=当前路径长度+剩余曼哈顿距离),并扩展该路径,并继续前进直到找到解决方案。
据我所知,对于一个8-puzzle的强制执行可能就好像不比A *更可行,但如果我的代码也可以用于15-puzzle,我也会喜欢它。
从我的调试开始,看起来代码有点像预期的那样工作,我只是不确定为什么它花费这么长时间并且对于大多数电路板导致堆栈溢出。如果我不得不猜测,我会说也许我可以消除更多的路径以加快速度,但我不确定如何在不消除最佳路径的情况下做到这一点
我是编程新手,所以我的代码中有一个简单的错误,或者我对算法有一个基本的误解?我相当自信我的帮助函数按预期工作,问题出在solve函数中。任何建议将不胜感激
import math
import copy
#Making move on board
def makeMove(board, move):
L = int(math.sqrt(len(board)))
copyBoard = copy.copy(board)
zI = copyBoard.index(L**2-1)
#Calculating move index in 1D list based off of x/y coords
moveI = move[0] + L*move[1]
copyBoard[zI], copyBoard[moveI] = copyBoard[moveI], copyBoard[zI]
return copyBoard
#Function to find the board based off of the given path
def makeMoves(board, path):
newBoard = copy.deepcopy(board)
for move in path:
newBoard = makeMove(newBoard, move)
return newBoard
def mDist(board): #Calculating manhattan distance of board
totalDist = 0
L = int(math.sqrt(len(board)))
for i in range(int(L**2)):
#Finding sum of differences between x and y coordinates
cX, cY = i % L, i // L
fX, fY = board[i] % L, board[i] // L
dX, dY = abs(cX-fX), abs(cY - fY)
totalDist += (dX+dY)
return totalDist
def nDisp(board):
score = 0
for i in range(len(board)):
if i != board[i]:
score += 1
return score
def getLegalMoves(board):
finalMoves = []
L = int(math.sqrt(len(board)))
#Finding the coordinates of the blank
zI = board.index(L**2-1)
zX, zY = zI % L, zI // L
#Finding possible moves from that blank
testMoves = [[zX+1, zY], [zX-1, zY], [zX, zY+1], [zX, zY-1]]
for move in testMoves:
if isLegalMove(move, L):
finalMoves.append(move)
return finalMoves
def isLegalMove(move, L):
#Move is legal if on board
for i in move:
if i < 0 or i >= L:
return False
return True
def solve(board):
queue = [] #List of paths, where a path is a sequence of moves
for move in getLegalMoves(board): #Getting initial paths
queue.append([move])
def search(queue, board):
bestScore = math.inf
bestPath = None
for path in queue:
#Score based off of A* = estimated distance to finish + current distance
dist = mDist(makeMoves(board, path))
score = dist + len(path)
#Checking if solved
if dist == 0:
return path
#Finding best path that has not already been expanded
if score < bestScore:
bestScore = score
bestPath = path
#Removing the path since it is going to be expanded
queue.remove(bestPath)
bestPathBoard = makeMoves(board, bestPath)
#Expanding the path
for move in getLegalMoves(bestPathBoard):
newPath = bestPath + [move]
queue.append(newPath)
#Recursing
return search(queue, board)
return search(queue, board)
print(solve([8, 0, 1, 6, 7, 3, 2, 5, 4]))