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()