задание 2: экспериментальная часть, визуализация, выводы и главное меню

This commit is contained in:
Sorokin Fedor 2026-05-25 02:57:25 +03:00
parent f04f36c12e
commit 2ff3ae7e2a

View File

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