import time from dataclasses import dataclass from typing import List, Optional from maze import Maze, Cell from pathfinding import PathFindingStrategy @dataclass class SearchStats: """Статистика поиска пути.""" time_ms: float # время выполнения в миллисекундах visited_cells: int # сколько клеток посетил алгоритм path_length: int # длина найденного пути algorithm_name: str # какой алгоритм использовался maze_name: str # название лабиринта class MazeSolver: """ Оркестратор поиска пути. Использует паттерн Strategy для переключения алгоритмов. """ def __init__(self, maze: Maze, strategy: PathFindingStrategy = None): self.maze = maze self.strategy = strategy self._observers = [] # для паттерна Observer (Этап 5) def set_strategy(self, strategy: PathFindingStrategy): """ Динамическая смена алгоритма. Без паттерна Strategy пришлось бы переписывать этот метод под каждый новый алгоритм. """ self.strategy = strategy def add_observer(self, observer): """Добавление наблюдателя (подготовка к Этапу 5).""" self._observers.append(observer) def _notify_observers(self, event: str): """Уведомляет всех наблюдателей о событии.""" for observer in self._observers: observer.update(event) def solve(self, maze_name: str = "unnamed") -> SearchStats: """ Выполняет поиск пути и возвращает статистику. Args: maze_name: название лабиринта для отчёта Returns: SearchStats с результатами поиска """ if not self.strategy: raise ValueError("Стратегия не установлена! Вызовите set_strategy()") # Уведомляем наблюдателей self._notify_observers("search_started") # Замер времени start_time = time.perf_counter() # Запускаем алгоритм (Strategy делает всю работу) path, visited_count = self.strategy.find_path( self.maze, self.maze.start, self.maze.exit ) # Останавливаем замер end_time = time.perf_counter() time_ms = (end_time - start_time) * 1000 # Уведомляем о результате event = "path_found" if path else "no_path" self._notify_observers(event) # Формируем статистику return SearchStats( time_ms=time_ms, visited_cells=visited_count, path_length=len(path), algorithm_name=self.strategy.get_name(), maze_name=maze_name )