2026-rff_mp/KislyuninED/docks/report-2-nd.md

11 KiB
Raw Blame History

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

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