本文使用递归,非递归,深度优先,广度优先,算法探索迷宫,且用Python turtle包绘制出迷宫,使迷宫过程可视化
迷宫类
# 迷宫类
class Maze(object):
# 读取迷宫数据,初始化迷宫内部,并找到海龟初始位置。
def __init__(self, mazeFileName):
rowsInMaze = 0 #初始化迷宫行数
columnsInMaze = 0 #初始化迷宫列数
self.mazelist = [] #初始化迷宫列表
mazeFile = open(mazeFileName, 'r') #读取迷宫文件
for line in mazeFile: #按行读取
rowList = [] #初始化行列表
col = 0 #初始化列
# for ch in line[:-1]: #这样会丢失最后一列
for ch in line: #按列读取
rowList.append(ch) #添加到行列表
if ch == 'S': #S为乌龟初始位置,即迷宫起点
self.startRow = rowsInMaze #乌龟初始行
self.startCol = col #乌龟初始列
col = col + 1 #下一列
rowsInMaze = rowsInMaze + 1 #下一行
self.mazelist.append(rowList) #行列表添加到迷宫列表
columnsInMaze = len(rowList) #获取迷宫总列数
self.rowsInMaze = rowsInMaze #设置迷宫总行数
self.columnsInMaze = columnsInMaze #设置迷宫总列数
self.xTranslate = -columnsInMaze/2 #设置迷宫左上角的初始x坐标
self.yTranslate = rowsInMaze/2 #设置迷宫左上角的初始y坐标
self.t = turtle.Turtle() #创建一个海龟对象
self.t.shape('turtle') #给当前指示点设置样式(类似鼠标箭头),海龟形状为参数指定的形状名,指定的形状名应存在于TurtleScreen的shape字典中。多边形的形状初始时有以下几种:"arrow", "turtle", "circle", "square", "triangle", "classic"。
self.wn = turtle.Screen() #创建一个能在里面作图的窗口
self.wn.setworldcoordinates(-columnsInMaze/2, -rowsInMaze/2, columnsInMaze/2, rowsInMaze/2) #设置世界坐标系,原点在迷宫正中心。参数依次为画布左下角x轴坐标、左下角y轴坐标、右上角x轴坐标、右上角y轴坐标
# 在屏幕上绘制迷宫
def drawMaze(self):
self.t.speed(20) #绘图速度
for y in range(self.rowsInMaze): #按单元格依次循环迷宫
for x in range(self.columnsInMaze):
if self.mazelist[y][x] == OBSTACLE: #如果迷宫列表的该位置为障碍物,则画方块
self.drawCenteredBox(x + self.xTranslate, -y + self.yTranslate, 'orange')
# 画方块
def drawCenteredBox(self, x, y, color):
self.t.up() #画笔抬起
self.t.goto(x - 0.5, y - 0.5) #前往参数位置,此处0.5偏移量的作用是使乌龟的探索路线在单元格的正中心位置
self.t.color(color) #方块边框为橙色
self.t.fillcolor('green') #方块内填充绿色
self.t.setheading(90) #设置海龟的朝向,标准模式:0 - 东,90 - 北,180 - 西,270 - 南。logo模式:0 - 北,90 - 东,180 - 南,270 - 西。
self.t.down() #画笔落下
self.t.begin_fill() #开始填充
for i in range(4): #画方块边框
self.t.forward(1) #前进1个单位
self.t.right(90) #右转90度
self.t.end_fill() #结束填充
# 移动海龟
def moveTurtle(self, x, y):
self.t.up() #画笔抬起
self.t.setheading(self.t.towards(x + self.xTranslate, -y + self.yTranslate)) #setheading()设置海龟朝向,towards()从海龟位置到由(x, y),矢量或另一海龟位置连线的夹角。此数值依赖于海龟初始朝向,由"standard"、"world"或"logo" 模式设置所决定。
self.t.goto(x + self.xTranslate, -y + self.yTranslate) #前往目标位置
# 画路径圆点
def dropBreadcrumb(self, color):
self.t.dot(color) #dot(size=None, color)画路径圆点
# 用以更新迷宫内的状态及在窗口中改变海龟位置,行列参数为乌龟的初始坐标。
def updatePosition(self, row, col, val):
self.mazelist[row][col] = val #设置该标记状态为当前单元格的值
self.moveTurtle(col, row) #移动海龟
if val == PART_OF_PATH: #其中一条成功路径的圆点的颜色
color = 'green'
elif val == TRIED: #尝试用的圆点的颜色
color = 'black'
elif val == DEAD_END: #死胡同用的圆点的颜色
color = 'red'
self.dropBreadcrumb(color) #画路径圆点并上色
# 用以判断当前位置是否为出口。
def isExit(self, row, col):
# 根据海龟位置是否在迷宫的4个边线位置判断
# return (row == 0 or row == self.rowsInMaze - 1 or col == 0 or col == self.columnsInMaze - 1)
return self.mazelist[row][col] == '0'
# 返回键对应的值,影响searchFrom()中maze[startRow][startColumn]值的获取
def __getitem__(self, key):
return self.mazelist[key]
# 将mazelist的内容写入到文件中
def save(self,mazeFileName):
self.mazelist[self.startRow][self.startCol] = 's'
with open(mazeFileName, 'w',encoding='utf-8') as fp:
str = ''
for rowlist in self.mazelist:
for ch in rowlist:
str += ch
fp.write(str)
str = ''
解析:重点讲一下save成员函数,后面的三种算法更新位置都是更新迷宫类中的mazelist,在探索迷宫后,利用save即可将mazelist写入到文件中,得到迷宫的解。
走迷宫算法中会用的栈和队列,下面是栈和队列的实现
栈类
# 栈 右边为栈顶
class Stark:
def __init__(self):
self.stark_list = []
def push(self, item):
self.stark_list.append(item)
def pop(self):
return self.stark_list.pop()
def peek(self):
return self.stark_list[-1]
def is_empty(self):
return self.stark_list == []
def size(self):
return len(self.stark_list)
def show(self):
print(self.stark_list)
队列
# 队列
class Queue:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def push(self,item):
self.items.insert(0,item)
def pop(self):
return self.items.pop()
def size(self):
return len(self.items)
def show(self):
print(self.items)
递归求解
递归求解的基本思路是:
走迷宫问题可化为若干个子问题,向某个方向走一格,然后以当前点为起点走迷宫,再向某个方向走一格,再以当前点为起点走迷宫......直到当前点就是起点结束递归
详细为:
判断当前点是不是障碍或者已走过的路径,如果是则结束此次递归调用
判断当前点是不是出口,如果是则结束整个函数递归
更新当前点的位置,更新为已走过的路径
依次尝试四个方向,进入更深一层的递归
def searchFrom(maze, startRow, startColumn):
# 从初始位置开始尝试四个方向,直到找到出路。
# 1. 遇到障碍
if maze[startRow][startColumn] == OBSTACLE:
return False
# 2. 发现已经探索过的路径或死胡同
if maze[startRow][startColumn] == TRIED or maze[startRow][startColumn] == DEAD_END:
return False
# 3. 发现出口
if maze.isExit(startRow, startColumn):
maze.updatePosition(startRow, startColumn, PART_OF_PATH)#显示出口位置,注释则不显示此点
return True
maze.updatePosition(startRow, startColumn, TRIED)#更新迷宫状态、设置海龟初始位置并开始尝试
# 4. 依次尝试每个方向
found = searchFrom(maze, startRow - 1, startColumn) or \
searchFrom(maze, startRow + 1, startColumn) or \
searchFrom(maze, startRow, startColumn - 1) or \
searchFrom(maze, startRow, startColumn + 1)
if found: #找到出口
maze.updatePosition(startRow, startColumn, PART_OF_PATH)#返回其中一条正确路径
else: #4个方向均是死胡同
maze.updatePosition(startRow, startColumn, DEAD_END)
return found
注:代码中found 的部分会在searchForm结束调用后,根据四个方向的探索结果,更新上一层函数探索的点位,其主要作用是为了将正确路径返回到迷宫文件中(后面会提到),与走迷宫关系不大,没有这一步也可以走迷宫,只是拿不到走迷宫的路径。
非递归求解
深度优先算法(利用栈)
深度优先算法的思路与递归算法无二,毕竟所有的递归算法都可以用栈改写为非递归算法
基本思路:
在此算法中,主要是用栈来存储可以探索的位置。利用栈后进先出的特点,在一条分路上探索失败时,回到最近一次存储的可探索位置,然后继续探索。
详细为:
判断当前点是不是出口,是的话就结束循环
判断当前点是不是以探索过的路径,是的话就弹出栈,回到上一个位置探索剩余方向,如果没有剩余探索方向继续弹出栈,直到回到有可以探索的方向
如果不是以前探索过过的路径,就在当前点依次探索四个方向,并且把当前位置入栈
def searchFrom_non_rec(maze, startRow, startColumn):
sta = Stark()
sta.push((startRow,startColumn))
find = False
while not sta.is_empty():
temp = sta.peek()
# 1.判断当前点是不是出口
if maze.isExit(temp[0],temp[1]):
find = True
break
# 2. 发现已经探索过的路径 回退专用,因为我判断的存在,我不可能进入已经走过的路径
if maze[temp[0]][temp[1]] == TRIED:
sta.pop()
temp = sta.peek()
# 3. 依次尝试每个方向
if maze[temp[0]][temp[1] + 1] != TRIED and maze[temp[0]][temp[1] + 1] != OBSTACLE:
sta.push((temp[0], temp[1] + 1))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
elif maze[temp[0]][temp[1] - 1] != TRIED and maze[temp[0]][temp[1] - 1] != OBSTACLE:
sta.push((temp[0], temp[1] - 1))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
elif maze[temp[0] + 1][temp[1]] != TRIED and maze[temp[0] + 1][temp[1]] != OBSTACLE:
sta.push((temp[0] + 1, temp[1]))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
elif maze[temp[0] - 1][temp[1]] != TRIED and maze[temp[0] - 1][temp[1]] != OBSTACLE:
sta.push((temp[0] - 1, temp[1]))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
else:
maze.updatePosition(temp[0], temp[1], TRIED)
continue
if find:
# 找到后依次弹出栈中元素
while not sta.is_empty():
temp = sta.peek()
maze.updatePosition(temp[0], temp[1], PART_OF_PATH)
sta.pop()
continue
注:本代码中的find部分是在找到出口后,依次弹出栈中位置,并更新位置为迷宫解路径的一部分,是为了得到迷宫的解所用,与走迷宫无关
广度优先算法(利用队列)(最短路径问题)
在本算法中我们要新定义一个节点类来辅助我们走迷宫,来得到迷宫的解
最短路径节点类
# 最短路径节点类
class Node():
def __init__(self,row,col,fat,st): # xy为当前位置,fat为父节点,st为当前步数
self.row_cur = row
self.col_cur = col
self.father = fat
self.step = st
解析:三个值,一个为当前位置,一个为父节点,一个为已走步数
不同于深度优先算法和递归算法的一条路走到黑,不碰墙壁不回头,广度优先算法是以入口为中心,一层层往外铺,就像打水漂泛起的涟漪
基本思路:
队列求解算法中,以队列存储可以探索的位置。利用队列先进先出的特点,实现在每个分支上同时进行搜索路径,直到找到出口。这是一种广度优先搜索的方法。
详细为:
从队列中弹出元素,判断当前点是不是出口,如果是出口就结束循环,否则标记当前点为已探索过路径
探索四个方向,新节点已当前节点为父节点入队列,四个方向能探索的都要探索到(不同于深度优先四个方向是if,elif 的关系,这四个方向都为if)
def search_short_path(maze, startRow, startColumn):
find = False
que = Queue()
# 1.用起点节点初始化列表
node = Node(startRow,startColumn,None,0)
que.push(node)
# 2.依次处理链表中数据,当某个节点的下一个元素是出口时停止,并保留此元素
while(not que.is_empty()):
node = que.pop()
if maze[node.row_cur][node.col_cur] == '0':
find = True
break
maze[node.row_cur][node.col_cur] = TRIED
# 向下
if maze[node.row_cur+1][node.col_cur] != OBSTACLE and maze[node.row_cur+1][node.col_cur] != TRIED:
new_node = Node(node.row_cur + 1,node.col_cur,node,node.step+1)
que.push(new_node)
# 向上
if maze[node.row_cur-1][node.col_cur] != OBSTACLE and maze[node.row_cur-1][node.col_cur] != TRIED:
new_node = Node(node.row_cur - 1, node.col_cur, node, node.step + 1)
que.push(new_node)
# 向右
if maze[node.row_cur][node.col_cur+1] != OBSTACLE and maze[node.row_cur][node.col_cur+1] != TRIED:
new_node = Node(node.row_cur, node.col_cur + 1, node, node.step + 1)
que.push(new_node)
# 向左
if maze[node.row_cur][node.col_cur-1] != OBSTACLE and maze[node.row_cur][node.col_cur-1] != TRIED:
new_node = Node(node.row_cur, node.col_cur - 1, node, node.step + 1)
que.push(new_node)
if find:
# 3.一直找此元素的父节点,入栈
sta = Stark()
while (node.father):
sta.push((node.row_cur, node.col_cur))
node = node.father
# 4.用栈中提供的位置控制乌龟移动
while(not sta.is_empty()):
temp = sta.pop()
maze.updatePosition(temp[0], temp[1], PART_OF_PATH)
注:此代码中的find部分一样是为了得到迷宫的解而写。利用得到出口的节点,一步步往前找其父节点,并将其父节点的坐标压栈,然后一步步弹出栈,将其坐标更新为路径的一部分,得到迷宫的解
迷宫的实现(利用文件)
此案例中的迷宫使用文件实现,迷宫类的初始化会从文件中读取迷宫
PART_OF_PATH = '*' # 部分路径
TRIED = '.' # 尝试
OBSTACLE = '+' # 障碍
DEAD_END = '-' # 死胡同 非递归不用死胡同
示例代码:
s为出生点,0为出口
++++++++++++++++++++++
+ ++ ++ 0
+ + + ++++++++
+ + + ++ + +++++ ++
+ +++++ +++ + +
+ ++++ + + +
+++++ + + + + +
+++++ +++ + + ++ +
+ + + S+ ++ +
+++++ + + + + +
++++++++++++++++++++++
随机迷宫实现:
随机迷宫还是写在文件中,整个案例都是从文件中读取迷宫
这个随机迷宫实现存在三个问题:
存在空心墙
有时出口会被堵死
出生点和出口的位置都是固定的
因为博主懒,此案例只是应付课程设计,所以没有去解决这三个问题
def produce_maze(maze_name:str):
my_dict = {1:'+',2:' ',3:' '}
maze_list = []
# 1.列表中随机填入障碍和通路
for x in range(15):
row_list = []
for y in range(15):
row_list.append(my_dict[random.randint(1, 3)])
maze_list.append(row_list)
# 2.最外圈改为墙壁
for x in range(15):
maze_list[0][x] = '+'
maze_list[14][x] = '+'
maze_list[x][0] = '+'
maze_list[x][14] = '+'
# 3.最外圈加入出口
# 4.随机一点加入出生地
# 固定利于走迷宫
maze_list[3][0] = '0'
maze_list[11][11] = 'S'
# 5.将列表写入文件
with open(maze_name, 'w', encoding='utf-8') as fp:
str = ''
for rowlist in maze_list:
for ch in rowlist:
str += ch
str+='\n'
fp.write(str)
str = ''
解析:简单的列表个点生成随机数1,2,3。1对应墙壁,2,3对应路径,再讲最外层一圈设置为墙壁,再开孔为出口,设置一点为出生点,最后写入文件中
全部代码,案例实现
import turtle
import random
# 栈 右边为栈顶
class Stark:
def __init__(self):
self.stark_list = []
def push(self, item):
self.stark_list.append(item)
def pop(self):
return self.stark_list.pop()
def peek(self):
return self.stark_list[-1]
def is_empty(self):
return self.stark_list == []
def size(self):
return len(self.stark_list)
def show(self):
print(self.stark_list)
# 队列
class Queue:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def push(self,item):
self.items.insert(0,item)
def pop(self):
return self.items.pop()
def size(self):
return len(self.items)
def show(self):
print(self.items)
# 最短路径节点类
class Node():
def __init__(self,row,col,fat,st): # xy为当前位置,fat为父节点,st为当前步数
self.row_cur = row
self.col_cur = col
self.father = fat
self.step = st
# 迷宫类
class Maze(object):
# 读取迷宫数据,初始化迷宫内部,并找到海龟初始位置。
def __init__(self, mazeFileName):
rowsInMaze = 0 #初始化迷宫行数
columnsInMaze = 0 #初始化迷宫列数
self.mazelist = [] #初始化迷宫列表
mazeFile = open(mazeFileName, 'r') #读取迷宫文件
for line in mazeFile: #按行读取
rowList = [] #初始化行列表
col = 0 #初始化列
# for ch in line[:-1]: #这样会丢失最后一列
for ch in line: #按列读取
rowList.append(ch) #添加到行列表
if ch == 'S': #S为乌龟初始位置,即迷宫起点
self.startRow = rowsInMaze #乌龟初始行
self.startCol = col #乌龟初始列
col = col + 1 #下一列
rowsInMaze = rowsInMaze + 1 #下一行
self.mazelist.append(rowList) #行列表添加到迷宫列表
columnsInMaze = len(rowList) #获取迷宫总列数
self.rowsInMaze = rowsInMaze #设置迷宫总行数
self.columnsInMaze = columnsInMaze #设置迷宫总列数
self.xTranslate = -columnsInMaze/2 #设置迷宫左上角的初始x坐标
self.yTranslate = rowsInMaze/2 #设置迷宫左上角的初始y坐标
self.t = turtle.Turtle() #创建一个海龟对象
self.t.shape('turtle') #给当前指示点设置样式(类似鼠标箭头),海龟形状为参数指定的形状名,指定的形状名应存在于TurtleScreen的shape字典中。多边形的形状初始时有以下几种:"arrow", "turtle", "circle", "square", "triangle", "classic"。
self.wn = turtle.Screen() #创建一个能在里面作图的窗口
self.wn.setworldcoordinates(-columnsInMaze/2, -rowsInMaze/2, columnsInMaze/2, rowsInMaze/2) #设置世界坐标系,原点在迷宫正中心。参数依次为画布左下角x轴坐标、左下角y轴坐标、右上角x轴坐标、右上角y轴坐标
# 在屏幕上绘制迷宫
def drawMaze(self):
self.t.speed(20) #绘图速度
for y in range(self.rowsInMaze): #按单元格依次循环迷宫
for x in range(self.columnsInMaze):
if self.mazelist[y][x] == OBSTACLE: #如果迷宫列表的该位置为障碍物,则画方块
self.drawCenteredBox(x + self.xTranslate, -y + self.yTranslate, 'orange')
# 画方块
def drawCenteredBox(self, x, y, color):
self.t.up() #画笔抬起
self.t.goto(x - 0.5, y - 0.5) #前往参数位置,此处0.5偏移量的作用是使乌龟的探索路线在单元格的正中心位置
self.t.color(color) #方块边框为橙色
self.t.fillcolor('green') #方块内填充绿色
self.t.setheading(90) #设置海龟的朝向,标准模式:0 - 东,90 - 北,180 - 西,270 - 南。logo模式:0 - 北,90 - 东,180 - 南,270 - 西。
self.t.down() #画笔落下
self.t.begin_fill() #开始填充
for i in range(4): #画方块边框
self.t.forward(1) #前进1个单位
self.t.right(90) #右转90度
self.t.end_fill() #结束填充
# 移动海龟
def moveTurtle(self, x, y):
self.t.up() #画笔抬起
self.t.setheading(self.t.towards(x + self.xTranslate, -y + self.yTranslate)) #setheading()设置海龟朝向,towards()从海龟位置到由(x, y),矢量或另一海龟位置连线的夹角。此数值依赖于海龟初始朝向,由"standard"、"world"或"logo" 模式设置所决定。
self.t.goto(x + self.xTranslate, -y + self.yTranslate) #前往目标位置
# 画路径圆点
def dropBreadcrumb(self, color):
self.t.dot(color) #dot(size=None, color)画路径圆点
# 用以更新迷宫内的状态及在窗口中改变海龟位置,行列参数为乌龟的初始坐标。
def updatePosition(self, row, col, val):
self.mazelist[row][col] = val #设置该标记状态为当前单元格的值
self.moveTurtle(col, row) #移动海龟
if val == PART_OF_PATH: #其中一条成功路径的圆点的颜色
color = 'green'
elif val == TRIED: #尝试用的圆点的颜色
color = 'black'
elif val == DEAD_END: #死胡同用的圆点的颜色
color = 'red'
self.dropBreadcrumb(color) #画路径圆点并上色
# 用以判断当前位置是否为出口。
def isExit(self, row, col):
# 根据海龟位置是否在迷宫的4个边线位置判断
# return (row == 0 or row == self.rowsInMaze - 1 or col == 0 or col == self.columnsInMaze - 1)
return self.mazelist[row][col] == '0'
# 返回键对应的值,影响searchFrom()中maze[startRow][startColumn]值的获取
def __getitem__(self, key):
return self.mazelist[key]
def save(self,mazeFileName):
self.mazelist[self.startRow][self.startCol] = 's'
with open(mazeFileName, 'w',encoding='utf-8') as fp:
str = ''
for rowlist in self.mazelist:
for ch in rowlist:
str += ch
fp.write(str)
str = ''
# 探索迷宫,注意此函数包括三个参数:一个迷宫对象、起始行、起始列。
def searchFrom(maze, startRow, startColumn):
# 从初始位置开始尝试四个方向,直到找到出路。
# 1. 遇到障碍
if maze[startRow][startColumn] == OBSTACLE:
return False
# 2. 发现已经探索过的路径或死胡同
if maze[startRow][startColumn] == TRIED or maze[startRow][startColumn] == DEAD_END:
return False
# 3. 发现出口
if maze.isExit(startRow, startColumn):
maze.updatePosition(startRow, startColumn, PART_OF_PATH)#显示出口位置,注释则不显示此点
return True
maze.updatePosition(startRow, startColumn, TRIED)#更新迷宫状态、设置海龟初始位置并开始尝试
# 4. 依次尝试每个方向
found = searchFrom(maze, startRow - 1, startColumn) or \
searchFrom(maze, startRow + 1, startColumn) or \
searchFrom(maze, startRow, startColumn - 1) or \
searchFrom(maze, startRow, startColumn + 1)
if found: #找到出口
maze.updatePosition(startRow, startColumn, PART_OF_PATH)#返回其中一条正确路径
else: #4个方向均是死胡同
maze.updatePosition(startRow, startColumn, DEAD_END)
return found
def searchFrom_non_rec(maze, startRow, startColumn):
sta = Stark()
sta.push((startRow,startColumn))
find = False
while not sta.is_empty():
temp = sta.peek()
# 1.判断当前点是不是出口
if maze.isExit(temp[0],temp[1]):
find = True
break
# 2. 发现已经探索过的路径 回退专用,因为我判断的存在,我不可能进入已经走过的路径
if maze[temp[0]][temp[1]] == TRIED:
sta.pop()
temp = sta.peek()
# 3. 依次尝试每个方向
if maze[temp[0]][temp[1] + 1] != TRIED and maze[temp[0]][temp[1] + 1] != OBSTACLE:
sta.push((temp[0], temp[1] + 1))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
elif maze[temp[0]][temp[1] - 1] != TRIED and maze[temp[0]][temp[1] - 1] != OBSTACLE:
sta.push((temp[0], temp[1] - 1))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
elif maze[temp[0] + 1][temp[1]] != TRIED and maze[temp[0] + 1][temp[1]] != OBSTACLE:
sta.push((temp[0] + 1, temp[1]))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
elif maze[temp[0] - 1][temp[1]] != TRIED and maze[temp[0] - 1][temp[1]] != OBSTACLE:
sta.push((temp[0] - 1, temp[1]))
maze.updatePosition(temp[0], temp[1], TRIED)
continue
else:
maze.updatePosition(temp[0], temp[1], TRIED)
continue
if find:
# 找到后依次弹出栈中元素
while not sta.is_empty():
temp = sta.peek()
maze.updatePosition(temp[0], temp[1], PART_OF_PATH)
sta.pop()
continue
def search_short_path(maze, startRow, startColumn):
find = False
que = Queue()
# 1.用起点节点初始化列表
node = Node(startRow,startColumn,None,0)
que.push(node)
# 2.依次处理链表中数据,当某个节点的下一个元素是出口时停止,并保留此元素
while(not que.is_empty()):
node = que.pop()
if maze[node.row_cur][node.col_cur] == '0':
find = True
break
maze[node.row_cur][node.col_cur] = TRIED
# 向下
if maze[node.row_cur+1][node.col_cur] != OBSTACLE and maze[node.row_cur+1][node.col_cur] != TRIED:
new_node = Node(node.row_cur + 1,node.col_cur,node,node.step+1)
que.push(new_node)
# 向上
if maze[node.row_cur-1][node.col_cur] != OBSTACLE and maze[node.row_cur-1][node.col_cur] != TRIED:
new_node = Node(node.row_cur - 1, node.col_cur, node, node.step + 1)
que.push(new_node)
# 向右
if maze[node.row_cur][node.col_cur+1] != OBSTACLE and maze[node.row_cur][node.col_cur+1] != TRIED:
new_node = Node(node.row_cur, node.col_cur + 1, node, node.step + 1)
que.push(new_node)
# 向左
if maze[node.row_cur][node.col_cur-1] != OBSTACLE and maze[node.row_cur][node.col_cur-1] != TRIED:
new_node = Node(node.row_cur, node.col_cur - 1, node, node.step + 1)
que.push(new_node)
if find:
# 3.一直找此元素的父节点,入栈
sta = Stark()
while (node.father):
sta.push((node.row_cur, node.col_cur))
node = node.father
# 4.用栈中提供的位置控制乌龟移动
while(not sta.is_empty()):
temp = sta.pop()
maze.updatePosition(temp[0], temp[1], PART_OF_PATH)
def produce_maze(maze_name:str):
my_dict = {1:'+',2:' ',3:' '}
maze_list = []
# 1.列表中随机填入障碍和通路
for x in range(15):
row_list = []
for y in range(15):
row_list.append(my_dict[random.randint(1, 3)])
maze_list.append(row_list)
# 2.最外圈改为墙壁
for x in range(15):
maze_list[0][x] = '+'
maze_list[14][x] = '+'
maze_list[x][0] = '+'
maze_list[x][14] = '+'
# 3.最外圈加入出口
# 4.随机一点加入出生地
# 固定利于走迷宫
maze_list[3][0] = '0'
maze_list[11][11] = 'S'
# 5.将列表写入文件
with open(maze_name, 'w', encoding='utf-8') as fp:
str = ''
for rowlist in maze_list:
for ch in rowlist:
str += ch
str+='\n'
fp.write(str)
str = ''
PART_OF_PATH = '*' # 部分路径
TRIED = '.' # 尝试
OBSTACLE = '+' # 障碍
DEAD_END = '-' # 死胡同 非递归不用死胡同
def test():
myMaze = Maze('maze.txt') # 实例化迷宫类,maze文件是使用“+”字符作为墙壁围出空心正方形空间,并用字母“S”来表示起始位置的迷宫文本文件。
myMaze.drawMaze() # 在屏幕上绘制迷宫。
searchFrom_non_rec(myMaze, myMaze.startRow, myMaze.startCol) # 探索迷宫
myMaze.save('maze_result.txt')
def test1(): # 随机迷宫
produce_maze('maze1.txt') # 向文件maze1.txt中写入随机迷宫
myMaze = Maze('maze1.txt') # 实例化迷宫类,maze文件是使用“+”字符作为墙壁围出空心正方形空间,并用字母“S”来表示起始位置的迷宫文本文件。
myMaze.drawMaze() # 在屏幕上绘制迷宫。
searchFrom_non_rec(myMaze, myMaze.startRow, myMaze.startCol) # 探索迷宫
myMaze.save('maze1_result.txt')
def test2():
myMaze = Maze('maze.txt') # 实例化迷宫类,maze文件是使用“+”字符作为墙壁围出空心正方形空间,并用字母“S”来表示起始位置的迷宫文本文件。
myMaze.drawMaze() # 在屏幕上绘制迷宫。
search_short_path(myMaze, myMaze.startRow, myMaze.startCol) # 探索迷宫
myMaze.save('maze_result.txt')
if __name__ == '__main__':
# test() # 深度优先走迷宫
# test1() # 随机迷宫+深度优先走迷宫
# test2() # 最短路径走迷宫
最后祝愿各位学业有成