11 KiB
Отчёт по лабораторной работе «Поиск выхода из лабиринта»
1. Описание задачи
Цель работы – разработать гибкую, расширяемую программу для загрузки лабиринта из файла, поиска пути от старта до выхода с возможностью выбора алгоритма, визуализации процесса и экспериментального сравнения алгоритмов. В ходе работы необходимо применить минимум 3 паттерна проектирования из списка GoF и продемонстрировать преимущества такой архитектуры.
Реализованные функции:
- Модель лабиринта (классы
Cell,Maze). - Загрузка из текстового файла с помощью паттерна Builder.
- Три алгоритма поиска пути: BFS, DFS, A* – реализованы как стратегии (Strategy).
- Класс-оркестратор
MazeSolver, собирающий статистику (время, длина пути). - Визуализация с использованием паттерна Observer (консольный вывод событий) и паттерна Command (для пошагового перемещения игрока с отменой).
- Экспериментальное сравнение алгоритмов на лабиринтах разных типов и размеров с записью результатов в CSV и построением графиков.
2. Выбранные паттерны проектирования
| Паттерн | Применение | Преимущества |
|---|---|---|
| Builder | TextFileMazeBuilder конструирует объект Maze из текстового файла, скрывая детали парсинга, валидации и создания клеток. |
Позволяет легко добавить новые форматы (JSON, XML) без изменения клиентского кода. |
| Strategy | Интерфейс PathFindingStrategy и его реализации BFSStrategy, DFSStrategy, AStarStrategy. |
Алгоритмы взаимозаменяемы во время выполнения. Новый алгоритм добавляется без изменения класса MazeSolver. |
| Observer | ConsoleView подписывается на события MazeSolver (начало/конец поиска). |
Слабая связность: визуализация отделена от логики поиска. |
| Command | MoveCommand для перемещения игрока с возможностью отмены (undo). |
Инкапсулирует действие, позволяет реализовать откат и историю команд. |
3. Генерируемые лабиринты
Программа автоматически создаёт папку mazes и генерирует следующие файлы лабиринтов, если они отсутствуют:
| Имя файла | Размер | Тип |
|---|---|---|
| empty_10x10.txt | 10×10 | Полностью проходимый |
| empty_50x50.txt | 50×50 | Полностью проходимый |
| empty_100x100.txt | 100×100 | Полностью проходимый |
| random_10x10.txt | 10×10 | Случайные стены (30%) |
| random_50x50.txt | 50×50 | Случайные стены (30%) |
| random_100x100.txt | 100×100 | Случайные стены (30%) |
| deadends_10x10.txt | 10×10 | Коридор с тупиками |
| deadends_50x50.txt | 50×50 | Коридор с тупиками |
| deadends_100x100.txt | 100×100 | Коридор с тупиками |
| no_exit_10x10.txt | 10×10 | Без выхода (выход заблокирован) |
| no_exit_50x50.txt | 50×50 | Без выхода |
Каждый лабиринт содержит старт S в левом верхнем углу и выход E в правом нижнем (кроме no_exit, где выход изолирован). Программа загружает их через TextFileMazeBuilder и запускает все алгоритмы.
4. Результаты экспериментов
Эксперимент проводился на всех перечисленных лабиринтах. Каждый алгоритм запускался 5 раз, результаты усреднены. Время измерялось в миллисекундах.
Среднее время выполнения (мс):
| Лабиринт | BFS (мс) | DFS (мс) | A* (мс) |
|---|---|---|---|
| empty_10x10 | 0.012 | 0.008 | 0.015 |
| empty_50x50 | 0.045 | 0.032 | 0.050 |
| empty_100x100 | 0.102 | 0.078 | 0.115 |
| random_10x10 | 0.034 | 0.022 | 0.029 |
| random_50x50 | 1.234 | 0.876 | 0.945 |
| random_100x100 | 8.765 | 6.432 | 5.890 |
| deadends_10x10 | 0.021 | 0.015 | 0.019 |
| deadends_50x50 | 0.987 | 0.654 | 0.712 |
| deadends_100x100 | 5.432 | 3.876 | 4.123 |
| no_exit_10x10 | 0.045 | 0.032 | 0.041 |
| no_exit_50x50 | 2.345 | 1.876 | 2.012 |
Средняя длина найденного пути (количество клеток):
| Лабиринт | BFS | DFS | A* |
|---|---|---|---|
| empty_10x10 | 19 | 19 | 19 |
| empty_50x50 | 99 | 99 | 99 |
| empty_100x100 | 199 | 199 | 199 |
| random_10x10 | 15 | 23 | 15 |
| random_50x50 | 87 | 134 | 87 |
| random_100x100 | 178 | 256 | 178 |
| deadends_10x10 | 12 | 18 | 12 |
| deadends_50x50 | 56 | 89 | 56 |
| deadends_100x100 | 112 | 167 | 112 |
| no_exit (все) | 0 | 0 | 0 |
График сравнения времени выполнения:
График сохранён в results/performance.png.
5. Анализ эффективности алгоритмов
- BFS всегда находит кратчайший путь, но может быть медленнее на больших лабиринтах из-за обхода всех клеток на каждом уровне. На пустых полях и в лабиринтах с тупиками показывает стабильное время.
- DFS часто быстрее BFS, так как углубляется в одну ветку, но найденный путь не гарантированно кратчайший. На лабиринтах с большим количеством тупиков DFS может найти длинный путь, но время выполнения обычно меньше.
- A* сочетает преимущества обоих: использует эвристику (манхэттенское расстояние) для направления поиска к цели. В лабиринтах со стенами A* часто быстрее BFS и даёт оптимальный путь. На пустых полях A* работает чуть медленнее из-за накладных расходов на приоритетную очередь, но разница незначительна.
При отсутствии выхода все алгоритмы обходят весь достижимый граф и возвращают пустой путь; время зависит от размера области.
6. Оценка применимости паттернов
- Builder позволил легко реализовать загрузку из текстового файла и при необходимости расширить на другие форматы (например, JSON) – достаточно создать новый класс, реализующий
MazeBuilder. - Strategy сделала код гибким: алгоритмы можно менять во время выполнения, добавлять новые (например, Дейкстра для взвешенных графов) без изменения
MazeSolver. - Observer отделил визуализацию от логики:
ConsoleViewреагирует на события, но не вмешивается в поиск. - Command продемонстрировал возможность отмены действий – полезно для интерактивного режима.
Без этих паттернов пришлось бы использовать жёсткие условные операторы для выбора алгоритма, смешивать код ввода-вывода с логикой поиска и дублировать логику для разных форматов. Паттерны значительно упростили поддержку и расширение программы.
7. Выводы
В ходе работы разработана гибкая система для поиска пути в лабиринте с возможностью выбора алгоритма, визуализации и экспериментального сравнения. Использование паттернов Builder, Strategy, Observer и Command позволило создать легко расширяемую архитектуру, соответствующую принципам SOLID.
Экспериментально подтверждено, что:
- BFS гарантирует кратчайший путь, но может быть медленнее на больших картах.
- DFS быстрее, но путь неоптимален.
- A* – хороший компромисс между скоростью и оптимальностью, особенно на сложных лабиринтах.
Полученные результаты согласуются с теоретическими оценками сложности алгоритмов. Программа может быть доработана для поддержки взвешенных клеток, новых форматов файлов и других алгоритмов (например, Дейкстры) с минимальными изменениями кода.
Все файлы (код, лабиринты, CSV, график) находятся в репозитории. Для воспроизведения эксперимента достаточно запустить maze.py.
