задание 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 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()
|
||||
Loading…
Reference in New Issue
Block a user