Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8ea5260

Browse files
add code
1 parent 707fb3e commit 8ea5260

File tree

2 files changed

+224
-1
lines changed

2 files changed

+224
-1
lines changed

‎doudou/2020-06-12-maze/maze.py

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import random
2+
import pyxel
3+
4+
5+
# Python 3.6.9+
6+
#
7+
# Win:
8+
# pip install -U pyxel
9+
# ************************
10+
# Mac
11+
# 1、brew install python3 sdl2 sdl2_image
12+
# 2、restart the terminal
13+
# 3、pip3 install -U pyxel
14+
# ************************
15+
# 「S」键开启游戏
16+
# https://github.com/kitao/pyxel/blob/master/README.cn.md
17+
18+
class Maze:
19+
def __init__(self, width, height):
20+
self.width = width
21+
self.height = height
22+
self.map = [[0 if x % 2 == 1 and y % 2 == 1 else 1 for x in range(width)] for y in range(height)]
23+
self.map[1][0] = 0 # 入口
24+
self.map[height - 2][width - 1] = 0 # 出口
25+
self.visited = []
26+
# right up left down
27+
self.dx = [1, 0, -1, 0]
28+
self.dy = [0, -1, 0, 1]
29+
30+
def set_value(self, point, value):
31+
self.map[point[1]][point[0]] = value
32+
33+
def get_value(self, point):
34+
return self.map[point[1]][point[0]]
35+
36+
# 获取坐标(x,y) 的邻居 返回数据结构为:二维数组
37+
def get_neighbor(self, x, y, value):
38+
res = []
39+
for i in range(4):
40+
if 0 < x + self.dx[i] < self.width - 1 and 0 < y + self.dy[i] < self.height - 1 and \
41+
self.get_value([x + self.dx[i], y + self.dy[i]]) == value:
42+
res.append([x + self.dx[i], y + self.dy[i]])
43+
return res
44+
45+
# 获取坐标(x,y) 的邻墙
46+
def get_neighbor_wall(self, point):
47+
return self.get_neighbor(point[0], point[1], 1)
48+
49+
# 获取坐标(x,y) 的邻路
50+
def get_neighbor_road(self, point):
51+
return self.get_neighbor(point[0], point[1], 0)
52+
53+
def deal_with_not_visited(self, point, wall_position, wall_list):
54+
if not [point[0], point[1]] in self.visited:
55+
self.set_value(wall_position, 0)
56+
self.visited.append(point)
57+
wall_list += self.get_neighbor_wall(point)
58+
59+
# generate maze
60+
# https://en.wikipedia.org/wiki/Maze_generation_algorithm
61+
#
62+
# 1、迷宫行和列必须为奇数。
63+
# 2、奇数行和奇数列的交叉点为路,其余点为墙。迷宫四周全是墙。
64+
# 3、选定一个为路的单元格(本例选 [1,1]),然后把它的邻墙放入列表 wall。
65+
# 4、当列表 wall 里还有墙时:
66+
# 4.1、从列表里随机选一面墙,如果这面墙分隔的两个单元格只有一个单元格被访问过
67+
# 3.1.1、那就从列表里移除这面墙,同时把墙打通
68+
# 3.1.2、将单元格标记为已访问
69+
# 3.1.3、将未访问的单元格的的邻墙加入列表 wall
70+
# 4.2、如果这面墙两面的单元格都已经被访问过,那就从列表里移除这面墙
71+
def generate(self):
72+
start = [1, 1]
73+
self.visited.append(start)
74+
wall_list = self.get_neighbor_wall(start)
75+
while wall_list:
76+
wall_position = random.choice(wall_list)
77+
neighbor_road = self.get_neighbor_road(wall_position)
78+
wall_list.remove(wall_position)
79+
self.deal_with_not_visited(neighbor_road[0], wall_position, wall_list)
80+
self.deal_with_not_visited(neighbor_road[1], wall_position, wall_list)
81+
82+
def is_out_of_index(self, x, y):
83+
return x == 0 or x == self.width - 1 or y == 0 or y == self.height - 1
84+
85+
# dfs
86+
def dfs(self, x, y, path, visited=[]):
87+
# 越界
88+
if self.is_out_of_index(x, y):
89+
return False
90+
91+
# 访问过 or 撞墙
92+
if [x, y] in visited or self.get_value([x, y]) == 1:
93+
return False
94+
95+
visited.append([x, y])
96+
path.append([x, y])
97+
98+
# over
99+
if x == self.width - 2 and y == self.height - 2:
100+
return True
101+
102+
# recursive
103+
for i in range(4):
104+
if 0 < x + self.dx[i] < self.width - 1 and 0 < y + self.dy[i] < self.height - 1 and \
105+
self.get_value([x + self.dx[i], y + self.dy[i]]) == 0:
106+
if self.dfs(x + self.dx[i], y + self.dy[i], path, visited):
107+
return True
108+
elif not self.is_out_of_index(x, y) and path[-1] != [x, y]:
109+
path.append([x, y])
110+
111+
# dfs
112+
def dfs_route(self):
113+
path = []
114+
self.dfs(1, 1, path)
115+
116+
ans = [[0, 1]]
117+
for i in range(len(path)):
118+
ans.append(path[i])
119+
if 0 < i < len(path) - 1 and path[i - 1] == path[i + 1]:
120+
ans.append(path[i])
121+
ans.append([width - 1, height - 2])
122+
return ans
123+
124+
# bfs
125+
def bfs_route(self):
126+
start = {'x': 0, 'y': 1, 'prev': None}
127+
now = start
128+
q = [start]
129+
visited = [[start['x'], start['y']]]
130+
# 1、从起点出发,获取起点周围所有连通的路
131+
# 2、如果该路没有走过,则加入队列 Q,否则跳过 同时记录其前驱节点
132+
while q:
133+
now = q.pop(0)
134+
# 结束
135+
if now['x'] == self.width - 2 and now['y'] == self.height - 2:
136+
break
137+
roads = my_maze.get_neighbor_road([now['x'], now['y']])
138+
for road in roads:
139+
if not road in visited:
140+
visited.append(road)
141+
q.append({'x': road[0], 'y': road[1], 'prev': now})
142+
143+
ans = []
144+
while now:
145+
ans.insert(0, [now['x'], now['y']])
146+
now = now['prev']
147+
ans.append([width - 1, height - 2])
148+
return ans
149+
150+
151+
pixel = 5
152+
width, height = 37, 21
153+
road_color, wall_color = 7, 13
154+
start_point_color, end_point_color, = 11, 11
155+
head_color, route_color, backtrack_color = 9, 11, 8
156+
157+
my_maze = Maze(width, height)
158+
my_maze.generate()
159+
160+
161+
class App:
162+
def __init__(self):
163+
#pyxel.init(width * pixel, height * pixel, caption='maze', border_width=10, border_color=0xFFFFFF)
164+
pyxel.init(width * pixel, height * pixel)
165+
self.death = True
166+
self.index = 0
167+
self.route = []
168+
self.step = 1 # 步长,数值越小速度越快,1:每次一格; 10:每次 1/10 格
169+
self.color = start_point_color
170+
self.bfs_route = my_maze.bfs_route()
171+
self.dfs_route = my_maze.dfs_route()
172+
self.dfs_model = True
173+
pyxel.run(self.update, self.draw)
174+
175+
def update(self):
176+
if pyxel.btn(pyxel.KEY_Q):
177+
pyxel.quit()
178+
179+
if pyxel.btn(pyxel.KEY_S):
180+
self.death = False
181+
182+
if not self.death:
183+
self.check_death()
184+
self.update_route()
185+
186+
def draw(self):
187+
# draw maze
188+
for x in range(height):
189+
for y in range(width):
190+
color = road_color if my_maze.map[x][y] is 0 else wall_color
191+
pyxel.rect(y * pixel, x * pixel, pixel, pixel, color)
192+
pyxel.rect(0, pixel, pixel, pixel, start_point_color)
193+
pyxel.rect((width - 1) * pixel, (height - 2) * pixel, pixel, pixel, end_point_color)
194+
195+
if self.index > 0:
196+
# draw route
197+
offset = pixel / 2
198+
for i in range(len(self.route) - 1):
199+
curr = self.route[i]
200+
next = self.route[i + 1]
201+
self.color = backtrack_color if curr in self.route[:i] and next in self.route[:i] else route_color
202+
pyxel.line(curr[0] + offset, (curr[1] + offset), next[0] + offset, next[1] + offset, self.color)
203+
pyxel.circ(self.route[-1][0] + 2, self.route[-1][1] + 2, 1, head_color)
204+
205+
def check_death(self):
206+
if self.dfs_model and len(self.route) == len(self.dfs_route) - 1:
207+
self.death = True
208+
elif not self.dfs_model and len(self.route) == len(self.bfs_route) - 1:
209+
self.death = True
210+
211+
def update_route(self):
212+
index = int(self.index / self.step)
213+
self.index += 1
214+
if index == len(self.route): # move
215+
if self.dfs_model:
216+
self.route.append([pixel * self.dfs_route[index][0], pixel * self.dfs_route[index][1]])
217+
else:
218+
self.route.append([pixel * self.bfs_route[index][0], pixel * self.bfs_route[index][1]])
219+
220+
221+
App()

‎doudou/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ Python技术 公众号文章代码库
1717
+ [520](https://github.com/JustDoPython/python-examples/tree/master/doudou/2020-05-17-520):Python 教你花式表白小姐姐
1818

1919
+ [字符画](https://github.com/JustDoPython/python-examples/tree/master/doudou/2020-05-17-character-drawing):字符画
20+
21+
+ [迷宫](https://github.com/JustDoPython/python-examples/tree/master/doudou/2020-06-12-maze):迷宫
2022
---
2123

2224
从小白到工程师的学习之路。
2325

24-
关注公众号:python 技术,回复"python"一起学习交流。
26+
关注公众号:python 技术,回复python一起学习交流。
2527

2628
![](http://favorites.ren/assets/images/python.jpg)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /