2026-rff_mp/VasilevIA/lab2/main.py

166 lines
4.8 KiB
Python
Raw Normal View History

import csv
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "codes"))
from maze import TextFileMazeBuilder, MazeSolver, BFSStrategy, DFSStrategy, AStarStrategy
from maze_generator import generate_all
try:
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use("Agg")
HAS_PLT = True
except ImportError:
HAS_PLT = False
BASE_DIR = os.path.dirname(__file__)
MAZES_DIR = os.path.join(BASE_DIR, "mazes")
RESULTS_DIR = os.path.join(BASE_DIR, "results")
RUNS = 7
MAZE_FILES = [
("small", "small.txt"),
("medium", "medium.txt"),
("large", "large.txt"),
("empty", "empty.txt"),
("no_exit", "no_exit.txt"),
]
def run():
os.makedirs(RESULTS_DIR, exist_ok=True)
if not os.path.exists(MAZES_DIR) or not os.listdir(MAZES_DIR):
generate_all(MAZES_DIR)
strategies = [BFSStrategy(), DFSStrategy(), AStarStrategy()]
builder = TextFileMazeBuilder()
all_results = []
for label, filename in MAZE_FILES:
path = os.path.join(MAZES_DIR, filename)
if not os.path.exists(path):
continue
maze = builder.build_from_file(path)
print(f"\nMaze: {label} ({maze.width}x{maze.height})")
solver = MazeSolver(maze, strategies[0])
for strategy in strategies:
solver.set_strategy(strategy)
times, visited_list, lengths = [], [], []
for _ in range(RUNS):
stats = solver.solve()
times.append(stats.time_ms)
visited_list.append(stats.visited)
lengths.append(stats.path_length)
avg_time = sum(times) / RUNS
avg_visited = sum(visited_list) / RUNS
avg_len = sum(lengths) / RUNS
found = f"length={avg_len:.0f}" if avg_len > 0 else "not found"
print(f" {strategy.name:<6} time={avg_time:.4f} ms visited={avg_visited:.0f} {found}")
all_results.append({
"maze": label,
"strategy": strategy.name,
"time_ms": round(avg_time, 4),
"visited_cells": round(avg_visited, 1),
"path_length": round(avg_len, 1),
})
save_csv(all_results)
save_plots(all_results)
show_sample()
print("\nDone. See results/ and docs/")
def save_csv(results):
path = os.path.join(RESULTS_DIR, "results_maze.csv")
with open(path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(
f, fieldnames=["maze", "strategy", "time_ms", "visited_cells", "path_length"]
)
writer.writeheader()
writer.writerows(results)
print(f"\nCSV saved: {path}")
def save_plots(results):
if not HAS_PLT:
return
mazes = list(dict.fromkeys(r["maze"] for r in results))
strategies = list(dict.fromkeys(r["strategy"] for r in results))
colors = ["#2196F3", "#FF5722", "#4CAF50"]
def val(maze, strat, key):
for r in results:
if r["maze"] == maze and r["strategy"] == strat:
return float(r[key])
return 0.0
metrics = [
("time_ms", "Time (ms)"),
("visited_cells", "Visited cells"),
("path_length", "Path length"),
]
fig, axes = plt.subplots(
len(metrics), len(mazes),
figsize=(3.5 * len(mazes), 4 * len(metrics))
)
def fmt(v):
if v == 0:
return "0"
if v >= 100:
return f"{v:.0f}"
if v >= 1:
return f"{v:.2f}"
return f"{v:.3f}"
for row_i, (key, ylabel) in enumerate(metrics):
for col_i, maze in enumerate(mazes):
ax = axes[row_i][col_i]
vals = [val(maze, s, key) for s in strategies]
bars = ax.bar(strategies, vals, color=colors[:len(strategies)])
if row_i == 0:
ax.set_title(maze, fontsize=9)
if col_i == 0:
ax.set_ylabel(ylabel)
for bar, v in zip(bars, vals):
ax.text(
bar.get_x() + bar.get_width() / 2,
bar.get_height() * 1.02,
fmt(v), ha="center", va="bottom", fontsize=7
)
ax.tick_params(axis="x", labelsize=8)
plt.tight_layout()
out = os.path.join(RESULTS_DIR, "benchmark_plot.png")
plt.savefig(out, dpi=120)
plt.close()
print(f"Chart saved: {out}")
def show_sample():
path = os.path.join(MAZES_DIR, "sample.txt")
if not os.path.exists(path):
return
builder = TextFileMazeBuilder()
maze = builder.build_from_file(path)
solver = MazeSolver(maze, BFSStrategy())
stats = solver.solve()
print("\nSample maze with BFS path:")
print(maze.render(path=stats.path))
if __name__ == "__main__":
run()