forked from UNN/2026-rff_mp
Merge pull request '[2]zadanie2' (#217) from zverevem/2026-rff_mp:zverevem into develop
Reviewed-on: UNN/2026-rff_mp#217
This commit is contained in:
commit
979a03c36f
345
zverevem/lab2/docs/Report.ipynb
Normal file
345
zverevem/lab2/docs/Report.ipynb
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9a863658",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Отчёт: Поиск выхода из лабиринта (ООП + паттерны проектирования)\n",
|
||||
"\n",
|
||||
"## Цель работы\n",
|
||||
"\n",
|
||||
"Разработать гибкую расширяемую программу для загрузки лабиринта из файла, поиска пути от старта до выхода с возможностью выбора алгоритма и экспериментального сравнения алгоритмов. Применить минимум 3 паттерна проектирования из списка GoF, обосновать их выбор и продемонстрировать преимущества такой архитектуры.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Описание задачи и выбранных паттернов\n",
|
||||
"\n",
|
||||
"Программа решает задачу поиска пути в лабиринте, загружаемом из текстового файла. Лабиринт представляет собой сетку клеток, где `#` — стена, пробел — проход, `S` — старт, `E` — выход. Алгоритм поиска выбирается динамически, результаты выводятся через систему событий.\n",
|
||||
"\n",
|
||||
"В проекте применены паттерны Builder, Strategy, Observer и Command.\n",
|
||||
"\n",
|
||||
"### 1. Builder (Строитель) — `MazeBuilder.py`\n",
|
||||
"\n",
|
||||
"**Проблема:** построение объекта `Maze` из текстового файла включает несколько этапов: чтение файла, анализ символов, создание объектов клеток, определение стартовой и конечной позиции, формирование структуры лабиринта.\n",
|
||||
"\n",
|
||||
"**Решение:** создан абстрактный класс `MazeBuilder` с методом `build_from_file()`. Класс `TextFileMazeBuilder` реализует построение лабиринта из текстового файла.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class MazeBuilder(ABC):\n",
|
||||
" @abstractmethod\n",
|
||||
" def build_from_file(self, filename) -> Maze:\n",
|
||||
" pass\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class TextFileMazeBuilder(MazeBuilder):\n",
|
||||
" def build_from_file(self, filename) -> Maze:\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Паттерн позволяет изолировать логику построения лабиринта от основной программы. При необходимости можно добавить другой формат загрузки без изменения клиентского кода.\n",
|
||||
"\n",
|
||||
"### 2. Strategy (Стратегия) — `FindingStrategy.py`\n",
|
||||
"\n",
|
||||
"**Проблема:** алгоритмы BFS, DFS и A* имеют разную реализацию, но используются одинаковым образом.\n",
|
||||
"\n",
|
||||
"**Решение:** создан интерфейс `PathFindingStrategy` с методом `find_path()`. Алгоритмы `BFSStrategy`, `DFSStrategy` и `AStarStrategy` реализуют общий интерфейс.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class PathFindingStrategy(ABC):\n",
|
||||
" @abstractmethod\n",
|
||||
" def find_path(self, maze, start, exit_cell):\n",
|
||||
" pass\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Смена алгоритма выполняется динамически:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"solver.set_strategy(BFSStrategy())\n",
|
||||
"solver.solve()\n",
|
||||
"\n",
|
||||
"solver.set_strategy(AStarStrategy())\n",
|
||||
"solver.solve()\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Паттерн Strategy позволяет добавлять новые алгоритмы поиска без изменения класса `MazeSolver`.\n",
|
||||
"\n",
|
||||
"### 3. Observer (Наблюдатель) — `MazeSolver.py`\n",
|
||||
"\n",
|
||||
"**Проблема:** необходимо уведомлять интерфейс о событиях поиска пути без жёсткой связи между логикой и выводом.\n",
|
||||
"\n",
|
||||
"**Решение:** реализован интерфейс `Observer` с методом `update()`. Класс `ConsoleView` подписывается на события `MazeSolver`.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class Observer(ABC):\n",
|
||||
" @abstractmethod\n",
|
||||
" def update(self, event, data=None):\n",
|
||||
" pass\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"solver.add_observer(view)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"При нахождении пути вызывается уведомление:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"self._notify('path_found', {\n",
|
||||
" 'stats': stats,\n",
|
||||
" 'strategy': type(self.strategy).__name__\n",
|
||||
"})\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Паттерн позволяет отделить вывод информации от алгоритмов поиска.\n",
|
||||
"\n",
|
||||
"### 4. Command (Команда) — `MazeSolver.py`\n",
|
||||
"\n",
|
||||
"**Проблема:** необходимо реализовать возможность перемещения игрока с поддержкой отмены действий.\n",
|
||||
"\n",
|
||||
"**Решение:** создан интерфейс `Command` с методами `execute()` и `undo()`. Класс `MoveCommand` хранит предыдущее состояние игрока.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class Command(ABC):\n",
|
||||
" @abstractmethod\n",
|
||||
" def execute(self):\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" @abstractmethod\n",
|
||||
" def undo(self):\n",
|
||||
" pass\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"cmd.execute()\n",
|
||||
"cmd.undo()\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Паттерн инкапсулирует действия в отдельные объекты и позволяет реализовать undo/redo.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Диаграмма классов (Mermaid)\n",
|
||||
"\n",
|
||||
"```mermaid\n",
|
||||
"classDiagram\n",
|
||||
" class MazeBuilder {\n",
|
||||
" <<interface>>\n",
|
||||
" +build_from_file(filename) Maze\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class TextFileMazeBuilder {\n",
|
||||
" +build_from_file(filename) Maze\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class Cell {\n",
|
||||
" +x\n",
|
||||
" +y\n",
|
||||
" +is_wall\n",
|
||||
" +is_start\n",
|
||||
" +is_exit\n",
|
||||
" +is_passable()\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class Maze {\n",
|
||||
" +width\n",
|
||||
" +height\n",
|
||||
" +get_cell(x, y)\n",
|
||||
" +get_neighbors(cell)\n",
|
||||
" +render(path, player_pos)\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class PathFindingStrategy {\n",
|
||||
" <<interface>>\n",
|
||||
" +find_path(maze, start, exit)\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class BFSStrategy\n",
|
||||
" class DFSStrategy\n",
|
||||
" class AStarStrategy\n",
|
||||
"\n",
|
||||
" class MazeSolver {\n",
|
||||
" +set_strategy(strategy)\n",
|
||||
" +solve()\n",
|
||||
" +add_observer(observer)\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class SearchStats\n",
|
||||
"\n",
|
||||
" class Observer {\n",
|
||||
" <<interface>>\n",
|
||||
" +update(event, data)\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class ConsoleView\n",
|
||||
"\n",
|
||||
" class Command {\n",
|
||||
" <<interface>>\n",
|
||||
" +execute()\n",
|
||||
" +undo()\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" class MoveCommand\n",
|
||||
" class Player\n",
|
||||
"\n",
|
||||
" MazeBuilder <|.. TextFileMazeBuilder\n",
|
||||
" Maze o-- Cell\n",
|
||||
"\n",
|
||||
" PathFindingStrategy <|.. BFSStrategy\n",
|
||||
" PathFindingStrategy <|.. DFSStrategy\n",
|
||||
" PathFindingStrategy <|.. AStarStrategy\n",
|
||||
"\n",
|
||||
" MazeSolver --> Maze\n",
|
||||
" MazeSolver --> PathFindingStrategy\n",
|
||||
" MazeSolver --> SearchStats\n",
|
||||
"\n",
|
||||
" Observer <|.. ConsoleView\n",
|
||||
" MazeSolver --> Observer\n",
|
||||
"\n",
|
||||
" Command <|.. MoveCommand\n",
|
||||
" MoveCommand --> Player\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Ключевые фрагменты реализации\n",
|
||||
"\n",
|
||||
"### Реализация BFS\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class BFSStrategy(PathFindingStrategy):\n",
|
||||
" def find_path(self, maze, start, exit_cell):\n",
|
||||
" queue = deque([start])\n",
|
||||
" came_from = {(start.x, start.y): None}\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Алгоритм BFS выполняет поиск в ширину и гарантирует нахождение кратчайшего пути.\n",
|
||||
"\n",
|
||||
"### Реализация DFS\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class DFSStrategy(PathFindingStrategy):\n",
|
||||
" def find_path(self, maze, start, exit_cell):\n",
|
||||
" stack = [start]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"DFS использует стек и выполняет поиск в глубину.\n",
|
||||
"\n",
|
||||
"### Реализация A*\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class AStarStrategy(PathFindingStrategy):\n",
|
||||
"\n",
|
||||
" def _heuristic(self, cell, goal):\n",
|
||||
" return abs(cell.x - goal.x) + abs(cell.y - goal.y)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"A* использует манхэттенскую эвристику для направления поиска к цели.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Экспериментальная часть\n",
|
||||
"\n",
|
||||
"### Параметры эксперимента\n",
|
||||
"\n",
|
||||
"| Параметр | Значение |\n",
|
||||
"| ---------- | ------------------------------------ |\n",
|
||||
"| Повторений | 7 |\n",
|
||||
"| Алгоритмы | BFS, DFS, A* |\n",
|
||||
"| Метрики | время, посещённые клетки, длина пути |\n",
|
||||
"\n",
|
||||
"### Тестовые лабиринты\n",
|
||||
"\n",
|
||||
"| Название | Размер |\n",
|
||||
"| ------------- | ------- |\n",
|
||||
"| small_10x10 | 10×10 |\n",
|
||||
"| medium_50x50 | 50×50 |\n",
|
||||
"| large_100x100 | 100×100 |\n",
|
||||
"| open_50x50 | 50×50 |\n",
|
||||
"| no_exit_20x20 | 20×20 |\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Результаты\n",
|
||||
"\n",
|
||||
"### Таблица результатов\n",
|
||||
"\n",
|
||||
"| Лабиринт | Алгоритм | Время (мс) | Посещено клеток | Длина пути |\n",
|
||||
"| ------------- | -------- | ---------- | --------------- | ---------- |\n",
|
||||
"| small_10x10 | BFS | 0.094 | 54 | 15 |\n",
|
||||
"| small_10x10 | DFS | 0.059 | 33 | 33 |\n",
|
||||
"| small_10x10 | A* | 0.078 | 36 | 15 |\n",
|
||||
"| medium_50x50 | BFS | 2.446 | 1639 | 95 |\n",
|
||||
"| medium_50x50 | DFS | 1.480 | 1063 | 185 |\n",
|
||||
"| medium_50x50 | A* | 1.528 | 588 | 95 |\n",
|
||||
"| large_100x100 | BFS | 9.891 | 6564 | — |\n",
|
||||
"| large_100x100 | DFS | 9.057 | 6564 | — |\n",
|
||||
"| large_100x100 | A* | 17.578 | 6564 | — |\n",
|
||||
"| open_50x50 | BFS | 3.296 | 2304 | 95 |\n",
|
||||
"| open_50x50 | DFS | 1.830 | 1223 | 1129 |\n",
|
||||
"| open_50x50 | A* | 5.566 | 2304 | 95 |\n",
|
||||
"| no_exit_20x20 | BFS | 0.368 | 260 | — |\n",
|
||||
"| no_exit_20x20 | DFS | 0.343 | 260 | — |\n",
|
||||
"| no_exit_20x20 | A* | 0.607 | 260 | — |\n",
|
||||
"\n",
|
||||
"### Визуализация\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Анализ результатов\n",
|
||||
"\n",
|
||||
"### BFS\n",
|
||||
"\n",
|
||||
"Алгоритм BFS во всех случаях находит кратчайший путь. На лабиринте medium_50x50 длина найденного пути составила 95 шагов. Недостатком алгоритма является большое количество посещённых клеток.\n",
|
||||
"\n",
|
||||
"### DFS\n",
|
||||
"\n",
|
||||
"DFS выполняет поиск быстрее, однако найденный путь значительно длиннее. На open_50x50 длина пути составила 1129 шагов против 95 у BFS.\n",
|
||||
"\n",
|
||||
"### A*\n",
|
||||
"\n",
|
||||
"Алгоритм A* использует эвристику и уменьшает количество посещённых клеток. На medium_50x50 было посещено 588 клеток против 1639 у BFS.\n",
|
||||
"\n",
|
||||
"На открытом лабиринте преимущества эвристики снижаются, из-за чего время работы увеличивается.\n",
|
||||
"\n",
|
||||
"### Лабиринты без пути\n",
|
||||
"\n",
|
||||
"На large_100x100 и no_exit_20x20 путь найден не был. Все алгоритмы корректно завершили работу после обхода доступных клеток.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Выводы\n",
|
||||
"\n",
|
||||
"В ходе работы была реализована объектно-ориентированная система поиска пути в лабиринте с применением паттернов проектирования GoF.\n",
|
||||
"\n",
|
||||
"Паттерн Strategy обеспечил возможность динамической смены алгоритма поиска. Builder отделил процесс создания лабиринта от логики приложения. Observer позволил реализовать систему уведомлений без жёстких зависимостей. Command обеспечил поддержку отмены действий.\n",
|
||||
"\n",
|
||||
"Экспериментальные результаты показали:\n",
|
||||
"\n",
|
||||
"* BFS гарантирует кратчайший путь;\n",
|
||||
"* DFS работает быстрее, но может находить неоптимальные маршруты;\n",
|
||||
"* A* наиболее эффективен на сложных лабиринтах благодаря эвристике.\n",
|
||||
"\n",
|
||||
"Архитектура программы получилась модульной и расширяемой. Добавление новых алгоритмов или способов загрузки лабиринтов возможно без изменения существующего кода.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a9cbb6c6",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
100
zverevem/lab2/docs/data/FindingStrategy.py
Normal file
100
zverevem/lab2/docs/data/FindingStrategy.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from collections import deque
|
||||
import heapq
|
||||
|
||||
|
||||
class PathFindingStrategy(ABC):
|
||||
@abstractmethod
|
||||
def find_path(self, maze, start, exit_cell):
|
||||
pass
|
||||
|
||||
|
||||
def _reconstruct_path(came_from, start, exit_cell):
|
||||
path = []
|
||||
current = exit_cell
|
||||
while current is not None:
|
||||
path.append(current)
|
||||
current = came_from.get((current.x, current.y))
|
||||
path.reverse()
|
||||
if path and path[0].x == start.x and path[0].y == start.y:
|
||||
return path
|
||||
return []
|
||||
|
||||
class BFSStrategy(PathFindingStrategy):
|
||||
def find_path(self, maze, start, exit_cell):
|
||||
queue = deque([start])
|
||||
came_from = {(start.x, start.y): None}
|
||||
self.visited_count = 0
|
||||
|
||||
while queue:
|
||||
current = queue.popleft()
|
||||
self.visited_count += 1
|
||||
|
||||
if current.x == exit_cell.x and current.y == exit_cell.y:
|
||||
return _reconstruct_path(came_from, start, exit_cell)
|
||||
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
key = (neighbor.x, neighbor.y)
|
||||
if key not in came_from:
|
||||
came_from[key] = current
|
||||
queue.append(neighbor)
|
||||
|
||||
self.visited_count = len(came_from)
|
||||
return [] # путь не найден
|
||||
|
||||
class DFSStrategy(PathFindingStrategy):
|
||||
|
||||
def find_path(self, maze, start, exit_cell):
|
||||
stack = [start]
|
||||
came_from = {(start.x, start.y): None}
|
||||
self.visited_count = 0
|
||||
|
||||
while stack:
|
||||
current = stack.pop()
|
||||
self.visited_count += 1
|
||||
|
||||
if current.x == exit_cell.x and current.y == exit_cell.y:
|
||||
return _reconstruct_path(came_from, start, exit_cell)
|
||||
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
key = (neighbor.x, neighbor.y)
|
||||
if key not in came_from:
|
||||
came_from[key] = current
|
||||
stack.append(neighbor)
|
||||
|
||||
self.visited_count = len(came_from)
|
||||
return []
|
||||
|
||||
class AStarStrategy(PathFindingStrategy):
|
||||
|
||||
def _heuristic(self, cell, goal):
|
||||
return abs(cell.x - goal.x) + abs(cell.y - goal.y)
|
||||
|
||||
def find_path(self, maze, start, exit_cell):
|
||||
# (f_score, счётчик для разрыва связей, клетка)
|
||||
counter = 0
|
||||
open_set = [(0, counter, start)]
|
||||
came_from = {(start.x, start.y): None}
|
||||
g_score = {(start.x, start.y): 0}
|
||||
self.visited_count = 0
|
||||
|
||||
while open_set:
|
||||
_, _, current = heapq.heappop(open_set)
|
||||
self.visited_count += 1
|
||||
|
||||
if current.x == exit_cell.x and current.y == exit_cell.y:
|
||||
return _reconstruct_path(came_from, start, exit_cell)
|
||||
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
key = (neighbor.x, neighbor.y)
|
||||
tentative_g = g_score[(current.x, current.y)] + 1
|
||||
|
||||
if key not in g_score or tentative_g < g_score[key]:
|
||||
g_score[key] = tentative_g
|
||||
f = tentative_g + self._heuristic(neighbor, exit_cell)
|
||||
counter += 1
|
||||
heapq.heappush(open_set, (f, counter, neighbor))
|
||||
came_from[key] = current
|
||||
|
||||
self.visited_count = len(came_from)
|
||||
return []
|
||||
44
zverevem/lab2/docs/data/MazeBuilder.py
Normal file
44
zverevem/lab2/docs/data/MazeBuilder.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from maze_model import Cell, Maze
|
||||
|
||||
|
||||
class MazeBuilder(ABC):
|
||||
@abstractmethod
|
||||
def build_from_file(self, filename) -> Maze:
|
||||
pass
|
||||
|
||||
|
||||
class TextFileMazeBuilder(MazeBuilder):
|
||||
def build_from_file(self, filename) -> Maze:
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
width = max(len(line) for line in lines) if lines else 0
|
||||
height = len(lines)
|
||||
|
||||
cells = []
|
||||
start = None
|
||||
exit_cell = None
|
||||
|
||||
for y, line in enumerate(lines):
|
||||
row = []
|
||||
line = line.ljust(width)
|
||||
for x, char in enumerate(line):
|
||||
is_wall = (char == '#')
|
||||
is_start = (char == 'S')
|
||||
is_exit = (char == 'E')
|
||||
cell = Cell(x, y, is_wall=is_wall,
|
||||
is_start=is_start, is_exit=is_exit)
|
||||
if is_start:
|
||||
start = cell
|
||||
if is_exit:
|
||||
exit_cell = cell
|
||||
row.append(cell)
|
||||
cells.append(row)
|
||||
|
||||
if start is None:
|
||||
raise ValueError("В файле лабиринта не найден старт (S)")
|
||||
if exit_cell is None:
|
||||
raise ValueError("В файле лабиринта не найден выход (E)")
|
||||
|
||||
return Maze(width, height, cells, start, exit_cell)
|
||||
62
zverevem/lab2/docs/data/MazeModel.py
Normal file
62
zverevem/lab2/docs/data/MazeModel.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
class Cell:
|
||||
def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.is_wall = is_wall
|
||||
self.is_start = is_start
|
||||
self.is_exit = is_exit
|
||||
|
||||
def is_passable(self):
|
||||
return not self.is_wall
|
||||
|
||||
def __repr__(self):
|
||||
if self.is_wall:
|
||||
return '#'
|
||||
if self.is_start:
|
||||
return 'S'
|
||||
if self.is_exit:
|
||||
return 'E'
|
||||
return ' '
|
||||
|
||||
|
||||
class Maze:
|
||||
def __init__(self, width, height, cells, start, exit_cell):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self._cells = cells
|
||||
self.start = start
|
||||
self.exit = exit_cell
|
||||
|
||||
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):
|
||||
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
|
||||
neighbors = []
|
||||
for dx, dy in directions:
|
||||
neighbor = self.get_cell(cell.x + dx, cell.y + dy)
|
||||
if neighbor is not None and neighbor.is_passable():
|
||||
neighbors.append(neighbor)
|
||||
return neighbors
|
||||
|
||||
def render(self, path=None, player_pos=None):
|
||||
path_set = set((c.x, c.y) for c in path) if path else set()
|
||||
|
||||
for row in self._cells:
|
||||
line = ''
|
||||
for cell in row:
|
||||
if player_pos and cell.x == player_pos.x and cell.y == player_pos.y:
|
||||
line += 'P'
|
||||
elif cell.is_wall:
|
||||
line += '#'
|
||||
elif cell.is_start:
|
||||
line += 'S'
|
||||
elif cell.is_exit:
|
||||
line += 'E'
|
||||
elif (cell.x, cell.y) in path_set:
|
||||
line += '.'
|
||||
else:
|
||||
line += ' '
|
||||
print(line)
|
||||
121
zverevem/lab2/docs/data/MazeSolver.py
Normal file
121
zverevem/lab2/docs/data/MazeSolver.py
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
import time
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class SearchStats:
|
||||
def __init__(self, time_ms, visited_cells, path_length, path):
|
||||
self.time_ms = time_ms
|
||||
self.visited_cells = visited_cells
|
||||
self.path_length = path_length
|
||||
self.path = path
|
||||
|
||||
def __repr__(self):
|
||||
return (f"SearchStats(time={self.time_ms:.3f}ms, "
|
||||
f"visited={self.visited_cells}, "
|
||||
f"path_len={self.path_length})")
|
||||
|
||||
class Observer(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def update(self, event, data=None):
|
||||
pass
|
||||
|
||||
|
||||
class ConsoleView(Observer):
|
||||
|
||||
def update(self, event, data=None):
|
||||
if event == 'maze_loaded':
|
||||
print(f"\n[ConsoleView] Лабиринт загружен: "
|
||||
f"{data['width']}×{data['height']}")
|
||||
|
||||
elif event == 'path_found':
|
||||
stats = data['stats']
|
||||
strategy_name = data['strategy']
|
||||
if stats.path_length > 0:
|
||||
print(f"\n[ConsoleView] [{strategy_name}] Путь найден! "
|
||||
f"Длина: {stats.path_length}, "
|
||||
f"Посещено клеток: {stats.visited_cells}, "
|
||||
f"Время: {stats.time_ms:.3f} мс")
|
||||
else:
|
||||
print(f"\n[ConsoleView] [{strategy_name}] Путь не найден. "
|
||||
f"Посещено клеток: {stats.visited_cells}")
|
||||
|
||||
elif event == 'move':
|
||||
print(f"[ConsoleView] Игрок переместился в "
|
||||
f"({data['x']}, {data['y']})")
|
||||
|
||||
class MazeSolver:
|
||||
def __init__(self, maze, strategy=None):
|
||||
self.maze = maze
|
||||
self.strategy = strategy
|
||||
self._observers = []
|
||||
|
||||
def set_strategy(self, strategy):
|
||||
self.strategy = strategy
|
||||
|
||||
def add_observer(self, observer):
|
||||
self._observers.append(observer)
|
||||
|
||||
def _notify(self, event, data=None):
|
||||
for obs in self._observers:
|
||||
obs.update(event, data)
|
||||
|
||||
def solve(self):
|
||||
if self.strategy is None:
|
||||
raise RuntimeError("Стратегия не задана. Используйте set_strategy().")
|
||||
|
||||
start = time.perf_counter()
|
||||
path = self.strategy.find_path(self.maze, self.maze.start, self.maze.exit)
|
||||
end = time.perf_counter()
|
||||
|
||||
stats = SearchStats(
|
||||
time_ms=(end - start) * 1000,
|
||||
visited_cells=getattr(self.strategy, 'visited_count', 0),
|
||||
path_length=len(path),
|
||||
path=path
|
||||
)
|
||||
|
||||
self._notify('path_found', {
|
||||
'stats': stats,
|
||||
'strategy': type(self.strategy).__name__
|
||||
})
|
||||
|
||||
return stats
|
||||
|
||||
class Command(ABC):
|
||||
@abstractmethod
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def undo(self):
|
||||
pass
|
||||
|
||||
|
||||
class Player:
|
||||
def __init__(self, start_cell):
|
||||
self.current_cell = start_cell
|
||||
|
||||
def move_to(self, cell):
|
||||
self.current_cell = cell
|
||||
|
||||
|
||||
class MoveCommand(Command):
|
||||
def __init__(self, player, target_cell, observers=None):
|
||||
self.player = player
|
||||
self.target_cell = target_cell
|
||||
self.previous_cell = None
|
||||
self._observers = observers or []
|
||||
|
||||
def execute(self):
|
||||
self.previous_cell = self.player.current_cell
|
||||
self.player.move_to(self.target_cell)
|
||||
for obs in self._observers:
|
||||
obs.update('move', {'x': self.target_cell.x,
|
||||
'y': self.target_cell.y})
|
||||
|
||||
def undo(self):
|
||||
if self.previous_cell is not None:
|
||||
self.player.move_to(self.previous_cell)
|
||||
for obs in self._observers:
|
||||
obs.update('move', {'x': self.previous_cell.x,
|
||||
'y': self.previous_cell.y})
|
||||
103
zverevem/lab2/docs/data/Results.py
Normal file
103
zverevem/lab2/docs/data/Results.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import csv
|
||||
import os
|
||||
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
HAS_MPL = True
|
||||
except ImportError:
|
||||
HAS_MPL = False
|
||||
print(" matplotlib не установлен: pip install matplotlib\n")
|
||||
|
||||
CSV_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'results.csv')
|
||||
OUT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
COLORS = {'BFS': '#4E9AF1', 'DFS': '#F4845F', 'A*': '#6BCB77'}
|
||||
STRATEGIES = ['BFS', 'DFS', 'A*']
|
||||
METRICS = [
|
||||
('время_мс', 'Среднее время (мс)'),
|
||||
('посещено_клеток', 'Посещено клеток'),
|
||||
('длина_пути', 'Длина пути (шагов)'),
|
||||
]
|
||||
|
||||
|
||||
def load_csv(path):
|
||||
data = {}
|
||||
with open(path, newline='', encoding='utf-8') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
key = (row['лабиринт'], row['стратегия'])
|
||||
data[key] = {
|
||||
'время_мс': float(row['время_мс']),
|
||||
'посещено_клеток': float(row['посещено_клеток']),
|
||||
'длина_пути': float(row['длина_пути']),
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
def get_mazes(data):
|
||||
seen = []
|
||||
for (maze, _) in data:
|
||||
if maze not in seen:
|
||||
seen.append(maze)
|
||||
return seen
|
||||
|
||||
|
||||
def plot_by_metric(data):
|
||||
mazes = get_mazes(data)
|
||||
x = range(len(mazes))
|
||||
w = 0.25
|
||||
|
||||
for metric_key, metric_label in METRICS:
|
||||
fig, ax = plt.subplots(figsize=(12, 5))
|
||||
fig.suptitle(f'{metric_label} по лабиринтам', fontweight='bold')
|
||||
|
||||
for i, strat in enumerate(STRATEGIES):
|
||||
vals = [data.get((m, strat), {}).get(metric_key, 0) for m in mazes]
|
||||
offset = [xi + (i - 1) * w for xi in x]
|
||||
bars = ax.bar(offset, vals, width=w,
|
||||
label=strat, color=COLORS[strat], edgecolor='white')
|
||||
for bar, val in zip(bars, vals):
|
||||
if val > 0:
|
||||
ax.text(bar.get_x() + bar.get_width() / 2,
|
||||
bar.get_height() + max(vals) * 0.01,
|
||||
f'{val:.1f}', ha='center', va='bottom', fontsize=7)
|
||||
|
||||
ax.set_xticks(list(x))
|
||||
ax.set_xticklabels(mazes, rotation=15, ha='right', fontsize=9)
|
||||
ax.set_ylabel(metric_label)
|
||||
ax.legend()
|
||||
ax.grid(axis='y', alpha=0.3)
|
||||
|
||||
safe = metric_key.replace('_', '-')
|
||||
out = os.path.join(OUT_DIR, f'chart_{safe}.png')
|
||||
plt.tight_layout()
|
||||
plt.savefig(out, dpi=150, bbox_inches='tight')
|
||||
print(f" График сохранён: {out}")
|
||||
plt.show()
|
||||
|
||||
|
||||
def print_table(data):
|
||||
print(f"\n{'Лабиринт':<20} {'Алгоритм':<6} "
|
||||
f"{'Время мс':>10} {'Посещено':>10} {'Путь':>6}")
|
||||
print('-' * 56)
|
||||
for (maze, strat), vals in sorted(data.items()):
|
||||
print(f"{maze:<20} {strat:<6} "
|
||||
f"{vals['время_мс']:>10.3f} "
|
||||
f"{vals['посещено_клеток']:>10.0f} "
|
||||
f"{vals['длина_пути']:>6.0f}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not os.path.exists(CSV_PATH):
|
||||
print(f" Файл не найден: {CSV_PATH}")
|
||||
print(" Сначала запустите: python benchmark.py")
|
||||
exit(1)
|
||||
|
||||
data = load_csv(CSV_PATH)
|
||||
print_table(data)
|
||||
|
||||
if HAS_MPL:
|
||||
plot_by_metric(data)
|
||||
else:
|
||||
print("\n Установите matplotlib: pip install matplotlib")
|
||||
153
zverevem/lab2/docs/data/Standard.py
Normal file
153
zverevem/lab2/docs/data/Standard.py
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
import time
|
||||
import csv
|
||||
import os
|
||||
import random
|
||||
|
||||
from maze_builder import TextFileMazeBuilder
|
||||
from maze_solver import MazeSolver
|
||||
from maze_strategies import BFSStrategy, DFSStrategy, AStarStrategy
|
||||
|
||||
REPEATS = 7
|
||||
OUTPUT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
CSV_PATH = os.path.join(OUTPUT_DIR, 'results.csv')
|
||||
|
||||
STRATEGIES = {
|
||||
'BFS': BFSStrategy,
|
||||
'DFS': DFSStrategy,
|
||||
'A*': AStarStrategy,
|
||||
}
|
||||
|
||||
MAZES = [
|
||||
('small_10x10', 'maze_small.txt'),
|
||||
('medium_50x50', 'maze_medium.txt'),
|
||||
('large_100x100', 'maze_large.txt'),
|
||||
('open_50x50', 'maze_open.txt'),
|
||||
('no_exit_20x20', 'maze_no_exit.txt'),
|
||||
]
|
||||
|
||||
def _make_grid(width, height, density=0.0, has_exit=True, seed=42):
|
||||
|
||||
rng = random.Random(seed)
|
||||
grid = []
|
||||
for y in range(height):
|
||||
row = []
|
||||
for x in range(width):
|
||||
on_border = (x == 0 or x == width - 1 or y == 0 or y == height - 1)
|
||||
row.append('#' if on_border else ' ')
|
||||
grid.append(row)
|
||||
|
||||
for y in range(1, height - 1):
|
||||
for x in range(1, width - 1):
|
||||
if rng.random() < density:
|
||||
grid[y][x] = '#'
|
||||
|
||||
grid[1][1] = 'S'
|
||||
if has_exit:
|
||||
grid[height - 2][width - 2] = 'E'
|
||||
|
||||
return '\n'.join(''.join(row) for row in grid)
|
||||
|
||||
|
||||
def generate_maze_files():
|
||||
mazes_data = {
|
||||
'maze_small.txt': _make_grid(10, 10, density=0.15),
|
||||
'maze_medium.txt': _make_grid(50, 50, density=0.28),
|
||||
'maze_large.txt': _make_grid(100, 100, density=0.30),
|
||||
'maze_open.txt': _make_grid(50, 50, density=0.0),
|
||||
'maze_no_exit.txt': _make_grid(20, 20, density=0.20, has_exit=False),
|
||||
}
|
||||
no_exit = list(mazes_data['maze_no_exit.txt'].splitlines())
|
||||
no_exit[18] = no_exit[18][:18] + 'E' + no_exit[18][19:]
|
||||
no_exit[17] = no_exit[17][:18] + '#' + no_exit[17][19:]
|
||||
no_exit[18] = no_exit[18][:17] + '#' + no_exit[18][18:]
|
||||
mazes_data['maze_no_exit.txt'] = '\n'.join(no_exit)
|
||||
|
||||
maze_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
for fname, content in mazes_data.items():
|
||||
path = os.path.join(maze_dir, fname)
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
print("Файлы лабиринтов созданы")
|
||||
def avg(lst):
|
||||
return sum(lst) / len(lst) if lst else 0
|
||||
|
||||
|
||||
def run_benchmark():
|
||||
builder = TextFileMazeBuilder()
|
||||
maze_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
all_results = [
|
||||
['лабиринт', 'стратегия', 'время_мс', 'посещено_клеток', 'длина_пути']
|
||||
+ [f'замер_{i+1}' for i in range(REPEATS)]
|
||||
]
|
||||
|
||||
print(f"\nЗапуск бенчмарков (повторений: {REPEATS})\n")
|
||||
print(f" {'Лабиринт':<18} {'Алгоритм':<6} {'Время мс':>10} "
|
||||
f"{'Посещено':>10} {'Путь':>6}")
|
||||
print(' ' + '-' * 56)
|
||||
|
||||
for maze_label, maze_file in MAZES:
|
||||
maze_path = os.path.join(maze_dir, maze_file)
|
||||
try:
|
||||
maze = builder.build_from_file(maze_path)
|
||||
except Exception as e:
|
||||
print(f" {maze_file}: {e}")
|
||||
continue
|
||||
|
||||
solver = MazeSolver(maze)
|
||||
|
||||
for strat_name, StratClass in STRATEGIES.items():
|
||||
times_ms, visited_list, path_len = [], [], 0
|
||||
|
||||
for _ in range(REPEATS):
|
||||
strat = StratClass()
|
||||
solver.set_strategy(strat)
|
||||
stats = solver.solve()
|
||||
times_ms.append(stats.time_ms)
|
||||
visited_list.append(stats.visited_cells)
|
||||
path_len = stats.path_length
|
||||
|
||||
mean_t = avg(times_ms)
|
||||
mean_v = avg(visited_list)
|
||||
|
||||
print(f" {maze_label:<18} {strat_name:<6} "
|
||||
f"{mean_t:>10.3f} {mean_v:>10.0f} {path_len:>6}")
|
||||
|
||||
all_results.append([
|
||||
maze_label, strat_name,
|
||||
f"{mean_t:.4f}", f"{mean_v:.0f}", str(path_len)
|
||||
] + [f"{t:.4f}" for t in times_ms])
|
||||
|
||||
with open(CSV_PATH, 'w', newline='', encoding='utf-8') as f:
|
||||
csv.writer(f).writerows(all_results)
|
||||
|
||||
print(f"\n Результаты сохранены: {CSV_PATH}")
|
||||
|
||||
def smoke_test():
|
||||
print(" Smoke Test\n")
|
||||
|
||||
maze_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
test_path = os.path.join(maze_dir, '_test_maze.txt')
|
||||
|
||||
with open(test_path, 'w', encoding='utf-8') as f:
|
||||
f.write("#######\n#S #\n# #\n# E#\n#######")
|
||||
|
||||
builder = TextFileMazeBuilder()
|
||||
maze = builder.build_from_file(test_path)
|
||||
|
||||
for name, StratClass in STRATEGIES.items():
|
||||
strat = StratClass()
|
||||
path = strat.find_path(maze, maze.start, maze.exit)
|
||||
assert len(path) > 0, f"{name}: путь не найден!"
|
||||
assert path[0].is_start
|
||||
assert path[-1].is_exit
|
||||
print(f" {name}: путь длиной {len(path)} — OK")
|
||||
|
||||
os.remove(test_path)
|
||||
print("\nВсе тесты пройдены!\n")
|
||||
|
||||
if __name__ == '__main__':
|
||||
smoke_test()
|
||||
generate_maze_files()
|
||||
run_benchmark()
|
||||
BIN
zverevem/lab2/docs/data/chart_время-мс.png
Normal file
BIN
zverevem/lab2/docs/data/chart_время-мс.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
zverevem/lab2/docs/data/chart_длина-пути.png
Normal file
BIN
zverevem/lab2/docs/data/chart_длина-пути.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
BIN
zverevem/lab2/docs/data/chart_посещено-клеток.png
Normal file
BIN
zverevem/lab2/docs/data/chart_посещено-клеток.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
100
zverevem/lab2/docs/data/maze_large.txt
Normal file
100
zverevem/lab2/docs/data/maze_large.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
####################################################################################################
|
||||
#S### # ## ## # # # ## ####### ## # # ## ## ## # # ### # #
|
||||
# # # # # # # # # # # # # # # # # ## ### # ## ## ## # ## ## #
|
||||
# # # # # # ## # # ## ## # # # # # ### # # # ### # # # # ## ##
|
||||
# ## ## ### # # # # # ### # # # ## # # # ## #
|
||||
# ## # ## #### # # # # # # ## ## #### ## # # # #
|
||||
### # # # # # # # # ### #### # # # ## # # # # # # # # #
|
||||
# # ## ## # ## ##### ## ###### # # ## # ## # # ## #### #
|
||||
# ## ## ## ## ## ## # # # # # # ## # # #
|
||||
## # # ## # # # # # # ## # # # # ## # # ###
|
||||
## # # # # # # # # ## ## # # # # ### ## # #
|
||||
## # # # # # ## # ## # ## # # #### ## # ## # # # ## ## # #
|
||||
# # # # # # ## # # ## # ## # # # # ### # # # # # # ### # #
|
||||
## # ## ## # # # # ### # ## ## # # ### ## # #
|
||||
## ## # # ## ### # # # # # # # # ## # # # # # #
|
||||
# ## # # ## # ### ## # # # ## # # # ## # # # #### # # # #
|
||||
# # # # # # # ## ## ## # # # # ### # # #
|
||||
# # # #### # # # # ## # ### # # #### # # # # # #
|
||||
# # # # # # ## # # # # # # # ## # ### # ##
|
||||
## # ### ## ## # # # # # # # # # # # # # # ### ## # #
|
||||
## ## ### # ## # # ### ## # # # # ## # # # # # # # #
|
||||
##### # # # #### # ## # # # # # # ### # ## # # # # #
|
||||
## # # ### # # # # ## # # # # # # #### # # # ### #
|
||||
# # ## ## # ### # # ## # ## ## ### # # # # # # # ###
|
||||
## ## # # # # # # # # # # ## ## # # ##
|
||||
# # # ### # # # # # ## # # # ### # # # # # ## ## ## # ## #
|
||||
# # # # # ##### # ## # # # # # # # # # ## ## # # # ##
|
||||
# # # # # # # ## # ## # # # # # # ## ### ## # # ##### #
|
||||
# # # # # ## # # ## # # ## # ## # # # # ## # # # ## #
|
||||
## ## # # # # # # ### # ## ### ## # ### # ## # # # ## # # ## # #
|
||||
# # # # #### # ## #### # # # # # # # # # # ### # ## # #
|
||||
# # ## # # # # # # # # # # ###### # ## # ## # # # #### #### # #
|
||||
# # ##### # # # ### # # # # # # # # # ## ### # #
|
||||
# # # # # # # ## # # ## # # ## # # # # # # # ## # # ###
|
||||
## # ## # # # # #### # # ## # ## ## # ## # # ## # #
|
||||
## # # # ## # # # # # # # # # # # # ###### # ## # # ## ### # #### # #
|
||||
## # # # # # # # # # # # ## # # # # # # ## # # # ## # ##
|
||||
## # # # ### # # # # # # # # # # # # # # ###
|
||||
# # ### # # # # # ## ## ## # # ## # ### ### # # #
|
||||
# # # # # ## # # ## ## # # # # # # ## ## ## #
|
||||
# ### # # ### # # # # ### # # # # # # # ## # ##
|
||||
# # ### ## ## ## ## # # ### # ## # # # # ## ## # # # # # #
|
||||
# ## # # # ## # # # # ## # ### #### # ## ###### ### #
|
||||
# # # # ### ### # # ## # # # ### ## # ## # # ## ##
|
||||
# # # ### #### # # # # ### # # # ## ### ## # ## #### # #
|
||||
# ### ## # # # # # # # # ### # # # # ## # ### ### ## #
|
||||
# # # # # # # # # # ## ### ## ### # ## # # # ## # #### # ## # #
|
||||
# # # # # # # # # # # ### # # # # # ## # # # # # # #
|
||||
# ## # # # # ## # # # # ## ## ## # # ## # ## # # ## # ## #
|
||||
# # # ## # # # # ### # # # # # # # ## # # # ## # ### ## # # #
|
||||
## # ## # ## ### ## # # # # ## # # # # # # #
|
||||
## ## # # ### # # # # # ## # # # # # ## # ## # # # #
|
||||
# # # ## # ### # ## # # ## # # # # # # # #
|
||||
# # # # # ## #### # # ### # ## # # ## # # ## #
|
||||
# # # # ## # ### # ## ## # # # # ### # # #
|
||||
# # # # # # # # # ## # ## ## ### ### # # ## # # # ## #
|
||||
# # # # ## # # ### ##### # # # # ## # # # # # ## # # #
|
||||
## # # # ## # # ## # ## ## # ## # ### # # # # #
|
||||
# ## ## # ### # ## ### # # ## # # # # # # # # # # # ###
|
||||
# ## # # # # # # # # # # # ## # # # # # # # # # # # ## #
|
||||
# # # # ## # # # # # ## # # ## # # ## # # # ### ### # # # ##
|
||||
# # # # ## # ## # # # # # # # ## # # ## # ### ##
|
||||
### # # ## ### # ## # # #### # # # # ##### # ## #### #
|
||||
# # # # # # # #### ## # ### ### # ## # ## # # ## # # # # # # ###
|
||||
# #### # ## # # # # # # ## # # # # # # # #
|
||||
# ## # # # # # # ## # ## ## # ### #### # # # # ## #
|
||||
# # ## # ## # # # # ## ## # ## # ## #
|
||||
# # # # # # # ## # # # # # # ### ## ### # ## # # ###
|
||||
### # # # ##### # ## ## # # # ## # ## ## # # # # # #
|
||||
# # # # # # ## ##### # ### # ## # # # ## # ### #### # #
|
||||
# # ### # ## # # ### ## ## # ## # ### # ## ### # ###
|
||||
# ## ## ## # # # # # # ### # ## # # ## # # # #
|
||||
## ## ## # ## # ## # # # ## # ## # ## # ## # # # #
|
||||
# # # # # # # # ## # # # ####### # ## ## ## ##
|
||||
# # # # # # # # # ## # # # # # ## # # ### # ##
|
||||
# # ## #### # # # # # ## ### # ### # ### # ### ## # # #
|
||||
## # # ## # # # # # # # # ## # ##### # ## ##### #### ###
|
||||
# # # # ## # ## # # ## # # ### ## ## # ######
|
||||
# # ## # # # # # # # # # ## ## # ## ## ## # ## # #
|
||||
### #### # # ## # # # # # ## # # ## # # # #### # # ## # #
|
||||
# ## ## # # ## # ## ## # # ## # # # # # #### # #
|
||||
# ## # # # ## ### ## #### # # # # # # ## ### # # # ##
|
||||
## # # # # # # # ## # ## ### # ## # ## # # # #
|
||||
# # # # # # # # # ### # # # ## # # ## ## # #### #
|
||||
# # ## # # # # # # # # # # ## ### # # # ##
|
||||
## ## # ## # # # ## # # # # # #### # # ## ### #
|
||||
## # ## ## # # # # ### # # ## # # # ## ## # # # # ## #
|
||||
# ## # ## # # #### # # # # # # ## # # # # # # ### #
|
||||
# ## # #### # # ## # # # # ### ## # ## ### # ## ## ##
|
||||
# # # # # # ## # # # ## # #### # ##### # # # # # # # #
|
||||
# # ## ## ### # ### ### # # #### # # # # ## # ## # # # # #### # #
|
||||
# # # # ## # # ## # # ## # # ## # ## # # # ## ## #
|
||||
# # ## # # # ## ## # ### ## # ## # # # # # # # ## # # #
|
||||
# # ## # ## ## ## # # ## # # # # # ## # # # # ### # #
|
||||
# # # ## # # # # # # # # # # # # ## # # # ## # # #
|
||||
## # ## # # # # ## # # ## # # # # # # ## # # # # # # # #
|
||||
# # ## # ## # ### # # ### # ## # # # ## # ### # ## # #
|
||||
# # # ## # # ## # # # ## # # #### ## # # # ### # ##
|
||||
# #### ## ### ### # # ### # # ## # # # ### # ####### # ## # #E#
|
||||
####################################################################################################
|
||||
50
zverevem/lab2/docs/data/maze_medium.txt
Normal file
50
zverevem/lab2/docs/data/maze_medium.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
##################################################
|
||||
#S### # ## ## # # # ## ## #####
|
||||
# ## # # ## ## ## # # ### # #
|
||||
# # # # # # # # # # # # # # #
|
||||
# # # ## ### # ## ## ## # ## ##
|
||||
## # # # # # # # # ## ## # #
|
||||
# # # # ### # # ### # # # ##
|
||||
# ## # ## ## ### # # # # #
|
||||
## ### # # # ## # # # #
|
||||
# # # # ## #### # # # # # #
|
||||
## ## ## ## # ## # # #
|
||||
# # ## # # # # # # # # ### ##
|
||||
#### # # # ## # # # # # #
|
||||
# # # # # ## ## # ## ######
|
||||
# ## ##### # # ## # ## # # #
|
||||
# ## #### # ## # ## ##
|
||||
## ## # # # # #
|
||||
## ## # # # # # # # ##
|
||||
# # # # ## # #
|
||||
## # ## # # ### # # # # # # #
|
||||
# # ## # # # # #
|
||||
# ### ## # # # # # # # ###
|
||||
# # ## # ## # # #### ## # ## # # ##
|
||||
# ## ## # # # # # # ## # #
|
||||
# # ## # ## # # # # ### #
|
||||
# # # # # # ### # # # ## ## ##
|
||||
# # # # ### # ## ## # # #
|
||||
# ### ## # ## # #
|
||||
# ## ### # # # # # # #
|
||||
# ## # # # # ## # # # # ##
|
||||
### # # # # ## # # # ## # #
|
||||
## # ### # # # # # #
|
||||
# # # # # ## ## ## # #
|
||||
# # # ### # # # # ###
|
||||
### # # # # ## ## # #
|
||||
# # ### # # # # # # ##
|
||||
# # # # ## # # #
|
||||
# # # # ## # ### # ## # # #
|
||||
### # # # # # # # # # #
|
||||
# # # # # ### ## # # ## ### #
|
||||
# # ## # ### ## # # # # ## # #
|
||||
# # # # # # # ### #
|
||||
## # # #### # ## # # # # #
|
||||
# # ### # ## # # # # # #
|
||||
# # # ### # # # # ## # #
|
||||
## # # # # #### # # # ### #
|
||||
## ## ## # ### # # ## #
|
||||
# # ## ## ### # # # # # # ### #
|
||||
# ## # # # # # E#
|
||||
##################################################
|
||||
20
zverevem/lab2/docs/data/maze_no_exit.txt
Normal file
20
zverevem/lab2/docs/data/maze_no_exit.txt
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
####################
|
||||
#S# # # ## #
|
||||
# # # ## #
|
||||
# # # # #
|
||||
# # # # #
|
||||
# ###
|
||||
## # # # #
|
||||
# # # # #
|
||||
## # # # # #
|
||||
# # # #
|
||||
# # # ## #
|
||||
# # # ##
|
||||
# # # #
|
||||
# # # # ## #
|
||||
# # #
|
||||
## # # ##
|
||||
# ### ##
|
||||
# # ## ###
|
||||
# # # #E#
|
||||
####################
|
||||
50
zverevem/lab2/docs/data/maze_open.txt
Normal file
50
zverevem/lab2/docs/data/maze_open.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
##################################################
|
||||
#S #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# E#
|
||||
##################################################
|
||||
10
zverevem/lab2/docs/data/maze_small.txt
Normal file
10
zverevem/lab2/docs/data/maze_small.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
##########
|
||||
#S# ##
|
||||
# # # #
|
||||
# # #
|
||||
# ## #
|
||||
# #
|
||||
# # # # #
|
||||
# #
|
||||
# E#
|
||||
##########
|
||||
16
zverevem/lab2/docs/data/results.csv
Normal file
16
zverevem/lab2/docs/data/results.csv
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
лабиринт,стратегия,время_мс,посещено_клеток,длина_пути,замер_1,замер_2,замер_3,замер_4,замер_5,замер_6,замер_7
|
||||
small_10x10,BFS,0.2443,54,15,0.2512,0.2377,0.2104,0.2098,0.3295,0.2628,0.2088
|
||||
small_10x10,DFS,0.1729,33,33,0.1438,0.3230,0.1467,0.1388,0.1570,0.1518,0.1490
|
||||
small_10x10,A*,0.2503,36,15,0.2849,0.4248,0.2063,0.2027,0.2010,0.2022,0.2305
|
||||
medium_50x50,BFS,7.8016,1639,95,9.7252,7.6549,7.1375,6.5061,7.8024,7.9052,7.8801
|
||||
medium_50x50,DFS,5.9674,1063,185,5.5163,4.6949,7.7879,7.1488,5.6215,5.1059,5.8962
|
||||
medium_50x50,A*,4.0049,588,95,4.1553,4.5408,4.1015,3.6816,3.9481,3.7989,3.8081
|
||||
large_100x100,BFS,30.9012,6564,0,33.9413,31.6451,30.0917,31.2012,30.8385,29.2073,29.3836
|
||||
large_100x100,DFS,29.7523,6564,0,31.0923,29.3284,29.7215,29.0498,29.9187,29.9990,29.1565
|
||||
large_100x100,A*,51.4814,6564,0,49.1005,51.0370,50.5359,54.6521,53.4745,49.4512,52.1183
|
||||
open_50x50,BFS,12.2218,2304,95,9.8705,12.1266,9.9576,10.8552,12.0067,18.9221,11.8140
|
||||
open_50x50,DFS,6.8283,1223,1129,7.7999,7.7336,7.2627,5.7576,6.6328,7.1781,5.4337
|
||||
open_50x50,A*,16.5740,2304,95,16.4528,16.5879,17.9772,16.4465,16.1444,16.7420,15.6672
|
||||
no_exit_20x20,BFS,1.0499,260,0,1.1731,1.0768,1.0067,1.0100,1.0201,1.0508,1.0120
|
||||
no_exit_20x20,DFS,1.0160,260,0,1.0409,1.0098,1.0178,1.0072,1.0130,1.0069,1.0166
|
||||
no_exit_20x20,A*,1.5796,260,0,1.5919,1.5782,1.5758,1.6349,1.5690,1.5579,1.5496
|
||||
|
Loading…
Reference in New Issue
Block a user