采用递归与栈结合的方式实现迷宫分析与走迷宫(python3)
生活随笔
收集整理的這篇文章主要介紹了
采用递归与栈结合的方式实现迷宫分析与走迷宫(python3)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、場景
1.?General presentation
2.Examples
The file named maze_1.txt has the following contents.
?
二、題目分析
題目首先給了我們一個迷宮,要我門做兩件事:
第一件事:分析迷宮
第二件事:在分析的基礎上畫迷宮
對于迷宮的分析:
所謂的迷宮只給了我們一些數字,數字的范圍是0-3。
0:代表當前這個點與右邊和下面都不相連;
1:代表這個點和和右面的點相連;
2:代表這個點和和下面的點相連;
3:代表這個點和下面與右面的點相連。
通過一個二維數組,可以將迷宮的墻確定下來。
在上圖中,藍色的線就是迷宮的墻,所給文件的第一個數字是1,所以在迷宮中,第一行的第一個點和第一行的第二個點相連。
第一件事:分析迷宮:分析六個數據
1.分析迷宮有多少個門,也可以說是迷宮有多少個入口。
2.分析迷宮有多少個墻體集合.
3.分析迷宮有多少不可達區域,也可以說有多少個死角塊,也就是某一塊是死的,從外面進不來.
4.分析迷宮中有多少個可達區域.
5.分析迷宮中有多少個紅叉X
6.分析迷宮有多少條路徑即圖中黃色路線有多少條
第二件事:畫圖
1.畫藍線
2.畫綠點
3.畫紅叉
4.畫黃線
題目輸入與輸出要求
輸入:
迷宮由數字的文件組成的.
輸出:
1.六項分析結果
2.一個latex文件
迷宮的建立來自文件maze_1.txt:
1 0 2 2 1 2 3 0 3 2 2 1 2 0 2 2 3 0 1 1 3 1 0 0 2 0 3 0 0 1 2 0 3 2 2 0 1 2 3 2 1 0 0 1 1 0 0 0?以上文件規定了墻體的連線.
三、編寫代碼
class MazeError(Exception):def __init__(self, value):self.value = valueclass Road:up = Truedown = Trueleft = Trueright = Trueis_border = Falsedef __init__(self, up, down, left, right):self.up = upself.down = downself.left = leftself.right = rightclass Maze:file_name = ""model = [1, 2, 3, 0, "0", "1", "2", "3"]result = [0, 0, 0, 0, 0, 0, 0] # 記錄結果maze = list() # 最初的迷宮b_maze = list() # 擴大的迷宮road = list() # 路徑b_road = list() # 擴大的路徑viewed = list() # 記錄路的訪問對應第5項viewed6 = list() # 記錄唯一路徑的訪問對應第6項viewed4 = list() # 記錄路的連通訪問對應第4項viewed3 = list() # 記錄封閉點site_view = list() # 記錄點的訪問entry = list() # 記錄死角個數death = 0 # 記錄封閉路的個數death_list = list() # 記錄封閉路的起點success_path_start = list() # 記錄能夠走出去的路徑的起始點temp = list() # 臨時存儲一條走出去的路徑包括的點path = list() # 存儲所有路徑的經過的點walls = list() # 畫圖的墻pillars = list() # 畫圖的點inner_points = list() # 畫X的塊entry_exit_paths = list() # 畫路徑def __init__(self, file_name):# 讀取file到數組maze里面,存儲所有墻體信息self.file_name = file_namefile = open(file_name).readlines()for line in file:a = list()for i in line:if i in self.model:a.append(i)if len(a) > 0:self.maze.append(a)# print(self.maze)# 檢測maze是否滿足條件self.check()# 擴大邊界,和初始化點的訪問for line in self.maze:b = list()b.append("0")x_site_view = list()x_site_view.append(False)for i in line:b.append(i)x_site_view.append(False)b.append("0")x_site_view.append(False)self.b_maze.append(b)self.site_view.append(x_site_view)tmp = list()for i in range(len(self.maze[0])):tmp.append(False)self.site_view.insert(0, tmp)self.site_view.append(tmp)self.b_maze.insert(0, ["0"] * len(self.b_maze[0]))self.b_maze.append(["0"]*len(self.b_maze[0]))# 根據墻體信息,設置路徑信息# 以每個點的左上角的點為基準,讀取其余影響該方格的點for y in range(len(self.maze)-1):x_line = list()for x in range(len(self.maze[0])-1):up = Truedown = Trueleft = Trueright = Trueif self.maze[y][x] == '1':up = Falseelif self.maze[y][x] == '2':left = Falseelif self.maze[y][x] == '3':up = Falseleft = Falseif self.maze[y+1][x] == "1" or self.maze[y+1][x] == "3":down = Falseif self.maze[y][x+1] == "2" or self.maze[y][x+1] == "3":right = Falseroad = Road(up, down, left, right)x_line.append(road)self.road.append(x_line)# 擴大路徑,并初始化路徑的訪問for y in self.road:x_line = list()road = Road(True, True, True, True)road.is_border = Truex_line.append(road)for x in y:x_line.append(x)x_line.append(road)self.b_road.append(x_line)temp = list()for _ in self.b_road[0]:road = Road(True, True, True, True)road.is_border = Truetemp.append(road)self.b_road.insert(0, temp)self.b_road.append(temp)# 畫圖初始化self.pillars.append("% Pillars\n")self.inner_points.append("% Inner points in accessible cul-de-sacs\n")self.entry_exit_paths.append("% Entry-exit paths without intersections\n")def check(self):length = len(self.maze[0])for i in self.maze:if len(i) != length:raise MazeError("Incorrect input.")for i in self.maze[len(self.maze)-1]:if i in ["2", "3"]:raise MazeError("Input does not represent a maze.")for i in range(len(self.maze)):if self.maze[i][len(self.maze[0])-1] in ["3", "1"]:raise MazeError("Input does not represent a maze.")def init_road_view(self):self.viewed = list()self.viewed6 = list()self.viewed4 = list()self.viewed3 = list()for y in self.b_road:x_viewed = list()x_viewed6 = list()x_viewed4 = list()x_viewed3 = list()for _ in y:x_viewed.append(False)x_viewed6.append(False)x_viewed4.append(False)x_viewed3.append(False)self.viewed.append(x_viewed)self.viewed6.append(x_viewed6)self.viewed4.append(x_viewed4)self.viewed3.append(x_viewed3)def analyse(self):self.init_road_view()self.analyse_gates() # 1self.analyse_wall_sets() # 2self.analyse_sets() # 5self.analyse_path() # 6self.analyse_accessible_areas() # 4self.analyse_inner_points() # 3self.print_result()# 分析第一項:分析迷宮有多少個門def analyse_gates(self):# 分四條邊考慮count = 0for i in self.road[0]:if i.up is True:count += 1for i in self.road[len(self.road)-1]:if i.down is True:count += 1for j in range(len(self.road)):if self.road[j][0].left is True:count += 1if self.road[j][len(self.road[0])-1].right is True:count += 1self.result[1] = count# 分析第二項:# 深度優先遍歷def analyse_wall_sets(self):count = 0for y in range(1, len(self.b_maze)-1):for x in range(1, len(self.b_maze[0])-1):if self.site_view[y][x] is False:if not self.is_inner(y, x):count += 1self.deep(y, x)self.result[2] = countdef deep(self, y, x):if self.site_view[y][x] is True:returnelse:self.site_view[y][x] = True# 檢測上面的線if self.b_maze[y-1][x] in ["2", "3"]:self.deep(y-1, x)# 檢測左邊的線if self.b_maze[y][x-1] in ["1", "3"]:self.deep(y, x-1)# 檢測下面和右面的線if self.b_maze[y][x] == "1":self.deep(y, x+1)elif self.b_maze[y][x] == "2":self.deep(y+1, x)elif self.b_maze[y][x] == "3":self.deep(y+1, x)self.deep(y, x+1)else:returndef is_inner(self, i, j):if self.b_maze[i][j] == '0' and self.b_maze[i - 1][j] in ['0', '1'] and self.b_maze[i][j - 1] in ['0', '2']:return Trueelse:return False# 分析第三項:def analyse_inner_points(self):count = 0for i in self.death_list:self.go3(i[2], i[0], i[1])for line in self.viewed3:for i in line:if i is True:count += 1for y in range(1, len(self.b_maze)-1):for x in range(1, len(self.b_maze[0])-1):if not self.not_death_block(y, x):count += 1self.result[3] = count# 找到所有死角塊def go3(self, direction, y, x):self.viewed3[y][x] = Truenext_y = ynext_x = xif direction == "up":next_y = y-1next_x = x# 走右面elif direction == "right":next_y = ynext_x = x + 1# 走下面elif direction == "down":next_y = y + 1next_x = x# 走左面elif direction == "left":next_y = ynext_x = x - 1# self.go(direction, y, x - 1)# direction 代表當前點的出口的方向up = Truedown = Trueleft = Trueright = Trueroad = self.b_road[next_y][next_x]if direction == "right" or road.left is False:left = Falseif direction == "left" or road.right is False:right = Falseif direction == "up" or road.down is False:down = Falseif direction == "down" or road.up is False:up = Falsenext_road = Road(up, down, left, right)next_direction = self.is_three_suround(next_road)if next_direction != "no":return self.go3(next_direction, next_y, next_x)elif next_road.up is False and next_road.down is False and next_road.left is False and next_road.right is False:self.viewed3[next_y][next_x] = Truereturn# 分析第四項:共有多少個連通塊def analyse_accessible_areas(self):count = 0for y in range(1, len(self.b_road)-1):for x in range(1, len(self.b_road[0])-1):if self.viewed4[y][x] is False:if self.not_death_block(y, x):count += 1self.view(y, x)self.result[4] = count-self.deathdef not_death_block(self, y, x):# 不是四面的死角 返回True 是四面的死角返回Falsereturn self.b_road[y][x].up or self.b_road[y][x].down or self.b_road[y][x].left or self.b_road[y][x].rightdef view(self, y, x):if self.viewed4[y][x] is True:returnself.viewed4[y][x] = Trueif not self.not_death_block(y, x):returnelse:if self.b_road[y][x].is_border is True:returnelse:# 四條路的判定與遍歷if self.b_road[y][x].up is True:self.view(y-1, x)if self.b_road[y][x].down is True:self.view(y+1, x)if self.b_road[y][x].left is True:self.view(y, x-1)if self.b_road[y][x].right is True:self.view(y, x+1)# 分析第五項:共有多少個死角# 思路:深度優先遍歷def analyse_sets(self):for y in range(1, len(self.b_road)-1):for x in range(1, len(self.b_road[0])-1):if self.viewed[y][x] is True:continuedirection = self.is_three_suround(self.b_road[y][x])if direction != "no":b = self.go(direction, y, x)if b is False:self.death_list.append([y, x, direction])self.result[5] = len(self.entry)def go(self, direction, y, x):self.viewed[y][x] = Truenext_y = ynext_x = xif direction == "up":next_y = y-1next_x = x# 走右面elif direction == "right":next_y = ynext_x = x + 1# 走下面elif direction == "down":next_y = y + 1next_x = x# 走左面elif direction == "left":next_y = ynext_x = x - 1# self.go(direction, y, x - 1)if self.b_road[next_y][next_x].is_border is True:self.entry.append([-2, -2, "end"])return True# direction 代表當前點的出口的方向up = Truedown = Trueleft = Trueright = Trueroad = self.b_road[next_y][next_x]if direction == "right" or road.left is False:left = Falseif direction == "left" or road.right is False:right = Falseif direction == "up" or road.down is False:down = Falseif direction == "down" or road.up is False:up = Falsenext_road = Road(up, down, left, right)next_direction = self.is_three_suround(next_road)if next_direction != "no":return self.go(next_direction, next_y, next_x)elif self.is_two_surround(next_road):the_point = [next_y, next_x, direction]index = self.is_point_in_list(the_point)if index >= 0:# past_direction,direction是兩個入口,轉化成邊之后即可與另一條邊構成三環塊,然后繼續往下走past_direction = self.entry.pop(index)[2]the_direction = self.get_the_direction(past_direction, direction, next_y, next_x)# 找到出口,調用go方法if the_direction != "no":self.go(the_direction, next_y, next_x)# 該點入list,并記錄該點的已知入口else:self.entry.append(the_point)return Trueelif next_road.up is False and next_road.down is False and next_road.left is False and next_road.right is False:self.viewed[next_y][next_x] = Trueself.death += 1return Falseelse:self.entry.append([next_y, next_x, "end"])return Truedef is_three_suround(self, road):count = 0direction = "no"if road.up is False:count += 1else:direction = "up"if road.down is False:count += 1else:direction = "down"if road.left is False:count += 1else:direction = "left"if road.right is False:count += 1else:direction = "right"if count == 3:return directionelse:return "no"def is_two_surround(self,road):count = 0if road.up is False:count += 1if road.down is False:count += 1if road.left is False:count += 1if road.right is False:count += 1if count == 2:return Trueelse:return Falsedef is_point_in_list(self, point):b = -1for i in range(len(self.entry)):if self.entry[i][0] == point[0] and self.entry[i][1] == point[1] and self.entry[i][2] != "end":b = ibreakreturn bdef get_the_direction(self, past_direction, direction, next_y, next_x):# 尋找出口up = Truedown = Trueleft = Trueright = Trueif "up" in [past_direction, direction] or self.b_road[next_y][next_x].down is False:down = Falseif "down" in [past_direction, direction] or self.b_road[next_y][next_x].up is False:up = Falseif "right" in [past_direction, direction] or self.b_road[next_y][next_x].left is False:left = Falseif "left" in [past_direction, direction] or self.b_road[next_y][next_x].right is False:right = Falseroad = Road(up, down, left, right)return self.is_three_suround(road)# 分析第六項:共有多少個連通路徑def analyse_path(self):# 分四面進入,上面的就從上面進入,下面的就從下面進入,左面從左面進入。count = 0for x1 in range(1, len(self.b_road[0])-1):if self.viewed6[1][x1] is False and self.b_road[1][x1].up is True:if self.cross("up", 1, x1) is True:self.success_path_start.append(["up", 1, x1])count += 1n = len(self.b_road)-2for xn in range(1, len(self.b_road[0])-1):if self.viewed6[n][xn] is False and self.b_road[n][xn].down is True:if self.cross("down", n, xn) is True:self.success_path_start.append(["down", n, xn])count += 1for y1 in range(1, len(self.b_road)-1):if self.viewed6[y1][1] is False and self.b_road[y1][1].left is True:if self.cross("left", y1, 1) is True:self.success_path_start.append(["left", y1, 1])count += 1n2 = len(self.b_road[0])-2for yn in range(1, len(self.b_road) - 1):if self.viewed6[yn][n2] is False and self.b_road[yn][n2].right is True:if self.cross("right", yn, n2) is True:self.success_path_start.append(["right", yn, n2])count += 1self.result[6] = countdef cross(self, direction, y, x):self.viewed6[y][x] = Trueup = Truedown = Trueleft = Trueright = Trueif direction == "left" or self.viewed[y][x-1] is True or self.b_road[y][x].left is False:left = Falseif direction == "right" or self.viewed[y][x+1] is True or self.b_road[y][x].right is False:right = Falseif direction == "down" or self.viewed[y+1][x] is True or self.b_road[y][x].down is False:down = Falseif direction == "up" or self.viewed[y-1][x] is True or self.b_road[y][x].up is False:up = Falseroad = Road(up, down, left, right)next_direction = self.is_three_suround(road)if next_direction != "no":n_direction = ""next_y = ynext_x = xif next_direction == "up":next_y = y - 1next_x = xn_direction = "down"# self.go(direction, y - 1, x)# 走右面elif next_direction == "right":next_y = ynext_x = x + 1n_direction = "left"# self.go(direction, y, x + 1)# 走下面elif next_direction == "down":next_y = y + 1next_x = xn_direction = "up"# self.go(direction, y + 1, x)# 走左面elif next_direction == "left":next_y = ynext_x = x - 1n_direction = "right"# self.go(direction, y, x - 1)if self.b_road[next_y][next_x].is_border is True:return Trueelse:return self.cross(n_direction, next_y, next_x)else:return Falsedef cross2(self, direction, y, x):self.temp.append([x-0.5, y-0.5])up = Truedown = Trueleft = Trueright = Trueif direction == "left" or self.viewed[y][x-1] is True or self.b_road[y][x].left is False:left = Falseif direction == "right" or self.viewed[y][x+1] is True or self.b_road[y][x].right is False:right = Falseif direction == "down" or self.viewed[y+1][x] is True or self.b_road[y][x].down is False:down = Falseif direction == "up" or self.viewed[y-1][x] is True or self.b_road[y][x].up is False:up = Falseroad = Road(up, down, left, right)next_direction = self.is_three_suround(road)if next_direction != "no":n_direction = ""next_y = ynext_x = xif next_direction == "up":next_y = y - 1next_x = xn_direction = "down"# 走右面elif next_direction == "right":next_y = ynext_x = x + 1n_direction = "left"# 走下面elif next_direction == "down":next_y = y + 1next_x = xn_direction = "up"# 走左面elif next_direction == "left":next_y = ynext_x = x - 1n_direction = "right"if self.b_road[next_y][next_x].is_border is True:self.temp.append([next_x-0.5, next_y-0.5])return Trueelse:self.cross2(n_direction, next_y, next_x)else:returndef go2(self, direction, y, x):self.viewed[y][x] = Falsenext_y = ynext_x = xif direction == "up":next_y = y-1next_x = x# self.go(direction, y - 1, x)# 走右面elif direction == "right":next_y = ynext_x = x + 1# self.go(direction, y, x + 1)# 走下面elif direction == "down":next_y = y + 1next_x = x# self.go(direction, y + 1, x)# 走左面elif direction == "left":next_y = ynext_x = x - 1# self.go(direction, y, x - 1)# direction 代表當前點的出口的方向up = Truedown = Trueleft = Trueright = Trueroad = self.b_road[next_y][next_x]if direction == "right" or road.left is False:left = Falseif direction == "left" or road.right is False:right = Falseif direction == "up" or road.down is False:down = Falseif direction == "down" or road.up is False:up = Falsenext_road = Road(up, down, left, right)next_direction = self.is_three_suround(next_road)if next_direction != "no":self.go(next_direction, next_y, next_x)elif next_road.up is False and next_road.down is False and next_road.left is False and next_road.right is False:self.viewed[next_y][next_x] = False# 輸出結果def print_result(self):# print(self.result)out_result = list()for i in range(1, 7):if self.result[i] == 0:out_result.append(str('no'))elif self.result[i] == 1:out_result.append(str('a'))else:out_result.append(str(self.result[i]))# 輸出print("The maze has "+out_result[0]+" gates. ")print("The maze has "+out_result[1]+" sets of walls that are all connected.")print("The maze has "+out_result[2]+" inaccessible inner point.")print("The maze has "+out_result[3]+" unique accessible area.")print("The maze has "+out_result[4]+" sets of accessible cul-de-sacs that are all connected.")print("The maze has "+out_result[5]+" unique entry-exit path with no intersection not to cul-de-sacs. ")# 展示def display(self):tex_file_name = self.file_name.split('.')[0] + ".tex"tex_file = open(tex_file_name, 'w')head =["\\documentclass[10pt]{article}\n","\\usepackage{tikz}\n","\\usetikzlibrary{shapes.misc}\n","\\usepackage[margin=0cm]{geometry}\n","\\pagestyle{empty}\n","\n","\\tikzstyle{every node}=[cross out, draw, red]\n","\n","\\begin{document}\n","\\vspace*{\\fill}\n","\\begin{center}\n","\\begin{tikzpicture}[x=0.5cm, y=-0.5cm, ultra thick, blue]\n","% Walls\n"]border = ["\\end{tikzpicture}\n","\\end{center}\n","\\vspace*{\\fill}\n","\n","\\end{document}\n"]# 開始畫墻for y in range(len(self.maze)):for x in range(len(self.maze[0])):if self.maze[y][x] in ["1", "3"]:x1 = x+1y1 = ys = " \\draw (" + str(x)+" ,"+str(y)+") -- ("+str(x1)+", "+str(y1)+");\n"self.walls.append(s)if self.maze[y][x] in ["2", "3"]:x1 = xy1 = y+1s = " \\draw (" + str(x)+" ,"+str(y)+") -- ("+str(x1)+", "+str(y1)+");\n"self.walls.append(s)# 開始畫點for i in range(1, len(self.b_maze) - 1):for j in range(1, len(self.b_maze[0]) - 1):if self.is_inner(i, j):s = " \\fill[green] (" + str(j - 1) + "," + str(i - 1) + ") circle(0.2);\n"self.pillars.append(s)# 開始畫pathfor i in self.success_path_start:self.temp = list()if i[0] == "up":self.temp.append([i[2]-0.5, -0.5])elif i[0] == "down":self.temp.append([i[2]-0.5, len(self.b_road) - 1.5])elif i[0] == "left":self.temp.append([-0.5, i[1]-0.5])elif i[0] == "right":self.temp.append([len(self.b_road[0]) - 1.5, i[1]-0.5])self.cross2(i[0], i[1], i[2])self.path.append(self.temp)for i in self.path:for j in range(len(i)-1):s = " \draw[dashed, yellow] ("+str(i[j][0])+","+str(i[j][1])+") -- ("+str(i[j+1][0])+","+str(i[j+1][1])+");\n"self.entry_exit_paths.append(s)# 開始畫 X ,# 1.計算出所有的死塊,設置viewedfor i in self.death_list:self.go2(i[2], i[0], i[1])# 2.將所有visited中的點畫上Xfor y in range(1, len(self.b_road)-1):for x in range(1, len(self.b_road[0])-1):if self.viewed[y][x] is True:y1 = str(y-0.5)x1 = str(x-0.5)s = " \\node at ("+x1+","+y1+") {};\n"self.inner_points.append(s)tex_file.writelines(head)tex_file.writelines(self.walls)tex_file.writelines(self.pillars)tex_file.writelines(self.inner_points)tex_file.writelines(self.entry_exit_paths)tex_file.writelines(border)my_maze = Maze('maze_1.txt') my_maze.analyse() my_maze.display()?
總結
以上是生活随笔為你收集整理的采用递归与栈结合的方式实现迷宫分析与走迷宫(python3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python计算能够包含两个圆的最小圆
- 下一篇: 百练OJ:4016:班级排名