""" Экспериментальный запуск для всех лабиринтов и алгоритмов Создание CSV и графиков """ import os import csv from datetime import datetime from maze_model import Maze from maze_builder import TextFileMazeBuilder from pathfinding_strategies import BFSStrategy, DFSStrategy, AStarStrategy from maze_solver import MazeSolver, SearchStats class ExperimentRunner: def __init__(self): self.all_results = [] self.labirints = { 'labirint1.txt': 'Маленький (10x10) с простым путём', 'labirint2.txt': 'Средний (50x50) с тупиками', 'labirint3.txt': 'Большой (100x100) запутанный', 'labirint4.txt': 'Пустой (20x20) без стен', 'labirint5.txt': 'Без выхода (20x20)' } self.strategies = [ BFSStrategy(), DFSStrategy(), AStarStrategy() ] def run_all_experiments(self): """Запускает эксперименты для всех лабиринтов и алгоритмов""" print("\n" + "="*70) print("ЗАПУСК ЭКСПЕРИМЕНТОВ") print("="*70) builder = TextFileMazeBuilder() for filename, description in self.labirints.items(): if not os.path.exists(filename): print(f"\n⚠️ Файл {filename} не найден, пропускаем...") continue print(f"\n📁 Лабиринт: {description}") print(f" Файл: {filename}") print("-" * 50) try: maze = builder.build_from_file(filename) maze_name = filename.replace('.txt', '') for strategy in self.strategies: print(f" Тестирование {strategy.get_name()}...", end=" ", flush=True) solver = MazeSolver(maze, maze_name, strategy) path, stats = solver.solve_with_stats() self.all_results.append({ 'лабиринт': description, 'стратегия': stats.algorithm_name, 'время_мс': stats.execution_time_ms, 'посещено_клеток': stats.visited_cells, 'длина_пути': stats.path_length, 'путь_найден': 'Да' if stats.path_found else 'Нет', 'размер': stats.maze_size }) print(f"готово! время={stats.execution_time_ms:.3f}мс, путь={stats.path_length}") except Exception as e: print(f" ❌ Ошибка: {e}") print("\n" + "="*70) print("ЭКСПЕРИМЕНТЫ ЗАВЕРШЕНЫ") print("="*70) def save_to_csv(self, filename="experiment_results.csv"): """Сохраняет результаты в CSV""" if not self.all_results: print("Нет результатов для сохранения!") return with open(filename, 'w', newline='', encoding='utf-8-sig') as f: fieldnames = ['лабиринт', 'стратегия', 'время_мс', 'посещено_клеток', 'длина_пути', 'путь_найден', 'размер'] writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(self.all_results) print(f"\n✅ Результаты сохранены в {filename}") # Показываем содержимое CSV print("\n" + "="*70) print("СОДЕРЖИМОЕ CSV ФАЙЛА:") print("="*70) with open(filename, 'r', encoding='utf-8-sig') as f: print(f.read()) def create_charts(self): """Создаёт графики для каждого лабиринта""" try: import matplotlib.pyplot as plt import numpy as np print("\n" + "="*70) print("ПОСТРОЕНИЕ ГРАФИКОВ") print("="*70) # Группируем результаты по лабиринтам results_by_maze = {} for result in self.all_results: maze = result['лабиринт'] if maze not in results_by_maze: results_by_maze[maze] = [] results_by_maze[maze].append(result) # Для каждого лабиринта создаём отдельный график for maze_name, maze_results in results_by_maze.items(): fig, axes = plt.subplots(1, 3, figsize=(15, 5)) fig.suptitle(f'Сравнение алгоритмов: {maze_name}', fontsize=14, fontweight='bold') algorithms = [r['стратегия'] for r in maze_results] # График 1: Время выполнения times = [r['время_мс'] for r in maze_results] bars1 = axes[0].bar(algorithms, times, color=['blue', 'green', 'red']) axes[0].set_ylabel('Время (мс)') axes[0].set_title('Время выполнения') axes[0].tick_params(axis='x', rotation=15) for bar, val in zip(bars1, times): axes[0].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5, f'{val:.3f}', ha='center', va='bottom', fontsize=9) # График 2: Посещённые клетки visited = [r['посещено_клеток'] for r in maze_results] bars2 = axes[1].bar(algorithms, visited, color=['blue', 'green', 'red']) axes[1].set_ylabel('Количество клеток') axes[1].set_title('Посещённые клетки') axes[1].tick_params(axis='x', rotation=15) for bar, val in zip(bars2, visited): axes[1].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1, f'{val:.0f}', ha='center', va='bottom', fontsize=9) # График 3: Длина пути lengths = [r['длина_пути'] for r in maze_results] bars3 = axes[2].bar(algorithms, lengths, color=['blue', 'green', 'red']) axes[2].set_ylabel('Шагов') axes[2].set_title('Длина найденного пути') axes[2].tick_params(axis='x', rotation=15) for bar, val in zip(bars3, lengths): axes[2].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5, f'{val:.0f}', ha='center', va='bottom', fontsize=9) plt.tight_layout() # Сохраняем график safe_name = maze_name.replace(' ', '_').replace('(', '').replace(')', '').replace('×', 'x') filename = f"chart_{safe_name}.png" plt.savefig(filename, dpi=150, bbox_inches='tight') print(f"✅ Сохранён: {filename}") plt.close() # Общий сводный график self._create_summary_chart() except ImportError: print("\n⚠️ Для построения графиков установите matplotlib:") print(" pip install matplotlib numpy") def _create_summary_chart(self): """Создаёт сводный график по всем лабиринтам""" import matplotlib.pyplot as plt import numpy as np fig, axes = plt.subplots(2, 2, figsize=(14, 10)) fig.suptitle('Сводное сравнение алгоритмов по всем лабиринтам', fontsize=14, fontweight='bold') # Получаем уникальные лабиринты и алгоритмы mazes = list(set([r['лабиринт'] for r in self.all_results])) algorithms = ['BFS (Поиск в ширину)', 'DFS (Поиск в глубину)', 'A* (A-Star)'] # 1. Время по лабиринтам ax1 = axes[0, 0] x = np.arange(len(mazes)) width = 0.25 for i, algo in enumerate(algorithms): times = [] for maze in mazes: result = next((r for r in self.all_results if r['лабиринт'] == maze and r['стратегия'] == algo), None) times.append(result['время_мс'] if result else 0) bars = ax1.bar(x + (i - 1) * width, times, width, label=algo) for bar, val in zip(bars, times): if val > 0: ax1.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5, f'{val:.1f}', ha='center', va='bottom', fontsize=7) ax1.set_xlabel('Лабиринт') ax1.set_ylabel('Время (мс)') ax1.set_title('Сравнение времени выполнения') ax1.set_xticks(x) ax1.set_xticklabels([m[:20] for m in mazes], rotation=45, ha='right') ax1.legend() # 2. Посещённые клетки ax2 = axes[0, 1] for i, algo in enumerate(algorithms): visited = [] for maze in mazes: result = next((r for r in self.all_results if r['лабиринт'] == maze and r['стратегия'] == algo), None) visited.append(result['посещено_клеток'] if result else 0) bars = ax2.bar(x + (i - 1) * width, visited, width, label=algo) for bar, val in zip(bars, visited): if val > 0: ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5, f'{val:.0f}', ha='center', va='bottom', fontsize=7) ax2.set_xlabel('Лабиринт') ax2.set_ylabel('Посещённые клетки') ax2.set_title('Сравнение посещённых клеток') ax2.set_xticks(x) ax2.set_xticklabels([m[:20] for m in mazes], rotation=45, ha='right') ax2.legend() # 3. Длина пути ax3 = axes[1, 0] for i, algo in enumerate(algorithms): lengths = [] for maze in mazes: result = next((r for r in self.all_results if r['лабиринт'] == maze and r['стратегия'] == algo), None) lengths.append(result['длина_пути'] if result else 0) bars = ax3.bar(x + (i - 1) * width, lengths, width, label=algo) for bar, val in zip(bars, lengths): if val > 0: ax3.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1, f'{val:.0f}', ha='center', va='bottom', fontsize=7) ax3.set_xlabel('Лабиринт') ax3.set_ylabel('Длина пути (шагов)') ax3.set_title('Сравнение длины пути') ax3.set_xticks(x) ax3.set_xticklabels([m[:20] for m in mazes], rotation=45, ha='right') ax3.legend() # 4. Таблица результатов ax4 = axes[1, 1] ax4.axis('tight') ax4.axis('off') # Создаём таблицу table_data = [] for maze in mazes: row = [maze[:25]] for algo in algorithms: result = next((r for r in self.all_results if r['лабиринт'] == maze and r['стратегия'] == algo), None) if result: row.append(f"{result['время_мс']:.1f}мс") else: row.append("-") table_data.append(row) columns = ['Лабиринт', 'BFS', 'DFS', 'A*'] table = ax4.table(cellText=table_data, colLabels=columns, cellLoc='center', loc='center') table.auto_set_font_size(False) table.set_fontsize(9) table.scale(1.2, 1.5) ax4.set_title('Сводная таблица (время в мс)', fontsize=10) plt.tight_layout() plt.savefig('summary_chart.png', dpi=150, bbox_inches='tight') print("Сохранён: summary_chart.png") plt.close() def main(): runner = ExperimentRunner() runner.run_all_experiments() runner.save_to_csv("experiment_results.csv") runner.create_charts() if __name__ == "__main__": main()