import heapq from abc import ABC, abstractmethod from collections import deque from typing import List from .cell import Cell from .maze import Maze class PathFindingStrategy(ABC): def __init__(self): self.visited_count = 0 @abstractmethod def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]: pass def reconstruct_path(self, came_from: dict, exit_cell: Cell) -> List[Cell]: path = [] current = exit_cell while current is not None: path.append(current) current = came_from.get(current) path.reverse() return path class BFSStrategy(PathFindingStrategy): def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]: queue = deque([start]) came_from = {start: None} visited = {start} while queue: current = queue.popleft() if current == exit_cell: self.visited_count = len(visited) return self.reconstruct_path(came_from, exit_cell) for neighbor in maze.get_neighbors(current): if neighbor not in visited: visited.add(neighbor) came_from[neighbor] = current queue.append(neighbor) self.visited_count = len(visited) return [] class DFSStrategy(PathFindingStrategy): def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]: stack = [start] came_from = {start: None} visited = {start} while stack: current = stack.pop() if current == exit_cell: self.visited_count = len(visited) return self.reconstruct_path(came_from, exit_cell) for neighbor in maze.get_neighbors(current): if neighbor not in visited: visited.add(neighbor) came_from[neighbor] = current stack.append(neighbor) self.visited_count = len(visited) return [] class AStarStrategy(PathFindingStrategy): def heuristic(self, cell: Cell, exit_cell: Cell) -> int: return abs(cell.x - exit_cell.x) + abs(cell.y - exit_cell.y) def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]: heap = [] counter = 0 start_f = self.heuristic(start, exit_cell) heapq.heappush(heap, (start_f, counter, start)) counter += 1 came_from = {} g_score = {start: 0} f_score = {start: start_f} visited = set() while heap: current_f, _, current = heapq.heappop(heap) visited.add(current) if current == exit_cell: self.visited_count = len(visited) return self.reconstruct_path(came_from, exit_cell) if current_f > f_score.get(current, float("inf")): continue for neighbor in maze.get_neighbors(current): tentative_g = g_score[current] + 1 if tentative_g < g_score.get(neighbor, float("inf")): came_from[neighbor] = current g_score[neighbor] = tentative_g new_f = tentative_g + self.heuristic(neighbor, exit_cell) f_score[neighbor] = new_f heapq.heappush(heap, (new_f, counter, neighbor)) counter += 1 self.visited_count = len(visited) return []