# Отчёт по лабораторной работе «Поиск выхода из лабиринта»
## 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** часто быстрее 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`.