forked from UNN/2026-rff_mp
Конвертировка всех файлом в расширение py
This commit is contained in:
parent
5207bb8682
commit
d8ab579a46
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "761fe720-5ebb-456c-96dc-fa3288bc6280",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "",
|
||||
"name": ""
|
||||
},
|
||||
"language_info": {
|
||||
"name": ""
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
10
MininaVD/docs2/data2/buildersMaze_builder.py
Normal file
10
MininaVD/docs2/data2/buildersMaze_builder.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from modelsMaze import Maze
|
||||
|
||||
class MazeBuilder(ABC):
|
||||
"""Интерфейс строителя лабиринта (паттерн Builder)."""
|
||||
|
||||
@abstractmethod
|
||||
def build_from_file(self, filename: str) -> Maze:
|
||||
"""Загрузить лабиринт из файла."""
|
||||
pass
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6c5d97cf-bcbf-428a-b12c-1b86e9a02b96",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "",
|
||||
"name": ""
|
||||
},
|
||||
"language_info": {
|
||||
"name": ""
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
60
MininaVD/docs2/data2/buildersText_maze_builder.py
Normal file
60
MininaVD/docs2/data2/buildersText_maze_builder.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
from typing import List, Tuple
|
||||
from buildersMaze_builder import MazeBuilder
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
|
||||
class TextFieldMazeBuilder(MazeBuilder):
|
||||
"""Загрузчик лабиринта из текстового файла."""
|
||||
|
||||
# Символы в файле
|
||||
WALL_CHAR = '#'
|
||||
PASS_CHAR = ' '
|
||||
START_CHAR = 'S'
|
||||
EXIT_CHAR = 'E'
|
||||
|
||||
def build_from_file(self, filename: str) -> Maze:
|
||||
"""Загрузить лабиринт из текстового файла."""
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
lines = [line.rstrip('\n') for line in f.readlines()]
|
||||
|
||||
if not lines:
|
||||
raise ValueError("Файл пуст")
|
||||
|
||||
height = len(lines)
|
||||
width = max(len(line) for line in lines)
|
||||
|
||||
maze = Maze(width, height)
|
||||
start_cell = None
|
||||
exit_cell = None
|
||||
|
||||
for y, line in enumerate(lines):
|
||||
for x, ch in enumerate(line):
|
||||
if x >= width:
|
||||
continue
|
||||
|
||||
is_wall = (ch == self.WALL_CHAR)
|
||||
is_start = (ch == self.START_CHAR)
|
||||
is_exit = (ch == self.EXIT_CHAR)
|
||||
|
||||
# Пробел или буква - проходимая клетка
|
||||
if ch == self.PASS_CHAR or is_start or is_exit:
|
||||
is_wall = False
|
||||
|
||||
cell = Cell(x=x, y=y, is_wall=is_wall, is_start=is_start, is_exit=is_exit)
|
||||
maze.set_cell(x, y, cell)
|
||||
|
||||
if is_start:
|
||||
start_cell = cell
|
||||
if is_exit:
|
||||
exit_cell = cell
|
||||
|
||||
# Валидация
|
||||
if start_cell is None:
|
||||
raise ValueError("В лабиринте нет стартовой клетки (S)")
|
||||
if exit_cell is None:
|
||||
raise ValueError("В лабиринте нет выходной клетки (E)")
|
||||
|
||||
maze.start_cell = start_cell
|
||||
maze.exit_cell = exit_cell
|
||||
|
||||
return maze
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "29468b18-8654-4914-a68e-76c1a7f01c49",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from abc import ABC, abstractmethod\n",
|
||||
"\n",
|
||||
"class Command(ABC):\n",
|
||||
" \"\"\"Интерфейс команды (паттерн Command).\"\"\"\n",
|
||||
" \n",
|
||||
" @abstractmethod\n",
|
||||
" def execute(self) -> None:\n",
|
||||
" \"\"\"Выполнить команду.\"\"\"\n",
|
||||
" pass\n",
|
||||
" \n",
|
||||
" @abstractmethod\n",
|
||||
" def undo(self) -> None:\n",
|
||||
" \"\"\"Отменить команду.\"\"\"\n",
|
||||
" pass"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
21
MininaVD/docs2/data2/commandsCommand.py
Normal file
21
MininaVD/docs2/data2/commandsCommand.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class Command(ABC):
|
||||
"""Интерфейс команды (паттерн Command)."""
|
||||
|
||||
@abstractmethod
|
||||
def execute(self) -> None:
|
||||
"""Выполнить команду."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def undo(self) -> None:
|
||||
"""Отменить команду."""
|
||||
pass
|
||||
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "492dd9b1-922e-4c95-9112-4b2df086eae6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Optional\n",
|
||||
"from commandsCommand import Command\n",
|
||||
"from commandsPlayer import Player\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"\n",
|
||||
"class MoveCommand(Command):\n",
|
||||
" \"\"\"Команда перемещения игрока.\"\"\"\n",
|
||||
" \n",
|
||||
" # Направления\n",
|
||||
" DIRECTIONS = {\n",
|
||||
" 'w': (0, -1), # вверх\n",
|
||||
" 's': (0, 1), # вниз\n",
|
||||
" 'a': (-1, 0), # влево\n",
|
||||
" 'd': (1, 0), # вправо\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" def __init__(self, player: Player, maze: Maze, direction: str):\n",
|
||||
" self.player = player\n",
|
||||
" self.maze = maze\n",
|
||||
" self.direction = direction.lower()\n",
|
||||
" self._target_cell: Optional[Cell] = None\n",
|
||||
" self._executed = False\n",
|
||||
" \n",
|
||||
" def execute(self) -> bool:\n",
|
||||
" \"\"\"Выполнить перемещение.\"\"\"\n",
|
||||
" if self.direction not in self.DIRECTIONS:\n",
|
||||
" return False\n",
|
||||
" \n",
|
||||
" dx, dy = self.DIRECTIONS[self.direction]\n",
|
||||
" x = self.player.current_cell.x + dx\n",
|
||||
" y = self.player.current_cell.y + dy\n",
|
||||
" \n",
|
||||
" self._target_cell = self.maze.get_cell(x, y)\n",
|
||||
" \n",
|
||||
" if self._target_cell and self._target_cell.is_passable():\n",
|
||||
" self.player.move_to(self._target_cell)\n",
|
||||
" self._executed = True\n",
|
||||
" return True\n",
|
||||
" \n",
|
||||
" return False\n",
|
||||
" \n",
|
||||
" def undo(self) -> bool:\n",
|
||||
" \"\"\"Отменить перемещение.\"\"\"\n",
|
||||
" if self._executed:\n",
|
||||
" success = self.player.undo_move()\n",
|
||||
" if success:\n",
|
||||
" self._executed = False\n",
|
||||
" return True\n",
|
||||
" return False"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
57
MininaVD/docs2/data2/commandsMove_command.py
Normal file
57
MininaVD/docs2/data2/commandsMove_command.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from typing import Optional
|
||||
from commandsCommand import Command
|
||||
from commandsPlayer import Player
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
|
||||
class MoveCommand(Command):
|
||||
"""Команда перемещения игрока."""
|
||||
|
||||
# Направления
|
||||
DIRECTIONS = {
|
||||
'w': (0, -1), # вверх
|
||||
's': (0, 1), # вниз
|
||||
'a': (-1, 0), # влево
|
||||
'd': (1, 0), # вправо
|
||||
}
|
||||
|
||||
def __init__(self, player: Player, maze: Maze, direction: str):
|
||||
self.player = player
|
||||
self.maze = maze
|
||||
self.direction = direction.lower()
|
||||
self._target_cell: Optional[Cell] = None
|
||||
self._executed = False
|
||||
|
||||
def execute(self) -> bool:
|
||||
"""Выполнить перемещение."""
|
||||
if self.direction not in self.DIRECTIONS:
|
||||
return False
|
||||
|
||||
dx, dy = self.DIRECTIONS[self.direction]
|
||||
x = self.player.current_cell.x + dx
|
||||
y = self.player.current_cell.y + dy
|
||||
|
||||
self._target_cell = self.maze.get_cell(x, y)
|
||||
|
||||
if self._target_cell and self._target_cell.is_passable():
|
||||
self.player.move_to(self._target_cell)
|
||||
self._executed = True
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def undo(self) -> bool:
|
||||
"""Отменить перемещение."""
|
||||
if self._executed:
|
||||
success = self.player.undo_move()
|
||||
if success:
|
||||
self._executed = False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c2a5ffd4-9644-453e-83de-bdac76215a37",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Optional\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"\n",
|
||||
"class Player:\n",
|
||||
" \"\"\"Игрок, перемещающийся по лабиринту.\"\"\"\n",
|
||||
" \n",
|
||||
" def __init__(self, maze: Maze, start_cell: Cell):\n",
|
||||
" self.maze = maze\n",
|
||||
" self.current_cell = start_cell\n",
|
||||
" self._previous_cell: Optional[Cell] = None\n",
|
||||
" \n",
|
||||
" def move_to(self, cell: Cell) -> bool:\n",
|
||||
" \"\"\"Переместить игрока в указанную клетку (если она проходима).\"\"\"\n",
|
||||
" if cell and cell.is_passable():\n",
|
||||
" self._previous_cell = self.current_cell\n",
|
||||
" self.current_cell = cell\n",
|
||||
" return True\n",
|
||||
" return False\n",
|
||||
" \n",
|
||||
" def undo_move(self) -> bool:\n",
|
||||
" \"\"\"Отменить последнее перемещение.\"\"\"\n",
|
||||
" if self._previous_cell:\n",
|
||||
" self.current_cell = self._previous_cell\n",
|
||||
" self._previous_cell = None\n",
|
||||
" return True\n",
|
||||
" return False\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def position(self) -> Cell:\n",
|
||||
" return self.current_cell"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
38
MininaVD/docs2/data2/commandsPlayer.py
Normal file
38
MininaVD/docs2/data2/commandsPlayer.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from typing import Optional
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
|
||||
class Player:
|
||||
"""Игрок, перемещающийся по лабиринту."""
|
||||
|
||||
def __init__(self, maze: Maze, start_cell: Cell):
|
||||
self.maze = maze
|
||||
self.current_cell = start_cell
|
||||
self._previous_cell: Optional[Cell] = None
|
||||
|
||||
def move_to(self, cell: Cell) -> bool:
|
||||
"""Переместить игрока в указанную клетку (если она проходима)."""
|
||||
if cell and cell.is_passable():
|
||||
self._previous_cell = self.current_cell
|
||||
self.current_cell = cell
|
||||
return True
|
||||
return False
|
||||
|
||||
def undo_move(self) -> bool:
|
||||
"""Отменить последнее перемещение."""
|
||||
if self._previous_cell:
|
||||
self.current_cell = self._previous_cell
|
||||
self._previous_cell = None
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def position(self) -> Cell:
|
||||
return self.current_cell
|
||||
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c7d4d33a-ead6-4906-b307-e357ba0995e2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import csv\n",
|
||||
"import time\n",
|
||||
"from typing import List, Dict, Any\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from strategiesBfs_strategy import BFSStrategy\n",
|
||||
"from strategiesDfs_strategy import DFSStrategy\n",
|
||||
"from strategiesA_star_strategy import AStarStrategy\n",
|
||||
"from solverMaze_solver import MazeSolver\n",
|
||||
"\n",
|
||||
"class Benchmark:\n",
|
||||
" \"\"\"Экспериментальное сравнение алгоритмов.\"\"\"\n",
|
||||
" \n",
|
||||
" def __init__(self):\n",
|
||||
" self.strategies = [\n",
|
||||
" BFSStrategy(),\n",
|
||||
" DFSStrategy(),\n",
|
||||
" AStarStrategy(),\n",
|
||||
" ]\n",
|
||||
" self.results: List[Dict[str, Any]] = []\n",
|
||||
" \n",
|
||||
" def run_on_maze(self, maze: Maze, maze_name: str, iterations: int = 5) -> List[Dict]:\n",
|
||||
" \"\"\"Запустить все стратегии на одном лабиринте.\"\"\"\n",
|
||||
" results = []\n",
|
||||
" \n",
|
||||
" for strategy in self.strategies:\n",
|
||||
" solver = MazeSolver(maze, strategy)\n",
|
||||
" \n",
|
||||
" times = []\n",
|
||||
" visited_counts = []\n",
|
||||
" path_lengths = []\n",
|
||||
" path_found = False\n",
|
||||
" \n",
|
||||
" for i in range(iterations):\n",
|
||||
" # Сбрасываем состояние стратегии для честного замера\n",
|
||||
" # (кэш посещённых клеток не должен влиять)\n",
|
||||
" start_time = time.perf_counter()\n",
|
||||
" path = strategy.find_path(maze, maze.start_cell, maze.exit_cell)\n",
|
||||
" end_time = time.perf_counter()\n",
|
||||
" \n",
|
||||
" times.append((end_time - start_time) * 1000)\n",
|
||||
" visited_counts.append(getattr(strategy, 'last_visited_count', 0))\n",
|
||||
" path_lengths.append(len(path))\n",
|
||||
" path_found = len(path) > 0\n",
|
||||
" \n",
|
||||
" result = {\n",
|
||||
" 'maze': maze_name,\n",
|
||||
" 'algorithm': strategy.name,\n",
|
||||
" 'avg_time_ms': sum(times) / len(times),\n",
|
||||
" 'min_time_ms': min(times),\n",
|
||||
" 'max_time_ms': max(times),\n",
|
||||
" 'avg_visited': sum(visited_counts) / len(visited_counts),\n",
|
||||
" 'avg_path_length': sum(path_lengths) / len(path_lengths),\n",
|
||||
" 'path_found': path_found,\n",
|
||||
" 'iterations': iterations\n",
|
||||
" }\n",
|
||||
" results.append(result)\n",
|
||||
" self.results.append(result)\n",
|
||||
" \n",
|
||||
" return results\n",
|
||||
" \n",
|
||||
" def save_to_csv(self, filename: str = \"benchmark_results.csv\") -> None:\n",
|
||||
" \"\"\"Сохранить результаты в CSV.\"\"\"\n",
|
||||
" if not self.results:\n",
|
||||
" print(\"Нет результатов для сохранения\")\n",
|
||||
" return\n",
|
||||
" \n",
|
||||
" fieldnames = ['maze', 'algorithm', 'avg_time_ms', 'min_time_ms', \n",
|
||||
" 'max_time_ms', 'avg_visited', 'avg_path_length', \n",
|
||||
" 'path_found', 'iterations']\n",
|
||||
" \n",
|
||||
" with open(filename, 'w', newline='', encoding='utf-8') as f:\n",
|
||||
" writer = csv.DictWriter(f, fieldnames=fieldnames)\n",
|
||||
" writer.writeheader()\n",
|
||||
" writer.writerows(self.results)\n",
|
||||
" \n",
|
||||
" print(f\"Результаты сохранены в {filename}\")\n",
|
||||
" \n",
|
||||
" def print_summary(self) -> None:\n",
|
||||
" \"\"\"Вывести сводку результатов.\"\"\"\n",
|
||||
" print(\"РЕЗУЛЬТАТЫ ЭКСПЕРИМЕНТОВ\")\n",
|
||||
" \n",
|
||||
" current_maze = None\n",
|
||||
" for r in self.results:\n",
|
||||
" if r['maze'] != current_maze:\n",
|
||||
" current_maze = r['maze']\n",
|
||||
" print(f\"\\n--- Лабиринт: {current_maze} ---\")\n",
|
||||
" \n",
|
||||
" status = \" НАЙДЕН\" if r['path_found'] else \" НЕ НАЙДЕН\"\n",
|
||||
" print(f\" {r['algorithm']:6} | Время: {r['avg_time_ms']:8.2f} мс | \"\n",
|
||||
" f\"Посещено: {r['avg_visited']:8.1f} | \"\n",
|
||||
" f\"Путь: {r['avg_path_length']:6.1f} | {status}\")\n",
|
||||
" \n",
|
||||
" "
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
100
MininaVD/docs2/data2/experimentsBenchmark.py
Normal file
100
MininaVD/docs2/data2/experimentsBenchmark.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
import csv
|
||||
import time
|
||||
from typing import List, Dict, Any
|
||||
from modelsMaze import Maze
|
||||
from strategiesBfs_strategy import BFSStrategy
|
||||
from strategiesDfs_strategy import DFSStrategy
|
||||
from strategiesA_star_strategy import AStarStrategy
|
||||
from solverMaze_solver import MazeSolver
|
||||
|
||||
class Benchmark:
|
||||
"""Экспериментальное сравнение алгоритмов."""
|
||||
|
||||
def __init__(self):
|
||||
self.strategies = [
|
||||
BFSStrategy(),
|
||||
DFSStrategy(),
|
||||
AStarStrategy(),
|
||||
]
|
||||
self.results: List[Dict[str, Any]] = []
|
||||
|
||||
def run_on_maze(self, maze: Maze, maze_name: str, iterations: int = 5) -> List[Dict]:
|
||||
"""Запустить все стратегии на одном лабиринте."""
|
||||
results = []
|
||||
|
||||
for strategy in self.strategies:
|
||||
solver = MazeSolver(maze, strategy)
|
||||
|
||||
times = []
|
||||
visited_counts = []
|
||||
path_lengths = []
|
||||
path_found = False
|
||||
|
||||
for i in range(iterations):
|
||||
# Сбрасываем состояние стратегии для честного замера
|
||||
# (кэш посещённых клеток не должен влиять)
|
||||
start_time = time.perf_counter()
|
||||
path = strategy.find_path(maze, maze.start_cell, maze.exit_cell)
|
||||
end_time = time.perf_counter()
|
||||
|
||||
times.append((end_time - start_time) * 1000)
|
||||
visited_counts.append(getattr(strategy, 'last_visited_count', 0))
|
||||
path_lengths.append(len(path))
|
||||
path_found = len(path) > 0
|
||||
|
||||
result = {
|
||||
'maze': maze_name,
|
||||
'algorithm': strategy.name,
|
||||
'avg_time_ms': sum(times) / len(times),
|
||||
'min_time_ms': min(times),
|
||||
'max_time_ms': max(times),
|
||||
'avg_visited': sum(visited_counts) / len(visited_counts),
|
||||
'avg_path_length': sum(path_lengths) / len(path_lengths),
|
||||
'path_found': path_found,
|
||||
'iterations': iterations
|
||||
}
|
||||
results.append(result)
|
||||
self.results.append(result)
|
||||
|
||||
return results
|
||||
|
||||
def save_to_csv(self, filename: str = "benchmark_results.csv") -> None:
|
||||
"""Сохранить результаты в CSV."""
|
||||
if not self.results:
|
||||
print("Нет результатов для сохранения")
|
||||
return
|
||||
|
||||
fieldnames = ['maze', 'algorithm', 'avg_time_ms', 'min_time_ms',
|
||||
'max_time_ms', 'avg_visited', 'avg_path_length',
|
||||
'path_found', 'iterations']
|
||||
|
||||
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(self.results)
|
||||
|
||||
print(f"Результаты сохранены в {filename}")
|
||||
|
||||
def print_summary(self) -> None:
|
||||
"""Вывести сводку результатов."""
|
||||
print("РЕЗУЛЬТАТЫ ЭКСПЕРИМЕНТОВ")
|
||||
|
||||
current_maze = None
|
||||
for r in self.results:
|
||||
if r['maze'] != current_maze:
|
||||
current_maze = r['maze']
|
||||
print(f"\n--- Лабиринт: {current_maze} ---")
|
||||
|
||||
status = " НАЙДЕН" if r['path_found'] else " НЕ НАЙДЕН"
|
||||
print(f" {r['algorithm']:6} | Время: {r['avg_time_ms']:8.2f} мс | "
|
||||
f"Посещено: {r['avg_visited']:8.1f} | "
|
||||
f"Путь: {r['avg_path_length']:6.1f} | {status}")
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "ac02445d-6e74-4f6e-bb96-2c28ccd82d83",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ModuleNotFoundError",
|
||||
"evalue": "No module named 'modelsMaze'",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
||||
"\u001b[31mModuleNotFoundError\u001b[39m Traceback (most recent call last)",
|
||||
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[7]\u001b[39m\u001b[32m, line 8\u001b[39m\n\u001b[32m 5\u001b[39m sys.path.insert(\u001b[32m0\u001b[39m, os.getcwd())\n\u001b[32m 7\u001b[39m \u001b[38;5;66;03m# Импорты с вашими именами файлов\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m8\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mmodelsMaze\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Maze, Cell\n\u001b[32m 9\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mbuildersText_maze_builder\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m TextFieldMazeBuilder\n\u001b[32m 10\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mstrategiesBFS_strategy\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BFSStrategy\n",
|
||||
"\u001b[31mModuleNotFoundError\u001b[39m: No module named 'modelsMaze'"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Добавляем текущую папку в путь\n",
|
||||
"sys.path.insert(0, os.getcwd())\n",
|
||||
"\n",
|
||||
"# Импорты с вашими именами файлов\n",
|
||||
"from modelsMaze import Maze, Cell\n",
|
||||
"from buildersText_maze_builder import TextFieldMazeBuilder\n",
|
||||
"from strategiesBFS_strategy import BFSStrategy\n",
|
||||
"from strategiesDFS_strategy import DFSStrategy\n",
|
||||
"from strategiesA_star_strategy import AStarStrategy\n",
|
||||
"from solverMaze_solver import MazeSolver\n",
|
||||
"from visualizationConsole_view import ConsoleView\n",
|
||||
"from commandsPlayer import Player\n",
|
||||
"from commandsMove_command import MoveCommand\n",
|
||||
"from experimentsBenchmark import Benchmark\n",
|
||||
"\n",
|
||||
"def create_test_mazes():\n",
|
||||
" \"\"\"Создать тестовые лабиринты в папке mazes/.\"\"\"\n",
|
||||
" mazes_dir = \"mazes\"\n",
|
||||
" os.makedirs(mazes_dir, exist_ok=True)\n",
|
||||
" \n",
|
||||
" # Маленький лабиринт 10×10\n",
|
||||
" small = [\n",
|
||||
" \"##########\",\n",
|
||||
" \"#S #\",\n",
|
||||
" \"# ##### #\",\n",
|
||||
" \"# # # #\",\n",
|
||||
" \"# # # # #\",\n",
|
||||
" \"# # # #\",\n",
|
||||
" \"##### # #\",\n",
|
||||
" \"# #\",\n",
|
||||
" \"# E#\",\n",
|
||||
" \"##########\",\n",
|
||||
" ]\n",
|
||||
" \n",
|
||||
" # Пустой лабиринт\n",
|
||||
" empty = [\"S\" + \" \" * 48 + \"E\"] + [\" \" * 50 for _ in range(48)]\n",
|
||||
" \n",
|
||||
" # Лабиринт без выхода\n",
|
||||
" no_exit = [\n",
|
||||
" \"##########\",\n",
|
||||
" \"#S #\",\n",
|
||||
" \"# ##### #\",\n",
|
||||
" \"# # # #\",\n",
|
||||
" \"# # # # #\",\n",
|
||||
" \"# # # #\",\n",
|
||||
" \"##### # #\",\n",
|
||||
" \"# #\",\n",
|
||||
" \"##########\",\n",
|
||||
" \"##########\",\n",
|
||||
" ]\n",
|
||||
" \n",
|
||||
" mazes = {\n",
|
||||
" \"small.txt\": small,\n",
|
||||
" \"empty.txt\": empty,\n",
|
||||
" \"no_exit.txt\": no_exit,\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" for name, content in mazes.items():\n",
|
||||
" path = os.path.join(mazes_dir, name)\n",
|
||||
" with open(path, 'w', encoding='utf-8') as f:\n",
|
||||
" f.write('\\n'.join(content))\n",
|
||||
" print(f\"Создан тестовый лабиринт: {path}\")\n",
|
||||
" \n",
|
||||
" print()\n",
|
||||
"\n",
|
||||
"def demo_builder_and_strategy():\n",
|
||||
" \"\"\"Демонстрация паттернов Builder и Strategy.\"\"\"\n",
|
||||
" print(\"\\n\" + \"=\" * 60)\n",
|
||||
" print(\"ДЕМОНСТРАЦИЯ ПАТТЕРНОВ BUILDER И STRATEGY\")\n",
|
||||
" print(\"=\" * 60)\n",
|
||||
" \n",
|
||||
" builder = TextFieldMazeBuilder()\n",
|
||||
" maze = builder.build_from_file(\"mazes/small.txt\")\n",
|
||||
" \n",
|
||||
" strategies = [\n",
|
||||
" BFSStrategy(),\n",
|
||||
" DFSStrategy(),\n",
|
||||
" AStarStrategy(),\n",
|
||||
" ]\n",
|
||||
" \n",
|
||||
" for strategy in strategies:\n",
|
||||
" print(f\"\\n--- Используем стратегию: {strategy.name} ---\")\n",
|
||||
" solver = MazeSolver(maze, strategy)\n",
|
||||
" path = solver.solve()\n",
|
||||
" \n",
|
||||
" if path:\n",
|
||||
" print(f\" Путь найден! Длина: {len(path)}\")\n",
|
||||
" print(f\" Время: {solver.last_stats.time_ms:.2f} мс\")\n",
|
||||
" print(f\" Посещено клеток: {solver.last_stats.visited_cells}\")\n",
|
||||
" else:\n",
|
||||
" print(\" Путь не найден!\")\n",
|
||||
" \n",
|
||||
" return maze\n",
|
||||
"\n",
|
||||
"def demo_observer(maze: Maze):\n",
|
||||
" \"\"\"Демонстрация паттерна Observer.\"\"\"\n",
|
||||
" print(\"\\n\" + \"=\" * 60)\n",
|
||||
" print(\"ДЕМОНСТРАЦИЯ ПАТТЕРНА OBSERVER\")\n",
|
||||
" print(\"=\" * 60)\n",
|
||||
" \n",
|
||||
" view = ConsoleView(maze)\n",
|
||||
" solver = MazeSolver(maze, BFSStrategy())\n",
|
||||
" solver.attach(view)\n",
|
||||
" \n",
|
||||
" print(\"Запускаем поиск с наблюдателем...\")\n",
|
||||
" path = solver.solve()\n",
|
||||
" \n",
|
||||
" view.set_solution_path(path)\n",
|
||||
" view.render()\n",
|
||||
" \n",
|
||||
" return view\n",
|
||||
"\n",
|
||||
"def demo_command(maze: Maze, view: ConsoleView):\n",
|
||||
" \"\"\"Демонстрация паттерна Command.\"\"\"\n",
|
||||
" print(\"\\n\" + \"=\" * 60)\n",
|
||||
" print(\"ДЕМОНСТРАЦИЯ ПАТТЕРНА COMMAND\")\n",
|
||||
" print(\"=\" * 60)\n",
|
||||
" \n",
|
||||
" player = Player(maze, maze.start_cell)\n",
|
||||
" view.set_player_position(player.position)\n",
|
||||
" \n",
|
||||
" print(\"Управление игроком:\")\n",
|
||||
" print(\" W/A/S/D - движение, Z - отмена, Q - выход\")\n",
|
||||
" \n",
|
||||
" history = []\n",
|
||||
" \n",
|
||||
" while True:\n",
|
||||
" view.render()\n",
|
||||
" \n",
|
||||
" cmd = input(\"Ваш ход: \").strip().lower()\n",
|
||||
" \n",
|
||||
" if cmd == 'q':\n",
|
||||
" break\n",
|
||||
" elif cmd == 'z':\n",
|
||||
" if history:\n",
|
||||
" last_cmd = history.pop()\n",
|
||||
" last_cmd.undo()\n",
|
||||
" view.set_player_position(player.position)\n",
|
||||
" print(\"Последний ход отменён\")\n",
|
||||
" else:\n",
|
||||
" print(\"Нечего отменять\")\n",
|
||||
" elif cmd in MoveCommand.DIRECTIONS:\n",
|
||||
" move_cmd = MoveCommand(player, maze, cmd)\n",
|
||||
" if move_cmd.execute():\n",
|
||||
" history.append(move_cmd)\n",
|
||||
" view.set_player_position(player.position)\n",
|
||||
" \n",
|
||||
" if player.position == maze.exit_cell:\n",
|
||||
" print(\"\\n🎉 ПОБЕДА! ВЫ НАШЛИ ВЫХОД! 🎉\")\n",
|
||||
" view.render()\n",
|
||||
" break\n",
|
||||
" else:\n",
|
||||
" print(\"Туда нельзя пройти\")\n",
|
||||
" else:\n",
|
||||
" print(\"Неизвестная команда\")\n",
|
||||
" \n",
|
||||
" print(\"Игра завершена\")\n",
|
||||
"\n",
|
||||
"def run_experiments():\n",
|
||||
" \"\"\"Запуск экспериментального сравнения.\"\"\"\n",
|
||||
" print(\"\\n\" + \"=\" * 60)\n",
|
||||
" print(\"ЭКСПЕРИМЕНТАЛЬНОЕ СРАВНЕНИЕ АЛГОРИТМОВ\")\n",
|
||||
" print(\"=\" * 60)\n",
|
||||
" \n",
|
||||
" builder = TextFieldMazeBuilder()\n",
|
||||
" benchmark = Benchmark()\n",
|
||||
" \n",
|
||||
" maze_files = [\"small.txt\", \"empty.txt\", \"no_exit.txt\"]\n",
|
||||
" \n",
|
||||
" for maze_file in maze_files:\n",
|
||||
" try:\n",
|
||||
" maze = builder.build_from_file(f\"mazes/{maze_file}\")\n",
|
||||
" print(f\"\\nТестируем: {maze_file} ({maze.width}×{maze.height})\")\n",
|
||||
" benchmark.run_on_maze(maze, maze_file, iterations=5)\n",
|
||||
" except FileNotFoundError:\n",
|
||||
" print(f\"Файл {maze_file} не найден\")\n",
|
||||
" except ValueError as e:\n",
|
||||
" print(f\"Ошибка: {e}\")\n",
|
||||
" \n",
|
||||
" benchmark.print_summary()\n",
|
||||
" benchmark.save_to_csv()\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" \"\"\"Главная функция.\"\"\"\n",
|
||||
" print(\"=\" * 60)\n",
|
||||
" print(\"ПРОГРАММА ПОИСКА ВЫХОДА ИЗ ЛАБИРИНТА\")\n",
|
||||
" print(\"Паттерны: Builder, Strategy, Observer, Command\")\n",
|
||||
" print(\"=\" * 60)\n",
|
||||
" \n",
|
||||
" create_test_mazes()\n",
|
||||
" maze = demo_builder_and_strategy()\n",
|
||||
" view = demo_observer(maze)\n",
|
||||
" demo_command(maze, view)\n",
|
||||
" run_experiments()\n",
|
||||
" \n",
|
||||
" print(\"\\nПрограмма завершена!\")\n",
|
||||
"\n",
|
||||
"if __name__ == \"__main__\":\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d0972138-e9f0-4612-a87c-741d9d0bea13",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
215
MininaVD/docs2/data2/main.py
Normal file
215
MininaVD/docs2/data2/main.py
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[7]:
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Добавляем текущую папку в путь
|
||||
sys.path.insert(0, os.getcwd())
|
||||
|
||||
# Импорты с вашими именами файлов
|
||||
from modelsMaze import Maze, Cell
|
||||
from buildersText_maze_builder import TextFieldMazeBuilder
|
||||
from strategiesBfs_strategy import BFSStrategy
|
||||
from strategiesDfs_strategy import DFSStrategy
|
||||
from strategiesA_star_strategy import AStarStrategy
|
||||
from solverMaze_solver import MazeSolver
|
||||
from visualizationConsole_view import ConsoleView
|
||||
from commandsPlayer import Player
|
||||
from commandsMove_command import MoveCommand
|
||||
from experimentsBenchmark import Benchmark
|
||||
|
||||
def create_test_mazes():
|
||||
"""Создать тестовые лабиринты в папке mazes/."""
|
||||
mazes_dir = "mazes"
|
||||
os.makedirs(mazes_dir, exist_ok=True)
|
||||
|
||||
# Маленький лабиринт 10×10
|
||||
small = [
|
||||
"##########",
|
||||
"#S #",
|
||||
"# ##### #",
|
||||
"# # # #",
|
||||
"# # # # #",
|
||||
"# # # #",
|
||||
"##### # #",
|
||||
"# #",
|
||||
"# E#",
|
||||
"##########",
|
||||
]
|
||||
|
||||
# Пустой лабиринт
|
||||
empty = ["S" + " " * 48 + "E"] + [" " * 50 for _ in range(48)]
|
||||
|
||||
# Лабиринт без выхода
|
||||
no_exit = [
|
||||
"##########",
|
||||
"#S #",
|
||||
"# ##### #",
|
||||
"# # # #",
|
||||
"# # # # #",
|
||||
"# # # #",
|
||||
"##### # #",
|
||||
"# #",
|
||||
"##########",
|
||||
"##########",
|
||||
]
|
||||
|
||||
mazes = {
|
||||
"small.txt": small,
|
||||
"empty.txt": empty,
|
||||
"no_exit.txt": no_exit,
|
||||
}
|
||||
|
||||
for name, content in mazes.items():
|
||||
path = os.path.join(mazes_dir, name)
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(content))
|
||||
print(f"Создан тестовый лабиринт: {path}")
|
||||
|
||||
print()
|
||||
|
||||
def demo_builder_and_strategy():
|
||||
"""Демонстрация паттернов Builder и Strategy."""
|
||||
print("\n" + "=" * 60)
|
||||
print("ДЕМОНСТРАЦИЯ ПАТТЕРНОВ BUILDER И STRATEGY")
|
||||
print("=" * 60)
|
||||
|
||||
builder = TextFieldMazeBuilder()
|
||||
maze = builder.build_from_file("mazes/small.txt")
|
||||
|
||||
strategies = [
|
||||
BFSStrategy(),
|
||||
DFSStrategy(),
|
||||
AStarStrategy(),
|
||||
]
|
||||
|
||||
for strategy in strategies:
|
||||
print(f"\n--- Используем стратегию: {strategy.name} ---")
|
||||
solver = MazeSolver(maze, strategy)
|
||||
path = solver.solve()
|
||||
|
||||
if path:
|
||||
print(f" Путь найден! Длина: {len(path)}")
|
||||
print(f" Время: {solver.last_stats.time_ms:.2f} мс")
|
||||
print(f" Посещено клеток: {solver.last_stats.visited_cells}")
|
||||
else:
|
||||
print(" Путь не найден!")
|
||||
|
||||
return maze
|
||||
|
||||
def demo_observer(maze: Maze):
|
||||
"""Демонстрация паттерна Observer."""
|
||||
print("\n" + "=" * 60)
|
||||
print("ДЕМОНСТРАЦИЯ ПАТТЕРНА OBSERVER")
|
||||
print("=" * 60)
|
||||
|
||||
view = ConsoleView(maze)
|
||||
solver = MazeSolver(maze, BFSStrategy())
|
||||
solver.attach(view)
|
||||
|
||||
print("Запускаем поиск с наблюдателем...")
|
||||
path = solver.solve()
|
||||
|
||||
view.set_solution_path(path)
|
||||
view.render()
|
||||
|
||||
return view
|
||||
|
||||
def demo_command(maze: Maze, view: ConsoleView):
|
||||
"""Демонстрация паттерна Command."""
|
||||
print("\n" + "=" * 60)
|
||||
print("ДЕМОНСТРАЦИЯ ПАТТЕРНА COMMAND")
|
||||
print("=" * 60)
|
||||
|
||||
player = Player(maze, maze.start_cell)
|
||||
view.set_player_position(player.position)
|
||||
|
||||
print("Управление игроком:")
|
||||
print(" W/A/S/D - движение, Z - отмена, Q - выход")
|
||||
|
||||
history = []
|
||||
|
||||
while True:
|
||||
view.render()
|
||||
|
||||
cmd = input("Ваш ход: ").strip().lower()
|
||||
|
||||
if cmd == 'q':
|
||||
break
|
||||
elif cmd == 'z':
|
||||
if history:
|
||||
last_cmd = history.pop()
|
||||
last_cmd.undo()
|
||||
view.set_player_position(player.position)
|
||||
print("Последний ход отменён")
|
||||
else:
|
||||
print("Нечего отменять")
|
||||
elif cmd in MoveCommand.DIRECTIONS:
|
||||
move_cmd = MoveCommand(player, maze, cmd)
|
||||
if move_cmd.execute():
|
||||
history.append(move_cmd)
|
||||
view.set_player_position(player.position)
|
||||
|
||||
if player.position == maze.exit_cell:
|
||||
print("\n🎉 ПОБЕДА! ВЫ НАШЛИ ВЫХОД! 🎉")
|
||||
view.render()
|
||||
break
|
||||
else:
|
||||
print("Туда нельзя пройти")
|
||||
else:
|
||||
print("Неизвестная команда")
|
||||
|
||||
print("Игра завершена")
|
||||
|
||||
def run_experiments():
|
||||
"""Запуск экспериментального сравнения."""
|
||||
print("\n" + "=" * 60)
|
||||
print("ЭКСПЕРИМЕНТАЛЬНОЕ СРАВНЕНИЕ АЛГОРИТМОВ")
|
||||
print("=" * 60)
|
||||
|
||||
builder = TextFieldMazeBuilder()
|
||||
benchmark = Benchmark()
|
||||
|
||||
maze_files = ["small.txt", "empty.txt", "no_exit.txt"]
|
||||
|
||||
for maze_file in maze_files:
|
||||
try:
|
||||
maze = builder.build_from_file(f"mazes/{maze_file}")
|
||||
print(f"\nТестируем: {maze_file} ({maze.width}×{maze.height})")
|
||||
benchmark.run_on_maze(maze, maze_file, iterations=5)
|
||||
except FileNotFoundError:
|
||||
print(f"Файл {maze_file} не найден")
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: {e}")
|
||||
|
||||
benchmark.print_summary()
|
||||
benchmark.save_to_csv()
|
||||
|
||||
def main():
|
||||
"""Главная функция."""
|
||||
print("=" * 60)
|
||||
print("ПРОГРАММА ПОИСКА ВЫХОДА ИЗ ЛАБИРИНТА")
|
||||
print("Паттерны: Builder, Strategy, Observer, Command")
|
||||
print("=" * 60)
|
||||
|
||||
create_test_mazes()
|
||||
maze = demo_builder_and_strategy()
|
||||
view = demo_observer(maze)
|
||||
demo_command(maze, view)
|
||||
run_experiments()
|
||||
|
||||
print("\nПрограмма завершена!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3a6bb811-80ad-4ef5-95b6-0b7cffc6545e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from dataclasses import dataclass\n",
|
||||
"from typing import Optional\n",
|
||||
"\n",
|
||||
"@dataclass\n",
|
||||
"class Cell:\n",
|
||||
" \"\"\"Клетка лабиринта.\"\"\"\n",
|
||||
" x: int\n",
|
||||
" y: int\n",
|
||||
" is_wall: bool = False\n",
|
||||
" is_start: bool = False\n",
|
||||
" is_exit: bool = False\n",
|
||||
" weight: int = 1 # Для взвешенных лабиринтов (доп. задание)\n",
|
||||
" \n",
|
||||
" def is_passable(self) -> bool:\n",
|
||||
" \"\"\"Проходима ли клетка.\"\"\"\n",
|
||||
" return not self.is_wall\n",
|
||||
" \n",
|
||||
" def __hash__(self) -> int:\n",
|
||||
" return hash((self.x, self.y))\n",
|
||||
" \n",
|
||||
" def __eq__(self, other) -> bool:\n",
|
||||
" if not isinstance(other, Cell):\n",
|
||||
" return False\n",
|
||||
" return self.x == other.x and self.y == other.y"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
31
MininaVD/docs2/data2/modelsCell.py
Normal file
31
MininaVD/docs2/data2/modelsCell.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
@dataclass
|
||||
class Cell:
|
||||
"""Клетка лабиринта."""
|
||||
x: int
|
||||
y: int
|
||||
is_wall: bool = False
|
||||
is_start: bool = False
|
||||
is_exit: bool = False
|
||||
weight: int = 1 # Для взвешенных лабиринтов (доп. задание)
|
||||
|
||||
def is_passable(self) -> bool:
|
||||
"""Проходима ли клетка."""
|
||||
return not self.is_wall
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.x, self.y))
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if not isinstance(other, Cell):
|
||||
return False
|
||||
return self.x == other.x and self.y == other.y
|
||||
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bc164689-22b6-4efd-bdd7-6a9913be9303",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List, Optional, Tuple\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"\n",
|
||||
"class Maze:\n",
|
||||
" \"\"\"Модель лабиринта.\"\"\"\n",
|
||||
" \n",
|
||||
" def __init__(self, width: int = 0, height: int = 0):\n",
|
||||
" self.width = width\n",
|
||||
" self.height = height\n",
|
||||
" self._cells: List[List[Optional[Cell]]] = [\n",
|
||||
" [None for _ in range(width)] for _ in range(height)\n",
|
||||
" ]\n",
|
||||
" self.start_cell: Optional[Cell] = None\n",
|
||||
" self.exit_cell: Optional[Cell] = None\n",
|
||||
" \n",
|
||||
" def set_cell(self, x: int, y: int, cell: Cell) -> None:\n",
|
||||
" \"\"\"Установить клетку.\"\"\"\n",
|
||||
" if 0 <= x < self.width and 0 <= y < self.height:\n",
|
||||
" self._cells[y][x] = cell\n",
|
||||
" \n",
|
||||
" def get_cell(self, x: int, y: int) -> Optional[Cell]:\n",
|
||||
" \"\"\"Получить клетку по координатам.\"\"\"\n",
|
||||
" if 0 <= x < self.width and 0 <= y < self.height:\n",
|
||||
" return self._cells[y][x]\n",
|
||||
" return None\n",
|
||||
" \n",
|
||||
" def get_neighbors(self, cell: Cell) -> List[Cell]:\n",
|
||||
" \"\"\"Получить проходимых соседей клетки (вверх, вниз, влево, вправо).\"\"\"\n",
|
||||
" neighbors = []\n",
|
||||
" directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] # вверх, вниз, влево, вправо\n",
|
||||
" \n",
|
||||
" for dx, dy in directions:\n",
|
||||
" nx, ny = cell.x + dx, cell.y + dy\n",
|
||||
" neighbor = self.get_cell(nx, ny)\n",
|
||||
" if neighbor and neighbor.is_passable():\n",
|
||||
" neighbors.append(neighbor)\n",
|
||||
" \n",
|
||||
" return neighbors\n",
|
||||
" \n",
|
||||
" def get_all_cells(self) -> List[Cell]:\n",
|
||||
" \"\"\"Получить все клетки лабиринта.\"\"\"\n",
|
||||
" cells = []\n",
|
||||
" for y in range(self.height):\n",
|
||||
" for x in range(self.width):\n",
|
||||
" cell = self.get_cell(x, y)\n",
|
||||
" if cell:\n",
|
||||
" cells.append(cell)\n",
|
||||
" return cells"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
55
MininaVD/docs2/data2/modelsMaze.py
Normal file
55
MininaVD/docs2/data2/modelsMaze.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from typing import List, Optional, Tuple
|
||||
from modelsCell import Cell
|
||||
|
||||
class Maze:
|
||||
"""Модель лабиринта."""
|
||||
|
||||
def __init__(self, width: int = 0, height: int = 0):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self._cells: List[List[Optional[Cell]]] = [
|
||||
[None for _ in range(width)] for _ in range(height)
|
||||
]
|
||||
self.start_cell: Optional[Cell] = None
|
||||
self.exit_cell: Optional[Cell] = None
|
||||
|
||||
def set_cell(self, x: int, y: int, cell: Cell) -> None:
|
||||
"""Установить клетку."""
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
self._cells[y][x] = cell
|
||||
|
||||
def get_cell(self, x: int, y: int) -> Optional[Cell]:
|
||||
"""Получить клетку по координатам."""
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
return self._cells[y][x]
|
||||
return None
|
||||
|
||||
def get_neighbors(self, cell: Cell) -> List[Cell]:
|
||||
"""Получить проходимых соседей клетки (вверх, вниз, влево, вправо)."""
|
||||
neighbors = []
|
||||
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] # вверх, вниз, влево, вправо
|
||||
|
||||
for dx, dy in directions:
|
||||
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
|
||||
|
||||
def get_all_cells(self) -> List[Cell]:
|
||||
"""Получить все клетки лабиринта."""
|
||||
cells = []
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
cell = self.get_cell(x, y)
|
||||
if cell:
|
||||
cells.append(cell)
|
||||
return cells
|
||||
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1ef30a86-b41f-49eb-84c3-5d425614cbdd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"from typing import List, Optional\n",
|
||||
"from dataclasses import dataclass, field\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"from strategiesPathfinding_strategy import PathFindingStrategy\n",
|
||||
"from visualizationObserver import Observer\n",
|
||||
"\n",
|
||||
"@dataclass\n",
|
||||
"class SearchStats:\n",
|
||||
" \"\"\"Статистика поиска.\"\"\"\n",
|
||||
" algorithm_name: str\n",
|
||||
" time_ms: float\n",
|
||||
" visited_cells: int\n",
|
||||
" path_length: int\n",
|
||||
" path_found: bool = True\n",
|
||||
"\n",
|
||||
"class MazeSolver:\n",
|
||||
" \"\"\"\n",
|
||||
" Оркестратор для решения лабиринта.\n",
|
||||
" Использует паттерн Strategy для алгоритмов поиска.\n",
|
||||
" Поддерживает Observer для уведомлений.\n",
|
||||
" \"\"\"\n",
|
||||
" \n",
|
||||
" def __init__(self, maze: Maze, strategy: Optional[PathFindingStrategy] = None):\n",
|
||||
" self.maze = maze\n",
|
||||
" self._strategy = strategy\n",
|
||||
" self._observers: List[Observer] = []\n",
|
||||
" self._last_path: List[Cell] = []\n",
|
||||
" self._last_stats: Optional[SearchStats] = None\n",
|
||||
" \n",
|
||||
" def set_strategy(self, strategy: PathFindingStrategy) -> None:\n",
|
||||
" \"\"\"Динамическая смена стратегии.\"\"\"\n",
|
||||
" self._strategy = strategy\n",
|
||||
" self._notify(f\"Стратегия изменена на {strategy.name}\")\n",
|
||||
" \n",
|
||||
" def attach(self, observer: Observer) -> None:\n",
|
||||
" \"\"\"Подписать наблюдателя.\"\"\"\n",
|
||||
" self._observers.append(observer)\n",
|
||||
" \n",
|
||||
" def detach(self, observer: Observer) -> None:\n",
|
||||
" \"\"\"Отписать наблюдателя.\"\"\"\n",
|
||||
" if observer in self._observers:\n",
|
||||
" self._observers.remove(observer)\n",
|
||||
" \n",
|
||||
" def _notify(self, event: str) -> None:\n",
|
||||
" \"\"\"Уведомить всех наблюдателей.\"\"\"\n",
|
||||
" for observer in self._observers:\n",
|
||||
" observer.update(event)\n",
|
||||
" \n",
|
||||
" def solve(self) -> List[Cell]:\n",
|
||||
" \"\"\"\n",
|
||||
" Выполнить поиск пути с текущей стратегией.\n",
|
||||
" Возвращает путь (список клеток).\n",
|
||||
" \"\"\"\n",
|
||||
" if self._strategy is None:\n",
|
||||
" raise ValueError(\"Стратегия не установлена\")\n",
|
||||
" \n",
|
||||
" if not self.maze.start_cell or not self.maze.exit_cell:\n",
|
||||
" raise ValueError(\"Лабиринт не имеет старта или выхода\")\n",
|
||||
" \n",
|
||||
" self._notify(f\"Начинаем поиск пути с использованием {self._strategy.name}...\")\n",
|
||||
" \n",
|
||||
" start_time = time.perf_counter()\n",
|
||||
" path = self._strategy.find_path(self.maze, self.maze.start_cell, self.maze.exit_cell)\n",
|
||||
" end_time = time.perf_counter()\n",
|
||||
" \n",
|
||||
" time_ms = (end_time - start_time) * 1000\n",
|
||||
" \n",
|
||||
" # Получаем количество посещённых клеток из стратегии\n",
|
||||
" visited_cells = getattr(self._strategy, 'last_visited_count', 0)\n",
|
||||
" \n",
|
||||
" self._last_path = path\n",
|
||||
" self._last_stats = SearchStats(\n",
|
||||
" algorithm_name=self._strategy.name,\n",
|
||||
" time_ms=time_ms,\n",
|
||||
" visited_cells=visited_cells,\n",
|
||||
" path_length=len(path),\n",
|
||||
" path_found=len(path) > 0\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" if path:\n",
|
||||
" self._notify(f\"Путь найден! Длина: {len(path)}, время: {time_ms:.2f} мс, посещено: {visited_cells}\")\n",
|
||||
" else:\n",
|
||||
" self._notify(f\"Путь не найден! Время: {time_ms:.2f} мс, посещено: {visited_cells}\")\n",
|
||||
" \n",
|
||||
" return path\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def last_path(self) -> List[Cell]:\n",
|
||||
" return self._last_path\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def last_stats(self) -> Optional[SearchStats]:\n",
|
||||
" return self._last_stats"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
102
MininaVD/docs2/data2/solverMaze_solver.py
Normal file
102
MininaVD/docs2/data2/solverMaze_solver.py
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
import time
|
||||
from typing import List, Optional
|
||||
from dataclasses import dataclass, field
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
from strategiesPathfinding_strategy import PathFindingStrategy
|
||||
from visualizationObserver import Observer
|
||||
|
||||
@dataclass
|
||||
class SearchStats:
|
||||
"""Статистика поиска."""
|
||||
algorithm_name: str
|
||||
time_ms: float
|
||||
visited_cells: int
|
||||
path_length: int
|
||||
path_found: bool = True
|
||||
|
||||
class MazeSolver:
|
||||
"""
|
||||
Оркестратор для решения лабиринта.
|
||||
Использует паттерн Strategy для алгоритмов поиска.
|
||||
Поддерживает Observer для уведомлений.
|
||||
"""
|
||||
|
||||
def __init__(self, maze: Maze, strategy: Optional[PathFindingStrategy] = None):
|
||||
self.maze = maze
|
||||
self._strategy = strategy
|
||||
self._observers: List[Observer] = []
|
||||
self._last_path: List[Cell] = []
|
||||
self._last_stats: Optional[SearchStats] = None
|
||||
|
||||
def set_strategy(self, strategy: PathFindingStrategy) -> None:
|
||||
"""Динамическая смена стратегии."""
|
||||
self._strategy = strategy
|
||||
self._notify(f"Стратегия изменена на {strategy.name}")
|
||||
|
||||
def attach(self, observer: Observer) -> None:
|
||||
"""Подписать наблюдателя."""
|
||||
self._observers.append(observer)
|
||||
|
||||
def detach(self, observer: Observer) -> None:
|
||||
"""Отписать наблюдателя."""
|
||||
if observer in self._observers:
|
||||
self._observers.remove(observer)
|
||||
|
||||
def _notify(self, event: str) -> None:
|
||||
"""Уведомить всех наблюдателей."""
|
||||
for observer in self._observers:
|
||||
observer.update(event)
|
||||
|
||||
def solve(self) -> List[Cell]:
|
||||
"""
|
||||
Выполнить поиск пути с текущей стратегией.
|
||||
Возвращает путь (список клеток).
|
||||
"""
|
||||
if self._strategy is None:
|
||||
raise ValueError("Стратегия не установлена")
|
||||
|
||||
if not self.maze.start_cell or not self.maze.exit_cell:
|
||||
raise ValueError("Лабиринт не имеет старта или выхода")
|
||||
|
||||
self._notify(f"Начинаем поиск пути с использованием {self._strategy.name}...")
|
||||
|
||||
start_time = time.perf_counter()
|
||||
path = self._strategy.find_path(self.maze, self.maze.start_cell, self.maze.exit_cell)
|
||||
end_time = time.perf_counter()
|
||||
|
||||
time_ms = (end_time - start_time) * 1000
|
||||
|
||||
# Получаем количество посещённых клеток из стратегии
|
||||
visited_cells = getattr(self._strategy, 'last_visited_count', 0)
|
||||
|
||||
self._last_path = path
|
||||
self._last_stats = SearchStats(
|
||||
algorithm_name=self._strategy.name,
|
||||
time_ms=time_ms,
|
||||
visited_cells=visited_cells,
|
||||
path_length=len(path),
|
||||
path_found=len(path) > 0
|
||||
)
|
||||
|
||||
if path:
|
||||
self._notify(f"Путь найден! Длина: {len(path)}, время: {time_ms:.2f} мс, посещено: {visited_cells}")
|
||||
else:
|
||||
self._notify(f"Путь не найден! Время: {time_ms:.2f} мс, посещено: {visited_cells}")
|
||||
|
||||
return path
|
||||
|
||||
@property
|
||||
def last_path(self) -> List[Cell]:
|
||||
return self._last_path
|
||||
|
||||
@property
|
||||
def last_stats(self) -> Optional[SearchStats]:
|
||||
return self._last_stats
|
||||
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f8e6c2ad-712c-44a0-8ebc-ed0d67234c05",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import heapq\n",
|
||||
"from typing import List, Dict, Optional, Tuple\n",
|
||||
"from strategiesPathfinding_strategy import PathFindingStrategy\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"\n",
|
||||
"class AStarStrategy(PathFindingStrategy):\n",
|
||||
" \"\"\"Алгоритм A* с манхэттенской эвристикой.\"\"\"\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def name(self) -> str:\n",
|
||||
" return \"A*\"\n",
|
||||
" \n",
|
||||
" def _heuristic(self, a: Cell, b: Cell) -> int:\n",
|
||||
" \"\"\"Манхэттенское расстояние.\"\"\"\n",
|
||||
" return abs(a.x - b.x) + abs(a.y - b.y)\n",
|
||||
" \n",
|
||||
" def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:\n",
|
||||
" if start == exit_cell:\n",
|
||||
" return [start]\n",
|
||||
" \n",
|
||||
" # Приоритетная очередь: (f_score, counter, cell)\n",
|
||||
" open_set = [(0, 0, start)]\n",
|
||||
" counter = 1\n",
|
||||
" \n",
|
||||
" came_from: Dict[Cell, Optional[Cell]] = {}\n",
|
||||
" \n",
|
||||
" g_score: Dict[Cell, float] = {start: 0}\n",
|
||||
" f_score: Dict[Cell, float] = {start: self._heuristic(start, exit_cell)}\n",
|
||||
" \n",
|
||||
" visited_count = 0\n",
|
||||
" \n",
|
||||
" while open_set:\n",
|
||||
" current_f, _, current = heapq.heappop(open_set)\n",
|
||||
" visited_count += 1\n",
|
||||
" \n",
|
||||
" if current == exit_cell:\n",
|
||||
" self._last_visited_count = visited_count\n",
|
||||
" return self._reconstruct_path(came_from, start, current)\n",
|
||||
" \n",
|
||||
" for neighbor in maze.get_neighbors(current):\n",
|
||||
" tentative_g_score = g_score.get(current, float('inf')) + 1\n",
|
||||
" \n",
|
||||
" if tentative_g_score < g_score.get(neighbor, float('inf')):\n",
|
||||
" came_from[neighbor] = current\n",
|
||||
" g_score[neighbor] = tentative_g_score\n",
|
||||
" f_score[neighbor] = tentative_g_score + self._heuristic(neighbor, exit_cell)\n",
|
||||
" heapq.heappush(open_set, (f_score[neighbor], counter, neighbor))\n",
|
||||
" counter += 1\n",
|
||||
" \n",
|
||||
" self._last_visited_count = visited_count\n",
|
||||
" return []\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def last_visited_count(self) -> int:\n",
|
||||
" return getattr(self, '_last_visited_count', 0)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
63
MininaVD/docs2/data2/strategiesA_star_strategy.py
Normal file
63
MininaVD/docs2/data2/strategiesA_star_strategy.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
import heapq
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from strategiesPathfinding_strategy import PathFindingStrategy
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
|
||||
class AStarStrategy(PathFindingStrategy):
|
||||
"""Алгоритм A* с манхэттенской эвристикой."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "A*"
|
||||
|
||||
def _heuristic(self, a: Cell, b: Cell) -> int:
|
||||
"""Манхэттенское расстояние."""
|
||||
return abs(a.x - b.x) + abs(a.y - b.y)
|
||||
|
||||
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
|
||||
if start == exit_cell:
|
||||
return [start]
|
||||
|
||||
# Приоритетная очередь: (f_score, counter, cell)
|
||||
open_set = [(0, 0, start)]
|
||||
counter = 1
|
||||
|
||||
came_from: Dict[Cell, Optional[Cell]] = {}
|
||||
|
||||
g_score: Dict[Cell, float] = {start: 0}
|
||||
f_score: Dict[Cell, float] = {start: self._heuristic(start, exit_cell)}
|
||||
|
||||
visited_count = 0
|
||||
|
||||
while open_set:
|
||||
current_f, _, current = heapq.heappop(open_set)
|
||||
visited_count += 1
|
||||
|
||||
if current == exit_cell:
|
||||
self._last_visited_count = visited_count
|
||||
return self._reconstruct_path(came_from, start, current)
|
||||
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
tentative_g_score = g_score.get(current, float('inf')) + 1
|
||||
|
||||
if tentative_g_score < g_score.get(neighbor, float('inf')):
|
||||
came_from[neighbor] = current
|
||||
g_score[neighbor] = tentative_g_score
|
||||
f_score[neighbor] = tentative_g_score + self._heuristic(neighbor, exit_cell)
|
||||
heapq.heappush(open_set, (f_score[neighbor], counter, neighbor))
|
||||
counter += 1
|
||||
|
||||
self._last_visited_count = visited_count
|
||||
return []
|
||||
|
||||
@property
|
||||
def last_visited_count(self) -> int:
|
||||
return getattr(self, '_last_visited_count', 0)
|
||||
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "263fab53-6f76-4853-b167-a51b1198ddee",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from collections import deque\n",
|
||||
"from typing import List, Dict, Optional\n",
|
||||
"from strategiesPathfinding_strategy import PathFindingStrategy\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"\n",
|
||||
"class BFSStrategy(PathFindingStrategy):\n",
|
||||
" \"\"\"Поиск в ширину - гарантирует кратчайший путь.\"\"\"\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def name(self) -> str:\n",
|
||||
" return \"BFS\"\n",
|
||||
" \n",
|
||||
" def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:\n",
|
||||
" if start == exit_cell:\n",
|
||||
" return [start]\n",
|
||||
" \n",
|
||||
" queue = deque([start])\n",
|
||||
" came_from: Dict[Cell, Optional[Cell]] = {start: None}\n",
|
||||
" visited_count = 0 # Для статистики\n",
|
||||
" \n",
|
||||
" while queue:\n",
|
||||
" current = queue.popleft()\n",
|
||||
" visited_count += 1\n",
|
||||
" \n",
|
||||
" if current == exit_cell:\n",
|
||||
" # Сохраняем количество посещённых клеток для статистики\n",
|
||||
" self._last_visited_count = visited_count\n",
|
||||
" return self._reconstruct_path(came_from, start, current)\n",
|
||||
" \n",
|
||||
" for neighbor in maze.get_neighbors(current):\n",
|
||||
" if neighbor not in came_from:\n",
|
||||
" came_from[neighbor] = current\n",
|
||||
" queue.append(neighbor)\n",
|
||||
" \n",
|
||||
" self._last_visited_count = visited_count\n",
|
||||
" return []\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def last_visited_count(self) -> int:\n",
|
||||
" return getattr(self, '_last_visited_count', 0)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
48
MininaVD/docs2/data2/strategiesBfs_strategy.py
Normal file
48
MininaVD/docs2/data2/strategiesBfs_strategy.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from collections import deque
|
||||
from typing import List, Dict, Optional
|
||||
from strategiesPathfinding_strategy import PathFindingStrategy
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
|
||||
class BFSStrategy(PathFindingStrategy):
|
||||
"""Поиск в ширину - гарантирует кратчайший путь."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "BFS"
|
||||
|
||||
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
|
||||
if start == exit_cell:
|
||||
return [start]
|
||||
|
||||
queue = deque([start])
|
||||
came_from: Dict[Cell, Optional[Cell]] = {start: None}
|
||||
visited_count = 0 # Для статистики
|
||||
|
||||
while queue:
|
||||
current = queue.popleft()
|
||||
visited_count += 1
|
||||
|
||||
if current == exit_cell:
|
||||
# Сохраняем количество посещённых клеток для статистики
|
||||
self._last_visited_count = visited_count
|
||||
return self._reconstruct_path(came_from, start, current)
|
||||
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
if neighbor not in came_from:
|
||||
came_from[neighbor] = current
|
||||
queue.append(neighbor)
|
||||
|
||||
self._last_visited_count = visited_count
|
||||
return []
|
||||
|
||||
@property
|
||||
def last_visited_count(self) -> int:
|
||||
return getattr(self, '_last_visited_count', 0)
|
||||
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4d8d9af1-63da-4f25-9140-a0b3c58cb96d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List, Dict, Optional\n",
|
||||
"from strategiesPathfinding_strategy import PathFindingStrategy\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"\n",
|
||||
"class DFSStrategy(PathFindingStrategy):\n",
|
||||
" \"\"\"Поиск в глубину - быстрый, но не обязательно кратчайший.\"\"\"\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def name(self) -> str:\n",
|
||||
" return \"DFS\"\n",
|
||||
" \n",
|
||||
" def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:\n",
|
||||
" if start == exit_cell:\n",
|
||||
" return [start]\n",
|
||||
" \n",
|
||||
" stack = [start]\n",
|
||||
" came_from: Dict[Cell, Optional[Cell]] = {start: None}\n",
|
||||
" visited_count = 0\n",
|
||||
" \n",
|
||||
" while stack:\n",
|
||||
" current = stack.pop()\n",
|
||||
" visited_count += 1\n",
|
||||
" \n",
|
||||
" if current == exit_cell:\n",
|
||||
" self._last_visited_count = visited_count\n",
|
||||
" return self._reconstruct_path(came_from, start, current)\n",
|
||||
" \n",
|
||||
" for neighbor in maze.get_neighbors(current):\n",
|
||||
" if neighbor not in came_from:\n",
|
||||
" came_from[neighbor] = current\n",
|
||||
" stack.append(neighbor)\n",
|
||||
" \n",
|
||||
" self._last_visited_count = visited_count\n",
|
||||
" return []\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" def last_visited_count(self) -> int:\n",
|
||||
" return getattr(self, '_last_visited_count', 0)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
46
MininaVD/docs2/data2/strategiesDfs_strategy.py
Normal file
46
MininaVD/docs2/data2/strategiesDfs_strategy.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from typing import List, Dict, Optional
|
||||
from strategiesPathfinding_strategy import PathFindingStrategy
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
|
||||
class DFSStrategy(PathFindingStrategy):
|
||||
"""Поиск в глубину - быстрый, но не обязательно кратчайший."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "DFS"
|
||||
|
||||
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
|
||||
if start == exit_cell:
|
||||
return [start]
|
||||
|
||||
stack = [start]
|
||||
came_from: Dict[Cell, Optional[Cell]] = {start: None}
|
||||
visited_count = 0
|
||||
|
||||
while stack:
|
||||
current = stack.pop()
|
||||
visited_count += 1
|
||||
|
||||
if current == exit_cell:
|
||||
self._last_visited_count = visited_count
|
||||
return self._reconstruct_path(came_from, start, current)
|
||||
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
if neighbor not in came_from:
|
||||
came_from[neighbor] = current
|
||||
stack.append(neighbor)
|
||||
|
||||
self._last_visited_count = visited_count
|
||||
return []
|
||||
|
||||
@property
|
||||
def last_visited_count(self) -> int:
|
||||
return getattr(self, '_last_visited_count', 0)
|
||||
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3f8f5923-00bf-4fc2-88e9-6a51d6183c5b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from abc import ABC, abstractmethod\n",
|
||||
"from typing import List, Optional\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"\n",
|
||||
"class PathFindingStrategy(ABC):\n",
|
||||
" \"\"\"Интерфейс стратегии поиска пути (паттерн Strategy).\"\"\"\n",
|
||||
" \n",
|
||||
" @abstractmethod\n",
|
||||
" def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:\n",
|
||||
" \"\"\"\n",
|
||||
" Найти путь от start до exit_cell.\n",
|
||||
" Возвращает список клеток пути (включая start и exit) или пустой список.\n",
|
||||
" \"\"\"\n",
|
||||
" pass\n",
|
||||
" \n",
|
||||
" @property\n",
|
||||
" @abstractmethod\n",
|
||||
" def name(self) -> str:\n",
|
||||
" \"\"\"Имя стратегии для отчётов.\"\"\"\n",
|
||||
" pass\n",
|
||||
" \n",
|
||||
" def _reconstruct_path(self, came_from: dict, start: Cell, current: Cell) -> List[Cell]:\n",
|
||||
" \"\"\"Восстановить путь из словаря предков.\"\"\"\n",
|
||||
" path = []\n",
|
||||
" while current != start:\n",
|
||||
" path.append(current)\n",
|
||||
" current = came_from.get(current)\n",
|
||||
" if current is None:\n",
|
||||
" return []\n",
|
||||
" path.append(start)\n",
|
||||
" path.reverse()\n",
|
||||
" return path"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
40
MininaVD/docs2/data2/strategiesPathfinding_strategy.py
Normal file
40
MininaVD/docs2/data2/strategiesPathfinding_strategy.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Optional
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
|
||||
class PathFindingStrategy(ABC):
|
||||
"""Интерфейс стратегии поиска пути (паттерн Strategy)."""
|
||||
|
||||
@abstractmethod
|
||||
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
|
||||
"""
|
||||
Найти путь от start до exit_cell.
|
||||
Возвращает список клеток пути (включая start и exit) или пустой список.
|
||||
"""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def name(self) -> str:
|
||||
"""Имя стратегии для отчётов."""
|
||||
pass
|
||||
|
||||
def _reconstruct_path(self, came_from: dict, start: Cell, current: Cell) -> List[Cell]:
|
||||
"""Восстановить путь из словаря предков."""
|
||||
path = []
|
||||
while current != start:
|
||||
path.append(current)
|
||||
current = came_from.get(current)
|
||||
if current is None:
|
||||
return []
|
||||
path.append(start)
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9d15670f-4ae1-48f5-801c-7a1a84cafba3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from typing import List, Optional, Set\n",
|
||||
"from modelsMaze import Maze\n",
|
||||
"from modelsCell import Cell\n",
|
||||
"from visualizationObserver import Observer\n",
|
||||
"\n",
|
||||
"class ConsoleView(Observer):\n",
|
||||
" \"\"\"Консольная визуализация лабиринта.\"\"\"\n",
|
||||
" \n",
|
||||
" # Символы для отображения\n",
|
||||
" SYMBOLS = {\n",
|
||||
" 'wall': '█',\n",
|
||||
" 'path': '·',\n",
|
||||
" 'start': 'S',\n",
|
||||
" 'exit': 'E',\n",
|
||||
" 'player': 'P',\n",
|
||||
" 'solution': '★'\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" def __init__(self, maze: Maze):\n",
|
||||
" self.maze = maze\n",
|
||||
" self.player_pos: Optional[Cell] = None\n",
|
||||
" self.solution_path: Set[Cell] = set()\n",
|
||||
" self.messages: List[str] = []\n",
|
||||
" \n",
|
||||
" def update(self, event: str) -> None:\n",
|
||||
" \"\"\"Обработка событий от MazeSolver.\"\"\"\n",
|
||||
" self.messages.append(f\"[СОБЫТИЕ] {event}\")\n",
|
||||
" self.render()\n",
|
||||
" \n",
|
||||
" def set_solution_path(self, path: List[Cell]) -> None:\n",
|
||||
" \"\"\"Установить найденный путь для отображения.\"\"\"\n",
|
||||
" self.solution_path = set(path)\n",
|
||||
" \n",
|
||||
" def set_player_position(self, cell: Cell) -> None:\n",
|
||||
" \"\"\"Установить позицию игрока.\"\"\"\n",
|
||||
" self.player_pos = cell\n",
|
||||
" \n",
|
||||
" def render(self) -> None:\n",
|
||||
" \"\"\"Отрисовать лабиринт в консоли.\"\"\"\n",
|
||||
" # Очистка консоли (опционально)\n",
|
||||
" # os.system('cls' if os.name == 'nt' else 'clear')\n",
|
||||
" \n",
|
||||
" print(\"\\n\" + \"=\" * (self.maze.width * 2 + 4))\n",
|
||||
" print(f\"Лабиринт {self.maze.width}×{self.maze.height}\")\n",
|
||||
" print(\"=\" * (self.maze.width * 2 + 4))\n",
|
||||
" \n",
|
||||
" for y in range(self.maze.height):\n",
|
||||
" row = \"\"\n",
|
||||
" for x in range(self.maze.width):\n",
|
||||
" cell = self.maze.get_cell(x, y)\n",
|
||||
" if not cell:\n",
|
||||
" row += \" \"\n",
|
||||
" continue\n",
|
||||
" \n",
|
||||
" if self.player_pos and cell == self.player_pos:\n",
|
||||
" row += self.SYMBOLS['player'] + \" \"\n",
|
||||
" elif cell.is_start:\n",
|
||||
" row += self.SYMBOLS['start'] + \" \"\n",
|
||||
" elif cell.is_exit:\n",
|
||||
" row += self.SYMBOLS['exit'] + \" \"\n",
|
||||
" elif cell in self.solution_path:\n",
|
||||
" row += self.SYMBOLS['solution'] + \" \"\n",
|
||||
" elif cell.is_wall:\n",
|
||||
" row += self.SYMBOLS['wall'] * 2\n",
|
||||
" else:\n",
|
||||
" row += self.SYMBOLS['path'] * 2\n",
|
||||
" print(row)\n",
|
||||
" \n",
|
||||
" print(\"-\" * (self.maze.width * 2 + 4))\n",
|
||||
" \n",
|
||||
" # Показать последние сообщения\n",
|
||||
" if self.messages:\n",
|
||||
" print(\"Последние события:\")\n",
|
||||
" for msg in self.messages[-3:]:\n",
|
||||
" print(f\" {msg}\")\n",
|
||||
" \n",
|
||||
" print()\n",
|
||||
" \n",
|
||||
" def clear_messages(self) -> None:\n",
|
||||
" \"\"\"Очистить сообщения.\"\"\"\n",
|
||||
" self.messages.clear()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
89
MininaVD/docs2/data2/visualizationConsole_view.py
Normal file
89
MininaVD/docs2/data2/visualizationConsole_view.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
import os
|
||||
from typing import List, Optional, Set
|
||||
from modelsMaze import Maze
|
||||
from modelsCell import Cell
|
||||
from visualizationObserver import Observer
|
||||
|
||||
class ConsoleView(Observer):
|
||||
"""Консольная визуализация лабиринта."""
|
||||
|
||||
# Символы для отображения
|
||||
SYMBOLS = {
|
||||
'wall': '█',
|
||||
'path': '·',
|
||||
'start': 'S',
|
||||
'exit': 'E',
|
||||
'player': 'P',
|
||||
'solution': '★'
|
||||
}
|
||||
|
||||
def __init__(self, maze: Maze):
|
||||
self.maze = maze
|
||||
self.player_pos: Optional[Cell] = None
|
||||
self.solution_path: Set[Cell] = set()
|
||||
self.messages: List[str] = []
|
||||
|
||||
def update(self, event: str) -> None:
|
||||
"""Обработка событий от MazeSolver."""
|
||||
self.messages.append(f"[СОБЫТИЕ] {event}")
|
||||
self.render()
|
||||
|
||||
def set_solution_path(self, path: List[Cell]) -> None:
|
||||
"""Установить найденный путь для отображения."""
|
||||
self.solution_path = set(path)
|
||||
|
||||
def set_player_position(self, cell: Cell) -> None:
|
||||
"""Установить позицию игрока."""
|
||||
self.player_pos = cell
|
||||
|
||||
def render(self) -> None:
|
||||
"""Отрисовать лабиринт в консоли."""
|
||||
# Очистка консоли (опционально)
|
||||
# os.system('cls' if os.name == 'nt' else 'clear')
|
||||
|
||||
print("\n" + "=" * (self.maze.width * 2 + 4))
|
||||
print(f"Лабиринт {self.maze.width}×{self.maze.height}")
|
||||
print("=" * (self.maze.width * 2 + 4))
|
||||
|
||||
for y in range(self.maze.height):
|
||||
row = ""
|
||||
for x in range(self.maze.width):
|
||||
cell = self.maze.get_cell(x, y)
|
||||
if not cell:
|
||||
row += " "
|
||||
continue
|
||||
|
||||
if self.player_pos and cell == self.player_pos:
|
||||
row += self.SYMBOLS['player'] + " "
|
||||
elif cell.is_start:
|
||||
row += self.SYMBOLS['start'] + " "
|
||||
elif cell.is_exit:
|
||||
row += self.SYMBOLS['exit'] + " "
|
||||
elif cell in self.solution_path:
|
||||
row += self.SYMBOLS['solution'] + " "
|
||||
elif cell.is_wall:
|
||||
row += self.SYMBOLS['wall'] * 2
|
||||
else:
|
||||
row += self.SYMBOLS['path'] * 2
|
||||
print(row)
|
||||
|
||||
print("-" * (self.maze.width * 2 + 4))
|
||||
|
||||
# Показать последние сообщения
|
||||
if self.messages:
|
||||
print("Последние события:")
|
||||
for msg in self.messages[-3:]:
|
||||
print(f" {msg}")
|
||||
|
||||
print()
|
||||
|
||||
def clear_messages(self) -> None:
|
||||
"""Очистить сообщения."""
|
||||
self.messages.clear()
|
||||
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8998420f-2c73-4f8a-a102-cc403777f3e9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from abc import ABC, abstractmethod\n",
|
||||
"\n",
|
||||
"class Observer(ABC):\n",
|
||||
" \"\"\"Интерфейс наблюдателя (паттерн Observer).\"\"\"\n",
|
||||
" \n",
|
||||
" @abstractmethod\n",
|
||||
" def update(self, event: str) -> None:\n",
|
||||
" \"\"\"Обработчик события.\"\"\"\n",
|
||||
" pass"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python [conda env:base] *",
|
||||
"language": "python",
|
||||
"name": "conda-base-py"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
16
MininaVD/docs2/data2/visualizationObserver.py
Normal file
16
MininaVD/docs2/data2/visualizationObserver.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class Observer(ABC):
|
||||
"""Интерфейс наблюдателя (паттерн Observer)."""
|
||||
|
||||
@abstractmethod
|
||||
def update(self, event: str) -> None:
|
||||
"""Обработчик события."""
|
||||
pass
|
||||
|
||||
Loading…
Reference in New Issue
Block a user