checkpoint: visited methods

- Add methods to mark cells as visited and to get results of the visits.
- renamed MazeDirections to MazeDirection
This commit is contained in:
Dan Anglin 2024-02-16 10:36:06 +00:00
parent 5c48f47a0a
commit c809292c04
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
4 changed files with 63 additions and 38 deletions

24
cell.py
View file

@ -76,8 +76,10 @@ class Cell:
# A reference to the root Window class for drawing purposes. # A reference to the root Window class for drawing purposes.
self._window = window self._window = window
self.visited_by_maze_generator = False self._visited: Dict[str, bool] = {
self.visited_by_maze_solver = False "generator": False,
"solver": False,
}
def configure_walls( def configure_walls(
self, self,
@ -137,3 +139,21 @@ class Cell:
fill_colour = "grey" fill_colour = "grey"
line = Line(self.centre(), to_cell.centre()) line = Line(self.centre(), to_cell.centre())
self._window.draw_line(line, fill_colour) self._window.draw_line(line, fill_colour)
def was_visited_by(self, visitor: str) -> bool:
"""
returns True if the cell was visited by the
specified visitor.
"""
if visitor not in ("solver", "generator"):
raise ValueError(f"This is an unknown visitor ({visitor})")
return self._visited[visitor]
def mark_as_visited_by(self, visitor: str) -> None:
"""
marks the cell as visited by the specified visitor.
"""
if visitor not in ("solver", "generator"):
raise ValueError(f"This is an unknown visitor ({visitor})")
self._visited[visitor] = True

View file

@ -8,10 +8,10 @@ def main():
game = Maze( game = Maze(
x_position=10, x_position=10,
y_position=10, y_position=10,
num_cell_rows=30, num_cell_rows=16,
num_cells_per_row=30, num_cells_per_row=16,
cell_size_x=20, cell_size_x=40,
cell_size_y=20, cell_size_y=40,
window=window window=window
) )

53
maze.py
View file

@ -6,7 +6,7 @@ from graphics import Window
from cell import Cell, CellWallLabels from cell import Cell, CellWallLabels
class MazeDirections(Enum): class MazeDirection(Enum):
""" """
MazeDirection represents the directions you can MazeDirection represents the directions you can
take in the maze. take in the maze.
@ -35,35 +35,35 @@ class MazePosition:
def get_adjacent_position( def get_adjacent_position(
self, self,
direction: MazeDirections direction: MazeDirection
) -> 'MazePosition': ) -> 'MazePosition':
if direction not in MazeDirections: if direction not in MazeDirection:
raise TypeError( raise TypeError(
"The argument does not appear to be a valid maze direction." "The argument does not appear to be a valid maze direction."
) )
if direction is MazeDirections.ABOVE and (self.i-1 >= 0): if direction is MazeDirection.ABOVE and (self.i-1 >= 0):
return MazePosition( return MazePosition(
i=self.i-1, i=self.i-1,
j=self.j, j=self.j,
max_i=self.max_i, max_i=self.max_i,
max_j=self.max_j, max_j=self.max_j,
) )
if direction is MazeDirections.BELOW and (self.i+1 <= self.max_i): if direction is MazeDirection.BELOW and (self.i+1 <= self.max_i):
return MazePosition( return MazePosition(
i=self.i+1, i=self.i+1,
j=self.j, j=self.j,
max_i=self.max_i, max_i=self.max_i,
max_j=self.max_j, max_j=self.max_j,
) )
if direction is MazeDirections.LEFT and (self.j-1 >= 0): if direction is MazeDirection.LEFT and (self.j-1 >= 0):
return MazePosition( return MazePosition(
i=self.i, i=self.i,
j=self.j-1, j=self.j-1,
max_i=self.max_i, max_i=self.max_i,
max_j=self.max_j, max_j=self.max_j,
) )
if direction is MazeDirections.RIGHT and (self.j+1 <= self.max_j): if direction is MazeDirection.RIGHT and (self.j+1 <= self.max_j):
return MazePosition( return MazePosition(
i=self.i, i=self.i,
j=self.j+1, j=self.j+1,
@ -179,19 +179,21 @@ class Maze:
cells and randomly knocking down the walls to create the maze's paths. cells and randomly knocking down the walls to create the maze's paths.
""" """
generator = "generator"
current_cell = self._cells[current_position.i][current_position.j] current_cell = self._cells[current_position.i][current_position.j]
current_cell.visited_by_maze_generator = True current_cell.mark_as_visited_by(generator)
while True: while True:
possible_directions: List[MazeDirections] = [] possible_directions: List[MazeDirection] = []
for direction in MazeDirections: for direction in MazeDirection:
adjacent_position = current_position.get_adjacent_position( adjacent_position = current_position.get_adjacent_position(
direction) direction)
if adjacent_position is None: if adjacent_position is None:
continue continue
adjacent_cell = self._cells[adjacent_position.i][adjacent_position.j] adjacent_cell = self._cells[adjacent_position.i][adjacent_position.j]
if adjacent_cell.visited_by_maze_generator: if adjacent_cell.was_visited_by(generator):
continue continue
possible_directions.append(direction) possible_directions.append(direction)
@ -205,16 +207,16 @@ class Maze:
chosen_direction) chosen_direction)
next_cell = self._cells[next_position.i][next_position.j] next_cell = self._cells[next_position.i][next_position.j]
if chosen_direction is MazeDirections.ABOVE: if chosen_direction is MazeDirection.ABOVE:
current_cell.configure_walls(top=False) current_cell.configure_walls(top=False)
next_cell.configure_walls(bottom=False) next_cell.configure_walls(bottom=False)
elif chosen_direction is MazeDirections.BELOW: elif chosen_direction is MazeDirection.BELOW:
current_cell.configure_walls(bottom=False) current_cell.configure_walls(bottom=False)
next_cell.configure_walls(top=False) next_cell.configure_walls(top=False)
elif chosen_direction is MazeDirections.LEFT: elif chosen_direction is MazeDirection.LEFT:
current_cell.configure_walls(left=False) current_cell.configure_walls(left=False)
next_cell.configure_walls(right=False) next_cell.configure_walls(right=False)
elif chosen_direction is MazeDirections.RIGHT: elif chosen_direction is MazeDirection.RIGHT:
current_cell.configure_walls(right=False) current_cell.configure_walls(right=False)
next_cell.configure_walls(left=False) next_cell.configure_walls(left=False)
@ -248,25 +250,28 @@ class Maze:
current_position: MazePosition, current_position: MazePosition,
end_position: MazePosition, end_position: MazePosition,
) -> bool: ) -> bool:
solver = "solver"
if current_position == end_position: if current_position == end_position:
return True return True
current_cell = self._cells[current_position.i][current_position.j] current_cell = self._cells[current_position.i][current_position.j]
current_cell.visited_by_maze_solver = True current_cell.mark_as_visited_by(solver)
wall_map: Dict[MazeDirections, CellWallLabels] = { wall_map: Dict[MazeDirection, CellWallLabels] = {
MazeDirections.ABOVE: CellWallLabels.BOTTOM, MazeDirection.ABOVE: CellWallLabels.BOTTOM,
MazeDirections.BELOW: CellWallLabels.TOP, MazeDirection.BELOW: CellWallLabels.TOP,
MazeDirections.LEFT: CellWallLabels.RIGHT, MazeDirection.LEFT: CellWallLabels.RIGHT,
MazeDirections.RIGHT: CellWallLabels.LEFT, MazeDirection.RIGHT: CellWallLabels.LEFT,
} }
for direction in MazeDirections: for direction in MazeDirection:
adjacent_position = current_position.get_adjacent_position( adjacent_position = current_position.get_adjacent_position(
direction) direction
)
if adjacent_position is None: if adjacent_position is None:
continue continue
adjacent_cell = self._cells[adjacent_position.i][adjacent_position.j] adjacent_cell = self._cells[adjacent_position.i][adjacent_position.j]
if adjacent_cell.visited_by_maze_solver or adjacent_cell.wall_exists(wall_map[direction]): if adjacent_cell.was_visited_by(solver) or adjacent_cell.wall_exists(wall_map[direction]):
continue continue
self._draw_path(current_cell, adjacent_cell) self._draw_path(current_cell, adjacent_cell)
result = self._solve_r(adjacent_position, end_position) result = self._solve_r(adjacent_position, end_position)

View file

@ -131,42 +131,42 @@ class Tests(unittest.TestCase):
cases = [ cases = [
{ {
"position": maze.MazePosition(i=3, j=4, max_i=10, max_j=10), "position": maze.MazePosition(i=3, j=4, max_i=10, max_j=10),
"direction": maze.MazeDirections.ABOVE, "direction": maze.MazeDirection.ABOVE,
"expected": maze.MazePosition(i=2, j=4, max_i=10, max_j=10), "expected": maze.MazePosition(i=2, j=4, max_i=10, max_j=10),
}, },
{ {
"position": maze.MazePosition(i=9, j=4, max_i=10, max_j=10), "position": maze.MazePosition(i=9, j=4, max_i=10, max_j=10),
"direction": maze.MazeDirections.BELOW, "direction": maze.MazeDirection.BELOW,
"expected": maze.MazePosition(i=10, j=4, max_i=10, max_j=10), "expected": maze.MazePosition(i=10, j=4, max_i=10, max_j=10),
}, },
{ {
"position": maze.MazePosition(i=1, j=1, max_i=10, max_j=10), "position": maze.MazePosition(i=1, j=1, max_i=10, max_j=10),
"direction": maze.MazeDirections.LEFT, "direction": maze.MazeDirection.LEFT,
"expected": maze.MazePosition(i=1, j=0, max_i=10, max_j=10), "expected": maze.MazePosition(i=1, j=0, max_i=10, max_j=10),
}, },
{ {
"position": maze.MazePosition(i=3, j=9, max_i=10, max_j=10), "position": maze.MazePosition(i=3, j=9, max_i=10, max_j=10),
"direction": maze.MazeDirections.RIGHT, "direction": maze.MazeDirection.RIGHT,
"expected": maze.MazePosition(i=3, j=10, max_i=10, max_j=10), "expected": maze.MazePosition(i=3, j=10, max_i=10, max_j=10),
}, },
{ {
"position": maze.MazePosition(i=0, j=4, max_i=10, max_j=10), "position": maze.MazePosition(i=0, j=4, max_i=10, max_j=10),
"direction": maze.MazeDirections.ABOVE, "direction": maze.MazeDirection.ABOVE,
"expected": None, "expected": None,
}, },
{ {
"position": maze.MazePosition(i=10, j=4, max_i=10, max_j=10), "position": maze.MazePosition(i=10, j=4, max_i=10, max_j=10),
"direction": maze.MazeDirections.BELOW, "direction": maze.MazeDirection.BELOW,
"expected": None, "expected": None,
}, },
{ {
"position": maze.MazePosition(i=1, j=0, max_i=10, max_j=10), "position": maze.MazePosition(i=1, j=0, max_i=10, max_j=10),
"direction": maze.MazeDirections.LEFT, "direction": maze.MazeDirection.LEFT,
"expected": None, "expected": None,
}, },
{ {
"position": maze.MazePosition(i=3, j=10, max_i=10, max_j=10), "position": maze.MazePosition(i=3, j=10, max_i=10, max_j=10),
"direction": maze.MazeDirections.RIGHT, "direction": maze.MazeDirection.RIGHT,
"expected": None, "expected": None,
}, },
] ]