from abc import ABC, abstractmethod from collections import deque import heapq class PathFindingStrategy(ABC): @abstractmethod def find_path(self, maze, start, exit_cell): pass class BFSStrategy(PathFindingStrategy): def find_path(self, maze, start, exit_cell): queue = deque([start]) visited = set() visited.add((start.x, start.y)) parent = {} while queue: current = queue.popleft() if current == exit_cell: return self.restore_path(parent, start, exit_cell), len(visited) for neighbor in maze.get_neighbors(current): key = (neighbor.x, neighbor.y) if key not in visited: visited.add(key) parent[key] = current queue.append(neighbor) return [], len(visited) def restore_path(self, parent, start, exit_cell): path = [] current = exit_cell while current != start: path.append(current) current = parent[(current.x, current.y)] path.append(start) path.reverse() return path class DFSStrategy(PathFindingStrategy): def find_path(self, maze, start, exit_cell): stack = [start] visited = set() visited.add((start.x, start.y)) parent = {} while stack: current = stack.pop() if current == exit_cell: return self.restore_path(parent, start, exit_cell), len(visited) for neighbor in maze.get_neighbors(current): key = (neighbor.x, neighbor.y) if key not in visited: visited.add(key) parent[key] = current stack.append(neighbor) return [], len(visited) def restore_path(self, parent, start, exit_cell): path = [] current = exit_cell while current != start: path.append(current) current = parent[(current.x, current.y)] path.append(start) path.reverse() return path class AStarStrategy(PathFindingStrategy): def heuristic(self, cell, exit_cell): return abs(cell.x - exit_cell.x) + abs(cell.y - exit_cell.y) def find_path(self, maze, start, exit_cell): heap = [] heapq.heappush(heap, (0, start.x, start.y, start)) visited = set() parent = {} g_score = { (start.x, start.y): 0 } while heap: _, _, _, current = heapq.heappop(heap) key_current = (current.x, current.y) if key_current in visited: continue visited.add(key_current) if current == exit_cell: return self.restore_path(parent, start, exit_cell), len(visited) for neighbor in maze.get_neighbors(current): key = (neighbor.x, neighbor.y) tentative = g_score[key_current] + 1 if key not in g_score or tentative < g_score[key]: g_score[key] = tentative priority = tentative + self.heuristic(neighbor, exit_cell) heapq.heappush( heap, (priority, neighbor.x, neighbor.y, neighbor) ) parent[key] = current return [], len(visited) def restore_path(self, parent, start, exit_cell): path = [] current = exit_cell while current != start: path.append(current) current = parent[(current.x, current.y)] path.append(start) path.reverse() return path