2026-rff_mp/MarkinAM/2/solver.py

71 lines
2.8 KiB
Python
Raw Normal View History

2026-05-25 06:57:30 +00:00
import time
from dataclasses import dataclass
from classes import Maze, Cell
from strategies import PathFindingStrategy
from observer import Observer
@dataclass
class SearchStats:
"""Результаты одного запуска поиска."""
time_ms: float # время выполнения в миллисекундах
visited_cells: int # количество посещённых клеток
path_length: int # длина найденного пути (0 если не найден)
path: list[Cell] # сам путь
class MazeSolver:
def __init__(self, maze: Maze, strategy: PathFindingStrategy | None = None):
self.maze = maze
self.strategy = strategy
self._observers: list[Observer] = []
# ── Strategy ──────────────────────────────────────────────────────────────
def set_strategy(self, strategy: PathFindingStrategy) -> None:
"""Динамически меняет алгоритм поиска."""
self.strategy = strategy
# ── Observer ──────────────────────────────────────────────────────────────
def add_observer(self, observer: Observer) -> None:
self._observers.append(observer)
def remove_observer(self, observer: Observer) -> None:
self._observers.remove(observer)
def _notify(self, event: dict) -> None:
for obs in self._observers:
obs.update(event)
# ── Solve ─────────────────────────────────────────────────────────────────
def solve(self) -> SearchStats:
"""Запускает поиск пути и возвращает статистику."""
if self.strategy is None:
raise RuntimeError("Стратегия не задана. Используйте set_strategy().")
self._notify({"type": "maze_loaded", "maze": self.maze})
t_start = time.perf_counter()
path = self.strategy.find_path(self.maze, self.maze.start, self.maze.exit)
t_end = time.perf_counter()
time_ms = (t_end - t_start) * 1000
visited = getattr(self.strategy, "visited_count", 0)
stats = SearchStats(
time_ms=time_ms,
visited_cells=visited,
path_length=len(path),
path=path,
)
if path:
self._notify({"type": "path_found", "maze": self.maze, "path": path})
else:
self._notify({"type": "no_path"})
return stats