2026-rff_mp/meosyam/docs/2-report.md
2026-09-03 15:32:39 +00:00

221 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Вот полное содержимое отчёта в формате `.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 быстр, но даёт неоптимальные результаты и может быть неэффективен на сложных картах.
Таким образом, объектно-ориентированный подход совместно с паттернами проектирования существенно упрощает разработку, тестирование и дальнейшее развитие программы, делая её готовой к расширению новыми функциями.
```