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

@ -16,4 +16,5 @@ def RunBenchmark(maze, strategies, repeats = 5):
with open("results.csv", "w", newline="") as f: with open("results.csv", "w", newline="") as f:
writer = csv.writer(f) writer = csv.writer(f)
writer.writerow(["strategy", "time_ms", "visited", "path_length"]) writer.writerow(["strategy", "time_ms", "visited", "path_length"])
writer.writerows(rows) writer.writerows(rows)

View File

@ -1,5 +1,5 @@
class Cell: 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.x = x
self.y = y self.y = y
self.isWall = isWall 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 import time
class MazeSolver: 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): class MoveCommand(Command):

View File

@ -1,4 +1,4 @@
from strat import PathFindingStrategy from Strategies.strat import PathFindingStrategy
from path import restore from path import restore
import heapq 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 from path import restore
class DFS(PathFindingStrategy): class DFS(PathFindingStrategy):
def find_path(self, maze, start, exit): def findPath(self, maze, start, exit):
stack = [start] stack = [start]
visited = {start} visited = {start}
parent = {} parent = {}

View File

@ -2,23 +2,344 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 21,
"id": "66bfd079", "id": "a1dff6b4",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [
"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": [ "source": [
"from Builder.Builder import TextFileMazeBuilder\n", "from Builder.Builder import TextFileMazeBuilder\n",
"from Core.Benchmark import RunBenchmark\n", "from Core.Benchmark import RunBenchmark\n",
"from Core.Cell import Cell\n", "from MazeSolver.Solver import MazeSolver\n",
"from Core.Maze import Maze\n", "from Observer_Command.ConsoleView import ConsoleView\n",
"from MazeSolver.SearchStats import SearchStats\n", "from Strategies.BFS import BFS\n",
"from MazeSolver.SearchStats import SearchStats" "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": { "metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": { "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, "nbformat": 4,