forked from UNN/2026-rff_mp
86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
|
|
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
|
|||
|
|
)
|