版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kangyucheng/article/details/83934135
一、场景
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 = value
class Road:
up = True
down = True
left = True
right = True
is_border = False
def __init__(self, up, down, left, right):
self.up = up
self.down = down
self.left = left
self.right = right
class 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_name
file = 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 = True
down = True
left = True
right = True
if self.maze[y][x] == '1':
up = False
elif self.maze[y][x] == '2':
left = False
elif self.maze[y][x] == '3':
up = False
left = False
if self.maze[y+1][x] == "1" or self.maze[y+1][x] == "3":
down = False
if self.maze[y][x+1] == "2" or self.maze[y][x+1] == "3":
right = False
road = 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 = True
x_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 = True
temp.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() # 1
self.analyse_wall_sets() # 2
self.analyse_sets() # 5
self.analyse_path() # 6
self.analyse_accessible_areas() # 4
self.analyse_inner_points() # 3
self.print_result()
# 分析第一项:分析迷宫有多少个门
def analyse_gates(self):
# 分四条边考虑
count = 0
for i in self.road[0]:
if i.up is True:
count += 1
for i in self.road[len(self.road)-1]:
if i.down is True:
count += 1
for j in range(len(self.road)):
if self.road[j][0].left is True:
count += 1
if self.road[j][len(self.road[0])-1].right is True:
count += 1
self.result[1] = count
# 分析第二项:
# 深度优先遍历
def analyse_wall_sets(self):
count = 0
for 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 += 1
self.deep(y, x)
self.result[2] = count
def deep(self, y, x):
if self.site_view[y][x] is True:
return
else:
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:
return
def 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 True
else:
return False
# 分析第三项:
def analyse_inner_points(self):
count = 0
for 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 += 1
for 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 += 1
self.result[3] = count
# 找到所有死角块
def go3(self, direction, y, x):
self.viewed3[y][x] = True
next_y = y
next_x = x
if direction == "up":
next_y = y-1
next_x = x
# 走右面
elif direction == "right":
next_y = y
next_x = x + 1
# 走下面
elif direction == "down":
next_y = y + 1
next_x = x
# 走左面
elif direction == "left":
next_y = y
next_x = x - 1
# self.go(direction, y, x - 1)
# direction 代表当前点的出口的方向
up = True
down = True
left = True
right = True
road = self.b_road[next_y][next_x]
if direction == "right" or road.left is False:
left = False
if direction == "left" or road.right is False:
right = False
if direction == "up" or road.down is False:
down = False
if direction == "down" or road.up is False:
up = False
next_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] = True
return
# 分析第四项:共有多少个连通块
def analyse_accessible_areas(self):
count = 0
for 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 += 1
self.view(y, x)
self.result[4] = count-self.death
def not_death_block(self, y, x):
# 不是四面的死角 返回True 是四面的死角返回False
return 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].right
def view(self, y, x):
if self.viewed4[y][x] is True:
return
self.viewed4[y][x] = True
if not self.not_death_block(y, x):
return
else:
if self.b_road[y][x].is_border is True:
return
else:
# 四条路的判定与遍历
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:
continue
direction = 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] = True
next_y = y
next_x = x
if direction == "up":
next_y = y-1
next_x = x
# 走右面
elif direction == "right":
next_y = y
next_x = x + 1
# 走下面
elif direction == "down":
next_y = y + 1
next_x = x
# 走左面
elif direction == "left":
next_y = y
next_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 = True
down = True
left = True
right = True
road = self.b_road[next_y][next_x]
if direction == "right" or road.left is False:
left = False
if direction == "left" or road.right is False:
right = False
if direction == "up" or road.down is False:
down = False
if direction == "down" or road.up is False:
up = False
next_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 True
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] = True
self.death += 1
return False
else:
self.entry.append([next_y, next_x, "end"])
return True
def is_three_suround(self, road):
count = 0
direction = "no"
if road.up is False:
count += 1
else:
direction = "up"
if road.down is False:
count += 1
else:
direction = "down"
if road.left is False:
count += 1
else:
direction = "left"
if road.right is False:
count += 1
else:
direction = "right"
if count == 3:
return direction
else:
return "no"
def is_two_surround(self,road):
count = 0
if road.up is False:
count += 1
if road.down is False:
count += 1
if road.left is False:
count += 1
if road.right is False:
count += 1
if count == 2:
return True
else:
return False
def is_point_in_list(self, point):
b = -1
for 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 = i
break
return b
def get_the_direction(self, past_direction, direction, next_y, next_x):
# 寻找出口
up = True
down = True
left = True
right = True
if "up" in [past_direction, direction] or self.b_road[next_y][next_x].down is False:
down = False
if "down" in [past_direction, direction] or self.b_road[next_y][next_x].up is False:
up = False
if "right" in [past_direction, direction] or self.b_road[next_y][next_x].left is False:
left = False
if "left" in [past_direction, direction] or self.b_road[next_y][next_x].right is False:
right = False
road = Road(up, down, left, right)
return self.is_three_suround(road)
# 分析第六项:共有多少个连通路径
def analyse_path(self):
# 分四面进入,上面的就从上面进入,下面的就从下面进入,左面从左面进入。
count = 0
for 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 += 1
n = len(self.b_road)-2
for 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 += 1
for 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 += 1
n2 = len(self.b_road[0])-2
for 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 += 1
self.result[6] = count
def cross(self, direction, y, x):
self.viewed6[y][x] = True
up = True
down = True
left = True
right = True
if direction == "left" or self.viewed[y][x-1] is True or self.b_road[y][x].left is False:
left = False
if direction == "right" or self.viewed[y][x+1] is True or self.b_road[y][x].right is False:
right = False
if direction == "down" or self.viewed[y+1][x] is True or self.b_road[y][x].down is False:
down = False
if direction == "up" or self.viewed[y-1][x] is True or self.b_road[y][x].up is False:
up = False
road = Road(up, down, left, right)
next_direction = self.is_three_suround(road)
if next_direction != "no":
n_direction = ""
next_y = y
next_x = x
if next_direction == "up":
next_y = y - 1
next_x = x
n_direction = "down"
# self.go(direction, y - 1, x)
# 走右面
elif next_direction == "right":
next_y = y
next_x = x + 1
n_direction = "left"
# self.go(direction, y, x + 1)
# 走下面
elif next_direction == "down":
next_y = y + 1
next_x = x
n_direction = "up"
# self.go(direction, y + 1, x)
# 走左面
elif next_direction == "left":
next_y = y
next_x = x - 1
n_direction = "right"
# self.go(direction, y, x - 1)
if self.b_road[next_y][next_x].is_border is True:
return True
else:
return self.cross(n_direction, next_y, next_x)
else:
return False
def cross2(self, direction, y, x):
self.temp.append([x-0.5, y-0.5])
up = True
down = True
left = True
right = True
if direction == "left" or self.viewed[y][x-1] is True or self.b_road[y][x].left is False:
left = False
if direction == "right" or self.viewed[y][x+1] is True or self.b_road[y][x].right is False:
right = False
if direction == "down" or self.viewed[y+1][x] is True or self.b_road[y][x].down is False:
down = False
if direction == "up" or self.viewed[y-1][x] is True or self.b_road[y][x].up is False:
up = False
road = Road(up, down, left, right)
next_direction = self.is_three_suround(road)
if next_direction != "no":
n_direction = ""
next_y = y
next_x = x
if next_direction == "up":
next_y = y - 1
next_x = x
n_direction = "down"
# 走右面
elif next_direction == "right":
next_y = y
next_x = x + 1
n_direction = "left"
# 走下面
elif next_direction == "down":
next_y = y + 1
next_x = x
n_direction = "up"
# 走左面
elif next_direction == "left":
next_y = y
next_x = x - 1
n_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 True
else:
self.cross2(n_direction, next_y, next_x)
else:
return
def go2(self, direction, y, x):
self.viewed[y][x] = False
next_y = y
next_x = x
if direction == "up":
next_y = y-1
next_x = x
# self.go(direction, y - 1, x)
# 走右面
elif direction == "right":
next_y = y
next_x = x + 1
# self.go(direction, y, x + 1)
# 走下面
elif direction == "down":
next_y = y + 1
next_x = x
# self.go(direction, y + 1, x)
# 走左面
elif direction == "left":
next_y = y
next_x = x - 1
# self.go(direction, y, x - 1)
# direction 代表当前点的出口的方向
up = True
down = True
left = True
right = True
road = self.b_road[next_y][next_x]
if direction == "right" or road.left is False:
left = False
if direction == "left" or road.right is False:
right = False
if direction == "up" or road.down is False:
down = False
if direction == "down" or road.up is False:
up = False
next_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+1
y1 = y
s = " \\draw (" + str(x)+" ,"+str(y)+") -- ("+str(x1)+", "+str(y1)+");\n"
self.walls.append(s)
if self.maze[y][x] in ["2", "3"]:
x1 = x
y1 = y+1
s = " \\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)
# 开始画path
for 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.计算出所有的死块,设置viewed
for i in self.death_list:
self.go2(i[2], i[0], i[1])
# 2.将所有visited中的点画上X
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:
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()