# Лабораторная работа: Поиск выхода из лабиринта

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

### Графики

![Сравнение алгоритмов](algorithm_comparison.png)

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

## 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* является наиболее сбалансированным алгоритмом для поиска пути в лабиринте, обеспечивая оптимальный путь при приемлемой скорости.