import os import random import time import csv from typing import Dict, List import matplotlib.pyplot as plt import numpy as np from maze import Maze, Cell from maze_builder import RandomMazeBuilder from pathfinding import BFSStrategy, DFSStrategy, AStarStrategy, DijkstraStrategy from maze_solver import MazeSolver, SearchStats def create_test_mazes() -> Dict[str, Maze]: """Создаёт тестовые лабиринты разной сложности.""" mazes = {} # 1. Маленький 10×10 с простым путём small = Maze(10, 10) for y in range(10): for x in range(10): is_wall = (x == 0 or x == 9 or y == 0 or y == 9 or (x == 3 and y < 7) or (x == 6 and y > 2)) is_start = (x == 1 and y == 1) is_exit = (x == 8 and y == 8) small.set_cell(x, y, Cell(x, y, is_wall=is_wall, is_start=is_start, is_exit=is_exit)) mazes['small_10x10'] = small # 2. Средний 50×50 — случайный mazes['medium_50x50'] = RandomMazeBuilder(51, 51).build_from_file() # 3. Большой 100×100 — случайный mazes['large_100x100'] = RandomMazeBuilder(101, 101).build_from_file() # 4. Пустой 20×20 — без стен empty = Maze(20, 20) for y in range(20): for x in range(20): empty.set_cell(x, y, Cell(x, y, is_wall=False, is_start=(x==1 and y==1), is_exit=(x==18 and y==18))) mazes['empty_20x20'] = empty # 5. Без выхода — проверка обработки no_exit = Maze(10, 10) for y in range(10): for x in range(10): is_wall = (x == 0 or x == 9 or y == 0 or y == 9 or x == 5) no_exit.set_cell(x, y, Cell(x, y, is_wall=is_wall, is_start=(x==1 and y==1))) mazes['no_exit_10x10'] = no_exit # 6. Взвешенный 15×15 weighted = Maze(15, 15) for y in range(15): for x in range(15): is_wall = (x == 0 or x == 14 or y == 0 or y == 14 or (x == 5 and y != 7) or (x == 10 and y != 3)) weight = 1 if 3 <= x <= 7 and 3 <= y <= 7: weight = 2 # песок elif 8 <= x <= 12 and 8 <= y <= 12: weight = 3 # болото weighted.set_cell(x, y, Cell(x, y, is_wall=is_wall, is_start=(x==1 and y==1), is_exit=(x==13 and y==13), weight=weight)) mazes['weighted_15x15'] = weighted return mazes def run_experiments(mazes: Dict[str, Maze], strategies: List, runs_per_test: int = 5) -> List[SearchStats]: """Запускает эксперименты, возвращает список статистик.""" results = [] for maze_name, maze in mazes.items(): print(f"\n{'='*60}") print(f"Лабиринт: {maze_name} ({maze.width}x{maze.height})") print(f"{'='*60}") for strategy in strategies: print(f"\nАлгоритм: {strategy.get_name()}") times = [] visited_list = [] path_lens = [] solver = MazeSolver(maze, strategy) for run in range(runs_per_test): stats = solver.solve(maze_name) times.append(stats.time_ms) visited_list.append(stats.visited_cells) path_lens.append(stats.path_length) print(f" Запуск {run+1}: {stats.time_ms:.4f} мс, " f"посещено: {stats.visited_cells}, " f"длина: {stats.path_length}") # Средние значения avg = SearchStats( time_ms=np.mean(times), visited_cells=int(np.mean(visited_list)), path_length=int(np.mean(path_lens)), algorithm_name=strategy.get_name(), maze_name=maze_name ) results.append(avg) print(f" СРЕДНЕЕ: {avg.time_ms:.4f} мс, " f"посещено: {avg.visited_cells}, " f"длина: {avg.path_length}") return results def save_csv(results: List[SearchStats], filename: str): """Сохраняет результаты в CSV.""" with open(filename, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(['Лабиринт', 'Алгоритм', 'Время_мс', 'Посещено_клеток', 'Длина_пути']) for r in results: writer.writerow([ r.maze_name, r.algorithm_name, f"{r.time_ms:.6f}", r.visited_cells, r.path_length ]) print(f"\nCSV сохранён: {filename}") def create_plots(results: List[SearchStats], output_dir: str = "."): """Создаёт графики сравнения.""" os.makedirs(output_dir, exist_ok=True) maze_names = sorted(set(r.maze_name for r in results)) algorithms = sorted(set(r.algorithm_name for r in results)) # 1. Общее сравнение по лабиринтам fig, axes = plt.subplots(2, 3, figsize=(18, 12)) fig.suptitle('Сравнение алгоритмов поиска пути', fontsize=16) for idx, maze_name in enumerate(maze_names): ax = axes[idx // 3, idx % 3] maze_res = [r for r in results if r.maze_name == maze_name] names = [r.algorithm_name for r in maze_res] times = [r.time_ms for r in maze_res] visited = [r.visited_cells for r in maze_res] paths = [r.path_length for r in maze_res] x = np.arange(len(names)) w = 0.25 ax.bar(x - w, times, w, label='Время (мс)', color='skyblue') ax.bar(x, [v/10 for v in visited], w, label='Посещено (÷10)', color='lightcoral') ax.bar(x + w, paths, w, label='Длина пути', color='lightgreen') ax.set_title(maze_name) ax.set_xticks(x) ax.set_xticklabels(names, rotation=45) ax.legend(fontsize=8) ax.grid(True, alpha=0.3) plt.tight_layout() plt.savefig(f'{output_dir}/maze_comparison.png', dpi=150) plt.close() # 2. Посещённые клетки fig, ax = plt.subplots(figsize=(14, 8)) for algo in algorithms: algo_res = [r for r in results if r.algorithm_name == algo] names = [r.maze_name for r in algo_res] vals = [r.visited_cells for r in algo_res] ax.plot(names, vals, marker='o', label=algo, linewidth=2) ax.set_title('Посещённые клетки по лабиринтам', fontsize=14) ax.set_xlabel('Лабиринт') ax.set_ylabel('Клетки') ax.legend() ax.grid(True, alpha=0.3) plt.xticks(rotation=45) plt.tight_layout() plt.savefig(f'{output_dir}/visited_cells.png', dpi=150) plt.close() # 3. Время выполнения (логарифмическая шкала) fig, ax = plt.subplots(figsize=(14, 8)) for algo in algorithms: algo_res = [r for r in results if r.algorithm_name == algo] names = [r.maze_name for r in algo_res] vals = [max(r.time_ms, 0.001) for r in algo_res] ax.plot(names, vals, marker='s', label=algo, linewidth=2) ax.set_title('Время выполнения (лог. шкала)', fontsize=14) ax.set_xlabel('Лабиринт') ax.set_ylabel('Время (мс)') ax.set_yscale('log') ax.legend() ax.grid(True, alpha=0.3, which='both') plt.xticks(rotation=45) plt.tight_layout() plt.savefig(f'{output_dir}/time_comparison.png', dpi=150) plt.close() print(f"Графики сохранены в {output_dir}/") if __name__ == "__main__": print("=" * 70) print("ЭКСПЕРИМЕНТАЛЬНАЯ ЧАСТЬ") print("=" * 70) # Создаём лабиринты mazes = create_test_mazes() # Алгоритмы для сравнения strategies = [BFSStrategy(), DFSStrategy(), AStarStrategy(), DijkstraStrategy()] # Запускаем эксперименты results = run_experiments(mazes, strategies, runs_per_test=5) # Сохраняем CSV save_csv(results, "experiment_results.csv") # Строим графики create_plots(results) print("\n" + "=" * 70) print("ГОТОВО!") print("=" * 70)