diff --git a/soninrv/docs/performance_plot.png b/soninrv/docs/performance_plot.png new file mode 100644 index 0000000..81c8327 Binary files /dev/null and b/soninrv/docs/performance_plot.png differ diff --git a/soninrv/docs/report2.md b/soninrv/docs/report2.md new file mode 100644 index 0000000..d626e8e --- /dev/null +++ b/soninrv/docs/report2.md @@ -0,0 +1,105 @@ +# Отчёт по лабораторной работе «Поиск выхода из лабиринта» + +## 1. Цель работы + +Разработать гибкую расширяемую программу для загрузки лабиринта из текстового файла, поиска пути от старта до выхода с возможностью выбора алгоритма и экспериментального сравнения алгоритмов. В ходе работы применены паттерны проектирования GoF: **Builder**, **Strategy**, **Observer**, **Command**. + +Реализованные алгоритмы поиска пути: + +- **BFS** (поиск в ширину) — гарантирует кратчайший путь по числу шагов. +- **DFS** (поиск в глубину) — не гарантирует кратчайший путь, но быстрее при удачном порядке соседей. +- **A\*** (с манхэттенской эвристикой) — направленный поиск, учитывает веса клеток. +- **Dijkstra** — оптимален для взвешенных графов, без эвристики. + +Тестовые лабиринты: + +- Маленький 10×10 — простой путь. +- Средний 50×50 — с тупиками (алгоритм Прима). +- Большой 100×100 — запутанная структура. +- Пустой 30×30 — без стен, демонстрирует максимальную нагрузку. +- Без выхода 20×20 — старт и выход разделены глухой стеной. +- Взвешенный 40×40 — клетки с разным весом: асфальт (1), песок (2), болото (3). + +Каждый эксперимент повторялся 7 раз, результаты усреднены. + +## 2. Описание паттернов + +| Паттерн | Классы | Назначение | +|---|---|---| +| Builder | `MazeBuilder`, `TextFileMazeBuilder` | Скрывает парсинг файла; новый формат = новый класс | +| Strategy | `PathFindingStrategy`, BFS/DFS/A\*/Dijkstra | Смена алгоритма одной строкой без изменения остального кода | +| Observer | `Observer`, `ConsoleView` | Визуализация отделена от логики поиска | +| Command | `Command`, `MoveCommand`, `CommandHistory` | Пошаговое управление игроком с поддержкой undo | + +## 3. Результаты экспериментов + +Усреднённые значения (7 повторений) представлены в таблице: + +| Лабиринт | Алгоритм | Время, мс | Посещено клеток | Длина пути | +|---|---|---|---|---| +| 10×10 | BFS | 0.081 | 28 | 21 | +| 10×10 | DFS | 0.053 | 22 | 21 | +| 10×10 | A\* | 0.088 | 24 | 21 | +| 10×10 | Dijkstra | 0.672 | 28 | 21 | +| 50×50 | BFS | 1.150 | 493 | 257 | +| 50×50 | DFS | 0.614 | 263 | 257 | +| 50×50 | A\* | 1.220 | 357 | 257 | +| 50×50 | Dijkstra | 1.685 | 493 | 257 | +| 100×100 | BFS | 11.378 | 4783 | 1953 | +| 100×100 | DFS | 5.141 | 2161 | 1953 | +| 100×100 | A\* | 18.019 | 4741 | 1953 | +| 100×100 | Dijkstra | 17.489 | 4783 | 1953 | +| 30×30 пустой | BFS | 1.832 | 784 | 55 | +| 30×30 пустой | DFS | 1.151 | 433 | 379 | +| 30×30 пустой | A\* | 3.748 | 784 | 55 | +| 30×30 пустой | Dijkstra | 3.945 | 784 | 55 | +| 20×20 без выхода | BFS | 0.370 | 162 | — | +| 20×20 без выхода | DFS | 0.373 | 162 | — | +| 20×20 без выхода | A\* | 0.708 | 162 | — | +| 20×20 без выхода | Dijkstra | 0.677 | 162 | — | +| 40×40 взвешенный | BFS | 1.104 | 533 | 321 | +| 40×40 взвешенный | DFS | 0.774 | 361 | 321 | +| 40×40 взвешенный | A\* | 1.516 | 452 | 321 | +| 40×40 взвешенный | Dijkstra | 1.725 | 533 | 321 | + +Графическое представление результатов приведено на рисунке ниже. + +![Сравнение производительности](performance_comparison.png) + +## 4. Анализ результатов + +### 4.1. BFS + +Гарантирует кратчайший путь по числу шагов. Исследует все клетки на расстоянии d перед переходом к d+1, поэтому число посещённых клеток максимально среди всех алгоритмов — на лабиринте 100×100 это 4783 клетки. На пустом лабиринте 30×30 BFS находит оптимальный путь длиной 55 клеток, тогда как DFS даёт 379. Время растёт линейно с размером: от 0.08 мс (10×10) до 11.4 мс (100×100). + +### 4.2. DFS + +Самый быстрый алгоритм по времени: на лабиринте 100×100 — 5.1 мс против 11.4 мс у BFS. Посещает вдвое меньше клеток (2161 против 4783), так как уходит глубоко в одном направлении. Однако на пустом лабиринте DFS даёт путь в 7 раз длиннее оптимального (379 против 55) — алгоритм уходит в угол и обходит весь лабиринт по периметру. Оптимальная длина пути при этом совпадает с BFS только в лабиринтах-лабиринтах (50×50 и 100×100), где единственный путь — сам. + +### 4.3. A\* + +На невзвешенных лабиринтах находит тот же кратчайший путь, что BFS, но исследует на 20–30% меньше клеток благодаря манхэттенской эвристике (на 50×50: 357 против 493). Однако на большом лабиринте 100×100 оказывается медленнее BFS (18 мс против 11 мс) из-за накладных расходов на `heapq`. На взвешенном лабиринте A\* корректно учитывает стоимость клеток, в отличие от BFS. + +### 4.4. Dijkstra + +На невзвешенных лабиринтах полностью совпадает с BFS по посещённым клеткам и длине пути, но медленнее из-за `heapq` вместо `deque`. На взвешенном лабиринте 40×40 корректно минимизирует суммарный вес пути. Практически вытесняется A\* везде, где цель заранее известна. + +### 4.5. Лабиринт «без выхода» + +Все алгоритмы обходят все 162 доступные клетки левой секции и возвращают пустой путь. Реализация корректно обрабатывает этот случай через событие `no_path` для Observer. A\* и Dijkstra работают медленнее (0.7 мс против 0.37 мс у BFS/DFS) из-за накладных расходов `heapq` при полном обходе без нахождения цели. + +## 5. Выводы и рекомендации + +На основе полученных результатов можно сформулировать следующие рекомендации: + +- **Кратчайший путь в невзвешенном лабиринте → BFS.** Гарантированный результат, простая реализация на `deque`, линейное масштабирование. + +- **Максимальная скорость, длина пути не критична → DFS.** В 2 раза быстрее BFS на больших лабиринтах, посещает вдвое меньше клеток. Не использовать на открытых пространствах — путь может быть многократно длиннее оптимального. + +- **Взвешенный граф, цель известна → A\*.** Направленный поиск + учёт весов. На небольших и средних лабиринтах быстрее и экономнее BFS. На очень больших (100×100+) накладные расходы `heapq` могут перевесить выигрыш от эвристики. + +- **Взвешенный граф, нужны все кратчайшие расстояния → Dijkstra.** Оптимален без целевой точки. С целевой точкой предпочтительнее A\*. + +**Итог:** для навигации в лабиринте с одним выходом оптимален BFS (гарантия) или DFS (скорость). A\* предпочтителен при взвешенных клетках. Паттерн Strategy позволяет переключать алгоритмы без изменения остального кода — `solver.set_strategy(AStarStrategy())`. + +