在python中使用递归解决迷宫
所以,我有一个作业,要求我用递归解一个迷宫。我会把作业指导贴出来,这样你就能明白我在说什么了。教授没有对递归进行太多的解释,他给了我们一些递归的例子,我将在这里发布,但我希望有人能给我一个更深入的递归解释,以及我如何将其应用于解决迷宫。我不是要求任何人编写代码,我只是希望一些解释能让我走上正确的道路。感谢所有回答的人 以下是我的例子:在python中使用递归解决迷宫,python,recursion,maze,Python,Recursion,Maze,所以,我有一个作业,要求我用递归解一个迷宫。我会把作业指导贴出来,这样你就能明白我在说什么了。教授没有对递归进行太多的解释,他给了我们一些递归的例子,我将在这里发布,但我希望有人能给我一个更深入的递归解释,以及我如何将其应用于解决迷宫。我不是要求任何人编写代码,我只是希望一些解释能让我走上正确的道路。感谢所有回答的人 以下是我的例子: def foo(): print("Before") bar() print("After")
def foo():
print("Before")
bar()
print("After")
def bar():
print("During")
def factorial(n):
"""n!"""
product = 1
for i in range(n,0,-1):
product *= i
return product
def recFac(n):
"""n! = n * (n-1)!"""
if(n == 1):
return 1
return n * recFac(n-1)
def hello():
"""Stack overflow!"""
hello()
def fib(n):
"""f(n) = f(n-1) + f(n-2)
f(0) = 0
f(1) = 1"""
if n == 0 or n == 1: #base case
return n
return fib(n-1) + fib(n-2) #recursive case
def mult(a,b):
"""a*b = a + a + a + a ..."""
#base case
if (b == 1):
return a
#recursive case
prod = mult(a,b-1)
prod *= a
return prod
def exp(a,b):
"""a ** b = a* a * a * a * a *.... 'b times'"""
#base case
if (b==0):
return 1
if (b == 1):
return a
#recursive case
return exp(a,b-1)*a
def pallindrome(word):
"""Returns True if word is a pallindrome, False otherwise"""
#base case
if word == "" or len(word)==1:
return True
#recursive case
if word[0] == word[len(word)-1]:
word = word[1:len(word)-1]
return pallindrome(word)
else:
return False
以下是指导原则:
def foo():
print("Before")
bar()
print("After")
def bar():
print("During")
def factorial(n):
"""n!"""
product = 1
for i in range(n,0,-1):
product *= i
return product
def recFac(n):
"""n! = n * (n-1)!"""
if(n == 1):
return 1
return n * recFac(n-1)
def hello():
"""Stack overflow!"""
hello()
def fib(n):
"""f(n) = f(n-1) + f(n-2)
f(0) = 0
f(1) = 1"""
if n == 0 or n == 1: #base case
return n
return fib(n-1) + fib(n-2) #recursive case
def mult(a,b):
"""a*b = a + a + a + a ..."""
#base case
if (b == 1):
return a
#recursive case
prod = mult(a,b-1)
prod *= a
return prod
def exp(a,b):
"""a ** b = a* a * a * a * a *.... 'b times'"""
#base case
if (b==0):
return 1
if (b == 1):
return a
#recursive case
return exp(a,b-1)*a
def pallindrome(word):
"""Returns True if word is a pallindrome, False otherwise"""
#base case
if word == "" or len(word)==1:
return True
#recursive case
if word[0] == word[len(word)-1]:
word = word[1:len(word)-1]
return pallindrome(word)
else:
return False
你将要创建一个迷宫爬虫,能够解决任何你用递归的力量给它的迷宫
问题1-加载迷宫
在解迷宫之前,你必须先加载它。对于本作业,您将使用迷宫的简单文本格式。您可以使用此示例迷宫或创建自己的迷宫
这个问题的目的是加载任何给定的迷宫文件,并将其读入二维列表。
例如:loadMaze(“somemaze.maze”)应该加载somemaze.maze文件并创建如下列表
[['#','#','#','#','#','#','#','#','#'],
['#','S','#',' ',' ',' ','#','E','#'],
['#',' ','#',' ','#',' ',' ',' ','#'],
['#',' ',' ',' ','#',' ','#',' ','#'],
['#', #','#','#','#','#','#','#','#']]
请注意,列表中已删除所有“\r”和“\n”字符。为了简化下一个问题,可以将此列表设置为全局变量
接下来编写一个函数,以更好的格式打印迷宫:
例如:
继续之前,请使用不同的迷宫测试代码
问题2-准备解决迷宫
在解决迷宫之前,你需要找到起点!在代码中添加一个名为findStart()的函数,该函数将搜索迷宫(逐个字符),并返回“S”字符的x和y坐标。你可以假设迷宫中最多有一个这样的角色。如果在迷宫中未找到“S”,则返回-1作为x和y坐标
继续之前,在多个位置(包括无位置)使用“S”测试代码
问题3-解决迷宫
最后,您已经准备好递归求解迷宫了!您的解决方案应该只需要一种方法:solve(y,x)
solve方法的单个实例应该可以解决迷宫中的单个位置。参数y和x是要求解的当前坐标。有几件事你的解决方法应该完成。它应该检查当前是否正在解决“E”的位置。在这种情况下,您的求解方法已成功完成。否则,它应该尝试递归地求解右边的空间。注意,您的方法应该只尝试求解空间,而不是墙(“#”)。如果递归没有结束,那么尝试向下、向左和向上。如果所有这些都失败了,代码应该回溯一个步骤,然后尝试另一个方向
最后,在解决迷宫时,您的代码应该留下进度指标。如果它正在右侧搜索,则当前位置应该有一个“>”来代替空白。如果向下搜索,请输入“v”。如果搜索左'len(mazeList)或x>len(mazeList[y]):
返回错误
如果mazeList[y][x]=“E”:
返回真值
如果mazeList[y][x]!=" ":
返回错误
#标记
如果解算(x+1,y)=真:#右
mazeList[x][y]='>'
elif solve(x,y+1)=真:#向下
mazeList[x][y]=“v”
elif solve(x-1,y)=真:#左
mazeList[x][y]='递归实际上是一个简单的想法:为了解决问题,你将问题缩小一步,然后解决简化后的问题。这会一直持续到你遇到一个你知道如何完全解决的“基本问题”。返回基本解决方案,然后添加到每个步骤返回的解决方案中,直到得到完整的解决方案 所以要解n!,我们记住n并求(n-1)!。基本情况是1!,为此,我们返回1;然后在每个返回步骤中,我们乘以记忆中的数字(2*1!是2,3*2!是6,4*3!是24,5*4!是120),直到我们乘以n得到完整解。这实际上是一种相当苍白和贫血的复发;每个步骤只有一个可能的决定。这被称为“尾部递归”,非常容易从内到外转换为迭代解(从1开始,乘以每个数,直到n) 一种更有趣的递归方法是将问题一分为二,解决每一半,然后将两个一半的解决方案结合起来;例如,快速排序通过选取一个项目对列表进行排序,将列表分为“小于项目的所有项目”和“大于项目的所有项目”,每一半进行快速排序,然后返回快速排序(较小)+项目+快速排序(较大)。基本情况是“当我的列表只有一项时,它被排序” 对于迷宫,我们将把问题分为四种方式——如果我从当前位置向右、向左、向上和向下搜索,所有的解决方案都是可能的——特别的是,只有一种递归搜索会真正找到解决方案。基本情况是“我站在E上”,失败情况是“我在墙上”或“我在我已经访问过的空间上”
编辑:出于兴趣,这里有一个OO解决方案(与Python 2.x和3.x兼容): 请注意,给定的赋值有几个非音速元素:
- 它要求使用
函数名,而不是camelCase
下划线\u分隔的
- 它建议使用全局变量,而不是显式地传递数据
- 它要求
在失败时返回标志值,而不是引发异常find\u start
- (和我自己约会时,我在高中的COBOL中确实遇到过这个问题。)
你可以把解决迷宫看作是采取步骤
当你迈出一步时,同样的规则每次都适用。因为每次都应用相同的规则,所以可以对每个步骤使用完全相同的指令集。什么时候
main("somemaze.maze")
#########
#S# #E#
# # # #
# # # #
#########
#########
#S#>>v#E#
#v#^#>>^#
#>>^# # #
#########
def loadMaze():
readIt = open('Maze.txt', 'r')
readLines = readIt.readlines()
global mazeList
mazeList = [list(i.strip()) for i in readLines]
def showMaze():
for i in mazeList:
mazeprint = ''
for j in i:
mazeprint = mazeprint + j
print(mazeprint)
print('\n')
def solve(x,y, mazeList):
mazeList[x][y] = "o"
#Base case
if y > len(mazeList) or x > len(mazeList[y]):
return False
if mazeList[y][x] == "E":
return True
if mazeList[y][x] != " ":
return False
#marking
if solve(x+1,y) == True: #right
mazeList[x][y]= '>'
elif solve(x,y+1) == True: #down
mazeList[x][y]= 'v'
elif solve(x-1,y) == True: #left
mazeList[x][y]= '<'
elif solve(x,y-1) == True: #up
mazeList[x][y]= '^'
else:
mazeList[x][y]= ' '
return (mazeList[x][y]!= ' ')
from collections import namedtuple
Dir = namedtuple("Dir", ["char", "dy", "dx"])
class Maze:
START = "S"
END = "E"
WALL = "#"
PATH = " "
OPEN = {PATH, END} # map locations you can move to (not WALL or already explored)
RIGHT = Dir(">", 0, 1)
DOWN = Dir("v", 1, 0)
LEFT = Dir("<", 0, -1)
UP = Dir("^", -1, 0)
DIRS = [RIGHT, DOWN, LEFT, UP]
@classmethod
def load_maze(cls, fname):
with open(fname) as inf:
lines = (line.rstrip("\r\n") for line in inf)
maze = [list(line) for line in lines]
return cls(maze)
def __init__(self, maze):
self.maze = maze
def __str__(self):
return "\n".join(''.join(line) for line in self.maze)
def find_start(self):
for y,line in enumerate(self.maze):
try:
x = line.index("S")
return y, x
except ValueError:
pass
# not found!
raise ValueError("Start location not found")
def solve(self, y, x):
if self.maze[y][x] == Maze.END:
# base case - endpoint has been found
return True
else:
# search recursively in each direction from here
for dir in Maze.DIRS:
ny, nx = y + dir.dy, x + dir.dx
if self.maze[ny][nx] in Maze.OPEN: # can I go this way?
if self.maze[y][x] != Maze.START: # don't overwrite Maze.START
self.maze[y][x] = dir.char # mark direction chosen
if self.solve(ny, nx): # recurse...
return True # solution found!
# no solution found from this location
if self.maze[y][x] != Maze.START: # don't overwrite Maze.START
self.maze[y][x] = Maze.PATH # clear failed search from map
return False
def main():
maze = Maze.load_maze("somemaze.txt")
print("Maze loaded:")
print(maze)
try:
sy, sx = maze.find_start()
print("solving...")
if maze.solve(sy, sx):
print(maze)
else:
print(" no solution found")
except ValueError:
print("No start point found.")
if __name__=="__main__":
main()
Maze loaded:
####################################
#S# ## ######## # # # # #
# # # # # # #
# # ##### ## ###### # ####### # #
### # ## ## # # # #### #
# # # ####### # ### #E#
####################################
solving...
####################################
#S# ## ######## # #>>>>>v# >>v# #
#v#>>v# >>>v #^# >>>>^#>>v#
#>>^#v#####^##v######^# ####### #v#
### #v##>>>^##>>>>>v#^# # ####v#
# #>>>^# #######>>^# ### #E#
####################################
1. Start at the entrance.
2. Call the function solve(x,y) with the entrance co-ordinates
3. in solve, return false if the input point has already been handled or is a wall.
4. Mark the current point as handled (tag = 'o')
5. go to the right and call solve on that point. If it returns true, set tag to '>'
6 elif do the same for left and '<'
7 elif do the same for up and '^'
8 elif do the same for down and 'v'
9 else this is a false path, set tag = ' '
10 set the current maze point to tag
11 return (tag != ' ')
return(tag != 'o')
import sys
sys.setrecursionlimit(5000)
class Maze(object):
FLOOR = ' '
WALLS = '*'
PATH = '+'
def __init__(self):
self.cols = 0
self.rows = 0
self.maze = []
def walk_forward(self, current_k, r, c):
self.maze[r][c] = current_k
next_k = current_k + 1
# up
if r > 1:
up = self.maze[r - 1][c]
if up != self.WALLS:
if up == self.FLOOR or int(up) > current_k:
self.walk_forward(next_k, r - 1, c)
# down
if r < self.rows - 1:
down = self.maze[r + 1][c]
if down != self.WALLS:
if down == self.FLOOR or int(down) > current_k:
self.walk_forward(next_k, r + 1, c)
# left
if c > 1:
left = self.maze[r][c - 1]
if left != self.WALLS:
if left == self.FLOOR or int(left) > current_k:
self.walk_forward(next_k, r, c - 1)
# right
if c < self.cols - 1:
right = self.maze[r][c + 1]
if right != self.WALLS:
if right == self.FLOOR or int(right) > current_k:
self.walk_forward(next_k, r, c + 1)
def walk_backward(self, r, c):
current_k = self.maze[r][c]
if not isinstance(current_k, int):
return False
self.maze[r][c] = self.PATH
up = self.maze[r - 1][c] if r > 0 else None
down = self.maze[r + 1][c] if r < self.rows - 1 else None
left = self.maze[r][c - 1] if c > 1 else None
right = self.maze[r][c + 1] if c < self.cols else None
passed = False
if up and isinstance(up, int) and up == current_k - 1:
self.walk_backward(r - 1, c)
passed = True
if down and isinstance(down, int) and down == current_k - 1:
self.walk_backward(r + 1, c)
passed = True
if left and isinstance(left, int) and left == current_k - 1:
self.walk_backward(r, c - 1)
passed = True
if right and isinstance(right, int) and right == current_k - 1:
self.walk_backward(r, c + 1)
def cleanup(self, cleanup_path=False):
for r in range(0, self.rows):
for c in range(0, self.cols):
if isinstance(self.maze[r][c], int):
self.maze[r][c] = self.FLOOR
if cleanup_path and self.maze[r][c] == self.PATH:
self.maze[r][c] = self.FLOOR
def solve(self, start='up', show_path=True):
# finding start and finish points
upper = lower = None
for c in range(0, self.cols):
if self.maze[0][c] == self.FLOOR:
upper = (0, c)
break
for c in range(0, self.cols):
if self.maze[self.rows - 1][c] == self.FLOOR:
lower = (self.rows - 1, c)
break
if start == 'up':
start = upper
finish = lower
else:
start = lower
finish = upper
self.cleanup(cleanup_path=True)
self.walk_forward(1, start[0], start[1])
length = self.maze[finish[0]][finish[1]]
if not isinstance(length, int):
length = 0
if show_path:
self.walk_backward(finish[0], finish[1])
self.cleanup(cleanup_path=False)
else:
self.cleanup(cleanup_path=True)
return length
def save_to_file(self, filename):
with open(filename, 'w') as f:
f.writelines(str(self))
def load_from_file(self, filename):
self.maze = []
with open(filename, 'r') as f:
lines = f.readlines()
for line in lines:
row = []
for c in line.strip():
row.append(c)
self.maze.append(row)
self.rows = len(self.maze)
self.cols = len(self.maze[0]) if self.rows > 0 else 0
def get_maze(self):
return copy.copy(self.maze)
def __str__(self):
as_string = u''
for row in self.maze:
as_string += u''.join([str(s)[-1] for s in row]) + "\n"
return as_string
maze = Maze()
maze.load_from_file(sys.argv[1])
maze.solve(show_path=True)
print str(maze)
#import part
import time
import sys
import os
#global values
load = 0 # set initial loading value
walk = [(1,0),(-1,0),(0,1),(0,-1)] # set movements
backtracker = [] # set backtracker (remember that this is a stack)
gmainmaze = [] # set initial blank maze
def initialize(): #loading
sx = 0 # start x value
sy = 0 # start y value
ex = 0 # end x value
ey = 0 # end y value
while load == 0: #just some cool animation
sys.stdout.write("\rloading |")
time.sleep(0.1)
sys.stdout.write("\rloading /")
time.sleep(0.1)
sys.stdout.write("\rloading -")
time.sleep(0.1)
sys.stdout.write("\rloading \\")
time.sleep(0.1)
sys.stdout.write("\r")
mainmaze = loadMaze("maze.txt") # IMPORTANT: load the maze under the same folder named "maze.txt"
print("Maze Loaded")
print(" ")
time.sleep(1)
print(" ")
print("Locating start point...")
sx, sy = spotter(5,mainmaze)
time.sleep(1)
print(" ")
print("Locating end point...")
ex, ey = spotter(3,mainmaze)
print(" ")
time.sleep(1)
return sx, sy, ex, ey, mainmaze;
break
print(" ")
sys.stdout.write("\rInitialized!")
print(" ")
time.sleep(3)
os.system("cls")
def loadMaze(filename):
#load the data from the file into a 2D list
with open(filename) as i:
maze = []
for line in i:
line = line.strip()
spawnmaze = line.split(", ")
maze.append(spawnmaze)
return maze
def spotter(num,maze):
#Locate the 'element' in the maze (this can either be "5" or "3")
num = str(num)
rowcounter = -1
linecounter = 0
for rows in maze:
rowcounter = rowcounter + 1
if num in rows:
for element in rows:
if element == num:
print("Tango Spotted, Grid:", rowcounter, linecounter)
return rowcounter, linecounter;
break
linecounter = linecounter + 1
def valid(maze,x,y): # check if valid
height = len(maze) - 1
width = len(maze[0]) - 1
if 0 <= x <= height and 0 <= y <= width:
return 1
else:
return 0
def solveMaze(sx,sy,ex,ey): # solve maze
global gmainmaze
for i in walk: #try every direction
x = sx + i[0] #make the move
y = sy + i[1]
if valid(gmainmaze,x,y): # check if still in the maze
if x == ex and y == ey: #check if reached destination
print("SITREP:Destination Arrived")
print("The Logistic Path Is:\n",backtracker)
print(" ")
return 1
else:
if gmainmaze[x][y] == "0" and (x,y) not in backtracker: #add to the stack
backtracker.append((x,y))
else:
continue
else:
continue
if solveMaze(x,y,ex,ey) == 1: # Recursion (do the next step)
return 1
else:
continue
go = backtracker.pop(-1) #moveback while
return 0
def printMaze(maze):
for x in range(len(maze)):
for y in range(len(maze[x])):
print(maze[x][y], end=' ')
print("")
def visualize(maze): # a cool function to visualize the maze
for x in range(len(maze)):
for y in range(len(maze[x])):
if maze[x][y] == "5":
maze[x][y] = "╳" # path
elif maze[x][y] == "0":
maze[x][y] = "░" # unbeen path
elif maze[x][y] == "1":
maze[x][y] = "█" # wall
elif maze[x][y] == "3":
maze[x][y] = "╳" # basically path as well
print(maze[x][y], end=' ')
print("")
def main():
#initialize the maze
sx, sy, ex, ey, mainmaze = initialize()
global gmainmaze
gmainmaze = mainmaze
load = 1
#solve the maze
gmainmaze[sx][sy] = "0"
gmainmaze[ex][ey] = "0" # change the start and end into "0" to make it a way
solveMaze(sx,sy,ex,ey)
for i in backtracker:
gmainmaze[i[0]][i[1]] = "5"
gmainmaze[sx][sy] = "5"
gmainmaze[ex][ey] = "3" # change the start and end back
#print the maze
width = len(gmainmaze[0]) - 1
print("Check Your Map...")
print("Map:")
print("--"*(width+1))
printMaze(gmainmaze)
print("--"*(width+1))
#visualize the maze uncomment to establish the function (btw check if your terminal can print these unicodes)
#visualize(gmainmaze)
time.sleep(5)
main()
© 2020 GitHub, Inc.