micro bag fix

This commit is contained in:
4eker 2026-05-23 13:37:43 +03:00
parent 31f166f293
commit afa3c146b0
18 changed files with 437 additions and 14 deletions

View File

@ -0,0 +1,30 @@
from Core.Cell import Cell
from Core.Maze import Maze
from Builder.BuilderInterface import MazeBuilders
class TextFileMazeBuilder(MazeBuilders):
def build_from_file(self, filename):
grid = []
start = None
exit = None
with open(filename, "r", encoding="utf-8") as f:
lines = [line.rstrip("\n") for line in f]
for y, line in enumerate(lines):
row = []
for x, ch in enumerate(line):
cell = Cell(x, y, is_wall = (ch == "#"), is_start = (ch == "S"), is_exit = (ch == "E"))
if (ch == "S"):
start = cell
if (ch == "E"):
exit = cell
row.append(cell)
grid.append(row)
return Maze(grid, start, exit)

View File

@ -0,0 +1,6 @@
from abc import ABC, abstractmethod
class MazeBuilders(ABC):
@abstractmethod
def build_from_file(self, filename):
pass

View File

View File

@ -17,3 +17,4 @@ def RunBenchmark(maze, strategies, repeats = 5):
writer = csv.writer(f)
writer.writerow(["strategy", "time_ms", "visited", "path_length"])
writer.writerows(rows)

View File

@ -1,5 +1,5 @@
class Cell:
def __init__(self, x, y, isWall = False, isStart = False, isExit = False):
def __init__(self, x = 0, y = 0, isWall = False, isStart = False, isExit = False):
self.x = x
self.y = y
self.isWall = isWall

View File

View File

@ -0,0 +1,5 @@
class SearchStats:
def __init__(self, time_ms, visited_cells, path_length):
self.time_ms = time_ms
self.visited_cells = visited_cells
self.path_length = path_length

View File

@ -1,4 +1,4 @@
from SearchStats import SearchStats
from .SearchStats import SearchStats
import time
class MazeSolver:

View File

@ -0,0 +1,6 @@
class Command:
def execute(self):
pass
def undo(self):
pass

View File

@ -0,0 +1,31 @@
from .Observer import Observer
class ConsoleView(Observer):
def update(self, event):
print("[событие]", event)
def render(self, maze, path = None):
path = set(path or [])
for row in maze.grid:
line = ""
for cell in row:
if cell in path:
line += "*"
elif cell.is_wall:
line += "#"
elif cell.is_start:
line += "S"
elif cell.is_exit:
line += "E"
else:
line += " "
print(line)

View File

@ -1,4 +1,4 @@
from Command import Command
from .Command import Command
class MoveCommand(Command):

View File

@ -1,4 +1,4 @@
from strat import PathFindingStrategy
from Strategies.strat import PathFindingStrategy
from path import restore
import heapq

View File

@ -0,0 +1,23 @@
from Strategies.strat import PathFindingStrategy
from path import restore
from collections import deque
class BFS(PathFindingStrategy):
def findPath(self, maze, start, exit):
queue = deque([start])
visited = {start}
parent = {}
while queue:
current = queue.popleft()
if current == exit:
break
for n in maze.get_neigbors(current):
if n not in visited:
visited.add(n)
parent[n] = current
queue.append(n)
return self.restore(parent, start, exit), len(visited)

View File

@ -1,9 +1,9 @@
from strat import PathFindingStrategy
from Strategies.strat import PathFindingStrategy
from path import restore
class DFS(PathFindingStrategy):
def find_path(self, maze, start, exit):
def findPath(self, maze, start, exit):
stack = [start]
visited = {start}
parent = {}

View File

@ -2,23 +2,344 @@
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "66bfd079",
"execution_count": 21,
"id": "a1dff6b4",
"metadata": {},
"outputs": [],
"source": [
"from Builder.Builder import TextFileMazeBuilder\n",
"from Core.Benchmark import RunBenchmark\n",
"from Core.Cell import Cell\n",
"from Core.Maze import Maze\n",
"from MazeSolver.SearchStats import SearchStats\n",
"from MazeSolver.SearchStats import SearchStats"
"import time\n",
"import csv\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "66bfd079",
"metadata": {},
"outputs": [
{
"ename": "ModuleNotFoundError",
"evalue": "No module named 'path'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[4], line 5\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mMazeSolver\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mSolver\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m MazeSolver\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mObserver_Command\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mConsoleView\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ConsoleView\n\u001b[0;32m----> 5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mBFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m BFS\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mDFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m DFS\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mAStar\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m AStar\n",
"File \u001b[0;32m~/2026-rff_mp/pomelovsd/ExitMaze/Strategies/BFS.py:2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mstrat\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m PathFindingStrategy\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpath\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m restore\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mcollections\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m deque\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mclass\u001b[39;00m \u001b[38;5;21;01mBFS\u001b[39;00m(PathFindingStrategy):\n",
"\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'path'"
]
}
],
"source": [
"from Builder.Builder import TextFileMazeBuilder\n",
"from Core.Benchmark import RunBenchmark\n",
"from MazeSolver.Solver import MazeSolver\n",
"from Observer_Command.ConsoleView import ConsoleView\n",
"from Strategies.BFS import BFS\n",
"from Strategies.DFS import DFS\n",
"from Strategies.AStar import AStar"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "50c7010d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'Builder.Builder.TextFileMazeBuilder'>\n"
]
}
],
"source": [
"print(TextFileMazeBuilder)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6ed7f922",
"metadata": {},
"outputs": [
{
"ename": "ImportError",
"evalue": "cannot import name 'BFS' from 'Strategies.BFS' (/home/i4eker/2026-rff_mp/pomelovsd/ExitMaze/Strategies/BFS.py)",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[13], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mBuilder\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mBuilder\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m TextFileMazeBuilder\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mBFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m BFS\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mDFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m DFS\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mAStar\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m AStar\n",
"\u001b[0;31mImportError\u001b[0m: cannot import name 'BFS' from 'Strategies.BFS' (/home/i4eker/2026-rff_mp/pomelovsd/ExitMaze/Strategies/BFS.py)"
]
}
],
"source": [
"\n",
"from Builder.Builder import TextFileMazeBuilder\n",
"\n",
"from Strategies.BFS import BFS\n",
"from Strategies.DFS import DFS\n",
"from Strategies.AStar import AStar\n",
"\n",
"from MazeSolver.Solver import MazeSolver\n",
"\n",
"\n",
"# ============================================\n",
"# ЗАГРУЗКА ЛАБИРИНТОВ\n",
"# ============================================\n",
"\n",
"builder = TextFileMazeBuilder()\n",
"\n",
"mazes = {\n",
" \"small\": builder.build_from_file(\"Mazes/small.txt\"),\n",
" \"medium\": builder.build_from_file(\"Mazes/medium.txt\"),\n",
" \"large\": builder.build_from_file(\"Mazes/large.txt\"),\n",
" \"empty\": builder.build_from_file(\"Mazes/empty.txt\"),\n",
" \"no_exit\": builder.build_from_file(\"Mazes/no_exit.txt\"),\n",
"}\n",
"\n",
"\n",
"# ============================================\n",
"# СТРАТЕГИИ\n",
"# ============================================\n",
"\n",
"strategies = {\n",
" \"BFS\": BFS(),\n",
" \"DFS\": DFS(),\n",
" \"A*\": AStar()\n",
"}\n",
"\n",
"\n",
"# ============================================\n",
"# РЕЗУЛЬТАТЫ\n",
"# ============================================\n",
"\n",
"results = []\n",
"\n",
"\n",
"# ============================================\n",
"# BENCHMARK\n",
"# ============================================\n",
"\n",
"REPEATS = 5\n",
"\n",
"for maze_name, maze in mazes.items():\n",
"\n",
" print(f\"\\n===== LABYRINTH: {maze_name} =====\")\n",
"\n",
" for strategy_name, strategy in strategies.items():\n",
"\n",
" total_time = 0\n",
" total_visited = 0\n",
" total_path = 0\n",
"\n",
" print(f\"Testing {strategy_name}...\")\n",
"\n",
" for _ in range(REPEATS):\n",
"\n",
" solver = MazeSolver(maze, strategy)\n",
"\n",
" start_time = time.perf_counter()\n",
"\n",
" stats, path = solver.solve()\n",
"\n",
" end_time = time.perf_counter()\n",
"\n",
" elapsed_ms = (end_time - start_time) * 1000\n",
"\n",
" total_time += elapsed_ms\n",
" total_visited += stats.visited_cells\n",
" total_path += stats.path_length\n",
"\n",
" avg_time = total_time / REPEATS\n",
" avg_visited = total_visited / REPEATS\n",
" avg_path = total_path / REPEATS\n",
"\n",
" results.append({\n",
" \"maze\": maze_name,\n",
" \"strategy\": strategy_name,\n",
" \"time_ms\": round(avg_time, 3),\n",
" \"visited_cells\": int(avg_visited),\n",
" \"path_length\": int(avg_path)\n",
" })\n",
"\n",
" print(\n",
" f\"{strategy_name}: \"\n",
" f\"time={avg_time:.3f} ms | \"\n",
" f\"visited={avg_visited:.0f} | \"\n",
" f\"path={avg_path:.0f}\"\n",
" )\n",
"\n",
"\n",
"# ============================================\n",
"# СОХРАНЕНИЕ CSV\n",
"# ============================================\n",
"\n",
"csv_file = \"benchmark_results.csv\"\n",
"\n",
"with open(csv_file, \"w\", newline=\"\", encoding=\"utf-8\") as file:\n",
"\n",
" writer = csv.writer(file)\n",
"\n",
" writer.writerow([\n",
" \"maze\",\n",
" \"strategy\",\n",
" \"time_ms\",\n",
" \"visited_cells\",\n",
" \"path_length\"\n",
" ])\n",
"\n",
" for row in results:\n",
" writer.writerow([\n",
" row[\"maze\"],\n",
" row[\"strategy\"],\n",
" row[\"time_ms\"],\n",
" row[\"visited_cells\"],\n",
" row[\"path_length\"]\n",
" ])\n",
"\n",
"print(f\"\\nCSV saved: {csv_file}\")\n",
"\n",
"\n",
"# ============================================\n",
"# ВЫВОД ТАБЛИЦЫ\n",
"# ============================================\n",
"\n",
"print(\"\\nRESULTS:\\n\")\n",
"\n",
"for row in results:\n",
"\n",
" print(\n",
" f\"{row['maze']:10} | \"\n",
" f\"{row['strategy']:5} | \"\n",
" f\"{row['time_ms']:10} ms | \"\n",
" f\"{row['visited_cells']:10} visited | \"\n",
" f\"{row['path_length']:5} path\"\n",
" )\n",
"\n",
"\n",
"# ============================================\n",
"# ГРАФИК ВРЕМЕНИ\n",
"# ============================================\n",
"\n",
"for maze_name in mazes.keys():\n",
"\n",
" strategy_names = []\n",
" times = []\n",
"\n",
" for row in results:\n",
"\n",
" if row[\"maze\"] == maze_name:\n",
"\n",
" strategy_names.append(row[\"strategy\"])\n",
" times.append(row[\"time_ms\"])\n",
"\n",
" plt.figure(figsize=(8, 5))\n",
"\n",
" plt.bar(strategy_names, times)\n",
"\n",
" plt.title(f\"Execution Time — {maze_name}\")\n",
" plt.xlabel(\"Strategy\")\n",
" plt.ylabel(\"Time (ms)\")\n",
"\n",
" plt.show()\n",
"\n",
"\n",
"# ============================================\n",
"# ГРАФИК ПОСЕЩЁННЫХ КЛЕТОК\n",
"# ============================================\n",
"\n",
"for maze_name in mazes.keys():\n",
"\n",
" strategy_names = []\n",
" visited = []\n",
"\n",
" for row in results:\n",
"\n",
" if row[\"maze\"] == maze_name:\n",
"\n",
" strategy_names.append(row[\"strategy\"])\n",
" visited.append(row[\"visited_cells\"])\n",
"\n",
" plt.figure(figsize=(8, 5))\n",
"\n",
" plt.bar(strategy_names, visited)\n",
"\n",
" plt.title(f\"Visited Cells — {maze_name}\")\n",
" plt.xlabel(\"Strategy\")\n",
" plt.ylabel(\"Visited Cells\")\n",
"\n",
" plt.show()\n",
"\n",
"\n",
"# ============================================\n",
"# ГРАФИК ДЛИНЫ ПУТИ\n",
"# ============================================\n",
"\n",
"for maze_name in mazes.keys():\n",
"\n",
" strategy_names = []\n",
" path_lengths = []\n",
"\n",
" for row in results:\n",
"\n",
" if row[\"maze\"] == maze_name:\n",
"\n",
" strategy_names.append(row[\"strategy\"])\n",
" path_lengths.append(row[\"path_length\"])\n",
"\n",
" plt.figure(figsize=(8, 5))\n",
"\n",
" plt.bar(strategy_names, path_lengths)\n",
"\n",
" plt.title(f\"Path Length — {maze_name}\")\n",
" plt.xlabel(\"Strategy\")\n",
" plt.ylabel(\"Path Length\")\n",
"\n",
" plt.show()\n",
"\n",
"\n",
"print(\"\\nBenchmark completed.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b001bee8",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "083b0af8",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,