forked from UNN/2026-rff_mp
138 lines
5.4 KiB
Python
138 lines
5.4 KiB
Python
|
|
import csv
|
|||
|
|
import os
|
|||
|
|
import statistics
|
|||
|
|
import matplotlib.pyplot as plt
|
|||
|
|
|
|||
|
|
from maze_builder import TextFileMazeBuilder
|
|||
|
|
from solver import MazeSolver
|
|||
|
|
from strategies import BFSStrategy, DFSStrategy, AStarStrategy
|
|||
|
|
|
|||
|
|
# --- НАСТРОЙКИ ---
|
|||
|
|
MAZES_DIR = "mazes"
|
|||
|
|
OUTPUT_CSV = "results.csv"
|
|||
|
|
RUNS = 10 # Количество запусков для усреднения
|
|||
|
|
PLOTS_DIR = "plots" # Новая папка для графиков
|
|||
|
|
|
|||
|
|
STRATEGIES = {
|
|||
|
|
"BFS": BFSStrategy,
|
|||
|
|
"DFS": DFSStrategy,
|
|||
|
|
"A*": AStarStrategy,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Словарь для хранения всех данных для графиков
|
|||
|
|
all_data = {}
|
|||
|
|
|
|||
|
|
# Создаем папку для графиков, если её нет
|
|||
|
|
os.makedirs(PLOTS_DIR, exist_ok=True)
|
|||
|
|
|
|||
|
|
builder = TextFileMazeBuilder()
|
|||
|
|
maze_files = sorted(f for f in os.listdir(MAZES_DIR) if f.endswith(".txt"))
|
|||
|
|
rows = []
|
|||
|
|
|
|||
|
|
print("=== СТАРТ ЭКСПЕРИМЕНТА ===\n")
|
|||
|
|
|
|||
|
|
# --- ОСНОВНОЙ ЦИКЛ ЭКСПЕРИМЕНТА ---
|
|||
|
|
for maze_file in maze_files:
|
|||
|
|
maze_name = maze_file.replace(".txt", "")
|
|||
|
|
filepath = os.path.join(MAZES_DIR, maze_file)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
maze = builder.build_from_file(filepath)
|
|||
|
|
except ValueError as e:
|
|||
|
|
print(f" [!] Пропуск {maze_file}: {e}")
|
|||
|
|
continue # Переходим к следующему файлу, если этот не загрузился
|
|||
|
|
|
|||
|
|
# Эта строка теперь выполняется для каждого успешного лабиринта
|
|||
|
|
print(f"\n{'='*50}")
|
|||
|
|
print(f"Лабиринт: {maze_name} ({maze.width}×{maze.height})")
|
|||
|
|
|
|||
|
|
all_data[maze_name] = {}
|
|||
|
|
|
|||
|
|
for strat_name, StratClass in STRATEGIES.items():
|
|||
|
|
times, visited_counts, path_lengths = [], [], []
|
|||
|
|
run_stats = []
|
|||
|
|
|
|||
|
|
for run_num in range(1, RUNS + 1):
|
|||
|
|
solver = MazeSolver(maze, StratClass())
|
|||
|
|
stats = solver.solve()
|
|||
|
|
|
|||
|
|
times.append(stats.time_ms)
|
|||
|
|
visited_counts.append(stats.visited_cells)
|
|||
|
|
path_lengths.append(stats.path_length)
|
|||
|
|
|
|||
|
|
# Сохраняем данные каждой попытки
|
|||
|
|
run_stats.append({
|
|||
|
|
'попытка': run_num,
|
|||
|
|
'время_мс': stats.time_ms,
|
|||
|
|
'посещено_клеток': stats.visited_cells,
|
|||
|
|
'длина_пути': stats.path_length
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
print(f" {strat_name} | Попытка {run_num}/{RUNS} | Время: {stats.time_ms:.2f} мс")
|
|||
|
|
|
|||
|
|
# Вычисляем средние значения
|
|||
|
|
avg_time = statistics.mean(times)
|
|||
|
|
avg_visited = statistics.mean(visited_counts)
|
|||
|
|
|
|||
|
|
valid_path_lengths = [p for p in path_lengths if p is not None]
|
|||
|
|
avg_path = statistics.mean(valid_path_lengths) if valid_path_lengths else None
|
|||
|
|
|
|||
|
|
print(f" {strat_name:10s} | СРЕДНЕЕ: время {avg_time:.2f} мс | "
|
|||
|
|
f"посещено {avg_visited:.1f} | путь {avg_path if avg_path is not None else '—'}")
|
|||
|
|
|
|||
|
|
rows.append({
|
|||
|
|
"лабиринт": maze_name,
|
|||
|
|
"стратегия": strat_name,
|
|||
|
|
"время_мс": round(avg_time, 6),
|
|||
|
|
"посещено_клеток": round(avg_visited, 1),
|
|||
|
|
"длина_пути": round(avg_path, 1) if avg_path is not None else None,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
all_data[maze_name][strat_name] = run_stats
|
|||
|
|
|
|||
|
|
# --- СОХРАНЕНИЕ CSV ---
|
|||
|
|
with open(OUTPUT_CSV, "w", newline="", encoding="utf-8") as csvfile:
|
|||
|
|
fieldnames = ["лабиринт", "стратегия", "время_мс", "посещено_клеток", "длина_пути"]
|
|||
|
|
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
|||
|
|
writer.writeheader()
|
|||
|
|
writer.writerows(rows)
|
|||
|
|
print(f"\n✓ Результаты сохранены в {OUTPUT_CSV}")
|
|||
|
|
|
|||
|
|
# --- ПОСТРОЕНИЕ ГРАФИКОВ ---
|
|||
|
|
print("\n=== ПОСТРОЕНИЕ ГРАФИКОВ ===")
|
|||
|
|
for maze_name, strategies_data in all_data.items():
|
|||
|
|
print(f"\nСтроим графики для лабиринта: {maze_name}")
|
|||
|
|
|
|||
|
|
# Создаем ОДИН график для времени выполнения
|
|||
|
|
fig, ax = plt.subplots(figsize=(10, 6))
|
|||
|
|
fig.suptitle(f"Сравнение времени выполнения алгоритмов\nЛабиринт '{maze_name}'", fontsize=14)
|
|||
|
|
|
|||
|
|
ax.set_title("Время выполнения (мс)")
|
|||
|
|
ax.set_xlabel("Номер попытки")
|
|||
|
|
ax.set_ylabel("Время (мс)")
|
|||
|
|
|
|||
|
|
for strat_name in STRATEGIES.keys():
|
|||
|
|
# Извлекаем только данные о времени выполнения
|
|||
|
|
data_points = [
|
|||
|
|
run['время_мс'] for run in strategies_data.get(strat_name, [])
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
if data_points:
|
|||
|
|
x_values = range(1, len(data_points) + 1)
|
|||
|
|
ax.plot(x_values, data_points,
|
|||
|
|
marker='o',
|
|||
|
|
label=strat_name,
|
|||
|
|
linewidth=2)
|
|||
|
|
|
|||
|
|
ax.legend(title="Алгоритм")
|
|||
|
|
ax.grid(True, which='both', linestyle='--', linewidth=0.5)
|
|||
|
|
|
|||
|
|
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
|
|||
|
|
|
|||
|
|
# Сохраняем график в папку 'plots'
|
|||
|
|
plot_filename = os.path.join(PLOTS_DIR, f"plot_{maze_name}.png")
|
|||
|
|
plt.savefig(plot_filename)
|
|||
|
|
plt.close()
|
|||
|
|
|
|||
|
|
print(f"\n✓ Графики времени выполнения сохранены в папку '{PLOTS_DIR}'")
|
|||
|
|
print("=== ЭКСПЕРИМЕНТ ЗАВЕРШЕН ===")
|