forked from UNN/2026-rff_mp
127 lines
4.9 KiB
Python
127 lines
4.9 KiB
Python
|
|
import time
|
|||
|
|
from dataclasses import dataclass
|
|||
|
|
from typing import List, Optional
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
#Статистика поиска пути
|
|||
|
|
class SearchStats:
|
|||
|
|
time_ms: float #Время выполнения в миллисекундах
|
|||
|
|
visited_cells: int #Количество посещенных клеток
|
|||
|
|
path_length: int #Длина найденного пути (0 если путь не найден)
|
|||
|
|
path_found: bool #Найден ли путь
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
status = "Найден" if self.path_found else "Не найден"
|
|||
|
|
return f"Stats({status}, время={self.time_ms:.2f}мс, посещено={self.visited_cells}, длина={self.path_length})"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
"""Преобразует статистику в словарь для CSV"""
|
|||
|
|
return {
|
|||
|
|
'time_ms': f"{self.time_ms:.2f}",
|
|||
|
|
'visited_cells': self.visited_cells,
|
|||
|
|
'path_length': self.path_length,
|
|||
|
|
'path_found': self.path_found
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
class MazeSolver:
|
|||
|
|
"""Оркестратор для решения лабиринта"""
|
|||
|
|
#Инициализация решателя лабиринта
|
|||
|
|
def __init__(self, maze, strategy=None):
|
|||
|
|
self.maze = maze
|
|||
|
|
self._strategy = strategy
|
|||
|
|
self._last_path = None
|
|||
|
|
|
|||
|
|
#Динамическая смена стратегии поиска
|
|||
|
|
def set_strategy(self, strategy):
|
|||
|
|
self._strategy = strategy
|
|||
|
|
print(f"Стратегия изменена на: {strategy.name}")
|
|||
|
|
|
|||
|
|
def solve(self) -> SearchStats:
|
|||
|
|
if self._strategy is None:
|
|||
|
|
raise ValueError("Стратегия не установлена! Используйте set_strategy()")
|
|||
|
|
|
|||
|
|
if self.maze.start is None:
|
|||
|
|
raise ValueError("В лабиринте нет стартовой клетки!")
|
|||
|
|
|
|||
|
|
if self.maze.exit is None:
|
|||
|
|
raise ValueError("В лабиринте нет выходной клетки!")
|
|||
|
|
|
|||
|
|
# Замер времени
|
|||
|
|
start_time = time.perf_counter()
|
|||
|
|
|
|||
|
|
# Поиск пути
|
|||
|
|
path = self._strategy.find_path(self.maze, self.maze.start, self.maze.exit)
|
|||
|
|
|
|||
|
|
end_time = time.perf_counter()
|
|||
|
|
time_ms = (end_time - start_time) * 1000
|
|||
|
|
|
|||
|
|
self._last_path = path
|
|||
|
|
|
|||
|
|
return SearchStats(
|
|||
|
|
time_ms=time_ms,
|
|||
|
|
visited_cells=self._strategy.visited_count,
|
|||
|
|
path_length=len(path),
|
|||
|
|
path_found=len(path) > 0
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def get_path(self) -> Optional[List]:
|
|||
|
|
"""Возвращает последний найденный путь"""
|
|||
|
|
return self._last_path
|
|||
|
|
|
|||
|
|
#Выводит лабиринт с найденным путем
|
|||
|
|
def print_maze_with_path(self):
|
|||
|
|
if not self._last_path:
|
|||
|
|
print("Путь еще не найден. Сначала вызовите solve()")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
path_set = set(self._last_path)
|
|||
|
|
|
|||
|
|
print(f"\n {' ' * 4}", end="")
|
|||
|
|
for x in range(self.maze.width):
|
|||
|
|
print(f"{x} ", end="")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
for y in range(self.maze.height):
|
|||
|
|
print(f" {y} │ ", end="")
|
|||
|
|
for x in range(self.maze.width):
|
|||
|
|
cell = self.maze.get_cell(x, y)
|
|||
|
|
if cell == self.maze.start:
|
|||
|
|
print("S ", end="")
|
|||
|
|
elif cell == self.maze.exit:
|
|||
|
|
print("E ", end="")
|
|||
|
|
elif cell in path_set:
|
|||
|
|
print("● ", end="")
|
|||
|
|
elif cell.is_wall:
|
|||
|
|
print("# ", end="")
|
|||
|
|
else:
|
|||
|
|
print("· ", end="")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
print("\n Условные обозначения:")
|
|||
|
|
print(" # - стена · - проход ● - путь")
|
|||
|
|
print(" S - старт E - выход")
|
|||
|
|
|
|||
|
|
#Сравнивает несколько стратегий на одном лабиринте
|
|||
|
|
def compare_strategies(self, strategies: List) -> dict:
|
|||
|
|
results = {}
|
|||
|
|
|
|||
|
|
print(f"СРАВНЕНИЕ СТРАТЕГИЙ")
|
|||
|
|
print(f"Лабиринт: {self.maze.width}x{self.maze.height}")
|
|||
|
|
|
|||
|
|
for strategy in strategies:
|
|||
|
|
self.set_strategy(strategy)
|
|||
|
|
stats = self.solve()
|
|||
|
|
results[strategy.name] = {
|
|||
|
|
'stats': stats,
|
|||
|
|
'path': self.get_path()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Вывод результатов
|
|||
|
|
status = "OK" if stats.path_found else "BULLSHIT"
|
|||
|
|
print(f"\n {status} {strategy.name}:")
|
|||
|
|
print(f" Время: {stats.time_ms:.2f} мс")
|
|||
|
|
print(f" Посещено клеток: {stats.visited_cells}")
|
|||
|
|
print(f" Длина пути: {stats.path_length}")
|
|||
|
|
|
|||
|
|
return results
|