2026-rff_mp/SimonovaMS/lab2/experiments.py
2026-05-02 06:49:44 +03:00

200 lines
6.2 KiB
Python

# experiments.py
import time
import csv
from typing import List, Dict
from maze_model import Maze
from maze_builder import TextFileMazeBuilder
from pathfinding_strategies import BFSStrategy, DFSStrategy, AStarStrategy
from maze_solver import MazeSolver, SearchStats
class ExperimentRunner:
def __init__(self):
self.builder = TextFileMazeBuilder()
self.strategies = [
BFSStrategy(),
DFSStrategy(),
AStarStrategy(),
]
self.results: List[Dict] = []
def create_test_maze_file(self, filename: str, maze_data: List[str]) -> None:
with open(filename, 'w', encoding='utf-8') as f:
f.write('\n'.join(maze_data))
def generate_simple_maze(self) -> List[str]:
maze = [
"S E",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "
]
return maze
def generate_complex_maze(self, size: int = 50) -> List[str]:
import random
random.seed(42)
maze = []
for y in range(size):
row = []
for x in range(size):
if (x == 0 and y == 0):
row.append('S')
elif (x == size - 1 and y == size - 1):
row.append('E')
elif random.random() < 0.3: # 30% стен
row.append('#')
else:
row.append(' ')
maze.append(''.join(row))
for i in range(size):
if maze[i][0] == '#':
row = list(maze[i])
row[0] = ' '
maze[i] = ''.join(row)
if maze[0][i] == '#':
row = list(maze[0])
row[i] = ' '
maze[0] = ''.join(row)
return maze
def generate_empty_maze(self, size: int = 50) -> List[str]:
maze = []
for y in range(size):
row = []
for x in range(size):
if x == 0 and y == 0:
row.append('S')
elif x == size - 1 and y == size - 1:
row.append('E')
else:
row.append(' ')
maze.append(''.join(row))
return maze
def generate_no_exit_maze(self, size: int = 20) -> List[str]:
maze = []
for y in range(size):
row = []
for x in range(size):
if x == 0 and y == 0:
row.append('S')
elif x == size - 1 and y == size - 1:
row.append('#') # Выход заблокирован
else:
row.append('#') # Всё стены
maze.append(''.join(row))
# выход в тупике
row = list(maze[size - 1])
row[size - 1] = 'E'
maze[size - 1] = ''.join(row)
return maze
def run_experiment(self, maze_name: str, maze_data: List[str],
num_runs: int = 5) -> List[Dict]:
filename = f"test_{maze_name}.txt"
self.create_test_maze_file(filename, maze_data)
maze = self.builder.build_from_file(filename)
results = []
for strategy in self.strategies:
solver = MazeSolver(maze, strategy)
times = []
path_lengths = []
for run in range(num_runs):
stats = solver.solve()
times.append(stats.time_ms)
path_lengths.append(stats.path_length)
avg_time = sum(times) / len(times)
avg_path_length = sum(path_lengths) / len(path_lengths)
result = {
'maze': maze_name,
'strategy': strategy.name,
'avg_time_ms': round(avg_time, 3),
'min_time_ms': round(min(times), 3),
'max_time_ms': round(max(times), 3),
'path_length': int(avg_path_length) if avg_path_length else 0,
'path_found': avg_path_length > 0
}
results.append(result)
print(f"{maze_name} - {strategy.name}: "
f"{avg_time:.3f} мс, путь: {int(avg_path_length)}")
return results
def run_all_experiments(self):
experiments = [
("simple_10x10", self.generate_simple_maze()),
("complex_50x50", self.generate_complex_maze(50)),
("large_100x100", self.generate_complex_maze(100)),
("empty_50x50", self.generate_empty_maze(50)),
("no_exit_20x20", self.generate_no_exit_maze(20))
]
all_results = []
for name, data in experiments:
print(f"\n Лабиринт: {name} ---")
results = self.run_experiment(name, data)
all_results.extend(results)
self.save_to_csv(all_results, "experiment_results.csv")
return all_results
def save_to_csv(self, results: List[Dict], filename: str):
if not results:
return
with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = results[0].keys()
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results)
def print_analysis(results: List[Dict]):
# Группировка
mazes = set(r['maze'] for r in results)
for maze in sorted(mazes):
print(f"\nЛабиринт: {maze}")
print("-" * 40)
maze_results = [r for r in results if r['maze'] == maze]
#по времени
sorted_results = sorted(maze_results, key=lambda x: x['avg_time_ms'])
for r in sorted_results:
status = "" if r['path_found'] else ""
print(f" {status} {r['strategy']:8} | "
f"Время: {r['avg_time_ms']:8.3f} мс | "
f"Путь: {r['path_length']:4} шагов")
# Определяем лучший
fastest = sorted_results[0]
print(f"\n → Самый быстрый: {fastest['strategy']} "
f"({fastest['avg_time_ms']:.3f} мс)")