forked from UNN/2026-rff_mp
[2] add report.md
This commit is contained in:
parent
306380eb55
commit
3e5f6986d9
221
meosyam/docs/2-report.md
Normal file
221
meosyam/docs/2-report.md
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
Вот полное содержимое отчёта в формате `.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`.
|
||||
|
||||

|
||||
|
||||
- **График 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 быстр, но даёт неоптимальные результаты и может быть неэффективен на сложных картах.
|
||||
|
||||
Таким образом, объектно-ориентированный подход совместно с паттернами проектирования существенно упрощает разработку, тестирование и дальнейшее развитие программы, делая её готовой к расширению новыми функциями.
|
||||
```
|
||||
Loading…
Reference in New Issue
Block a user