11 KiB
Отчёт по лабораторной работе: Поиск выхода из лабиринта
1. Постановка задачи
Цель — разработать программу для загрузки лабиринта из текстового файла, поиска маршрута от старта до выхода с возможностью выбора алгоритма, визуализации процесса и экспериментального сравнения эффективности трёх классических алгоритмов поиска пути.
Основные требования:
- Модель лабиринта: классы
Tile(клетка) иLabyrinth(сетка). - Загрузка карты из файла с символами
#(стена),S(старт),E(выход). - Реализация трёх стратегий поиска: BFS, DFS, A*.
- Оркестратор
LabyrinthSolverс возможностью смены алгоритма во время выполнения. - Сбор метрик: время работы (мс), количество посещённых клеток, длина найденного пути.
- Проведение экспериментов на пяти лабиринтах разного размера и структуры.
Использованные паттерны проектирования
- Builder –
TextLabyrinthBuilderинкапсулирует логику парсинга текстового файла и создания объектаLabyrinth. Это упрощает добавление новых форматов. - Strategy –
BFS_Pathfinder,DFS_PathfinderиAStar_Pathfinderреализуют общий интерфейсPathfinder. КлассLabyrinthSolverможет динамически переключаться между ними. - Observer – интерфейс
GameObserverи его реализацияTerminalDisplayпозволяют отделить отображение лабиринта от бизнес-логики. - Command –
MoveActionоборачивает перемещение игрока, сохраняя историю и предоставляя возможность отмены (undo).
2. Архитектура приложения
- Модель:
Tile(клетка) иLabyrinth(лабиринт). - Загрузка:
LabyrinthBuilder(абстрактный) иTextLabyrinthBuilder. - Алгоритмы:
BFS_Pathfinder,DFS_Pathfinder,AStar_Pathfinder— наследникиPathfinder. - Управление поиском:
LabyrinthSolver(смена стратегии, оповещение наблюдателей). - Визуализация:
TerminalDisplay, реализующийGameObserver. - Интерактив:
Explorer(игрок) иMoveAction(команда перемещения).
3. Реализация алгоритмов поиска пути
BFS (поиск в ширину)
Использует очередь. Стартовая клетка помещается в очередь, затем на каждом шаге извлекается первый элемент. Если это выход — путь восстановлен. Иначе все непосещённые соседи добавляются в конец очереди. Гарантирует кратчайший путь по количеству шагов.
DFS (поиск в глубину)
Вместо очереди используется стек (LIFO). Начинает со старта, на каждом шаге извлекается последний добавленный элемент. Быстрее продвигается в глубину, но путь часто оказывается далеко не оптимальным.
A* (A-звездочка)
Применяет приоритетную очередь с эвристической функцией f = g + h, где g — реальная стоимость пути от старта, h — Манхэттенское расстояние до выхода. Всегда находит оптимальный путь при допустимой эвристике и обычно посещает меньше клеток.
4. Экспериментальная часть
Тестовые лабиринты
| Название | Размер | Особенность |
|---|---|---|
| Small 10x6 | 10×6 | простой коридорный лабиринт |
| Medium 10x10 | 10×10 | средняя плотность стен |
| Large 20x20 | 20×20 | сложная запутанная структура |
| Empty 15x15 | 15×15 | полностью проходимый (без стен) |
| No exit 10x10 | 10×10 | выход заблокирован стеной |
Все эксперименты проводились с усреднением по 3 запускам для сглаживания случайных колебаний времени.
Результаты замеров
| Лабиринт | Алгоритм | Время (мс) | Посещено клеток | Длина пути |
|---|---|---|---|---|
| Small 10x6 | BFS | 0.037 | 27 | 10 |
| Small 10x6 | DFS | 0.028 | 18 | 14 |
| Small 10x6 | A* | 0.069 | 22 | 10 |
| Medium 10x10 | BFS | 0.042 | 40 | 15 |
| Medium 10x10 | DFS | 0.017 | 21 | 15 |
| Medium 10x10 | A* | 0.058 | 28 | 15 |
| Large 20x20 | BFS | 0.091 | 64 | 31 |
| Large 20x20 | DFS | 0.054 | 64 | 41 |
| Large 20x20 | A* | 0.217 | 60 | 31 |
| Empty 15x15 | BFS | 0.380 | 223 | 25 |
| Empty 15x15 | DFS | 0.171 | 221 | 109 |
| Empty 15x15 | A* | 0.623 | 169 | 25 |
| No exit 10x10 | BFS | 0.014 | 9 | 0 |
| No exit 10x10 | DFS | 0.013 | 9 | 0 |
| No exit 10x10 | A* | 0.024 | 9 | 0 |
Примечание: длина пути 0 означает, что маршрут не существует.
Визуализация
На графиках отражены три метрики: время выполнения, число посещённых клеток и длина найденного пути.
5. Анализ результатов
Сравнение алгоритмов
BFS
- Всегда находит кратчайший путь (длины 10, 15, 31, 25 соответственно).
- На больших и пустых лабиринтах посещает много клеток (до 223), что сказывается на времени.
- Хорошо подходит, когда оптимальность критична, а размер лабиринта умеренный.
DFS
- Самый быстрый по времени (0.013–0.171 мс), но часто выдаёт длинные извилистые пути (14, 15, 41, 109). В пустом 15×15 путь составил 109 шагов вместо оптимальных 25.
- Число посещённых клеток невелико, что объясняет высокую скорость. Рекомендуется, когда важнее скорость, а не качество маршрута.
A*
- Находит кратчайший путь во всех случаях (где он существует).
- Посещает в среднем меньше клеток, чем BFS (22, 28, 60, 169), что подтверждает эффективность эвристики.
- Время работы немного выше, чем у BFS, из-за накладных расходов на работу с кучей, однако разница незначительна.
Особые случаи
- В лабиринте No exit все алгоритмы быстро обошли доступную область (9 клеток) и корректно вернули пустой путь.
- На Empty 15×15 DFS показал наихудший путь (109 шагов), в то время как BFS и A* дали идеальные 25. Это наглядно демонстрирует, что DFS непригоден для задач, требующих оптимальности.
- Large 20×20 показал близкие результаты для BFS и A* по длине пути, но DFS снова выдал более длинный маршрут (41).
Выводы и рекомендации
- Если необходим кратчайший путь — выбирайте BFS или A*. A* часто эффективнее по памяти, так как посещает меньше клеток.
- Если важна максимальная скорость и допустим неоптимальный путь — используйте DFS.
- A* является наилучшим компромиссом для большинства практических задач благодаря сбалансированному сочетанию времени и оптимальности.
6. Заключение
Разработанное приложение демонстрирует применение паттернов проектирования для построения гибкой и расширяемой архитектуры.
Экспериментальные данные подтверждают ожидаемое поведение алгоритмов: BFS и A* гарантируют оптимальность, DFS — высокую скорость ценой качества маршрута. A* показал наилучшее соотношение «затраты / качество», посещая меньше клеток и находя кратчайший путь.
Все полученные метрики сохранены в файл experiment_data.csv, графики — в maze_performance.png.
