Compare commits
No commits in common. "develop" and "1-st-exercise" have entirely different histories.
develop
...
1-st-exerc
|
|
@ -1 +0,0 @@
|
||||||
428b
|
|
||||||
183
README.md
183
README.md
|
|
@ -197,186 +197,3 @@ with open("results.csv", "w", newline="") as f:
|
||||||
- Как удаление работает в каждой структуре.
|
- Как удаление работает в каждой структуре.
|
||||||
|
|
||||||
* Вывод должен содержать ответ на вопрос: какую структуру и для каких задач (частые вставки, частый поиск, необходимость получать данные в порядке) стоит выбирать в реальной жизни.*
|
* Вывод должен содержать ответ на вопрос: какую структуру и для каких задач (частые вставки, частый поиск, необходимость получать данные в порядке) стоит выбирать в реальной жизни.*
|
||||||
|
|
||||||
## Задание: Поиск выхода из лабиринта (объектно-ориентированная реализация с паттернами)
|
|
||||||
|
|
||||||
### Цель работы
|
|
||||||
Разработать гибкую, расширяемую программу для загрузки лабиринта из файла, поиска пути от старта до выхода с возможностью выбора алгоритма, визуализации процесса и экспериментального сравнения алгоритмов. В ходе работы необходимо применить минимум 3 паттерна проектирования из списка GoF, обосновать их выбор и продемонстрировать преимущества такой архитектуры.
|
|
||||||
|
|
||||||
### Общая схема приложения (пример)
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
classDiagram
|
|
||||||
class Maze {
|
|
||||||
-Cell[] cells
|
|
||||||
-int width, height
|
|
||||||
-Cell start
|
|
||||||
-Cell exit
|
|
||||||
+getCell(x,y): Cell
|
|
||||||
+getNeighbors(cell): List~Cell~
|
|
||||||
}
|
|
||||||
|
|
||||||
class Cell {
|
|
||||||
-int x, y
|
|
||||||
-bool isWall
|
|
||||||
-bool isStart
|
|
||||||
-bool isExit
|
|
||||||
+isPassable(): bool
|
|
||||||
}
|
|
||||||
|
|
||||||
class MazeBuilder {
|
|
||||||
<<interface>>
|
|
||||||
+buildFromFile(filename): Maze
|
|
||||||
}
|
|
||||||
|
|
||||||
class TextFileMazeBuilder {
|
|
||||||
+buildFromFile(filename): Maze
|
|
||||||
}
|
|
||||||
|
|
||||||
class PathFindingStrategy {
|
|
||||||
<<interface>>
|
|
||||||
+findPath(maze, start, exit): List~Cell~
|
|
||||||
}
|
|
||||||
|
|
||||||
class BFSStrategy
|
|
||||||
class DFSStrategy
|
|
||||||
class AStarStrategy
|
|
||||||
class DijkstraStrategy
|
|
||||||
|
|
||||||
class SearchStats {
|
|
||||||
+timeMs: float
|
|
||||||
+visitedCells: int
|
|
||||||
+pathLength: int
|
|
||||||
}
|
|
||||||
|
|
||||||
class MazeSolver {
|
|
||||||
-Maze maze
|
|
||||||
-PathFindingStrategy strategy
|
|
||||||
+setStrategy(strategy)
|
|
||||||
+solve(): SearchStats
|
|
||||||
}
|
|
||||||
|
|
||||||
class Command {
|
|
||||||
<<interface>>
|
|
||||||
+execute()
|
|
||||||
+undo()
|
|
||||||
}
|
|
||||||
|
|
||||||
class MoveCommand {
|
|
||||||
-Player player
|
|
||||||
-Direction dir
|
|
||||||
-Cell previousCell
|
|
||||||
+execute()
|
|
||||||
+undo()
|
|
||||||
}
|
|
||||||
|
|
||||||
class Player {
|
|
||||||
-Cell currentCell
|
|
||||||
+moveTo(cell)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Observer {
|
|
||||||
<<interface>>
|
|
||||||
+update(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConsoleView {
|
|
||||||
+update(event)
|
|
||||||
+render(maze, player, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
MazeBuilder <|.. TextFileMazeBuilder
|
|
||||||
MazeBuilder --> Maze : creates
|
|
||||||
PathFindingStrategy <|.. BFSStrategy
|
|
||||||
PathFindingStrategy <|.. DFSStrategy
|
|
||||||
PathFindingStrategy <|.. AStarStrategy
|
|
||||||
PathFindingStrategy <|.. DijkstraStrategy
|
|
||||||
MazeSolver --> PathFindingStrategy : uses
|
|
||||||
MazeSolver --> Maze : uses
|
|
||||||
Command <|.. MoveCommand
|
|
||||||
MoveCommand --> Player
|
|
||||||
Player --> Cell
|
|
||||||
Observer <|.. ConsoleView
|
|
||||||
MazeSolver --> Observer : notifies
|
|
||||||
```
|
|
||||||
|
|
||||||
### Выполнение
|
|
||||||
|
|
||||||
#### Этап 1. Модель лабиринта (без паттернов, просто классы)
|
|
||||||
**Задача:** Создать классы `Cell` и `Maze`, которые представляют карту лабиринта.
|
|
||||||
- `Cell` хранит координаты (x, y), флаги `isWall`, `isStart`, `isExit`, метод `isPassable()` (возвращает `True` для прохода, если не стена).
|
|
||||||
- `Maze` хранит двумерный массив клеток, ширину, высоту, ссылки на стартовую и выходную клетку. Методы: `getCell(x, y)`, `getNeighbors(cell)` – возвращает список соседних проходимых клеток (вверх, вниз, влево, вправо, если в пределах границ и не стена).
|
|
||||||
|
|
||||||
**Результат:** Лабиринт можно создать вручную в коде, но загрузку пока не делаем.
|
|
||||||
|
|
||||||
#### Этап 2. Загрузка лабиринта из файла – применение паттерна **Builder**
|
|
||||||
**Задача:** Реализовать загрузку лабиринта из текстового файла, где `#` – стена, ` ` (пробел) – проход, `S` – старт, `E` – выход.
|
|
||||||
- Создать интерфейс `MazeBuilder` с методом `buildFromFile(filename)`.
|
|
||||||
- Реализовать класс `TextFileMazeBuilder`, который читает файл, парсит символы, создаёт объекты `Cell`, задаёт координаты и флаги, после чего возвращает готовый `Maze`.
|
|
||||||
|
|
||||||
Процесс построения лабиринта сложный (парсинг, валидация, установка старта/выхода). Builder скрывает детали создания от клиента. В будущем можно легко добавить другой формат (например, JSON или бинарный) через новую реализацию `MazeBuilder`.
|
|
||||||
|
|
||||||
#### Этап 3. Стратегии поиска пути – паттерн **Strategy**
|
|
||||||
**Задача:** Реализовать семейство алгоритмов поиска пути от старта до выхода.
|
|
||||||
- Создать интерфейс `PathFindingStrategy` с методом `findPath(maze, start, exit)`, возвращающим список клеток пути (от старта до выхода включительно) или пустой список, если пути нет.
|
|
||||||
- Реализовать минимум 3 стратегии:
|
|
||||||
- **BFS** (поиск в ширину) – гарантирует кратчайший путь по количеству шагов.
|
|
||||||
- **DFS** (поиск в глубину) – быстрый, но не обязательно кратчайший.
|
|
||||||
- **A*** (с эвристикой, например, манхэттенское расстояние) – компромисс между скоростью и оптимальностью.
|
|
||||||
- (Опционально) **Дейкстра** – полезна для взвешенных лабиринтов, но в базовом варианте все шаги имеют вес 1, тогда она совпадает с BFS.
|
|
||||||
|
|
||||||
Каждая стратегия возвращает путь. Для BFS/DFS используйте очередь/стек, для A* – приоритетную очередь (heapq). Важно: алгоритмы не должны модифицировать сам лабиринт, только читать состояние клеток.
|
|
||||||
|
|
||||||
Strategy позволяет легко переключать алгоритмы во время выполнения, не меняя код остальной программы. Новый алгоритм можно добавить, реализовав интерфейс.
|
|
||||||
|
|
||||||
#### Этап 4. Класс-оркестратор – **MazeSolver** (использует Strategy)
|
|
||||||
**Задача:** Создать класс, который принимает лабиринт и стратегию, выполняет поиск и собирает статистику.
|
|
||||||
- `MazeSolver` содержит поля `maze` и `strategy`.
|
|
||||||
- Метод `setStrategy(strategy)` для динамической смены алгоритма.
|
|
||||||
- Метод `solve()` вызывает `strategy.findPath(...)` и возвращает объект `SearchStats` (время выполнения в миллисекундах, количество посещённых клеток, длина найденного пути).
|
|
||||||
- Для замера времени используйте `time.perf_counter()` до и после вызова стратегии.
|
|
||||||
|
|
||||||
#### Этап 5. Визуализация и пошаговое управление – паттерны **Observer** и **Command** (по желанию)
|
|
||||||
**5.1. Наблюдатель (Observer)** – обновление консольного интерфейса.
|
|
||||||
- Создать интерфейс `Observer` с методом `update(event)`, где `event` может быть строкой или объектом с типом события (`"path_found"`, `"move"`, `"maze_loaded"`).
|
|
||||||
- Реализовать класс `ConsoleView`, который отображает лабиринт, текущее положение игрока (если реализован пошаговый режим) и найденный путь. Метод `render(maze, player_position, path)` рисует карту в консоли.
|
|
||||||
- `MazeSolver` (или отдельный контроллер) может иметь список наблюдателей и уведомлять их при изменении состояния.
|
|
||||||
|
|
||||||
**5.2. Команда (Command)** – для пошагового перемещения игрока по найденному пути (или ручного управления).
|
|
||||||
- Создать интерфейс `Command` с методами `execute()` и `undo()`.
|
|
||||||
- Реализовать `MoveCommand`, который принимает игрока (`Player`), направление и изменяет его позицию, сохраняя предыдущую для отмены.
|
|
||||||
- Создать класс `Player`, хранящий текущую клетку.
|
|
||||||
- Консольное меню позволяет вводить команды (W/A/S/D), выполнять `MoveCommand`, при необходимости отменять последний ход (Ctrl+Z). Это опционально, но очень наглядно демонстрирует паттерн.
|
|
||||||
|
|
||||||
*Observer можно реализовать только для вывода сообщений о начале/конце поиска, а Command – для демонстрации undo при ручном исследовании лабиринта.*
|
|
||||||
|
|
||||||
#### Этап 6. Экспериментальная часть (аналогично заданию со структурами данных)
|
|
||||||
**Задача:** Сравнить эффективность реализованных стратегий на лабиринтах разной сложности.
|
|
||||||
1. **Подготовка тестовых лабиринтов:**
|
|
||||||
- Маленький (10×10) с простым путём.
|
|
||||||
- Средний (50×50) с тупиками.
|
|
||||||
- Большой (100×100) с запутанной структурой.
|
|
||||||
- «Пустой» лабиринт (без стен) – для демонстрации максимальной производительности.
|
|
||||||
- «Без выхода» – чтобы проверить обработку отсутствия пути.
|
|
||||||
2. **Замеры:**
|
|
||||||
- Для каждого лабиринта и каждой стратегии запустить `solve()` 5–10 раз, усреднить время, количество посещённых клеток, длину пути.
|
|
||||||
- Записать результаты в CSV: `лабиринт,стратегия,время_мс,посещено_клеток,длина_пути`.
|
|
||||||
3. **Анализ:**
|
|
||||||
- Построить графики для каждого лабиринта.
|
|
||||||
- Проанализировать и написать выводы по итогам (эффективность того или иного алгоритма в разных случаях).
|
|
||||||
|
|
||||||
4. **Дополнительное задание:** Реализовать взвешенные клетки (например, болото – вес 3, песок – вес 2, асфальт – вес 1) и сравнить Дейкстру с A* на взвешенном графе.
|
|
||||||
|
|
||||||
#### Этап 7. Отчёт
|
|
||||||
**Структура отчёта:**
|
|
||||||
1. Описание задачи и выбранных паттернов (с диаграммой классов из Mermaid).
|
|
||||||
2. Листинги ключевых классов (можно выборочно) или ссылка на репозиторий.
|
|
||||||
3. Результаты экспериментов (таблицы, графики).
|
|
||||||
4. Анализ эффективности алгоритмов и применимости паттернов.
|
|
||||||
5. Выводы: как ООП и паттерны помогли сделать код гибким и расширяемым. Что было бы сложно изменить без них.
|
|
||||||
|
|
||||||
### Советы
|
|
||||||
- Для A* самая простая эвристика: `abs(x1 - x2) + abs(y1 - y2)`.
|
|
||||||
- При поиске пути надо хранить предшественников (`parent` для каждой посещённой клетки), чтобы восстановить путь.
|
|
||||||
- Для BFS/DFS используй `deque` (очередь) и `list` (стек).
|
|
||||||
- Визуализацию в консоли можно сделать с помощью `os.system('cls' if os.name == 'nt' else 'clear')` для перерисовки.
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{\rtf1\ansi\ansicpg1251\cocoartf2869
|
|
||||||
\cocoatextscaling0\cocoaplatform0{\fonttbl}
|
|
||||||
{\colortbl;\red255\green255\blue255;}
|
|
||||||
{\*\expandedcolortbl;;}
|
|
||||||
\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
<EFBFBD>¥¦¨¬ ¢כ¢®₪ ×®¬ ₪ ם×א (ECHO) ¢×«מח¥.
|
|
||||||
Loading…
Reference in New Issue
Block a user