from abc import ABC, abstractmethod from collections import deque import heapq from typing import List, Dict, Optional from models import Cell, Maze class PathFindingStrategy(ABC): def __init__(self): self.visited_count = 0 @abstractmethod def findPath(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: pass def _reconstruct_path(self, parent: Dict[Cell, Optional[Cell]], current: Cell) -> List[Cell]: path = [] while current: path.append(current) current = parent.get(current) return path[::-1] class BFSStrategy(PathFindingStrategy): def findPath(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: self.visited_count = 0 queue = deque([start]) visited = {start} parent = {start: None} while queue: current = queue.popleft() self.visited_count += 1 if current == exit: return self._reconstruct_path(parent, current) for neighbor in maze.getNeighbors(current): if neighbor not in visited: visited.add(neighbor) parent[neighbor] = current queue.append(neighbor) return [] class DFSStrategy(PathFindingStrategy): def findPath(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: self.visited_count = 0 stack = [start] visited = {start} parent = {start: None} while stack: current = stack.pop() self.visited_count += 1 if current == exit: return self._reconstruct_path(parent, current) for neighbor in maze.getNeighbors(current): if neighbor not in visited: visited.add(neighbor) parent[neighbor] = current stack.append(neighbor) return [] class AStarStrategy(PathFindingStrategy): @staticmethod def _heuristic(a: Cell, b: Cell) -> int: return abs(a.x - b.x) + abs(a.y - b.y) def findPath(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: self.visited_count = 0 counter = 0 open_set = [] heapq.heappush(open_set, (0, counter, start)) counter += 1 came_from = {start: None} g_score = {start: 0} visited = set() while open_set: _, _, current = heapq.heappop(open_set) self.visited_count += 1 if current == exit: return self._reconstruct_path(came_from, current) if current in visited: continue visited.add(current) for neighbor in maze.getNeighbors(current): tentative_g_score = g_score[current] + 1 if neighbor not in g_score or tentative_g_score < g_score[neighbor]: came_from[neighbor] = current g_score[neighbor] = tentative_g_score f_score = tentative_g_score + self._heuristic(neighbor, exit) heapq.heappush(open_set, (f_score, counter, neighbor)) counter += 1 return []