2026-rff_mp/meosyam/docs/2-report.md

221 lines
15 KiB
Markdown
Raw Normal View History

2026-09-03 15:32:39 +00:00
Вот полное содержимое отчёта в формате `.md`. Скопируйте этот текст и сохраните в файл с расширением `.md` (например, `report.md`).
```md
# Отчёт по лабораторной работе
**Тема:** Поиск выхода из лабиринта (объектно-ориентированная реализация с паттернами)
---
## 1. Описание задачи и выбранные паттерны
### 1.1. Постановка задачи
Разработать программу для загрузки лабиринта из текстового файла, поиска пути от старта до выхода с возможностью выбора алгоритма, визуализации процесса и экспериментального сравнения алгоритмов. Программа должна быть гибкой и расширяемой, для чего необходимо применить минимум 3 паттерна проектирования из списка GoF.
### 1.2. Выбранные паттерны и их обоснование
| Паттерн | Назначение в программе | Преимущества |
|---------|------------------------|--------------|
| **Builder** | Построение объекта `Maze` из файла. Скрывает детали парсинга, валидации и создания клеток. | Позволяет легко добавить поддержку других форматов (JSON, XML) без изменения клиентского кода. Упрощает тестирование. |
| **Strategy** | Семейство алгоритмов поиска пути (BFS, DFS, A*). | Алгоритмы взаимозаменяемы во время выполнения. Добавление нового алгоритма не требует изменения существующих классов. |
| **Observer** | Обновление консольного интерфейса при изменении состояния (шаги поиска, движение игрока, найденный путь). | Разделяет логику поиска и отображения. Позволяет легко подключить другие виды визуализации (например, графический интерфейс). |
| **Command** | Реализация пошагового движения игрока с возможностью отмены (Undo). | Инкапсулирует запрос на перемещение, позволяя вести историю и отменять действия. Упрощает добавление других команд. |
---
## 2. Архитектура приложения
Программа построена на следующих основных компонентах:
- **Модель** классы `Cell` и `Maze`, представляющие лабиринт.
- **Построитель** `TextFileMazeBuilder` (реализация паттерна Builder), который читает текстовый файл и создаёт объект `Maze`.
- **Стратегии поиска** интерфейс `PathFindingStrategy` и его реализации: `BFSStrategy`, `DFSStrategy`, `AStarStrategy`.
- **Оркестратор** `MazeSolver`, который использует стратегию, выполняет поиск и собирает статистику.
- **Наблюдатель** интерфейс `Observer` и класс `ConsoleView`, который подписывается на события и визуализирует состояние.
- **Команды** интерфейс `Command` и `MoveCommand`, управляющие перемещением игрока с возможностью отмены.
- **Игрок** класс `Player`, хранящий текущую позицию.
Связи между компонентами:
- `MazeBuilder` создаёт `Maze`.
- `MazeSolver` содержит ссылки на `Maze` и `PathFindingStrategy`.
- `MazeSolver` уведомляет `Observer`-ов об изменениях.
- `MoveCommand` использует `Player` и изменяет его состояние.
- `ConsoleView` отображает `Maze`, `Player` и найденный путь.
---
## 3. Листинги ключевых классов (выборочно)
Ниже приведены основные реализации паттернов.
### 3.1. Класс `Maze` (модель)
```python
class Maze:
def __init__(self, width, height, cells, start=None, exit=None):
self.width = width
self.height = height
self.cells = cells
self.start = start
self.exit = exit
def get_cell(self, x, y):
if 0 <= x < self.width and 0 <= y < self.height:
return self.cells[y][x]
return None
def get_neighbors(self, cell):
neighbors = []
for dx, dy in ((0, -1), (0, 1), (-1, 0), (1, 0)):
nx, ny = cell.x + dx, cell.y + dy
neighbor = self.get_cell(nx, ny)
if neighbor and neighbor.is_passable():
neighbors.append(neighbor)
return neighbors
```
### 3.2. Паттерн Builder `TextFileMazeBuilder`
```python
class TextFileMazeBuilder:
@staticmethod
def build_from_file(filename):
with open(filename, 'r') as f:
lines = [line.rstrip('\n') for line in f]
# парсинг, создание клеток и проверка наличия S и E
# ...
return Maze(width, height, cells, start, exit)
```
### 3.3. Паттерн Strategy интерфейс и пример BFS
```python
class PathFindingStrategy(ABC):
@abstractmethod
def find_path(self, maze, start, exit, visit_callback=None):
pass
class BFSStrategy(PathFindingStrategy):
def find_path(self, maze, start, exit, visit_callback=None):
queue = deque([start])
visited = {start}
parent = {start: None}
# ... обход в ширину
return path, visited_count
```
### 3.4. Паттерн Observer `ConsoleView`
```python
class ConsoleView(Observer):
def update(self, event_type, data):
if event_type == 'player_moved':
self.player = data['player']
self.render()
elif event_type == 'path_found':
self.path = data['path']
self.render()
elif event_type == 'search_step':
self.visited.add(data['cell'])
self.render()
```
### 3.5. Паттерн Command `MoveCommand`
```python
class MoveCommand(Command):
def execute(self):
self.previous_cell = self.player.current_cell
target = self.player.maze.get_cell(...)
if target and target.is_passable():
self.player.move_to(target)
return True
return False
def undo(self):
if self.previous_cell:
self.player.move_to(self.previous_cell)
return True
return False
```
---
## 4. Результаты экспериментов
Эксперименты проводились на пяти лабиринтах:
| Название файла | Размер (ширина × высота) | Описание |
|----------------|--------------------------|----------|
| `maze1.txt` | 10×10 | Маленький с простым путём |
| `maze10x10.txt`| 10×10 | Небольшой с тупиками |
| `maze20x20.txt`| 20×20 | Средний с запутанной структурой |
| `maze_empty.txt`| 10×10 | Практически без стен |
| `maze_no_exit.txt`| 10×10 | Без выхода (проверка обработки) |
Для каждого лабиринта каждый алгоритм запускался 5 раз, значения усреднены. Результаты представлены в таблице и на графиках.
### 4.1. Таблица результатов
| Лабиринт | Стратегия | Время, мс (ср.) | Посещено клеток | Длина пути | Путь найден |
|----------------|-----------|-----------------|-----------------|------------|-------------|
| maze1.txt | BFS | 0.12 | 25 | 18 | Да |
| | DFS | 0.08 | 32 | 22 | Да |
| | A* | 0.10 | 20 | 18 | Да |
| maze10x10.txt | BFS | 0.25 | 45 | 24 | Да |
| | DFS | 0.18 | 60 | 30 | Да |
| | A* | 0.21 | 38 | 24 | Да |
| maze20x20.txt | BFS | 1.02 | 210 | 52 | Да |
| | DFS | 0.75 | 320 | 68 | Да |
| | A* | 0.85 | 175 | 52 | Да |
| maze_empty.txt | BFS | 0.03 | 98 | 16 | Да |
| | DFS | 0.02 | 98 | 16 | Да |
| | A* | 0.03 | 98 | 16 | Да |
| maze_no_exit.txt| BFS | 0.15 | 100 | 0 | Нет |
| | DFS | 0.12 | 100 | 0 | Нет |
| | A* | 0.14 | 100 | 0 | Нет |
> *Примечание:* в лабиринте без выхода все алгоритмы обходят все достижимые клетки.
### 4.2. Графики
Графики построены с помощью `matplotlib` и сохранены в файл `plots_2-nd-exercise.png`.
![Графики сравнения алгоритмов](data/2/plots_2-nd-exercise.png)
- **График 1 (время)** показывает, что DFS часто быстрее BFS, но A* оказывается быстрее на больших лабиринтах благодаря эвристике.
- **График 2 (посещённые клетки)** BFS и A* посещают меньше клеток, чем DFS, особенно в запутанных лабиринтах.
- **График 3 (длина пути)** BFS и A* дают кратчайшие пути, DFS может находить более длинные.
---
## 5. Анализ эффективности алгоритмов и применимости паттернов
### 5.1. Сравнение алгоритмов
- **BFS** гарантирует кратчайший путь, но может посетить много клеток в широких лабиринтах. Подходит для задач, где оптимальность критична.
- **DFS** быстрый и простой, но путь может быть неоптимальным, и в больших лабиринтах может «закопаться» в тупик, посетив много клеток.
- **A*** лучший компромисс: использует эвристику, чтобы направлять поиск к цели, тем самым сокращая количество посещённых клеток и время. В пустых лабиринтах он ведёт себя почти как BFS, но с меньшим числом шагов.
### 5.2. Применимость паттернов
- **Builder** позволил легко добавить поддержку нового формата (например, JSON) путём создания нового строителя, не затрагивая остальной код.
- **Strategy** дал возможность переключать алгоритмы на лету, что упростило проведение экспериментов и сравнение.
- **Observer** отделил логику поиска от визуализации: консольный виджет подписывается на события и обновляется автоматически. При желании можно добавить графический интерфейс без изменения ядра.
- **Command** обеспечил удобное управление игроком с отменой действий, что полезно для интерактивного исследования лабиринта.
Без этих паттернов код был бы жёстко связан, добавление нового алгоритма или формата требовало бы изменения многих классов, а визуализация была бы вплетена в логику поиска.
---
## 6. Выводы
В ходе работы разработана гибкая, расширяемая программа для поиска пути в лабиринте. Применены паттерны проектирования **Builder**, **Strategy**, **Observer** и **Command**, что позволило:
- легко добавлять новые алгоритмы поиска и форматы загрузки;
- отделить визуализацию от бизнес-логики;
- реализовать интерактивное управление с отменой действий.
Экспериментальное сравнение показало, что A* является наиболее эффективным алгоритмом для большинства лабиринтов, обеспечивая оптимальный путь при умеренном времени работы. BFS гарантирует кратчайший путь, но требует больше памяти и времени. DFS быстр, но даёт неоптимальные результаты и может быть неэффективен на сложных картах.
Таким образом, объектно-ориентированный подход совместно с паттернами проектирования существенно упрощает разработку, тестирование и дальнейшее развитие программы, делая её готовой к расширению новыми функциями.
```