from abc import ABC, abstractmethod from typing import Optional from source.models.base import Maze, Cell class PathFindingStrategy(ABC): """Интерфейс стратегии поиска пути в лабиринте.""" @abstractmethod def find_path( self, maze: Maze, start: Cell = None, exit: Cell = None ) -> list[Cell]: """Найти путь от start до exit. Args: maze: Объект лабиринта. start: Стартовая клетка. exit: Целевая клетка. Returns: Список клеток пути (от start до exit включительно). Пустой список, если путь не найден. """ def _validate( self, maze: Maze, start: Optional[Cell], exit: Optional[Cell] ) -> tuple[Optional[Cell], Optional[Cell]]: """Подставляет start/exit из лабиринта если не переданы явно. Raises: ValueError: Если старт или выход не найдены. """ if start is None: start = maze.start if exit is None: exit = maze.exit if start is None: raise ValueError("Стартовая клетка не найдена в лабиринте") if exit is None: raise ValueError("Выходная клетка не найдена в лабиринте") return start, exit def _reconstruct_path( self, came_from: dict[Cell, Optional[Cell]], end: Cell ) -> list[Cell]: """Восстанавливает путь от старта до end, идя по came_from в обратном порядке. Args: came_from: Словарь {клетка: родитель}, где родитель старта = None. end: Конечная клетка. Returns: Список клеток пути от старта до end включительно. Пустой список, если end отсутствует в came_from. """ if end not in came_from: return [] path: list[Cell] = [] current: Optional[Cell] = end while current is not None: path.append(current) current = came_from[current] path.reverse() return path