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* – лучший баланс между скоростью и качеством решения
|