from __future__ import annotations import time from dataclasses import dataclass from .models import Cell, Maze from .observers import Event, Observer from .strategies import PathFindingStrategy @dataclass(frozen=True) class SearchStats: strategy_name: str time_ms: float visited_cells: int path_length: int path: list[Cell] class MazeSolver: def __init__(self, maze: Maze, strategy: PathFindingStrategy) -> None: self.maze = maze self.strategy = strategy self._observers: list[Observer] = [] def set_strategy(self, strategy: PathFindingStrategy) -> None: self.strategy = strategy def setStrategy(self, strategy: PathFindingStrategy) -> None: self.set_strategy(strategy) def add_observer(self, observer: Observer) -> None: self._observers.append(observer) def remove_observer(self, observer: Observer) -> None: self._observers.remove(observer) def solve(self) -> SearchStats: self._notify(Event("search_started", {"strategy": self.strategy.name})) started_at = time.perf_counter() result = self.strategy.find_path(self.maze, self.maze.start, self.maze.exit) elapsed_ms = (time.perf_counter() - started_at) * 1000 stats = SearchStats( strategy_name=self.strategy.name, time_ms=elapsed_ms, visited_cells=result.visited_count, path_length=len(result.path), path=result.path, ) event_name = "path_found" if result.path else "path_not_found" self._notify(Event(event_name, {"stats": stats})) return stats def _notify(self, event: Event) -> None: for observer in self._observers: observer.update(event)