diff --git a/SobolevNS/docs/data/task2_maze/docs/data/plots/path_compare.png b/SobolevNS/docs/data/task2_maze/docs/data/plots/path_compare.png new file mode 100644 index 0000000..74f7520 Binary files /dev/null and b/SobolevNS/docs/data/task2_maze/docs/data/plots/path_compare.png differ diff --git a/SobolevNS/docs/data/task2_maze/docs/data/plots/time_compare.png b/SobolevNS/docs/data/task2_maze/docs/data/plots/time_compare.png new file mode 100644 index 0000000..475729b Binary files /dev/null and b/SobolevNS/docs/data/task2_maze/docs/data/plots/time_compare.png differ diff --git a/SobolevNS/docs/data/task2_maze/docs/data/plots/visited_compare.png b/SobolevNS/docs/data/task2_maze/docs/data/plots/visited_compare.png new file mode 100644 index 0000000..10b33d7 Binary files /dev/null and b/SobolevNS/docs/data/task2_maze/docs/data/plots/visited_compare.png differ diff --git a/SobolevNS/docs/data/task2_maze/docs/data/plots/weighted_choice_compare.png b/SobolevNS/docs/data/task2_maze/docs/data/plots/weighted_choice_compare.png new file mode 100644 index 0000000..6b099f9 Binary files /dev/null and b/SobolevNS/docs/data/task2_maze/docs/data/plots/weighted_choice_compare.png differ diff --git a/SobolevNS/docs/data/task2_maze/docs/data/results.csv b/SobolevNS/docs/data/task2_maze/docs/data/results.csv new file mode 100644 index 0000000..264f0b4 --- /dev/null +++ b/SobolevNS/docs/data/task2_maze/docs/data/results.csv @@ -0,0 +1,228 @@ +лабиринт,стратегия,trial,время_мс,посещено_клеток,длина_пути,стоимость_пути +small_10x10,BFS,1,0.0454,34,16,16 +small_10x10,BFS,2,0.0314,34,16,16 +small_10x10,BFS,3,0.0286,34,16,16 +small_10x10,BFS,4,0.0275,34,16,16 +small_10x10,BFS,5,0.0270,34,16,16 +small_10x10,BFS,6,0.0264,34,16,16 +small_10x10,BFS,7,0.0279,34,16,16 +small_10x10,DFS,1,0.0167,18,16,16 +small_10x10,DFS,2,0.0146,18,16,16 +small_10x10,DFS,3,0.0138,18,16,16 +small_10x10,DFS,4,0.0132,18,16,16 +small_10x10,DFS,5,0.0138,18,16,16 +small_10x10,DFS,6,0.0133,18,16,16 +small_10x10,DFS,7,0.0138,18,16,16 +small_10x10,A*,1,0.0585,27,16,16 +small_10x10,A*,2,0.0514,27,16,16 +small_10x10,A*,3,0.0386,27,16,16 +small_10x10,A*,4,0.0366,27,16,16 +small_10x10,A*,5,0.0367,27,16,16 +small_10x10,A*,6,0.0367,27,16,16 +small_10x10,A*,7,0.0356,27,16,16 +small_10x10,Dijkstra,1,0.0467,33,16,16 +small_10x10,Dijkstra,2,0.0409,33,16,16 +small_10x10,Dijkstra,3,0.0395,33,16,16 +small_10x10,Dijkstra,4,0.0396,33,16,16 +small_10x10,Dijkstra,5,0.0642,33,16,16 +small_10x10,Dijkstra,6,0.0404,33,16,16 +small_10x10,Dijkstra,7,0.0392,33,16,16 +medium_51x51,BFS,1,0.5159,524,353,353 +medium_51x51,BFS,2,0.5299,524,353,353 +medium_51x51,BFS,3,0.5232,524,353,353 +medium_51x51,BFS,4,0.4525,524,353,353 +medium_51x51,BFS,5,0.4667,524,353,353 +medium_51x51,BFS,6,0.4594,524,353,353 +medium_51x51,BFS,7,0.4886,524,353,353 +medium_51x51,DFS,1,0.3356,379,353,353 +medium_51x51,DFS,2,0.3270,379,353,353 +medium_51x51,DFS,3,0.3471,379,353,353 +medium_51x51,DFS,4,0.3235,379,353,353 +medium_51x51,DFS,5,0.3309,379,353,353 +medium_51x51,DFS,6,0.3856,379,353,353 +medium_51x51,DFS,7,0.3248,379,353,353 +medium_51x51,A*,1,0.8707,421,353,353 +medium_51x51,A*,2,0.6813,421,353,353 +medium_51x51,A*,3,0.6357,421,353,353 +medium_51x51,A*,4,0.6464,421,353,353 +medium_51x51,A*,5,0.6520,421,353,353 +medium_51x51,A*,6,0.6231,421,353,353 +medium_51x51,A*,7,0.6365,421,353,353 +medium_51x51,Dijkstra,1,0.7634,523,353,353 +medium_51x51,Dijkstra,2,0.6893,523,353,353 +medium_51x51,Dijkstra,3,0.6817,523,353,353 +medium_51x51,Dijkstra,4,0.6965,523,353,353 +medium_51x51,Dijkstra,5,0.6920,523,353,353 +medium_51x51,Dijkstra,6,0.6702,523,353,353 +medium_51x51,Dijkstra,7,0.7281,523,353,353 +large_101x101,BFS,1,3.2679,2143,1265,1265 +large_101x101,BFS,2,1.9302,2143,1265,1265 +large_101x101,BFS,3,1.9559,2143,1265,1265 +large_101x101,BFS,4,1.9057,2143,1265,1265 +large_101x101,BFS,5,1.8770,2143,1265,1265 +large_101x101,BFS,6,1.8828,2143,1265,1265 +large_101x101,BFS,7,1.9345,2143,1265,1265 +large_101x101,DFS,1,1.2758,1443,1265,1265 +large_101x101,DFS,2,1.3043,1443,1265,1265 +large_101x101,DFS,3,1.2613,1443,1265,1265 +large_101x101,DFS,4,1.2846,1443,1265,1265 +large_101x101,DFS,5,1.3566,1443,1265,1265 +large_101x101,DFS,6,1.3296,1443,1265,1265 +large_101x101,DFS,7,1.2501,1443,1265,1265 +large_101x101,A*,1,3.2760,1831,1265,1265 +large_101x101,A*,2,3.3353,1831,1265,1265 +large_101x101,A*,3,4.1894,1831,1265,1265 +large_101x101,A*,4,4.6809,1831,1265,1265 +large_101x101,A*,5,3.4026,1831,1265,1265 +large_101x101,A*,6,3.1036,1831,1265,1265 +large_101x101,A*,7,3.2912,1831,1265,1265 +large_101x101,Dijkstra,1,3.4403,2139,1265,1265 +large_101x101,Dijkstra,2,3.3500,2139,1265,1265 +large_101x101,Dijkstra,3,3.4201,2139,1265,1265 +large_101x101,Dijkstra,4,3.2253,2139,1265,1265 +large_101x101,Dijkstra,5,5.0122,2139,1265,1265 +large_101x101,Dijkstra,6,3.3146,2139,1265,1265 +large_101x101,Dijkstra,7,3.2323,2139,1265,1265 +empty_30x30,BFS,1,0.8417,784,55,55 +empty_30x30,BFS,2,0.8160,784,55,55 +empty_30x30,BFS,3,0.7701,784,55,55 +empty_30x30,BFS,4,0.7609,784,55,55 +empty_30x30,BFS,5,0.7931,784,55,55 +empty_30x30,BFS,6,0.7647,784,55,55 +empty_30x30,BFS,7,0.8047,784,55,55 +empty_30x30,DFS,1,0.5067,784,379,379 +empty_30x30,DFS,2,0.6133,784,379,379 +empty_30x30,DFS,3,0.8051,784,379,379 +empty_30x30,DFS,4,0.4703,784,379,379 +empty_30x30,DFS,5,0.8029,784,379,379 +empty_30x30,DFS,6,0.5463,784,379,379 +empty_30x30,DFS,7,0.4602,784,379,379 +empty_30x30,A*,1,1.5117,784,55,55 +empty_30x30,A*,2,1.4866,784,55,55 +empty_30x30,A*,3,1.5878,784,55,55 +empty_30x30,A*,4,1.8756,784,55,55 +empty_30x30,A*,5,1.4943,784,55,55 +empty_30x30,A*,6,2.0146,784,55,55 +empty_30x30,A*,7,1.5262,784,55,55 +empty_30x30,Dijkstra,1,1.2824,784,55,55 +empty_30x30,Dijkstra,2,1.2897,784,55,55 +empty_30x30,Dijkstra,3,1.3428,784,55,55 +empty_30x30,Dijkstra,4,1.3181,784,55,55 +empty_30x30,Dijkstra,5,1.2785,784,55,55 +empty_30x30,Dijkstra,6,1.3634,784,55,55 +empty_30x30,Dijkstra,7,1.2709,784,55,55 +nopath_15x15,BFS,1,0.1595,165,0,0 +nopath_15x15,BFS,2,0.1705,165,0,0 +nopath_15x15,BFS,3,0.1489,165,0,0 +nopath_15x15,BFS,4,0.1461,165,0,0 +nopath_15x15,BFS,5,0.1972,165,0,0 +nopath_15x15,BFS,6,0.1461,165,0,0 +nopath_15x15,BFS,7,0.1436,165,0,0 +nopath_15x15,DFS,1,0.2023,165,0,0 +nopath_15x15,DFS,2,0.1506,165,0,0 +nopath_15x15,DFS,3,0.1511,165,0,0 +nopath_15x15,DFS,4,0.1477,165,0,0 +nopath_15x15,DFS,5,0.1513,165,0,0 +nopath_15x15,DFS,6,0.1455,165,0,0 +nopath_15x15,DFS,7,0.1654,165,0,0 +nopath_15x15,A*,1,0.2915,165,0,0 +nopath_15x15,A*,2,0.3024,165,0,0 +nopath_15x15,A*,3,0.2743,165,0,0 +nopath_15x15,A*,4,0.2980,165,0,0 +nopath_15x15,A*,5,0.2807,165,0,0 +nopath_15x15,A*,6,0.2838,165,0,0 +nopath_15x15,A*,7,0.3015,165,0,0 +nopath_15x15,Dijkstra,1,0.2476,165,0,0 +nopath_15x15,Dijkstra,2,0.2492,165,0,0 +nopath_15x15,Dijkstra,3,0.2435,165,0,0 +nopath_15x15,Dijkstra,4,0.2869,165,0,0 +nopath_15x15,Dijkstra,5,0.2466,165,0,0 +nopath_15x15,Dijkstra,6,0.2480,165,0,0 +nopath_15x15,Dijkstra,7,0.2445,165,0,0 +weighted_31x31,BFS,1,0.4261,433,265,391 +weighted_31x31,BFS,2,0.3905,433,265,391 +weighted_31x31,BFS,3,0.3713,433,265,391 +weighted_31x31,BFS,4,0.3713,433,265,391 +weighted_31x31,BFS,5,0.3672,433,265,391 +weighted_31x31,BFS,6,0.3788,433,265,391 +weighted_31x31,BFS,7,0.4045,433,265,391 +weighted_31x31,DFS,1,0.2646,318,265,391 +weighted_31x31,DFS,2,0.2761,318,265,391 +weighted_31x31,DFS,3,0.2978,318,265,391 +weighted_31x31,DFS,4,0.2618,318,265,391 +weighted_31x31,DFS,5,0.2717,318,265,391 +weighted_31x31,DFS,6,0.2581,318,265,391 +weighted_31x31,DFS,7,0.2787,318,265,391 +weighted_31x31,A*,1,0.6283,405,265,391 +weighted_31x31,A*,2,0.6319,405,265,391 +weighted_31x31,A*,3,0.7192,405,265,391 +weighted_31x31,A*,4,0.6285,405,265,391 +weighted_31x31,A*,5,0.6179,405,265,391 +weighted_31x31,A*,6,0.6571,405,265,391 +weighted_31x31,A*,7,1.0022,405,265,391 +weighted_31x31,Dijkstra,1,0.8638,431,265,391 +weighted_31x31,Dijkstra,2,0.8008,431,265,391 +weighted_31x31,Dijkstra,3,0.6000,431,265,391 +weighted_31x31,Dijkstra,4,0.6262,431,265,391 +weighted_31x31,Dijkstra,5,0.5502,431,265,391 +weighted_31x31,Dijkstra,6,0.5523,431,265,391 +weighted_31x31,Dijkstra,7,0.5431,431,265,391 +weighted_choice,BFS,1,0.1839,189,19,29 +weighted_choice,BFS,2,0.1642,189,19,29 +weighted_choice,BFS,3,0.1718,189,19,29 +weighted_choice,BFS,4,0.2025,189,19,29 +weighted_choice,BFS,5,0.1855,189,19,29 +weighted_choice,BFS,6,0.1656,189,19,29 +weighted_choice,BFS,7,0.1674,189,19,29 +weighted_choice,DFS,1,0.0238,55,19,29 +weighted_choice,DFS,2,0.0204,55,19,29 +weighted_choice,DFS,3,0.0196,55,19,29 +weighted_choice,DFS,4,0.0201,55,19,29 +weighted_choice,DFS,5,0.0372,55,19,29 +weighted_choice,DFS,6,0.0198,55,19,29 +weighted_choice,DFS,7,0.0198,55,19,29 +weighted_choice,A*,1,0.2451,117,25,25 +weighted_choice,A*,2,0.2572,117,25,25 +weighted_choice,A*,3,0.2276,117,25,25 +weighted_choice,A*,4,0.2337,117,25,25 +weighted_choice,A*,5,0.2305,117,25,25 +weighted_choice,A*,6,0.2742,117,25,25 +weighted_choice,A*,7,0.2275,117,25,25 +weighted_choice,Dijkstra,1,0.3360,209,25,25 +weighted_choice,Dijkstra,2,0.4054,209,25,25 +weighted_choice,Dijkstra,3,0.3169,209,25,25 +weighted_choice,Dijkstra,4,0.3882,209,25,25 +weighted_choice,Dijkstra,5,0.3406,209,25,25 +weighted_choice,Dijkstra,6,0.3182,209,25,25 +weighted_choice,Dijkstra,7,0.3200,209,25,25 + +--- СРЕДНИЕ --- +лабиринт,стратегия,среднее_время_мс,посещено_клеток,длина_пути,стоимость_пути +small_10x10,BFS,0.0306,34,16,16 +small_10x10,DFS,0.0142,18,16,16 +small_10x10,A*,0.0420,27,16,16 +small_10x10,Dijkstra,0.0444,33,16,16 +medium_51x51,BFS,0.4909,524,353,353 +medium_51x51,DFS,0.3392,379,353,353 +medium_51x51,A*,0.6780,421,353,353 +medium_51x51,Dijkstra,0.7030,523,353,353 +large_101x101,BFS,2.1077,2143,1265,1265 +large_101x101,DFS,1.2946,1443,1265,1265 +large_101x101,A*,3.6113,1831,1265,1265 +large_101x101,Dijkstra,3.5707,2139,1265,1265 +empty_30x30,BFS,0.7930,784,55,55 +empty_30x30,DFS,0.6007,784,379,379 +empty_30x30,A*,1.6424,784,55,55 +empty_30x30,Dijkstra,1.3066,784,55,55 +nopath_15x15,BFS,0.1588,165,0,0 +nopath_15x15,DFS,0.1591,165,0,0 +nopath_15x15,A*,0.2903,165,0,0 +nopath_15x15,Dijkstra,0.2523,165,0,0 +weighted_31x31,BFS,0.3871,433,265,391 +weighted_31x31,DFS,0.2727,318,265,391 +weighted_31x31,A*,0.6979,405,265,391 +weighted_31x31,Dijkstra,0.6481,431,265,391 +weighted_choice,BFS,0.1773,189,19,29 +weighted_choice,DFS,0.0230,55,19,29 +weighted_choice,A*,0.2423,117,25,25 +weighted_choice,Dijkstra,0.3465,209,25,25 diff --git a/SobolevNS/docs/data/task2_maze/experiment.py b/SobolevNS/docs/data/task2_maze/experiment.py new file mode 100644 index 0000000..1c84746 --- /dev/null +++ b/SobolevNS/docs/data/task2_maze/experiment.py @@ -0,0 +1,82 @@ +""" +experiment.py - экспериментальное сравнение стратегий поиска пути. + +Для каждого лабиринта × стратегии: + - запускаем solve() TRIALS раз + - усредняем время в мс, фиксируем число посещённых клеток и длину пути + - сохраняем в docs/data/results.csv +""" + +import csv +import os + +from maze_solver import ( + TextFileMazeBuilder, MazeSolver, + BFSStrategy, DFSStrategy, AStarStrategy, DijkstraStrategy, +) + + +TRIALS = 7 + +MAZES = [ + ("small_10x10", "mazes/small_10x10.txt"), + ("medium_51x51", "mazes/medium_51x51.txt"), + ("large_101x101", "mazes/large_101x101.txt"), + ("empty_30x30", "mazes/empty_30x30.txt"), + ("nopath_15x15", "mazes/nopath_15x15.txt"), + ("weighted_31x31", "mazes/weighted_31x31.txt"), + ("weighted_choice","mazes/weighted_choice.txt"), +] + +STRATEGY_CLASSES = [BFSStrategy, DFSStrategy, AStarStrategy, DijkstraStrategy] + +OUT_CSV = "docs/data/results.csv" + + +def main(): + os.makedirs(os.path.dirname(OUT_CSV), exist_ok=True) + builder = TextFileMazeBuilder() + + rows = [["лабиринт", "стратегия", "trial", + "время_мс", "посещено_клеток", "длина_пути", "стоимость_пути"]] + summary = [] + + for maze_name, maze_path in MAZES: + maze = builder.build_from_file(maze_path) + print(f"\n## {maze_name} ({maze.width}x{maze.height})") + + for cls in STRATEGY_CLASSES: + times, visited_vals, path_vals, cost_vals = [], [], [], [] + for trial in range(TRIALS): + solver = MazeSolver(maze, cls()) + stats = solver.solve() + cost = sum(c.weight for c in stats["path"]) + times.append(stats["elapsed_ms"]) + visited_vals.append(stats["visited"]) + path_vals.append(stats["path_length"]) + cost_vals.append(cost) + rows.append([maze_name, stats["strategy"], trial + 1, + f"{stats['elapsed_ms']:.4f}", + stats["visited"], stats["path_length"], cost]) + + mean_t = sum(times) / TRIALS + print(f" {cls.name:9s} t_avg={mean_t:7.3f} ms " + f"visited={visited_vals[0]:5d} " + f"path={path_vals[0]:5d} cost={cost_vals[0]:5d}") + summary.append((maze_name, cls.name, mean_t, + visited_vals[0], path_vals[0], cost_vals[0])) + + rows.append([]) + rows.append(["--- СРЕДНИЕ ---"]) + rows.append(["лабиринт", "стратегия", "среднее_время_мс", + "посещено_клеток", "длина_пути", "стоимость_пути"]) + for r in summary: + rows.append([r[0], r[1], f"{r[2]:.4f}", r[3], r[4], r[5]]) + + with open(OUT_CSV, "w", newline="", encoding="utf-8") as f: + csv.writer(f).writerows(rows) + print(f"\nГотово. Результаты записаны в {OUT_CSV}") + + +if __name__ == "__main__": + main() diff --git a/SobolevNS/docs/data/task2_maze/plot_results.py b/SobolevNS/docs/data/task2_maze/plot_results.py new file mode 100644 index 0000000..24913ba --- /dev/null +++ b/SobolevNS/docs/data/task2_maze/plot_results.py @@ -0,0 +1,99 @@ +"""plot_results.py - графики для эксперимента с лабиринтами.""" +import csv +import os +import matplotlib.pyplot as plt +import numpy as np + +CSV = "docs/data/results.csv" +PLOTS = "docs/data/plots" +os.makedirs(PLOTS, exist_ok=True) + + +def load_means(): + """Возвращает dict[(maze, strategy)] = (time_ms, visited, path_len, cost).""" + out = {} + with open(CSV, encoding="utf-8") as f: + rows = list(csv.reader(f)) + start = next(i for i, r in enumerate(rows) if r and r[0] == "--- СРЕДНИЕ ---") + 2 + for r in rows[start:]: + if not r: + continue + maze, strat, t, vis, plen, cost = r + out[(maze, strat)] = (float(t), int(vis), int(plen), int(cost)) + return out + + +MAZES = ["small_10x10", "medium_51x51", "large_101x101", + "empty_30x30", "nopath_15x15", + "weighted_31x31", "weighted_choice"] +STRATEGIES = ["BFS", "DFS", "A*", "Dijkstra"] +COLORS = {"BFS": "#3498db", "DFS": "#e67e22", "A*": "#2ecc71", "Dijkstra": "#9b59b6"} + + +def grouped_bar(means, idx, ylabel, title, fname, log=True): + x = np.arange(len(MAZES)) + w = 0.2 + fig, ax = plt.subplots(figsize=(11, 5)) + for i, s in enumerate(STRATEGIES): + vals = [means[(m, s)][idx] for m in MAZES] + bars = ax.bar(x + (i - 1.5) * w, vals, w, label=s, color=COLORS[s], alpha=0.9) + for b, v in zip(bars, vals): + ax.text(b.get_x() + b.get_width() / 2, b.get_height(), + f"{v:g}", ha="center", va="bottom", fontsize=7, rotation=0) + ax.set_xticks(x) + ax.set_xticklabels(MAZES, rotation=20, ha="right") + ax.set_ylabel(ylabel) + ax.set_title(title) + if log: + ax.set_yscale("log") + ax.legend() + ax.grid(axis="y", linestyle="--", alpha=0.4) + plt.tight_layout() + p = os.path.join(PLOTS, fname) + plt.savefig(p, dpi=130) + plt.close() + print("saved:", p) + + +def weighted_choice_chart(means): + """Отдельный график для weighted_choice: путь vs стоимость.""" + strategies = STRATEGIES + lengths = [means[("weighted_choice", s)][2] for s in strategies] + costs = [means[("weighted_choice", s)][3] for s in strategies] + x = np.arange(len(strategies)) + w = 0.35 + fig, ax = plt.subplots(figsize=(7.5, 4.5)) + b1 = ax.bar(x - w/2, lengths, w, label="длина пути (клеток)", + color="#3498db", alpha=0.9) + b2 = ax.bar(x + w/2, costs, w, label="стоимость пути (сумма весов)", + color="#e74c3c", alpha=0.9) + for bars in (b1, b2): + for bar in bars: + ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height(), + f"{bar.get_height():.0f}", ha="center", va="bottom", fontsize=9) + ax.set_xticks(x); ax.set_xticklabels(strategies) + ax.set_title("weighted_choice: BFS/DFS режут через болото,\n" + "Dijkstra/A* находят более дешёвый обход") + ax.set_ylabel("значение") + ax.legend() + ax.grid(axis="y", linestyle="--", alpha=0.4) + plt.tight_layout() + p = os.path.join(PLOTS, "weighted_choice_compare.png") + plt.savefig(p, dpi=130) + plt.close() + print("saved:", p) + + +def main(): + means = load_means() + grouped_bar(means, 0, "Время, мс (среднее по 7 запускам, лог. шкала)", + "Время поиска пути", "time_compare.png", log=True) + grouped_bar(means, 1, "Число посещённых клеток (лог. шкала)", + "Сколько клеток посетил алгоритм", "visited_compare.png", log=True) + grouped_bar(means, 2, "Длина пути (клеток)", + "Длина найденного пути", "path_compare.png", log=False) + weighted_choice_chart(means) + + +if __name__ == "__main__": + main()