# Отчёт по лабораторной работе: Поиск выхода из лабиринта

## 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 означает, что маршрут не существует.*

### Визуализация

![Сравнение производительности алгоритмов](maze_performance.png)

На графиках отражены три метрики: время выполнения, число посещённых клеток и длина найденного пути.

## 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`.