From cb5e43f85786c9298c8ea63df5ca5b66f847d38f Mon Sep 17 00:00:00 2001 From: lukovnikovde Date: Sun, 24 May 2026 22:33:48 +0000 Subject: [PATCH] [2] experimental module and plotting --- lukovnikovde/docs/data/2-nd-exercise/main.py | 231 ++++++++++++++----- 1 file changed, 175 insertions(+), 56 deletions(-) diff --git a/lukovnikovde/docs/data/2-nd-exercise/main.py b/lukovnikovde/docs/data/2-nd-exercise/main.py index 5291646..69a8852 100644 --- a/lukovnikovde/docs/data/2-nd-exercise/main.py +++ b/lukovnikovde/docs/data/2-nd-exercise/main.py @@ -3,6 +3,9 @@ import os from collections import deque import heapq import time +import csv +import matplotlib.pyplot as plt +import numpy as np # ---------- 1. Модель клетки и лабиринта ---------- class Tile: @@ -343,66 +346,182 @@ class MoveAction(Action): return False -# ---------- 7. Главный интерактивный цикл (коммит №4) ---------- -if __name__ == "__main__": - # Загружаем лабиринт (предполагается, что файл maze/maze1.txt существует) +# ---------- 7. Экспериментальные функции ---------- +def run_benchmark(maze_file, strategy, runs=5): loader = TextLabyrinthLoader() - lab = loader.load("maze/maze1.txt") + lab = loader.load(maze_file) + total_time = 0.0 + total_visited = 0 + total_len = 0 + for _ in range(runs): + solver = LabyrinthSolver(lab) + solver.set_strategy(strategy) + stats = solver.solve() + if stats: + total_time += stats['time_ms'] + total_visited += stats['visited'] + total_len += stats['length'] + return { + 'time_ms': total_time / runs, + 'visited': total_visited / runs, + 'length': total_len / runs + } - player = Walker(lab.start_tile, lab) - view = ConsoleRenderer(player) - view.notify("maze_loaded", lab) - solver = LabyrinthSolver(lab) - solver.attach(view) +def make_plots(results): + mazes = list({r['maze'] for r in results}) + algos = ['BFS', 'DFS', 'AStar'] + fig, axes = plt.subplots(1, 3, figsize=(15, 5)) + x = np.arange(len(mazes)) + width = 0.25 - print("\n УПРАВЛЕНИЕ:") - print(" H (влево) J (вниз) K (вверх) L (вправо)") - print(" U - отменить ход Q - выход") - print("\n АВТОПОИСК:") - print(" B - BFS D - DFS A - A*") - print("\n" + "=" * 50) + for i, algo in enumerate(algos): + times = [] + for m in mazes: + val = next((r['time_ms'] for r in results if r['maze'] == m and r['algo'] == algo), 0) + times.append(val) + axes[0].bar(x + i*width, times, width, label=algo) + axes[0].set_xlabel('Лабиринт') + axes[0].set_ylabel('Время (мс)') + axes[0].set_title('Сравнение времени выполнения') + axes[0].set_xticks(x + width) + axes[0].set_xticklabels(mazes, rotation=45, ha='right') + axes[0].legend() + axes[0].grid(True, alpha=0.3) - command_stack = [] - while True: - key = input("\n Команда > ").lower() - if key == 'q': - print("\n До свидания!") - break - elif key == 'b': - solver.set_strategy(BFS()) - stats = solver.solve() - if stats: - print(f"\n BFS: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}") - elif key == 'd': - solver.set_strategy(DFS()) - stats = solver.solve() - print(f"\n DFS: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}") - elif key == 'a': - solver.set_strategy(AStar()) - stats = solver.solve() - print(f"\n A*: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}") - elif key in ['h', 'j', 'k', 'l']: - dirs = {'h': (-1,0), 'l': (1,0), 'k': (0,-1), 'j': (0,1)} - act = MoveAction(player, dirs[key][0], dirs[key][1], lab) - if act.do(): - command_stack.append(act) - view.notify("player_moved", lab) - if player.current == lab.exit_tile: - print("\n ПОЗДРАВЛЯЮ! ВЫ НАШЛИ ВЫХОД!") - print(f" Сделано ходов: {len(command_stack)}") - break + for i, algo in enumerate(algos): + visited_vals = [] + for m in mazes: + val = next((r['visited'] for r in results if r['maze'] == m and r['algo'] == algo), 0) + visited_vals.append(val) + axes[1].bar(x + i*width, visited_vals, width, label=algo) + axes[1].set_xlabel('Лабиринт') + axes[1].set_ylabel('Посещено клеток') + axes[1].set_title('Сравнение посещённых клеток') + axes[1].set_xticks(x + width) + axes[1].set_xticklabels(mazes, rotation=45, ha='right') + axes[1].legend() + axes[1].grid(True, alpha=0.3) + + for i, algo in enumerate(algos): + lengths = [] + for m in mazes: + val = next((r['length'] for r in results if r['maze'] == m and r['algo'] == algo), 0) + lengths.append(val) + axes[2].bar(x + i*width, lengths, width, label=algo) + axes[2].set_xlabel('Лабиринт') + axes[2].set_ylabel('Длина пути') + axes[2].set_title('Сравнение длины пути') + axes[2].set_xticks(x + width) + axes[2].set_xticklabels(mazes, rotation=45, ha='right') + axes[2].legend() + axes[2].grid(True, alpha=0.3) + + plt.tight_layout() + plt.savefig('performance_comparison.png', dpi=150, bbox_inches='tight') + plt.show() + + +# ---------- 8. Главный блок ---------- +if __name__ == "__main__": + if len(sys.argv) > 1 and sys.argv[1] == 'experiment': + # Режим экспериментов + test_mazes = [ + ("maze/maze1.txt", "Small 10x6"), + ("maze/maze10x10.txt", "Medium 10x10"), + ("maze/maze20x20.txt", "Large 20x20"), + ("maze/maze_empty.txt", "Empty 15x15"), + ("maze/maze_no_exit.txt", "No exit 10x10") + ] + strategies = [ + ("BFS", BFS()), + ("DFS", DFS()), + ("AStar", AStar()) + ] + results = [] + for maze_path, maze_name in test_mazes: + print(f"Тестируем {maze_name}...") + for algo_name, algo in strategies: + try: + stats = run_benchmark(maze_path, algo, runs=3) + results.append({ + 'maze': maze_name, + 'algo': algo_name, + 'time_ms': stats['time_ms'], + 'visited': stats['visited'], + 'length': stats['length'] + }) + print(f" {algo_name}: время={stats['time_ms']:.3f}мс, посещено={stats['visited']:.0f}, длина={stats['length']:.0f}") + except Exception as e: + print(f" {algo_name}: ошибка - {e}") + # Сохраняем CSV + with open('experiment_results.csv', 'w', newline='', encoding='utf-8') as f: + writer = csv.DictWriter(f, fieldnames=['maze', 'algo', 'time_ms', 'visited', 'length']) + writer.writeheader() + writer.writerows(results) + # Строим графики + if results: + make_plots(results) + print("\nРезультаты сохранены в experiment_results.csv и performance_comparison.png") + else: + # Интерактивный режим + loader = TextLabyrinthLoader() + lab = loader.load("maze/maze1.txt") + + player = Walker(lab.start_tile, lab) + view = ConsoleRenderer(player) + view.notify("maze_loaded", lab) + + solver = LabyrinthSolver(lab) + solver.attach(view) + + print("\n УПРАВЛЕНИЕ:") + print(" H (влево) J (вниз) K (вверх) L (вправо)") + print(" U - отменить ход Q - выход") + print("\n АВТОПОИСК:") + print(" B - BFS D - DFS A - A*") + print("\n" + "=" * 50) + + command_stack = [] + while True: + key = input("\n Команда > ").lower() + if key == 'q': + print("\n До свидания!") + break + elif key == 'b': + solver.set_strategy(BFS()) + stats = solver.solve() + if stats: + print(f"\n BFS: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}") + elif key == 'd': + solver.set_strategy(DFS()) + stats = solver.solve() + print(f"\n DFS: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}") + elif key == 'a': + solver.set_strategy(AStar()) + stats = solver.solve() + print(f"\n A*: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}") + elif key in ['h', 'j', 'k', 'l']: + dirs = {'h': (-1,0), 'l': (1,0), 'k': (0,-1), 'j': (0,1)} + act = MoveAction(player, dirs[key][0], dirs[key][1], lab) + if act.do(): + command_stack.append(act) + view.notify("player_moved", lab) + if player.current == lab.exit_tile: + print("\n ПОЗДРАВЛЯЮ! ВЫ НАШЛИ ВЫХОД!") + print(f" Сделано ходов: {len(command_stack)}") + break + else: + print("\n Туда нельзя – стена!") + elif key == 'u': + if command_stack: + cmd = command_stack.pop() + cmd.undo() + view.notify("player_moved", lab) + print("\n Отмена последнего хода") + else: + print("\n Нечего отменять") else: - print("\n Туда нельзя – стена!") - elif key == 'u': - if command_stack: - cmd = command_stack.pop() - cmd.undo() - view.notify("player_moved", lab) - print("\n Отмена последнего хода") - else: - print("\n Нечего отменять") - else: - print("\n Неизвестная команда. Используйте h,j,k,l, u, b, d, a, q") + print("\n Неизвестная команда. Используйте h,j,k,l, u, b, d, a, q") - print("\n Игра окончена. Спасибо!") \ No newline at end of file + print("\n Игра окончена. Спасибо!") \ No newline at end of file