# Отчёт по работе «Поиск выхода из лабиринта» ## 1. Цель работы Разработать гибкую программу для загрузки лабиринта из файла, поиска пути от старта до выхода с возможностью выбора алгоритма, визуализации процесса и экспериментального сравнения алгоритмов. В работе использованы паттерны проектирования, чтобы отделить логику представления лабиринта, его загрузки, поиска пути и вывода результатов. ## 2. Описание задачи Лабиринт задаётся в текстовом файле символами: - `#` — стена; - пробел — проход; - `S` — старт; - `E` — выход. Программа должна: - загружать лабиринт; - строить его внутреннюю модель; - искать путь разными алгоритмами; - собирать статистику поиска; - визуализировать результат в консоли; - сравнивать стратегии на разных типах лабиринтов. ## 3. Выбранные паттерны проектирования ### 3.1 Builder Паттерн Builder используется для загрузки лабиринта из файла. Он скрывает детали парсинга и валидации, а клиент получает готовый объект `Maze`. Преимущества: - легко добавить новый формат загрузки; - клиентский код не зависит от формата файла; - создание лабиринта можно расширять без переписывания остальной программы. ### 3.2 Strategy Паттерн Strategy используется для выбора алгоритма поиска пути. В программе реализованы `BFS`, `DFS`, `A*`, а при необходимости можно добавить Дейкстру или любую другую стратегию. Преимущества: - алгоритм можно менять во время выполнения; - код оркестратора не зависит от конкретного метода поиска; - новые алгоритмы добавляются без изменения существующего кода. ### 3.3 Observer Паттерн Observer используется для обновления консольного интерфейса при изменении состояния программы: загрузка лабиринта, поиск пути, движение игрока. Преимущества: - вывод отделён от логики; - можно заменить консольный интерфейс на графический без изменения поискового кода; - упрощается расширение визуализации. ### 3.4 Command Паттерн Command используется для пошагового перемещения игрока и отмены последнего хода. Преимущества: - каждое действие оформляется как отдельный объект; - легко реализовать undo; - история ходов хранится отдельно от логики перемещения. ## 4. Диаграмма классов Ниже приведена упрощённая диаграмма классов в формате Mermaid: ```mermaid classDiagram class Cell { +int x +int y +bool isWall +bool isStart +bool isExit +isPassable() } class Maze { +cells +width +height +startCell +exitCell +getCell(x, y) +getNeighbors(cell) } class MazeBuilder { <> +buildFromFile(filename) } class TextFileMazeBuilder { +buildFromFile(filename) } class PathFindingStrategy { <> +findPath(maze, start, exitCell) } class BFSStrategy { +findPath(maze, start, exitCell) } class DFSStrategy { +findPath(maze, start, exitCell) } class AStarStrategy { +findPath(maze, start, exitCell) } class SearchStats { +timeMs +visitedCells +pathLength +path } class MazeSolver { +maze +strategy +setStrategy(strategy) +solve() } class Observer { <> +update(event) } class ConsoleView { +update(event) +render(maze, player_position, path) } class Command { <> +execute() +undo() } class MoveCommand { +execute() +undo() } class Player { +currentCell +setCell(cell) } Maze <|-- TextFileMazeBuilder : creates MazeBuilder <|.. TextFileMazeBuilder PathFindingStrategy <|.. BFSStrategy PathFindingStrategy <|.. DFSStrategy PathFindingStrategy <|.. AStarStrategy MazeSolver --> Maze MazeSolver --> PathFindingStrategy MazeSolver --> SearchStats Observer <|.. ConsoleView Command <|.. MoveCommand MoveCommand --> Player MoveCommand --> Maze ConsoleView --> Maze Maze --> Cell ``` ## 5. Ключевые классы и их роль ### Cell Хранит координаты клетки и её тип. Позволяет быстро проверять, является ли клетка проходимой. ### Maze Содержит двумерную карту клеток, размер лабиринта, а также ссылки на старт и выход. Даёт доступ к соседним клеткам по четырём направлениям. ### TextFileMazeBuilder Читает текстовый файл, создаёт объекты `Cell`, определяет старт и выход, затем возвращает готовый `Maze`. ### BFSStrategy Ищет кратчайший путь по числу шагов. Подходит для случая, когда все переходы одинаковой стоимости. ### DFSStrategy Быстро исследует пространство, но не гарантирует кратчайший путь. Полезен как сравнительный алгоритм. ### AStarStrategy Использует эвристику Манхэттенского расстояния. Обычно посещает меньше клеток, чем BFS, если эвристика удачно направляет поиск к цели. ### MazeSolver Оркестратор, который хранит лабиринт и текущую стратегию. Вызывает поиск, измеряет время и собирает статистику. ### SearchStats Содержит итог поиска: время выполнения, количество посещённых клеток и длину пути. ### ConsoleView Реализует наблюдателя и умеет выводить лабиринт и найденный путь в консоль. ### MoveCommand Оформляет ход игрока как объект-команду. Поддерживает отмену последнего перемещения. ## 6. Экспериментальная часть ### 6.1 Подготовка тестовых лабиринтов Для сравнения стратегий использовались следующие типы лабиринтов: - маленький 10×10 с простым путём; - средний 50×50 с тупиками; - большой 100×100 со сложной структурой; - пустой лабиринт без стен; - лабиринт без выхода. ### 6.2 Методика измерений Для каждой стратегии и каждого лабиринта поиск запускался несколько раз, после чего вычислялись средние значения: - время поиска в миллисекундах; - количество посещённых клеток; - длина найденного пути. Результаты сохранялись в CSV-файл в двух вариантах: - сырой набор измерений; - усреднённая таблица. ## 7. Анализ эффективности ### BFS BFS гарантирует кратчайший путь по числу шагов, если все переходы имеют одинаковую стоимость. На простых и пустых лабиринтах работает стабильно и предсказуемо. Минус — может посещать много клеток, особенно на больших лабиринтах. ### DFS DFS может быстро найти какой-то путь, но он не обязательно будет кратчайшим. На сложных лабиринтах иногда работает быстро, но на других может уйти далеко от цели и пройти лишние области. ### A* A* использует эвристику и обычно показывает хороший баланс между скоростью и качеством пути. На больших и запутанных лабиринтах часто посещает меньше клеток, чем BFS, потому что поиск направлен в сторону выхода. ### Лабиринт без пути Если пути нет, все алгоритмы вынуждены исследовать доступную область. В этом случае длина пути равна 0, а различия между алгоритмами проявляются в количестве просмотренных клеток и времени выполнения. ### Вывод по выбору алгоритма - BFS стоит выбирать, когда нужен гарантированно кратчайший путь и веса переходов одинаковы. - DFS полезен как простой и быстрый по реализации вариант, но без гарантии оптимальности. - A* подходит для практических задач, где нужно ускорить поиск и сократить число посещённых клеток. - При взвешенных переходах лучше использовать Дейкстру или взвешенный A*. ## 8. Роль ООП и паттернов ООП и паттерны сделали код более гибким и расширяемым. Благодаря этому: - можно заменить алгоритм поиска без переписывания логики программы; - можно добавить новый формат загрузки лабиринта; - можно поменять способ визуализации; - можно расширить управление игроком и добавить отмену действий. Без паттернов пришлось бы связывать загрузку, поиск, отображение и управление в один большой блок кода. Это усложнило бы отладку и дальнейшие изменения. ## 9. Вывод В ходе работы была создана расширяемая программа для поиска пути в лабиринте. Использование паттернов Builder, Strategy, Observer и Command позволило разделить обязанности между классами, упростить поддержку кода и сделать архитектуру удобной для дальнейшего развития. Эксперименты показали, что выбор алгоритма сильно зависит от типа лабиринта: BFS даёт кратчайший путь, DFS иногда быстрее в реализации, а A* чаще всего наиболее практичен на больших картах. ## 10. Приложения - Листинги ключевых классов. - CSV-файлы с результатами экспериментов. - Графики сравнений. - Файлы с тестовыми лабиринтами.