feat: add the Randomised DST search algorithm

Implement a variation to the DST search algorithm to the Solver class.
In this variation, the solver randomly chooses the next direction when
it reaches a fork in its path.
This commit is contained in:
Dan Anglin 2024-02-17 01:37:20 +00:00
parent a091f0a68d
commit 8466500092
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
2 changed files with 72 additions and 10 deletions

View file

@ -9,8 +9,8 @@ def main():
game = Maze( game = Maze(
x_position=10, x_position=10,
y_position=10, y_position=10,
height=16, height=19,
width=16, width=19,
cell_height=40, cell_height=40,
cell_width=40, cell_width=40,
window=window window=window
@ -18,7 +18,7 @@ def main():
solver = Solver(game) solver = Solver(game)
if solver.solve(): if solver.solve(solver.solve_with_randomised_dst_r):
print("Maze solved successfully :)") print("Maze solved successfully :)")
else: else:
print("I'm unable to solve the maze :(") print("I'm unable to solve the maze :(")

View file

@ -1,4 +1,5 @@
from typing import Dict from typing import Dict, Callable, List
import random
from maze import Maze, MazeDirection, MazePosition from maze import Maze, MazeDirection, MazePosition
from cell import CellWallLabels from cell import CellWallLabels
@ -20,7 +21,10 @@ class Solver:
MazeDirection.RIGHT: CellWallLabels.LEFT, MazeDirection.RIGHT: CellWallLabels.LEFT,
} }
def solve(self) -> bool: def solve(
self,
solve_method: Callable[[MazePosition, MazePosition], bool],
) -> bool:
""" """
solve attempts to solve the generated maze. solve attempts to solve the generated maze.
""" """
@ -38,9 +42,9 @@ class Solver:
last_j=self._game.get_last_j(), last_j=self._game.get_last_j(),
) )
return self._solve_r(start_position, end_position) return solve_method(start_position, end_position)
def _solve_r( def solve_with_dst_r(
self, self,
current_position: MazePosition, current_position: MazePosition,
end_position: MazePosition, end_position: MazePosition,
@ -73,9 +77,67 @@ class Solver:
continue continue
self._game.draw_path_between(current_position, adjacent_position) self._game.draw_path_between(current_position, adjacent_position)
result = self._solve_r(adjacent_position, end_position) solved = self.solve_with_dst_r(adjacent_position, end_position)
if result is True: if solved:
return True return True
self._game.draw_path_between(current_position, adjacent_position, undo=True) self._game.draw_path_between(
current_position, adjacent_position, undo=True)
return False
def solve_with_randomised_dst_r(
self,
current_position: MazePosition,
end_position: MazePosition,
) -> bool:
if current_position == end_position:
return True
self._game.mark_cell_as_visited(
i=current_position.i,
j=current_position.j,
visitor=self._solver,
)
random.seed()
while True:
possible_directions: List[MazeDirection] = []
for direction in MazeDirection:
adjacent_position = current_position.get_adjacent_position(
direction)
if adjacent_position is None:
continue
if self._game.cell_was_visited_by(
i=adjacent_position.i,
j=adjacent_position.j,
visitor=self._solver,
) or self._game.cell_wall_exists(
i=adjacent_position.i,
j=adjacent_position.j,
wall=self._wall_map[direction],
):
continue
possible_directions.append(direction)
if len(possible_directions) == 0:
break
chosen_direction = None
if len(possible_directions) == 1:
chosen_direction = possible_directions[0]
else:
chosen_direction = random.choice(possible_directions)
next_position = current_position.get_adjacent_position(
chosen_direction,
)
self._game.draw_path_between(current_position, next_position)
solved = self.solve_with_randomised_dst_r(
next_position, end_position)
if solved:
return True
self._game.draw_path_between(
current_position,
next_position,
undo=True
)
return False return False