import time import csv import os import random from maze_builder import TextFileMazeBuilder from maze_solver import MazeSolver from maze_strategies import BFSStrategy, DFSStrategy, AStarStrategy REPEATS = 7 OUTPUT_DIR = os.path.dirname(os.path.abspath(__file__)) CSV_PATH = os.path.join(OUTPUT_DIR, 'results.csv') STRATEGIES = { 'BFS': BFSStrategy, 'DFS': DFSStrategy, 'A*': AStarStrategy, } MAZES = [ ('small_10x10', 'maze_small.txt'), ('medium_50x50', 'maze_medium.txt'), ('large_100x100', 'maze_large.txt'), ('open_50x50', 'maze_open.txt'), ('no_exit_20x20', 'maze_no_exit.txt'), ] def _make_grid(width, height, density=0.0, has_exit=True, seed=42): rng = random.Random(seed) grid = [] for y in range(height): row = [] for x in range(width): on_border = (x == 0 or x == width - 1 or y == 0 or y == height - 1) row.append('#' if on_border else ' ') grid.append(row) for y in range(1, height - 1): for x in range(1, width - 1): if rng.random() < density: grid[y][x] = '#' grid[1][1] = 'S' if has_exit: grid[height - 2][width - 2] = 'E' return '\n'.join(''.join(row) for row in grid) def generate_maze_files(): mazes_data = { 'maze_small.txt': _make_grid(10, 10, density=0.15), 'maze_medium.txt': _make_grid(50, 50, density=0.28), 'maze_large.txt': _make_grid(100, 100, density=0.30), 'maze_open.txt': _make_grid(50, 50, density=0.0), 'maze_no_exit.txt': _make_grid(20, 20, density=0.20, has_exit=False), } no_exit = list(mazes_data['maze_no_exit.txt'].splitlines()) no_exit[18] = no_exit[18][:18] + 'E' + no_exit[18][19:] no_exit[17] = no_exit[17][:18] + '#' + no_exit[17][19:] no_exit[18] = no_exit[18][:17] + '#' + no_exit[18][18:] mazes_data['maze_no_exit.txt'] = '\n'.join(no_exit) maze_dir = os.path.dirname(os.path.abspath(__file__)) for fname, content in mazes_data.items(): path = os.path.join(maze_dir, fname) with open(path, 'w', encoding='utf-8') as f: f.write(content) print("✅ Файлы лабиринтов созданы") def avg(lst): return sum(lst) / len(lst) if lst else 0 def run_benchmark(): builder = TextFileMazeBuilder() maze_dir = os.path.dirname(os.path.abspath(__file__)) all_results = [ ['лабиринт', 'стратегия', 'время_мс', 'посещено_клеток', 'длина_пути'] + [f'замер_{i+1}' for i in range(REPEATS)] ] print(f"\nЗапуск бенчмарков (повторений: {REPEATS})\n") print(f" {'Лабиринт':<18} {'Алгоритм':<6} {'Время мс':>10} " f"{'Посещено':>10} {'Путь':>6}") print(' ' + '-' * 56) for maze_label, maze_file in MAZES: maze_path = os.path.join(maze_dir, maze_file) try: maze = builder.build_from_file(maze_path) except Exception as e: print(f" ❌ {maze_file}: {e}") continue solver = MazeSolver(maze) for strat_name, StratClass in STRATEGIES.items(): times_ms, visited_list, path_len = [], [], 0 for _ in range(REPEATS): strat = StratClass() solver.set_strategy(strat) stats = solver.solve() times_ms.append(stats.time_ms) visited_list.append(stats.visited_cells) path_len = stats.path_length mean_t = avg(times_ms) mean_v = avg(visited_list) print(f" {maze_label:<18} {strat_name:<6} " f"{mean_t:>10.3f} {mean_v:>10.0f} {path_len:>6}") all_results.append([ maze_label, strat_name, f"{mean_t:.4f}", f"{mean_v:.0f}", str(path_len) ] + [f"{t:.4f}" for t in times_ms]) with open(CSV_PATH, 'w', newline='', encoding='utf-8') as f: csv.writer(f).writerows(all_results) print(f"\n✅ Результаты сохранены: {CSV_PATH}") def smoke_test(): print("=== Smoke Test ===\n") maze_dir = os.path.dirname(os.path.abspath(__file__)) test_path = os.path.join(maze_dir, '_test_maze.txt') with open(test_path, 'w', encoding='utf-8') as f: f.write("#######\n#S #\n# #\n# E#\n#######") builder = TextFileMazeBuilder() maze = builder.build_from_file(test_path) for name, StratClass in STRATEGIES.items(): strat = StratClass() path = strat.find_path(maze, maze.start, maze.exit) assert len(path) > 0, f"{name}: путь не найден!" assert path[0].is_start assert path[-1].is_exit print(f" ✅ {name}: путь длиной {len(path)} — OK") os.remove(test_path) print("\nВсе тесты пройдены!\n") if __name__ == '__main__': smoke_test() generate_maze_files() run_benchmark()