from abc import ABC, abstractmethod from collections import deque import heapq class PathFindingStrategy(ABC): @abstractmethod def find_path(self, maze, start, exit_cell): pass def _reconstruct_path(came_from, start, exit_cell): path = [] current = exit_cell while current is not None: path.append(current) current = came_from.get((current.x, current.y)) path.reverse() if path and path[0].x == start.x and path[0].y == start.y: return path return [] class BFSStrategy(PathFindingStrategy): def find_path(self, maze, start, exit_cell): queue = deque([start]) came_from = {(start.x, start.y): None} self.visited_count = 0 while queue: current = queue.popleft() self.visited_count += 1 if current.x == exit_cell.x and current.y == exit_cell.y: return _reconstruct_path(came_from, start, exit_cell) for neighbor in maze.get_neighbors(current): key = (neighbor.x, neighbor.y) if key not in came_from: came_from[key] = current queue.append(neighbor) self.visited_count = len(came_from) return [] # путь не найден class DFSStrategy(PathFindingStrategy): def find_path(self, maze, start, exit_cell): stack = [start] came_from = {(start.x, start.y): None} self.visited_count = 0 while stack: current = stack.pop() self.visited_count += 1 if current.x == exit_cell.x and current.y == exit_cell.y: return _reconstruct_path(came_from, start, exit_cell) for neighbor in maze.get_neighbors(current): key = (neighbor.x, neighbor.y) if key not in came_from: came_from[key] = current stack.append(neighbor) self.visited_count = len(came_from) return [] class AStarStrategy(PathFindingStrategy): def _heuristic(self, cell, goal): return abs(cell.x - goal.x) + abs(cell.y - goal.y) def find_path(self, maze, start, exit_cell): # (f_score, счётчик для разрыва связей, клетка) counter = 0 open_set = [(0, counter, start)] came_from = {(start.x, start.y): None} g_score = {(start.x, start.y): 0} self.visited_count = 0 while open_set: _, _, current = heapq.heappop(open_set) self.visited_count += 1 if current.x == exit_cell.x and current.y == exit_cell.y: return _reconstruct_path(came_from, start, exit_cell) for neighbor in maze.get_neighbors(current): key = (neighbor.x, neighbor.y) tentative_g = g_score[(current.x, current.y)] + 1 if key not in g_score or tentative_g < g_score[key]: g_score[key] = tentative_g f = tentative_g + self._heuristic(neighbor, exit_cell) counter += 1 heapq.heappush(open_set, (f, counter, neighbor)) came_from[key] = current self.visited_count = len(came_from) return []