2026-rff_mp/semyanovra/docs/report2.md
2026-05-24 15:10:38 +00:00

177 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Отчет по лабораторной работе: Поиск выхода из лабиринта
## 1. Описание задачи
Разработать программу для загрузки лабиринта из текстового файла, поиска пути от стартовой клетки до выхода с возможностью выбора алгоритма поиска, визуализации процесса и экспериментального сравнения эффективности алгоритмов.
### Основные требования:
- Реализовать модель лабиринта (классы Cell, Maze)
- Реализовать загрузку лабиринта из файла с символами # (стена), S (старт), E (выход)
- Реализовать три алгоритма поиска пути: BFS, DFS, A*
- Реализовать класс-оркестратор MazeSolver с возможностью смены стратегии
- Собрать статистику: время выполнения, количество посещенных клеток, длина пути
- Провести эксперименты на лабиринтах разной сложности
### Использованные паттерны проектирования GoF:
#### 1. Builder
- **Где используется:** Классы `LabyrinthBuilder` и `TxtLabyrinthBuilder`
- **Почему выбран:** Создание лабиринта из файла включает сложную логику парсинга, валидации и установки старта и выхода. Builder скрывает эти детали от клиента и позволяет легко добавлять новые форматы файлов
- **Преимущества:** При добавлении нового формата достаточно создать новый класс-строитель, не меняя существующие классы Labyrinth и алгоритмы поиска
#### 2. Strategy
- **Где используется:** Классы `SearchAlgorithm`, `BFS`, `DFS`, `AStar`
- **Почему выбран:** Алгоритмы поиска пути взаимозаменяемы и решают одну задачу разными способами. Strategy позволяет динамически менять алгоритм во время выполнения и легко добавлять новые алгоритмы
- **Преимущества:** Класс Pathfinder может использовать любую стратегию через метод set_algorithm. Добавление нового алгоритма требует только создания нового класса
#### 3. Observer
- **Где используется:** Классы `EventListener` и `ConsoleDisplay`
- **Почему выбран:** Приложение должно обновлять консольный интерфейс при различных событиях. Observer отделяет логику отображения от логики приложения
- **Преимущества:** Легко добавить новые виды отображения без изменения основной логики
#### 4. Command
- **Где используется:** Классы `Action` и `MoveAction`
- **Почему выбран:** Для реализации пошагового перемещения игрока с возможностью отмены действий. Command инкапсулирует действие в объект и позволяет реализовать undo и redo
- **Преимущества:** Хранение истории действий и возможность отмены последних ходов без изменения логики класса Walker
## 2. Архитектура приложения
Приложение состоит из следующих основных компонентов:
| Компонент | Назначение |
|-----------|------------|
| `GridCell` | Модель клетки лабиринта (координаты, стена, старт, выход) |
| `Labyrinth` | Модель лабиринта (сетка клеток, методы доступа) |
| `TxtLabyrinthBuilder` | Загрузка лабиринта из текстового файла |
| `BFS`, `DFS`, `AStar` | Алгоритмы поиска пути |
| `Pathfinder` | Оркестратор, управляющий поиском |
| `ConsoleDisplay` | Визуализация лабиринта и игрока |
| `Walker` | Управление позицией игрока |
| `MoveAction` | Команда перемещения с поддержкой Undo |
## 3. Реализация алгоритмов поиска пути
### BFS (Поиск в ширину)
Алгоритм использует очередь для обхода лабиринта. Начинает со стартовой клетки, помещает её в очередь. Затем циклически извлекает клетку из начала очереди, проверяет не является ли она выходом, и добавляет всех непосещенных соседей в конец очереди. **Гарантирует нахождение кратчайшего пути** по количеству шагов.
### DFS (Поиск в глубину)
Алгоритм использует стек для обхода лабиринта. Начинает со стартовой клетки, помещает её в стек. Затем циклически извлекает клетку из конца стека, проверяет не является ли она выходом, и добавляет всех непосещенных соседей в стек. **Не гарантирует нахождение кратчайшего пути**, но обычно быстрее по времени.
### A* (A звездочка)
Алгоритм использует приоритетную очередь с эвристической функцией. Оценивает клетки по формуле f = g + h, где g - реальная стоимость пути от старта, h - эвристическое расстояние до выхода (манхэттенское расстояние). **Всегда находит кратчайший путь** при допустимой эвристике и обычно быстрее BFS.
## 4. Экспериментальная часть
### Тестовые лабиринты
| Имя файла | Размер | Описание |
|-----------|--------|----------|
| level1.txt | 10x6 | Простой лабиринт |
| medium10x10.txt | 10x10 | Лабиринт среднего размера |
| large20x20.txt | 20x20 | Большой запутанный лабиринт |
| empty15x15.txt | 15x15 | Пустой лабиринт без стен |
| no_exit10x10.txt | 10x10 | Лабиринт без достижимого выхода |
### Результаты замеров
Каждый эксперимент проводился 3 раза с усреднением результатов.
| Лабиринт | Алгоритм | Время (мс) | Посещено клеток | Длина пути |
|----------|----------|------------|-----------------|------------|
| Small 10x6 | BFS | 0.032 | 24 | 11 |
| Small 10x6 | DFS | 0.017 | 17 | 11 |
| Small 10x6 | A* | 0.064 | 24 | 11 |
| Medium 10x10 | BFS | 0.044 | 42 | 16 |
| Medium 10x10 | DFS | 0.024 | 26 | 16 |
| Medium 10x10 | A* | 0.060 | 30 | 16 |
| Large 20x20 | BFS | 0.245 | 211 | 36 |
| Large 20x20 | DFS | 0.211 | 170 | 100 |
| Large 20x20 | A* | 0.264 | 103 | 36 |
| Empty 15x15 | BFS | 0.199 | 169 | 25 |
| Empty 15x15 | DFS | 0.122 | 169 | 97 |
| Empty 15x15 | A* | 0.411 | 169 | 25 |
| No exit 10x10 | BFS | 0.054 | 45 | 18 |
| No exit 10x10 | DFS | 0.030 | 28 | 18 |
| No exit 10x10 | A* | 0.083 | 35 | 18 |
### Графики
![Сравнение производительности алгоритмов](maze_benchmark.png)
На графике представлено сравнение трех алгоритмов по трем метрикам: время выполнения (мс), количество посещенных клеток и длина найденного пути.
## 5. Анализ результатов
### Сравнение характеристик алгоритмов
| Характеристика | BFS | DFS | A* |
|----------------|-----|-----|-----|
| Гарантия кратчайшего пути | Да | Нет | Да |
| Скорость на малых лабиринтах | Средняя | Быстрая | Средняя |
| Скорость на больших лабиринтах | Средняя | Быстрая | Средняя |
| Потребление памяти | Высокое | Низкое | Среднее |
| Количество посещенных клеток | Много (211) | Среднее (170) | Мало (103) |
### Детальный анализ по лабиринтам
**Small 10x6:**
- Все алгоритмы нашли оптимальный путь длиной 11 шагов
- DFS оказался самым быстрым (0.017 мс) и посетил меньше всего клеток (17)
- A* посетил больше клеток (24), но нашел оптимальный путь
**Medium 10x10:**
- Оптимальный путь - 16 шагов (BFS и A*)
- DFS нашел путь длиной 16 (в данном случае совпал с оптимальным)
- DFS снова самый быстрый (0.024 мс) и посетил 26 клеток против 42 у BFS
**Large 20x20:**
- BFS и A* нашли оптимальный путь (36 шагов)
- **DFS нашел неоптимальный путь (100 шагов), что на 64 шага длиннее!**
- A* посетил значительно меньше клеток (103 против 211 у BFS)
- Это показывает преимущество эвристики A* на больших лабиринтах
**Empty 15x15:**
- Оптимальный путь - 25 шагов (по прямой)
- DFS нашел путь длиной 97 шагов, что в 3.8 раза длиннее!
- Все алгоритмы посетили одинаковое количество клеток (169) - весь лабиринт
- A* показал самое большое время из-за накладных расходов на эвристику
**No exit 10x10:**
- Все алгоритмы обошли весь достижимый лабиринт
- DFS посетил меньше клеток (28 против 45 у BFS)
- Длина пути 18 показывает, что алгоритмы прошли до тупика
### Ключевые выводы
1. **BFS** - надежный выбор, когда гарантия кратчайшего пути критична. Работает предсказуемо, но на больших лабиринтах посещает много клеток (211 против 103 у A*)
2. **DFS** - самый быстрый алгоритм в большинстве тестов (0.017-0.211 мс), но **ненадежен для поиска оптимального пути**. В большом лабиринте путь оказался на 64% длиннее оптимального!
3. **A*** - лучший баланс. Находит кратчайший путь (как BFS), но посещает на 51% меньше клеток в большом лабиринте. Немного медленнее DFS из-за вычисления эвристики.
### Рекомендации по выбору алгоритма
| Ситуация | Рекомендуемый алгоритм | Обоснование |
|----------|----------------------|-------------|
| Небольшой лабиринт (< 100 клеток) | Любой | Разница в производительности незначительна |
| Большой лабиринт, нужен кратчайший путь | **A*** | Быстрее BFS, посещает меньше клеток |
| Максимальная скорость, путь не важен | **DFS** | Самый быстрый, но может найти длинный путь |
| Лабиринт неизвестной структуры | **A*** | Лучшее соотношение скорость/качество |
## 6. Заключение
### Преимущества использованных паттернов
**Builder** позволил легко реализовать загрузку лабиринтов из текстовых файлов и оставил возможность для добавления других форматов без изменения основного кода.
**Strategy** сделал алгоритмы поиска взаимозаменяемыми. Добавление нового алгоритма (например, Дейкстры) потребовало бы только создания нового класса.
**Observer** отделил логику отображения от логики приложения, что упростило добавление новых видов визуализации.
**Command** позволил реализовать пошаговое управление игроком с возможностью отмены действий без усложнения класса Walker.
### Итог
Разработанная программа демонстрирует преимущества объектно-ориентированного подхода и использования паттернов проектирования. Код является гибким, расширяемым и легко поддерживаемым.
Эксперименты показали, что **A*** является наиболее сбалансированным алгоритмом для поиска пути в лабиринте, обеспечивая оптимальный путь при приемлемой скорости работы и минимальном количестве посещенных клеток. DFS может быть полезен только когда скорость критична, а оптимальность пути не важна. BFS остается надежным выбором для небольших лабиринтов, где простота реализации важнее производительности.