2026-rff_mp/krasnovia/lab2/docs/data/maze_solver.py
2026-05-20 23:04:18 +03:00

86 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Этап 4: Класс-оркестратор MazeSolver.
Принимает лабиринт и стратегию, запускает поиск,
собирает статистику и уведомляет наблюдателей.
"""
import time
from dataclasses import dataclass
from maze_model 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:
"""
Оркестратор: связывает лабиринт, стратегию и наблюдателей.
Паттерны внутри:
- Strategy: алгоритм задаётся снаружи через set_strategy()
- Observer: подписчики получают события о ходе поиска
"""
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