forked from UNN/2026-rff_mp
задание 2: экспериментальная часть, визуализация, выводы и главное меню
This commit is contained in:
parent
f04f36c12e
commit
2ff3ae7e2a
111
sorokinfi/427.py
111
sorokinfi/427.py
|
|
@ -6,6 +6,10 @@ from collections import defaultdict, deque
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
import os
|
||||||
|
|
||||||
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
os.chdir(current_dir)
|
||||||
|
|
||||||
# увеличиваем лимит рекурсии
|
# увеличиваем лимит рекурсии
|
||||||
sys.setrecursionlimit(25000)
|
sys.setrecursionlimit(25000)
|
||||||
|
|
@ -342,12 +346,11 @@ def print_report():
|
||||||
"""
|
"""
|
||||||
print(report)
|
print(report)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def run_task_1():
|
||||||
run_experiments()
|
run_experiments()
|
||||||
plot_results()
|
plot_results()
|
||||||
print_report()
|
print_report()
|
||||||
|
|
||||||
|
|
||||||
# ЗАДАНИЕ 2: ПОИСК ВЫХОДА ИЗ ЛАБИРИНТА
|
# ЗАДАНИЕ 2: ПОИСК ВЫХОДА ИЗ ЛАБИРИНТА
|
||||||
|
|
||||||
# поиск выхода из лабиринта
|
# поиск выхода из лабиринта
|
||||||
|
|
@ -379,7 +382,7 @@ class BFSStrategy(PathfindingStrategy):
|
||||||
|
|
||||||
# проверка входных данных
|
# проверка входных данных
|
||||||
if not maze.start or not maze.end:
|
if not maze.start or not maze.end:
|
||||||
return None
|
return None, 0
|
||||||
|
|
||||||
# инициализация структур данных
|
# инициализация структур данных
|
||||||
queue = deque([(maze.start, [maze.start])])
|
queue = deque([(maze.start, [maze.start])])
|
||||||
|
|
@ -443,8 +446,12 @@ class MazeFactory:
|
||||||
for c in range(width):
|
for c in range(width):
|
||||||
if random.random() < wall_chance: grid[r][c] = "#"
|
if random.random() < wall_chance: grid[r][c] = "#"
|
||||||
grid[0][0] = "S"
|
grid[0][0] = "S"
|
||||||
if has_exit: grid[height-1][width-1] = "E"
|
if has_exit:
|
||||||
else: grid[height-1][width-1] = "#"
|
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
|
return grid
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -468,4 +475,98 @@ class MazeFactory:
|
||||||
def run_maze_experiments():
|
def run_maze_experiments():
|
||||||
maze_types = ["маленький (10x10)", "средний (50x50)", "большой (100x100)", "пустой", "без выхода"]
|
maze_types = ["маленький (10x10)", "средний (50x50)", "большой (100x100)", "пустой", "без выхода"]
|
||||||
strategies = [("BFS", BFSStrategy()), ("DFS", DFSStrategy())]
|
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()
|
||||||
Loading…
Reference in New Issue
Block a user