import time from typing import List, Tuple, Optional from models import Maze, Cell from strategies import PathFindingStrategy class SearchStats: def __init__(self, time_ms: float, visited: int, path_length: int): self.time_ms = time_ms self.visited_count = visited self.path_length = path_length def __str__(self): return (f"Время: {self.time_ms:.4f} мс | " f"Посещено: {self.visited_count} | " f"Длина пути: {self.path_length}") class MazeSolver: def __init__(self, maze: Maze, strategy: Optional[PathFindingStrategy] = None): self.maze = maze self.strategy = strategy self._observers = [] def setStrategy(self, strategy: PathFindingStrategy): self.strategy = strategy def attach(self, observer): self._observers.append(observer) def detach(self, observer): self._observers.remove(observer) def _notify(self, event: str, data=None): for observer in self._observers: observer.update(event, data) def solve(self) -> Tuple[List[Cell], SearchStats]: if not self.strategy: raise ValueError("Стратегия поиска не установлена.") if not self.maze.start or not self.maze.exit: raise ValueError("В лабиринте не определены старт или выход.") self._notify("search_started", {"strategy": type(self.strategy).__name__}) start_time = time.perf_counter() path = self.strategy.findPath(self.maze, self.maze.start, self.maze.exit) end_time = time.perf_counter() elapsed_ms = (end_time - start_time) * 1000 visited = self.strategy.visited_count path_len = len(path) stats = SearchStats(elapsed_ms, visited, path_len) if path: self._notify("path_found", {"path": path, "stats": stats}) else: self._notify("path_not_found", {"stats": stats}) return path, stats