2026-05-24 14:17:02 +00:00
|
|
|
|
import time
|
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
|
|
|
|
|
|
from source.models.base import Maze, Cell
|
|
|
|
|
|
from source.strategy import PathFindingStrategy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class SearchStats:
|
|
|
|
|
|
"""Статистика выполнения поиска пути.
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
elapsed_ms: Время выполнения в миллисекундах.
|
|
|
|
|
|
visited_count: Количество посещённых клеток.
|
|
|
|
|
|
path_length: Длина найденного пути (0 если путь не найден).
|
|
|
|
|
|
path: Найденный путь — список клеток от старта до выхода.
|
|
|
|
|
|
"""
|
2026-05-25 07:23:00 +00:00
|
|
|
|
|
2026-05-24 14:17:02 +00:00
|
|
|
|
elapsed_ms: float
|
|
|
|
|
|
visited_count: int
|
|
|
|
|
|
path_length: int
|
|
|
|
|
|
path: list[Cell]
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
|
return (
|
|
|
|
|
|
f"Время: {self.elapsed_ms:.3f} мс | "
|
|
|
|
|
|
f"Посещено клеток: {self.visited_count} | "
|
|
|
|
|
|
f"Длина пути: {self.path_length}"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MazeSolver:
|
|
|
|
|
|
"""Оркестратор поиска пути в лабиринте.
|
|
|
|
|
|
|
|
|
|
|
|
Принимает лабиринт и стратегию поиска, выполняет поиск
|
|
|
|
|
|
и возвращает результат вместе со статистикой выполнения.
|
|
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
solver = MazeSolver(maze, BFSStrategy())
|
|
|
|
|
|
stats = solver.solve()
|
|
|
|
|
|
print(stats)
|
|
|
|
|
|
|
|
|
|
|
|
solver.set_strategy(AStarStrategy())
|
|
|
|
|
|
stats = solver.solve()
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, maze: Maze, strategy: PathFindingStrategy) -> None:
|
|
|
|
|
|
"""Инициализирует солвер с лабиринтом и стратегией поиска.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
maze: Объект лабиринта.
|
|
|
|
|
|
strategy: Стратегия поиска пути.
|
|
|
|
|
|
"""
|
|
|
|
|
|
self._maze = maze
|
|
|
|
|
|
self._strategy = strategy
|
|
|
|
|
|
|
|
|
|
|
|
def set_strategy(self, strategy: PathFindingStrategy) -> None:
|
|
|
|
|
|
"""Заменяет текущую стратегию поиска.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
strategy: Новая стратегия поиска пути.
|
|
|
|
|
|
"""
|
|
|
|
|
|
self._strategy = strategy
|
|
|
|
|
|
|
|
|
|
|
|
def solve(
|
|
|
|
|
|
self,
|
|
|
|
|
|
start: Cell = None,
|
|
|
|
|
|
exit: Cell = None,
|
|
|
|
|
|
) -> SearchStats:
|
|
|
|
|
|
"""Выполняет поиск пути и собирает статистику.
|
|
|
|
|
|
|
|
|
|
|
|
Если start или exit не переданы явно, стратегия найдёт
|
|
|
|
|
|
их самостоятельно по флагам is_start / is_exit в лабиринте.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
start: Стартовая клетка (опционально).
|
|
|
|
|
|
exit: Конечная клетка (опционально).
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
Объект SearchStats с временем выполнения, количеством
|
|
|
|
|
|
посещённых клеток и длиной найденного пути.
|
|
|
|
|
|
"""
|
|
|
|
|
|
t_start = time.perf_counter()
|
|
|
|
|
|
path = self._strategy.find_path(self._maze, start, exit)
|
|
|
|
|
|
t_end = time.perf_counter()
|
|
|
|
|
|
|
|
|
|
|
|
elapsed_ms = (t_end - t_start) * 1000
|
|
|
|
|
|
|
|
|
|
|
|
return SearchStats(
|
|
|
|
|
|
elapsed_ms=elapsed_ms,
|
|
|
|
|
|
visited_count=len(path),
|
|
|
|
|
|
path_length=len(path),
|
|
|
|
|
|
path=path,
|
2026-05-25 07:23:00 +00:00
|
|
|
|
)
|