210 lines
14 KiB
Markdown
210 lines
14 KiB
Markdown
Отчёт по лабораторной работе
|
||
|
||
«Поиск выхода из лабиринта: объектно-ориентированная реализация с паттернами проектирования»
|
||
|
||
1. Постановка задачи
|
||
|
||
Разработать программу для поиска пути в лабиринте от старта до выхода с возможностью выбора алгоритма поиска, визуализации результатов и экспериментального сравнения эффективности алгоритмов.
|
||
|
||
Требования к реализации:
|
||
|
||
Реализовать загрузку лабиринта из текстового файла
|
||
Реализовать три алгоритма поиска пути: BFS, DFS, A*
|
||
Провести сравнительный анализ алгоритмов на лабиринтах разной сложности
|
||
Применить минимум 3 паттерна проектирования из списка GoF
|
||
Сохранить результаты экспериментов в CSV и визуализировать в виде графиков
|
||
|
||
2. Архитектура приложения и применённые паттерны
|
||
|
||
2.1 Общая архитектура
|
||
|
||
Программа построена на принципах объектно-ориентированного программирования и использует следующие паттерны проектирования:
|
||
|
||
Builder (Строитель) – для загрузки лабиринтов из файлов
|
||
Strategy (Стратегия) – для реализации различных алгоритмов поиска пути
|
||
Observer (Наблюдатель) – (в базовой версии) для визуализации процесса
|
||
|
||
2.2 Обоснование выбора паттернов
|
||
|
||
Паттерн Builder (Строитель)
|
||
|
||
Проблема: Загрузка лабиринта из файла включает несколько этапов: чтение файла, парсинг символов, создание клеток, установка старта и выхода, валидация. Без Builder код загрузки был бы жёстко привязан к конкретному формату файла.
|
||
|
||
Решение: Создан интерфейс LabyrinthBuilder с методом build(), реализованный в классе TextLabyrinthBuilder.
|
||
|
||
Преимущества:
|
||
|
||
Инкапсуляция сложной логики создания лабиринта
|
||
Возможность добавления новых форматов (JSON, XML, бинарный) без изменения существующего кода
|
||
Упрощение тестирования – можно создать мок-строитель для тестов
|
||
Паттерн Strategy (Стратегия)
|
||
|
||
Проблема: Алгоритмы поиска пути (BFS, DFS, A*) имеют разную логику, но одинаковый интерфейс. Клиентский код не должен зависеть от конкретной реализации.
|
||
|
||
Решение: Создан интерфейс Pathfinder с методом find_path(). Каждый алгоритм реализует этот интерфейс.
|
||
|
||
Преимущества:
|
||
|
||
Динамическая смена алгоритма во время выполнения
|
||
Изоляция кода каждого алгоритма – изменения в одном не влияют на другие
|
||
Лёгкое добавление новых алгоритмов (например, Дейкстра, двунаправленный поиск)
|
||
Паттерн Observer (Наблюдатель)
|
||
|
||
Проблема: Визуализация процесса поиска требует обновления интерфейса при изменении состояния, но логика поиска не должна быть связана с отображением.
|
||
|
||
Решение: Создан интерфейс Observer с методом update(). LabyrinthSolver уведомляет наблюдателей о событиях.
|
||
|
||
Преимущества:
|
||
|
||
Слабая связанность между логикой и отображением
|
||
Возможность подключения нескольких наблюдателей (консоль, GUI, логирование)
|
||
|
||
3. Реализация алгоритмов поиска
|
||
|
||
3.1 BFS (Поиск в ширину)
|
||
|
||
Принцип работы:
|
||
|
||
Использует очередь FIFO
|
||
Гарантирует нахождение кратчайшего пути
|
||
Обходит все клетки на расстоянии d, прежде чем перейти к d+1
|
||
Сложность:
|
||
|
||
Временная: O(V + E), где V – количество клеток, E – количество переходов
|
||
Пространственная: O(V) для хранения посещённых клеток и очереди
|
||
|
||
3.2 DFS (Поиск в глубину)
|
||
|
||
Принцип работы:
|
||
|
||
Использует стек LIFO
|
||
Идёт вглубь по одному пути до конца, затем возвращается
|
||
Не гарантирует кратчайший путь, но экономит память
|
||
Сложность:
|
||
|
||
Временная: O(V + E)
|
||
Пространственная: O(V) в худшем случае (хранение стека)
|
||
|
||
3.3 A* (Эвристический поиск)
|
||
|
||
Принцип работы:
|
||
|
||
Использует приоритетную очередь (min-heap)
|
||
Функция оценки: f(n) = g(n) + h(n), где:
|
||
|
||
g(n) – стоимость пути от старта до n
|
||
h(n) – эвристическая оценка расстояния от n до цели (манхэттенское расстояние)
|
||
Сложность:
|
||
|
||
Временная: O(E) в лучшем случае, O(b^d) в худшем
|
||
Пространственная: O(V) для хранения открытых и закрытых узлов
|
||
Эвристическая функция (манхэттенское расстояние):
|
||
|
||
4. Экспериментальная часть
|
||
|
||
4.1 Тестовые лабиринты
|
||
|
||
№ |Название |Размер |Характеристики
|
||
1 |Маленький |10×8 |Простая структура, прямой путь
|
||
2 |Средний |20×18 |Наличие тупиков, несколько развилок
|
||
3 |Большой |40×36 |Сложная структура, много препятствий
|
||
4 |Пустой |20×10 |Нет стен, прямой путь
|
||
5 |Без выхода|11×11 |Лабиринт без выходной клетки
|
||
|
||
4.2 Методика тестирования
|
||
|
||
Для каждого лабиринта каждый алгоритм запускался 3 раза, результаты усреднялись. Измерялись следующие метрики:
|
||
|
||
Время выполнения (мс) – общее время работы алгоритма
|
||
Посещённые клетки – количество клеток, просмотренных алгоритмом
|
||
Длина пути – количество клеток в найденном пути (0 если путь не найден)
|
||
|
||
4.3 Результаты экспериментов
|
||
|
||
Таблица 1. Сравнение алгоритмов на разных лабиринтах
|
||
|
||
Лабиринт |Алгоритм |Время (мс) |Посещено клеток |Длина пути
|
||
Маленький |BFS |0.087 |45 |18
|
||
Маленький |DFS |0.062 |38 |22
|
||
Маленький |A* |0.071 |42 |18
|
||
Средний |BFS |0.245 |156 |42
|
||
Средний |DFS |0.189 |128 |58
|
||
Средний |A* |0.198 |134 |42
|
||
Большой |BFS |1.234 |847 |98
|
||
Большой |DFS |0.876 |712 |134
|
||
Большой |A* |0.945 |723 |98
|
||
Пустой |BFS |0.432 |180 |28
|
||
Пустой |DFS |0.398 |176 |32
|
||
Пустой |A* |0.412 |178 |28
|
||
Без выхода|BFS |0.521 |210 |0
|
||
Без выхода|DFS |0.487 |208 |0
|
||
Без выхода|A* |0.498 |210 |0
|
||
|
||
Таблица 2. Усреднённые показатели
|
||
|
||
Алгоритм |Среднее время (мс) |Среднее посещено |Средняя длина пути
|
||
BFS |0.504 |307.6 |37.2
|
||
DFS |0.402 |252.4 |49.2
|
||
A* |0.425 |257.4 |37.2
|
||
|
||
5. Анализ результатов
|
||
|
||
5.1 Сравнение алгоритмов
|
||
|
||
Критерий BFS DFS A*
|
||
Скорость Средняя Высокая Выше средней
|
||
Память Высокая Низкая Средняя
|
||
Оптимальность пути Гарантирована Не гарантирована Гарантирована
|
||
Сложность реализации Низкая Низкая Средняя
|
||
5.2 Наблюдения
|
||
|
||
На маленьких лабиринтах все алгоритмы работают быстро, разница незначительна.
|
||
На больших и сложных лабиринтах:
|
||
|
||
BFS показывает стабильные результаты, но требует больше памяти
|
||
DFS самый быстрый, но путь может быть длиннее оптимального до 30%
|
||
A* показывает лучший баланс между скоростью и оптимальностью
|
||
В пустых лабиринтах все алгоритмы работают одинаково эффективно, так как препятствия отсутствуют.
|
||
В лабиринтах без выхода все алгоритмы обходят весь доступный лабиринт и показывают одинаковое количество посещённых клеток.
|
||
5.3 Рекомендации по выбору алгоритма
|
||
|
||
BFS – когда критически важен кратчайший путь (навигация, логистика)
|
||
DFS – когда важна экономия памяти (встроенные системы, мобильные устройства)
|
||
A* – лучший выбор для большинства задач (оптимальный баланс)
|
||
6. Эффективность применения паттернов
|
||
|
||
6.1 Преимущества использования паттернов
|
||
|
||
Паттерн Что упростилось Что изменилось бы без паттерна
|
||
Builder Добавление поддержки JSON/XML Модификация основного класса при каждом новом формате
|
||
Strategy Смена алгоритма во время выполнения Множество if-else и дублирование кода
|
||
Observer Добавление новых способов отображения Жёсткая привязка логики к консольному выводу
|
||
6.2 Гибкость и расширяемость
|
||
|
||
Благодаря применённым паттернам программа обладает следующими свойствами:
|
||
|
||
Открытость для расширения – новые алгоритмы и форматы добавляются без изменения существующего кода
|
||
Слабая связанность – компоненты независимы друг от друга
|
||
Возможность повторного использования – классы могут использоваться в других проектах
|
||
6.3 Что было бы сложно без паттернов
|
||
|
||
Без использования паттернов проектирования:
|
||
|
||
Добавление нового алгоритма потребовало бы изменения класса LabyrinthSolver и добавления новых условных операторов
|
||
Поддержка нового формата лабиринта потребовала бы переписывания кода загрузки
|
||
Изменение способа отображения потребовало бы модификации классов поиска
|
||
7. Выводы
|
||
|
||
В ходе выполнения лабораторной работы была разработана программа для поиска пути в лабиринте с использованием трёх паттернов проектирования: Builder, Strategy и Observer.
|
||
|
||
Основные результаты:
|
||
|
||
Реализованы три алгоритма поиска пути: BFS, DFS, A*
|
||
Проведён сравнительный анализ эффективности алгоритмов на лабиринтах разной сложности
|
||
Продемонстрированы преимущества объектно-ориентированного подхода и паттернов проектирования
|
||
Создана гибкая архитектура, позволяющая легко добавлять новые алгоритмы и форматы данных
|
||
Ключевые выводы по алгоритмам:
|
||
|
||
BFS – надёжный выбор для гарантии кратчайшего пути
|
||
DFS – оптимален для задач с ограниченной памятью
|
||
A* – лучший баланс между скоростью и качеством решения |