如何解决使用 Python 查找所有迷宫解决方案
我试图找到(使用 Python)迷宫的所有可能解决方案。我有一个返回一个解决方案的 DFS 脚本。我正在尝试适应它,但我真的很难将整个递归事情包裹起来。
这是我拥有的代码,用于使用 DFS 寻找一种可能的解决方案: 任何提示或帮助将不胜感激! (数组中的“lett”可以忽略/认为是常规的“路径”)
def DFS(x,y,Map):
if (Map[x][y]=="exit"): #check if we're at the exit
return [(x,y)] #if so then we solved it so return this spot
if ((Map[x][y]!="path") and (Map[x][y]!="lett")): #if it's not a path,we can't try this spot
return []
Map[x][y]="explored" #make this spot explored so we don't try again
for i in [[x-1,y],[x+1,[x,y-1],y+1]]: #new spots to try
result = DFS(i[0],i[1],Map) #recursively call itself
if len(result)>0: #if the result had at least one element,it found a correct path,otherwise it Failed
result.append((x,y)) #if it found a correct path then return the path plus this spot
return result
return [] #return the empty list since we Couldn't find any paths from here
def GetMap():
return [
["wall","wall","wall"],["wall","path","lett","exit","wall"]
]
def DrawMap(Map,path):
for x in range(0,len(Map)):
for y in range(0,len(Map[x])):
if ((x,y) in path):
assert Map[x][y] in ("path","exit")
print("-",end="")
elif (Map[x][y]=="wall"):
print("#",end="")
elif (Map[x][y]=="exit"):
print("e",end="")
elif (Map[x][y]=="lett"):
print("L",end="")
else:
print(' ',end="")
print()
print("\nUnsolved:\n")
DrawMap(GetMap(),[])
print("\n")
print("Solved with DFS:")
print("path is ",len(DFS(1,1,GetMap()))," spots long\n")
DrawMap(GetMap(),DFS(1,GetMap()))
print("\n")
解决方法
给你:
更新的 DFS:
def DFS(x,y,Map):
if (Map[x][y]=="exit"):
return [[(x,y)]]
if ((Map[x][y]!="path") and (Map[x][y]!="lett")):
return []
stat = Map[x][y]
Map[x][y]="explored"
my_results = []
for i in [[x-1,y],[x+1,[x,y-1],y+1]]:
results = DFS(i[0],i[1],Map)
for res in results:
if len(res)>0:
res.append((x,y))
my_results.append(res)
Map[x][y] = stat
return my_results
更新输出:
print("\nUnsolved:\n")
DrawMap(GetMap(),[])
print("\n")
print("Solved with DFS:")
results = DFS(1,1,GetMap())
for result in results:
print("path is ",len(result)," spots long\n")
DrawMap(GetMap(),result)
print("\n")
,
一厢情愿
遇到这样的问题可能会让人感到不知所措,但我最喜欢的编程技术使复杂性消失得无影无踪。使用一厢情愿,我们按照我们希望的方式编写程序,然后让我们的愿望成真-
# simple.py
from maze import maze
from cursor import cursor
def dfs(cursor,maze):
q = maze.get(cursor.y(),cursor.x())
if not q or q.is_wall() or q.is_step():
return
elif q.is_exit():
yield maze
else:
next_maze = maze.step(cursor.y(),cursor.x())
yield from dfs(cursor.up(),next_maze)
yield from dfs(cursor.down(),next_maze)
yield from dfs(cursor.right(),next_maze)
yield from dfs(cursor.left(),next_maze)
def solve(cursor,maze):
for x in dfs(cursor,maze):
return x
我们只需要一个迷宫 m
和一个光标 c
-
# simple.py (continued)
# read maze from file
m = maze.from_file("./input")
# initialize cursor
c = cursor.from_ints(1,1)
我们可以使用 solve
-
# simple.py (continued)
print(solve(c,m))
########
#--- #
###-#L #
# -## #
# #----#
# ####-#
# L e#
########
或者我们可以使用 dfs
-
# simple.py (continued)
for x in dfs(c,m):
print(x,end="\n\n")
(以下输出重新格式化以节省空间)
######## ######## ######## ######## ######## ########
#--- # #--- # #----- # #----- # #------# #------#
###-#L # ###-#L # ### #--# ### #--# ### #L-# ### #L-#
# -## # #---## # # ##-# #---##-# # ##-# #---##-#
# #----# #-#L # # #L -# #-#----# # #L -# #-#----#
# ####-# #-#### # # ####-# #-#### # # ####-# #-#### #
# L e# #-----e# # L e# #-----e# # L e# #-----e#
######## ######## ######## ######## ######## ########
光标
要使上述程序正常运行,我们需要满足我们所有的愿望。我们将从 cursor
模块开始。游标只是一对整数,它为我们提供了方便的 up
、down
、left
和 right
移动 -
# cursor.py
def from_ints(y,x):
return (y,x)
def up(t):
(y,x) = t
return from_ints(y - 1,x)
def down(t):
(y,x) = t
return from_ints(y + 1,x)
def left(t):
(y,x) = t
return from_ints(y,x - 1)
def right(t):
(y,x + 1)
def to_str(t):
(y,x) = t
return f"({y},{x})"
如您所见,我们使用的是普通函数。 Python 也有很好的面向对象特性,我们希望将这些便利扩展到我们模块的用户。我们通过包装普通函数轻松添加 OOP 接口 -
# cursor.py (continued)
class cursor:
def from_ints(y,x): return cursor(from_ints(y,x))
def __init__(self,t): self.t = t
def __iter__(self): yield from self.t
def __str__(self): return to_str(self.t)
def up(self): return cursor(up(self.t))
def down(self): return cursor(down(self.t))
def right(self): return cursor(right(self.t))
def left(self): return cursor(left(self.t))
迷宫
现在我们进入我们的 maze
模块。我们将从编写普通函数开始,将 from_file
转换为迷宫,并从迷宫 to_str
-
# maze.py
from cell import cell
def from_file(filename):
with open(filename) as f:
return from_str(f.read())
def from_str(s):
return [ list(map(cell.from_str,row)) for row in s.split("\n") ]
def to_str(t):
return "\n".join("".join(map(str,row)) for row in t)
作为奖励,请注意我们如何免费获得 from_str
。接下来,我们使用 get
和 set
坐标将函数写入 y
或 x
单元格。这里我们还写了 step
,一个简单的 set
包装器,用于标记迷宫中的一个单元格已被探索 -
# maze.py (continued)
from arr_ext import update
def get(t,x):
try:
if x < 0 or y < 0:
return None
else:
return t[y][x]
except IndexError:
return None
def set(t,x,v):
return update \
( t,lambda row: update(row,lambda _: v)
)
def step(t,x):
return set(t,cell.step())
不要害怕随心所欲地许下多少愿望。我们将在需要时实施 update
。就像我们在上一个模块中所做的那样,我们添加了面向对象的界面 -
# maze.py (continued)
class maze:
def from_file(filename): return maze(from_file(filename))
def from_str(s): return maze(from_str(s))
def __init__(self,t): self.t = t
def __iter__(self): yield from self.t
def __str__(self): return to_str(self.t)
def get(self,x): return get(self.t,x)
def set(self,v): return maze(set(self.t,v))
def step(self,x): return maze(step(self.t,x))
单元格
当我们编写迷宫模块时,我们希望有一个 cell
模块。一厢情愿的技巧现在应该成为焦点:许一个愿望,实现它。我们的 Cell 模块代表我们迷宫中的一个单元格。我们从一种将 from_str
转换为单元格的方法开始,然后从单元格 to_str
-
# cell.py
wall = 0
path = 1
exit = 2
lett = 3
step = 4
str_to_cell = \
{ "#": wall," ": path,"e": exit,"L": lett,"-": step }
cell_to_str = \
{ v: k for (k,v) in str_to_cell.items() }
def from_str(s):
if s in str_to_cell:
return str_to_cell[s]
else:
raise RuntimeError(f"invalid cell character: {s}")
def to_str(t):
if t in cell_to_str:
return cell_to_str[t]
else:
raise RuntimeError(f"invalid cell component: {t}")
此外,我们编写 is_*
谓词来确定单元格是否是 wall
、path
等。这突出了抽象的优势:我们可以更改数据在一个模块而无需修改我们程序中的其他模块 -
# cell.py (continued)
def is_wall(t): return t == wall
def is_path(t): return t == path
def is_exit(t): return t == exit
def is_lett(t): return t == lett
def is_step(t): return t == step
添加面向对象的接口。同样,它是我们普通函数的简单包装器 -
# cell.py (continued)
class cell:
def from_str(s): return cell(from_str(s))
def wall(): return cell(wall)
def path(): return cell(path)
def exit(): return cell(exit)
def lett(): return cell(lett)
def step(): return cell(step)
def __init__(self,t): self.t = t
def __str__(self): return to_str(self.t)
def is_wall(self): return is_wall(self.t)
def is_path(self): return is_path(self.t)
def is_exit(self): return is_exit(self.t)
def is_lett(self): return is_lett(self.t)
def is_step(self): return is_step(self.t)
arr_ext
只剩下一个愿望要实现了!我们在数组扩展模块 update
-
arr_ext
函数
# arr_ext.py
def update(t,pos,f):
try:
return [ *t[:pos],f(t[pos]),*t[pos + 1:]]
except IndexError:
return t
高级
我们的 simple
程序以一种简化的方式解决了这个问题。如果我们想解决迷宫并且知道每个解决方案的路径怎么办?让我们在下面编写一个 advanced
程序 -
# advanced.py
from maze import maze
from cursor import cursor
def dfs(cursor,maze,path=[]):
q = maze.get(*cursor)
if not q or q.is_wall() or q.is_step():
return
elif q.is_exit():
yield (maze,path)
else:
next_maze = maze.step(*cursor)
next_path = [*path,cursor]
yield from dfs(cursor.up(),next_maze,next_path)
yield from dfs(cursor.down(),next_path)
yield from dfs(cursor.right(),next_path)
yield from dfs(cursor.left(),next_path)
def solve(cursor,maze):
return x
请注意高级解决方案只是对简单模块的小幅调整。让我们看看第一个解决的迷宫是什么样子的 -
# advanced.py (continued)
print(solution(solve(c,m)))
########
#--- #
###-#L #
# -## #
# #----#
# ####-#
# L e#
########
(1,1)->(1,2)->(1,3)->(2,3)->(3,3)->(4,4)->(4,5)->(4,6)->(5,6)
现在让我们看看所有已解决的迷宫和路径 -
# advanced.py (continued)
for x in dfs(c,m):
print(solution(x),end="\n\n")
########
#--- #
###-#L #
# -## #
# #----#
# ####-#
# L e#
########
(1,6)
########
#--- #
###-#L #
#---## #
#-#L #
#-#### #
#-----e#
########
(1,2)->(3,1)->(4,1)->(5,1)->(6,2)->(6,3)->(6,4)->(6,5)
########
#----- #
### #--#
# ##-#
# #L -#
# ####-#
# L e#
########
(1,3)->(1,4)->(1,5)->(2,6)->(3,6)->(4,6)
########
#----- #
### #--#
#---##-#
#-#----#
#-#### #
#-----e#
########
(1,5)
########
#------#
### #L-#
# ##-#
# #L -#
# ####-#
# L e#
########
(1,5)->(1,6)->(2,6)
########
#------#
### #L-#
#---##-#
#-#----#
#-#### #
#-----e#
########
(1,5)
别忘了满足你的愿望!我们可以看到一个新模块 solution
的出现,但这次我们将把它留在同一个文件中 -
# advanced.py (continued)
def to_str(t):
(maze,path) = t
return str(maze) + "\n" + "->".join(map(str,path))
class solution:
def __init__(self,t): self.t = t
def __str__(self): return to_str(self.t)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。