-
Notifications
You must be signed in to change notification settings - Fork 0
/
Maze_class.py
252 lines (218 loc) · 7.48 KB
/
Maze_class.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
from Window_class import Window
from Point_class import Point
from Cell_class import Cell
from Player_class import Player
from time import sleep as wait
import random
class Maze:
def __init__(
self,
win: Window = None,
x1: int = 50,
y1: int = 50,
num_rows: int = 14,
num_cols: int = 10,
cell_size_x: int = 50,
cell_size_y: int = 50,
entropy: int = 69420,
):
"""Creates a Maze instance, assumes most of the options, draws the maze and animates it. contains maze lol (List of Lists)
Args:
win (Window): The window / canvas it's drawn on to.
x1 (int, optional): Maze start position, X Coordinate. Defaults to 50.
y1 (int, optional): Maze start position, Y Coordinate. Defaults to x1.
num_rows (int, optional): Number of cell Rows (-). Defaults to 14.
num_cols (int, optional): Number of cell Columns (|). Defaults to 10.
cell_size_x (int, optional): Pixel Width per cell. Defaults to 50.
cell_size_y (int, optional): Pixel Height per cell. Defaults to cell_size_x.
"""
self.row_count = num_rows
self.column_count = num_cols
# another refrence for convinience.
self.width = num_rows
self.height = num_cols
self.grid: list[list[Cell]] = []
self._cells = self.grid
self.cell_size_x = cell_size_x
self.cell_size_y = cell_size_y
self._win = win
self._x = x1
self._y = y1
random.seed(entropy)
self._create_cells()
self._break_entrance_and_exit()
self._break_walls_r()
self._reset_cells_visited()
self.sovle()
def get_grid_by_pos(self, x: int, y: int):
if x > self.cell_size_x:
raise Exception("invalid X coordinate.")
if y > self.cell_size_y:
raise Exception("invalid Y coordinate.")
return self.grid[y][x]
def _create_cells(self):
self.grid = [
[None for _ in range(self.row_count)] for _ in range(self.column_count)
]
self._cells = self.grid
for column in range(self.column_count):
for row in range(self.row_count):
self.grid[column][row] = Cell(
Point(
(self.cell_size_x * row) + self._x,
(self.cell_size_y * column) + self._y,
),
Point(
(self.cell_size_x * (row + 1)) + self._x,
(self.cell_size_y * (column + 1)) + self._y,
),
self._win,
True,
True,
True,
True,
grid_coordinate_x=row,
grid_coordinate_y=column,
)
self._draw_cell()
def _draw_cell(self):
for column in range(self.column_count):
for row in range(self.row_count):
if self.grid[column][row] is not None:
if self._win == None:
continue
self.grid[column][row].draw_cell()
self._animate()
def _animate(self):
"""wait."""
self._win.redraw()
wait(0.05)
def _break_entrance_and_exit(self):
"""ensure there is a start and a end for the maze"""
self.grid[0][0].has_top_wall = False
self.grid[0][0].draw_cell()
self.grid[self.column_count - 1][self.row_count - 1].has_bottom_wall = False
self.grid[self.column_count - 1][self.row_count - 1].draw_cell()
def dedup(self, core: list[Cell], filter: list[Cell]):
"""
Returns a list containing elements from `core` that are not present in `filter`.
Parameters:
core (list): The main list of elements.
filter (list): The list containing elements to be removed from `core`.
Returns:
list: A new list with elements from `core` excluding those found in `filter`.
"""
return [item for item in core if item not in filter and not None]
def _break_walls_r(self, current_x=0, current_y=0, visited=None):
if visited == None:
visited = list()
#print(
# f"_break_walls_r(self, current_x={current_x}, current_y={current_y}, visited={visited})"
# )
visited.append(self.grid[current_y][current_x])
visited[-1].visited = True
while True:
options = list()
if current_x + 1 <= len(self.grid[0]) - 1: # updated to use width (columns)
cell = self.grid[current_y][current_x + 1]
if cell:
options.append(cell)
if current_y + 1 <= len(self.grid) - 1: # updated to use height (rows)
cell = self.grid[current_y + 1][current_x]
if cell:
options.append(cell)
if current_y > 0:
cell = self.grid[current_y - 1][current_x]
if cell:
options.append(cell)
if current_x > 0:
cell = self.grid[current_y][current_x - 1]
if cell:
options.append(cell)
options = self.dedup(core=options, filter=visited)
if len(options) == 0:
return
choice = random.randint(0, len(options) - 1)
#print(f"Choice = {choice}; len = {len(options)}")
choice = options[choice]
# Adjustments for walls between cells:
if choice.grid_coordinate_x != current_x:
if choice.grid_coordinate_x > current_x:
self.grid[current_y][current_x].has_right_wall = False
choice.has_left_wall = False
elif choice.grid_coordinate_x < current_x:
self.grid[current_y][current_x].has_left_wall = False
choice.has_right_wall = False
if choice.grid_coordinate_y != current_y:
if choice.grid_coordinate_y > current_y:
self.grid[current_y][current_x].has_bottom_wall = False
choice.has_top_wall = False
elif choice.grid_coordinate_y < current_y:
self.grid[current_y][current_x].has_top_wall = False
choice.has_bottom_wall = False
choice.draw_cell()
self.grid[current_y][current_x].draw_cell()
self._animate()
self._break_walls_r(
choice.grid_coordinate_x, choice.grid_coordinate_y, visited
)
def _reset_cells_visited(self):
for column in self.grid:
for cell in column:
cell.visited = False
def get_cell(self, x: int, y: int):
return self.grid[y][x]
def sovle(self) -> bool:
return self._solve_r(x=0, y=0)
def _solve_r(self, x: int, y: int) -> bool:
self._animate()
if x == self.width-1 and y == self.height-1:
print("S O L V E D")
return True
self.get_cell(x, y).visited = True
possible_moves = []
# Define potential moves with directions
directions = {
'up': (x, y - 1),
'down': (x, y + 1),
'left': (x - 1, y),
'right': (x + 1, y)
}
# Check each direction for wall constraints and boundaries
for direction, (nx, ny) in directions.items():
# Ensure we don't go out of bounds
if 0 <= nx < self.width and 0 <= ny < self.height:
current_cell = self.get_cell(x,y)
new_cell = self.get_cell(nx, ny)
# Check for walls and visited status if required
if direction == 'up' and not current_cell.has_top_wall and not new_cell.has_bottom_wall:
if new_cell.visited == False:
possible_moves.append(new_cell)
elif direction == 'down' and not current_cell.has_bottom_wall and not new_cell.has_top_wall:
if new_cell.visited == False:
possible_moves.append(new_cell)
elif direction == 'left' and not current_cell.has_left_wall and not new_cell.has_right_wall:
if new_cell.visited == False:
possible_moves.append(new_cell)
elif direction == 'right' and not current_cell.has_right_wall and not new_cell.has_left_wall:
if new_cell.visited == False:
possible_moves.append(new_cell)
solved = False
for move in possible_moves:
self.get_cell(x,y).draw_move(move)
if self._solve_r(move.grid_coordinate_x, move.grid_coordinate_y) == True:
solved = True
else:
self.get_cell(x,y).draw_move(move, True)
return solved
""" niggers do what?
direction_solve_occured = False
for direction, (nx, ny) in directions.items():
if self.get_cell(nx, ny) not in possible_moves:
self.get_cell(nx, ny).draw_move(self.get_cell(x, y), True)
continue
self.get_cell(nx, ny).draw_move(self.get_cell(x, y))
if self._solve_r(nx, ny) == True:
direction_solve_occured
return direction_solve_occured
"""