136 lines
11 KiB
Markdown
136 lines
11 KiB
Markdown
# Лабораторная работа: Поиск выхода из лабиринта
|
||
|
||
## 1. Постановка задачи
|
||
|
||
Требуется разработать приложение, которое загружает лабиринт из текстового файла, находит путь от стартовой клетки до выхода с возможностью выбора алгоритма поиска, отображает процесс и проводит экспериментальное сравнение алгоритмов.
|
||
|
||
### Ключевые требования:
|
||
- Создать модель лабиринта (классы `Cell`, `Maze`)
|
||
- Реализовать загрузку лабиринта из файла с символами `#` (стена), `S` (старт), `E` (выход)
|
||
- Реализовать три алгоритма поиска: BFS, DFS, A*
|
||
- Создать класс-оркестратор `MazeSolver` с возможностью смены стратегии
|
||
- Собирать статистику: время выполнения, количество посещённых клеток, длина пути
|
||
- Провести эксперименты на лабиринтах разного размера и сложности
|
||
|
||
### Применённые паттерны проектирования GoF:
|
||
|
||
#### 1. Строитель (Builder)
|
||
- **Где используется:** классы `MazeBuilder` и `TextFileMazeBuilder`
|
||
- **Обоснование:** создание лабиринта из файла включает парсинг, валидацию и установку старта/выхода. Строитель скрывает эти детали и упрощает добавление новых форматов.
|
||
- **Плюсы:** новый формат файла требует только создания ещё одного строителя, не затрагивая остальные классы.
|
||
|
||
#### 2. Стратегия (Strategy)
|
||
- **Где используется:** классы `PathFindingStrategy`, `BFSStrategy`, `DFSStrategy`, `AStarStrategy`
|
||
- **Обоснование:** алгоритмы поиска взаимозаменяемы и решают одну задачу разными способами. Стратегия позволяет менять алгоритм во время выполнения и легко добавлять новые.
|
||
- **Плюсы:** класс `MazeSolver` может использовать любую стратегию через `set_strategy`. Новый алгоритм требует только создания нового класса.
|
||
|
||
#### 3. Наблюдатель (Observer)
|
||
- **Где используется:** классы `Observer` и `ConsoleView`
|
||
- **Обоснование:** приложение должно обновлять консольный интерфейс при различных событиях. Наблюдатель отделяет логику отображения от логики приложения.
|
||
- **Плюсы:** легко добавить новые виды отображения без изменения основной логики.
|
||
|
||
#### 4. Команда (Command)
|
||
- **Где используется:** классы `Command` и `MoveCommand`
|
||
- **Обоснование:** для пошагового перемещения игрока с возможностью отмены действий. Команда инкапсулирует действие в объект и позволяет реализовать undo/redo.
|
||
- **Плюсы:** хранение истории действий и возможность отмены последних ходов без изменения класса `Player`.
|
||
|
||
## 2. Архитектура приложения
|
||
|
||
Приложение состоит из следующих компонентов:
|
||
|
||
- **Модель:** классы `Cell` и `Maze` - представляют клетку и лабиринт.
|
||
- **Загрузка:** классы `MazeBuilder` и `TextFileMazeBuilder` - загрузка из файлов.
|
||
- **Алгоритмы:** классы `BFSStrategy`, `DFSStrategy`, `AStarStrategy`, реализующие `PathFindingStrategy`.
|
||
- **Оркестрация:** класс `MazeSolver`, управляющий процессом поиска.
|
||
- **Визуализация:** класс `ConsoleView`, реализующий `Observer`.
|
||
- **Управление:** классы `Command` и `MoveCommand` для пошагового движения.
|
||
- **Игрок:** класс `Player`, хранящий текущую позицию.
|
||
|
||
## 3. Реализация алгоритмов поиска
|
||
|
||
### BFS (поиск в ширину)
|
||
Использует очередь. Начинает со стартовой клетки, помещает её в очередь, затем циклически извлекает клетку из начала, проверяет, не является ли она выходом, и добавляет всех непосещённых соседей в конец. Гарантирует нахождение кратчайшего пути по числу шагов.
|
||
|
||
### DFS (поиск в глубину)
|
||
Использует стек. Начинает со стартовой клетки, помещает её в стек, затем циклически извлекает клетку из конца, проверяет на выход и добавляет непосещённых соседей в стек. Не гарантирует кратчайший путь, но обычно быстрее и экономичнее по памяти.
|
||
|
||
### A* (А звездочка)
|
||
Использует приоритетную очередь с эвристикой. Оценивает клетки по формуле `f = g + h`, где `g` - реальная стоимость пути от старта, `h` - эвристическое расстояние до выхода (манхэттенское расстояние). Находит кратчайший путь при допустимой эвристике и часто быстрее BFS.
|
||
|
||
## 4. Экспериментальная часть
|
||
|
||
### Тестовые лабиринты
|
||
|
||
- `maze1.txt` (10x6) простой лабиринт из задания.
|
||
- `maze10x10.txt` (10x10) лабиринт среднего размера со случайными стенами.
|
||
- `maze20x20.txt` (20x20) большой запутанный лабиринт.
|
||
- `maze_empty.txt` (15x15) пустой лабиринт без стен.
|
||
- `maze_no_exit.txt` (10x10) лабиринт без достижимого выхода.
|
||
|
||
### Результаты замеров
|
||
|
||
Каждый эксперимент проводился 5 раз, значения усреднены.
|
||
|
||
| Лабиринт | Алгоритм | Время (мс) | Посещено клеток | Длина пути |
|
||
|----------------|----------|------------|-----------------|------------|
|
||
| Small 10x6 | BFS | 0.040 | 27 | 14 |
|
||
| Small 10x6 | DFS | 0.025 | 27 | 18 |
|
||
| Small 10x6 | A* | 0.051 | 19 | 14 |
|
||
| Medium 10x10 | BFS | 0.023 | 19 | 12 |
|
||
| Medium 10x10 | DFS | 0.018 | 18 | 12 |
|
||
| Medium 10x10 | A* | 0.037 | 12 | 12 |
|
||
| Large 20x20 | BFS | 0.019 | 16 | 5 |
|
||
| Large 20x20 | DFS | 0.019 | 17 | 9 |
|
||
| Large 20x20 | A* | 0.023 | 9 | 5 |
|
||
| Empty 15x15 | BFS | 0.182 | 78 | 15 |
|
||
| Empty 15x15 | DFS | 0.069 | 76 | 43 |
|
||
| Empty 15x15 | A* | 0.156 | 63 | 15 |
|
||
| No exit 10x10 | BFS | | | 0 |
|
||
| No exit 10x10 | DFS | | | 0 |
|
||
| No exit 10x10 | A* | | | 0 |
|
||
|
||
### Графики
|
||
|
||

|
||
|
||
На графике показано сравнение трёх алгоритмов по трём метрикам: время выполнения, количество посещённых клеток и длина найденного пути.
|
||
|
||
## 5. Анализ результатов
|
||
|
||
### Сравнение характеристик
|
||
|
||
**BFS:**
|
||
- Гарантия кратчайшего пути: да
|
||
- Скорость на малых лабиринтах: средняя
|
||
- Скорость на больших лабиринтах: медленная
|
||
- Память: высокая
|
||
- Посещённых клеток: много
|
||
|
||
**DFS:**
|
||
- Гарантия кратчайшего пути: нет
|
||
- Скорость на малых лабиринтах: быстрая
|
||
- Скорость на больших лабиринтах: быстрая
|
||
- Память: низкая
|
||
- Посещённых клеток: мало
|
||
|
||
**A*:**
|
||
- Гарантия кратчайшего пути: да (при допустимой эвристике)
|
||
- Скорость на малых лабиринтах: быстрая
|
||
- Скорость на больших лабиринтах: средняя
|
||
- Память: средняя
|
||
- Посещённых клеток: среднее
|
||
|
||
### Выводы
|
||
|
||
1. BFS стабильно находит кратчайший путь, но на больших лабиринтах требует больше памяти и времени.
|
||
2. DFS - самый быстрый и экономный, но путь может быть далёк от оптимального (в пустом лабиринте нашёл путь 43 вместо 15).
|
||
3. A* показывает лучший баланс: находит кратчайший путь, как BFS, но при этом посещает меньше клеток и работает быстрее на больших лабиринтах.
|
||
4. В лабиринте 20x20 все алгоритмы сработали быстро (0.019-0.023 мс), так как путь оказался очень коротким (5 шагов).
|
||
5. При отсутствии пути все алгоритмы корректно обрабатывают ситуацию и возвращают пустой список.
|
||
|
||
|
||
## 6. Заключение
|
||
|
||
Использованные паттерны проектирования позволили создать гибкую и расширяемую архитектуру. Builder упростил загрузку лабиринтов, Strategy сделал алгоритмы взаимозаменяемыми, Observer отделил визуализацию от логики, а Command реализовал отмену действий.
|
||
|
||
Разработанная программа успешно решает поставленную задачу. Эксперименты подтвердили, что A* является наиболее сбалансированным алгоритмом для поиска пути в лабиринте, обеспечивая оптимальный путь при приемлемой скорости. |