From 2ff3ae7e2a634800e1d9fe945bfaa1c5b5b47845 Mon Sep 17 00:00:00 2001 From: Sorokin Fedor Date: Mon, 25 May 2026 02:57:25 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=202:?= =?UTF-8?q?=20=D1=8D=D0=BA=D1=81=D0=BF=D0=B5=D1=80=D0=B8=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D1=8C=D0=BD=D0=B0=D1=8F=20=D1=87=D0=B0=D1=81?= =?UTF-8?q?=D1=82=D1=8C,=20=D0=B2=D0=B8=D0=B7=D1=83=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D0=B2=D1=8B=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=D1=8B=20=D0=B8=20=D0=B3=D0=BB=D0=B0=D0=B2=D0=BD=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=BC=D0=B5=D0=BD=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sorokinfi/427.py | 111 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/sorokinfi/427.py b/sorokinfi/427.py index 9048545..8a00d89 100644 --- a/sorokinfi/427.py +++ b/sorokinfi/427.py @@ -6,6 +6,10 @@ from collections import defaultdict, deque import pandas as pd import matplotlib.pyplot as plt from abc import ABC, abstractmethod +import os + +current_dir = os.path.dirname(os.path.abspath(__file__)) +os.chdir(current_dir) # увеличиваем лимит рекурсии sys.setrecursionlimit(25000) @@ -342,12 +346,11 @@ def print_report(): """ print(report) -if __name__ == "__main__": +def run_task_1(): run_experiments() plot_results() print_report() - # ЗАДАНИЕ 2: ПОИСК ВЫХОДА ИЗ ЛАБИРИНТА # поиск выхода из лабиринта @@ -379,7 +382,7 @@ class BFSStrategy(PathfindingStrategy): # проверка входных данных if not maze.start or not maze.end: - return None + return None, 0 # инициализация структур данных queue = deque([(maze.start, [maze.start])]) @@ -443,8 +446,12 @@ class MazeFactory: for c in range(width): if random.random() < wall_chance: grid[r][c] = "#" grid[0][0] = "S" - if has_exit: grid[height-1][width-1] = "E" - else: grid[height-1][width-1] = "#" + if has_exit: + grid[height-1][width-1] = "E" + else: + grid[height-1][width-1] = "E" + if height > 1: grid[height-1][width-2] = "#" + if width > 1: grid[height-2][width-1] = "#" return grid @staticmethod @@ -468,4 +475,98 @@ class MazeFactory: def run_maze_experiments(): maze_types = ["маленький (10x10)", "средний (50x50)", "большой (100x100)", "пустой", "без выхода"] strategies = [("BFS", BFSStrategy()), ("DFS", DFSStrategy())] + csv_rows = [["лабиринт", "стратегия", "время_мс", "посещено_клеток", "длина_пути"]] + + print("\nзапуск экспериментов(5 повторений)") + + for m_type in maze_types: + maze_obj = MazeFactory.create_maze(m_type) + for strat_name, strategy in strategies: + solver = MazeSolver(strategy) + + times = [] + visited_cells = 0 + path_len = 0 + + # запускаем по 5 раз для усреднения времени + for rep in range(5): + t_start = time.perf_counter() + path, visited = solver.solve_maze(maze_obj) + t_end = time.perf_counter() + + times.append((t_end - t_start) * 1000) # переводим в миллисекунды + visited_cells = visited + path_len = len(path) if path else 0 + + avg_time_ms = sum(times) / len(times) + csv_rows.append([m_type, strat_name, round(avg_time_ms, 4), visited_cells, path_len]) + # сохраняем в CSV + with open("maze_results.csv", "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerows(csv_rows) + print("Результаты сохранены в 'maze_results.csv'") + + df = pd.DataFrame(csv_rows[1:], columns=csv_rows[0]) + print("\nТАБЛИЦА СРАВНЕНИЯ АЛГОРИТМОВ ПОИСКА:") + print(df.to_string(index=False)) + + # визуализация графиков + print("\nпостроение графиков эффективности") + for m_type in maze_types: + sub_df = df[df["лабиринт"] == m_type] + + fig, ax1 = plt.subplots(figsize=(7, 4)) + ax2 = ax1.twinx() + + sub_df.plot(kind="bar", x="стратегия", y="время_мс", ax=ax1, position=0, width=0.2, color="blue", legend=False) + sub_df.plot(kind="bar", x="стратегия", y="посещено_клеток", ax=ax2, position=1, width=0.2, color="orange", legend=False) + + ax1.set_ylabel("время выполнения (мс)", color="blue") + ax2.set_ylabel("посещено клеток (ед)", color="orange") + plt.title(f"эффективность на лабиринте: {m_type}") + ax1.set_xticklabels(sub_df["стратегия"], rotation=0) + + lines1, labels1 = ax1.get_legend_handles_labels() + lines2, labels2 = ax2.get_legend_handles_labels() + ax1.legend(lines1 + lines2, ["время (мс)", "посещено клеток"], loc="upper center") + + plt.tight_layout() + filename = f"maze_chart_{m_type.replace(' ', '_').replace('(', '').replace(')', '')}.png" + plt.savefig(filename) + plt.close() + print("графики для каждого типа лабиринта сохранены в текущую папку") + +def print_maze_report(): + print(""" + ВЫВОДЫ ПО ИТОГАМ АНАЛИЗА ЛАБИРИНТОВ: + 1. Маленький и Пустой лабиринты: Оба алгоритма работают мгновенно. Однако в пустом + пространстве BFS проверяет почти все клетки «волной» до достижения цели, в то время + как DFS может случайно угадать прямую траекторию быстрее, но выдать неоптимальный путь. + 2. Средний и Большой лабиринты (с тупиками): BFS стабильно находит самый КОРОТКИЙ путь, + однако тратит много памяти и времени на посещение клеток. DFS работает непредсказуемо, + его путь часто длиннее в разы, так как он «плутает» по тупикам. + 3. Лабиринт без выхода: Оба алгоритма вынуждены совершить полный перебор графа. + Количество посещенных клеток у них совпадает и равняется общему числу доступных клеток. + """) + +def run_task_2(): + run_maze_experiments() + print_maze_report() + +# главное меню + +def main(): + while True: + print("МЕНЮ ЛАБОРАТОРНЫХ РАБОТ") + print("1. Задание 1: структуры данных") + print("2. Задание 2: эксперименты с Лабиринтами") + print("0. Выход") + choice = input("Введите номер задания: ") + if choice == '1': run_task_1() + elif choice == '2': run_task_2() + elif choice == '0': break + else: print("Ошибка ввода.") + +if __name__ == "__main__": + main() \ No newline at end of file