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
|
||
) |