python - 深度优先搜索 8 益智游戏“从空列表中弹出”
问题描述
我必须执行深度优先搜索来解决 8 益智游戏:(-1 代表空值)
initialState1 = [[-1,1,2], [7,8,3], [6,5,4]]
finalState1 = [[1,2,3], [8,-1,4], [7,6,5]]
我的代码:
def play(puzzle, direction):
print(puzzle)
if direction == "up":
for i in range(3):
for j in range(3):
if(puzzle[i][j]==-1):
if i!=0:
puzzle[i][j] = puzzle[i-1][j]
puzzle[i-1][j] = -1
return puzzle
if direction=="down":
for i in range(3):
for j in range(3):
if(puzzle[i][j]==-1):
if i!=2:
puzzle[i][j] = puzzle[i+1][j]
puzzle[i+1][j] = -1
return puzzle
if direction == "left":
for i in range(3):
for j in range(3):
if(puzzle[i][j] == -1):
if j!=0:
puzzle[i][j] = puzzle[i][j-1]
puzzle[i][j-1] = -1
return puzzle
if direction == "right":
for i in range(3):
for j in range(3):
if(puzzle[i][j] == -1):
if j!=2:
puzzle[i][j] = puzzle[i][j+1]
puzzle[i][j+1] = -1
return puzzle
def checkBoundaries(puzzle):
possibilities = []
for i in range(3):
for j in range(3):
if(puzzle[i][j]==-1):
if(i == 0):
if(j == 0):
possibilities.append("down")
possibilities.append("right")
elif(j == 1):
possibilities.append("down")
possibilities.append("right")
possibilities.append("left")
elif(j == 2):
possibilities.append("down")
possibilities.append("left")
if(i == 1):
if(j == 0):
possibilities.append("down")
possibilities.append("right")
possibilities.append("up")
elif(j == 1):
possibilities.append("down")
possibilities.append("right")
possibilities.append("left")
possibilities.append("up")
elif(j == 2):
possibilities.append("down")
possibilities.append("left")
possibilities.append("up")
if(i == 2):
if(j == 0):
possibilities.append("up")
possibilities.append("right")
elif(j == 1):
possibilities.append("up")
possibilities.append("right")
possibilities.append("left")
elif(j == 2):
possibilities.append("up")
possibilities.append("left")
return random.choice(possibilities)
def depthFirstSearch():
pathcost=0
queue=[]
initialFormatted=[initialState1,"none"]
queue.append(initialFormatted)
while(True):
puzzle=queue.pop(0)
pathcost=pathcost+1
print(str(puzzle[1])+" --> "+str(puzzle[0]))
if(puzzle[0] == finalState1):
print("Found")
print("Path cost -> "+str(pathcost-1))
break
else:
nextMove=play(puzzle[0], checkBoundaries(puzzle[0]))
if(nextMove!=puzzle[0]):
nextMove=[nextMove,checkBoundaries(puzzle[0])]
queue.insert(0, nextMove)
depthFirstSearch()
但运行此代码,我收到此错误:
puzzle=queue.pop(0) IndexError: 从空列表中弹出
如何处理?我做错了什么?
我的代码是否在做正确的事情来实现我的目标?在 checkBoudaries 方法中,我目前正在设置一个随机值(在可能性范围内)以返回.. 是正确的还是我必须更喜欢基于最后一步的移动?
解决方案
这里存在多个概念问题,以至于尝试编写更正版本的工作量太大。但是,我想我现在已经很好地理解了您尝试的一般结构,可以修复它。
您正在使用基于队列的方法(与递归方法相反),这意味着您需要跟踪队列节点本身中的路径成本(或者,如果您想跟踪它们,则需要跟踪整个路径)。(在递归方法中,您将在递归调用中传递此信息。)
您正在使用基于队列的方法。这自然实现了广度优先搜索。您需要一个堆栈,以便在“父”位置的其他可能性之前尝试来自当前位置的新可能性。
您正在解决的特定问题使循环成为可能。您需要对此进行某种检测。一个简单的方法是保持一个
set
先前看到的位置。您需要彻底搜索,而不仅仅是从当前位置选择一个动作。这就是算法的全部要点。
possibilities
您应该返回from的整个列表checkBoundaries
,并为每种可能性添加一个单独的节点到堆栈中。
但实际上导致报告的问题的事情:
if(nextMove!=puzzle[0]):
nextMove=[nextMove,checkBoundaries(puzzle[0])]
queue.insert(0, nextMove)
这个检查不应该是必要的,因为你只应该尝试有效的移动,而有效的移动应该(根据定义)改变棋盘位置。
但除此之外,你永远不会在队列中插入任何东西,因为这个条件永远不会满足 -nextMove
总是等于,即使你改变了棋盘位置。为什么?因为是同一个对象。您的代码中没有任何内容会复制板对象;所以队列包含多个副本;代码修改了相同的单个对象并将其返回给您等。这是 Python 中的一个常见问题,以多种形式表现出来 - 没有什么是完全重复的,但它与例如List of lists的问题相同意外反映在子列表中的更改。puzzle[0]
play
这意味着,即使您删除了不必要的检查,您仍然会遇到问题 - 因为您的play
函数会影响队列中的每个节点。您需要重写play
,以便它创建一个代表“下一个”棋盘位置的新列表列表,而无需修改输入。
推荐阅读
- python - Python 在 PostgreSQL 查询上使用多处理减少了运行时间
- python - 如何免费将带有 Kivy 的 python 文件上传到 iPhone?
- java - 当在 onCreate 中完成某些事情(不是声明或初始化)但在 onClick 中没有完成时,应用程序崩溃
- c++ - Qt WebEngineView:加载 WebGL 项目时出现问题(从 Unity 导出)
- java - 使用 Kotlin 解析多列文件
- couchbase - 如何在n1ql查询中检索父母的孩子
- swift - 如何使用 Moya RxSwift 合并 REST 数组
- javascript - 什么是等效于 es5 函数声明的 es6 胖箭头
- javascript - 服务器响应 500 错误时触发 XMLHttpRequest.upload.onprogress
- python - 使用 Python /F 标志终止进程