diff --git a/meosyam/docs/2-report.md b/meosyam/docs/2-report.md new file mode 100644 index 00000000..e3e4fbb1 --- /dev/null +++ b/meosyam/docs/2-report.md @@ -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`. + +![Графики сравнения алгоритмов](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 быстр, но даёт неоптимальные результаты и может быть неэффективен на сложных картах. + +Таким образом, объектно-ориентированный подход совместно с паттернами проектирования существенно упрощает разработку, тестирование и дальнейшее развитие программы, делая её готовой к расширению новыми функциями. +``` \ No newline at end of file