2026-rff_mp/MashinDD/lab2/docs/data/benchmark.py
2026-05-17 16:50:48 +03:00

154 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
import csv
import os
import random
from maze_builder import TextFileMazeBuilder
from maze_solver import MazeSolver
from maze_strategies import BFSStrategy, DFSStrategy, AStarStrategy
REPEATS = 7
OUTPUT_DIR = os.path.dirname(os.path.abspath(__file__))
CSV_PATH = os.path.join(OUTPUT_DIR, 'results.csv')
STRATEGIES = {
'BFS': BFSStrategy,
'DFS': DFSStrategy,
'A*': AStarStrategy,
}
MAZES = [
('small_10x10', 'maze_small.txt'),
('medium_50x50', 'maze_medium.txt'),
('large_100x100', 'maze_large.txt'),
('open_50x50', 'maze_open.txt'),
('no_exit_20x20', 'maze_no_exit.txt'),
]
def _make_grid(width, height, density=0.0, has_exit=True, seed=42):
rng = random.Random(seed)
grid = []
for y in range(height):
row = []
for x in range(width):
on_border = (x == 0 or x == width - 1 or y == 0 or y == height - 1)
row.append('#' if on_border else ' ')
grid.append(row)
for y in range(1, height - 1):
for x in range(1, width - 1):
if rng.random() < density:
grid[y][x] = '#'
grid[1][1] = 'S'
if has_exit:
grid[height - 2][width - 2] = 'E'
return '\n'.join(''.join(row) for row in grid)
def generate_maze_files():
mazes_data = {
'maze_small.txt': _make_grid(10, 10, density=0.15),
'maze_medium.txt': _make_grid(50, 50, density=0.28),
'maze_large.txt': _make_grid(100, 100, density=0.30),
'maze_open.txt': _make_grid(50, 50, density=0.0),
'maze_no_exit.txt': _make_grid(20, 20, density=0.20, has_exit=False),
}
no_exit = list(mazes_data['maze_no_exit.txt'].splitlines())
no_exit[18] = no_exit[18][:18] + 'E' + no_exit[18][19:]
no_exit[17] = no_exit[17][:18] + '#' + no_exit[17][19:]
no_exit[18] = no_exit[18][:17] + '#' + no_exit[18][18:]
mazes_data['maze_no_exit.txt'] = '\n'.join(no_exit)
maze_dir = os.path.dirname(os.path.abspath(__file__))
for fname, content in mazes_data.items():
path = os.path.join(maze_dir, fname)
with open(path, 'w', encoding='utf-8') as f:
f.write(content)
print("✅ Файлы лабиринтов созданы")
def avg(lst):
return sum(lst) / len(lst) if lst else 0
def run_benchmark():
builder = TextFileMazeBuilder()
maze_dir = os.path.dirname(os.path.abspath(__file__))
all_results = [
['лабиринт', 'стратегия', 'время_мс', 'посещено_клеток', 'длина_пути']
+ [f'замер_{i+1}' for i in range(REPEATS)]
]
print(f"\nЗапуск бенчмарков (повторений: {REPEATS})\n")
print(f" {'Лабиринт':<18} {'Алгоритм':<6} {'Время мс':>10} "
f"{'Посещено':>10} {'Путь':>6}")
print(' ' + '-' * 56)
for maze_label, maze_file in MAZES:
maze_path = os.path.join(maze_dir, maze_file)
try:
maze = builder.build_from_file(maze_path)
except Exception as e:
print(f"{maze_file}: {e}")
continue
solver = MazeSolver(maze)
for strat_name, StratClass in STRATEGIES.items():
times_ms, visited_list, path_len = [], [], 0
for _ in range(REPEATS):
strat = StratClass()
solver.set_strategy(strat)
stats = solver.solve()
times_ms.append(stats.time_ms)
visited_list.append(stats.visited_cells)
path_len = stats.path_length
mean_t = avg(times_ms)
mean_v = avg(visited_list)
print(f" {maze_label:<18} {strat_name:<6} "
f"{mean_t:>10.3f} {mean_v:>10.0f} {path_len:>6}")
all_results.append([
maze_label, strat_name,
f"{mean_t:.4f}", f"{mean_v:.0f}", str(path_len)
] + [f"{t:.4f}" for t in times_ms])
with open(CSV_PATH, 'w', newline='', encoding='utf-8') as f:
csv.writer(f).writerows(all_results)
print(f"\n✅ Результаты сохранены: {CSV_PATH}")
def smoke_test():
print("=== Smoke Test ===\n")
maze_dir = os.path.dirname(os.path.abspath(__file__))
test_path = os.path.join(maze_dir, '_test_maze.txt')
with open(test_path, 'w', encoding='utf-8') as f:
f.write("#######\n#S #\n# #\n# E#\n#######")
builder = TextFileMazeBuilder()
maze = builder.build_from_file(test_path)
for name, StratClass in STRATEGIES.items():
strat = StratClass()
path = strat.find_path(maze, maze.start, maze.exit)
assert len(path) > 0, f"{name}: путь не найден!"
assert path[0].is_start
assert path[-1].is_exit
print(f"{name}: путь длиной {len(path)} — OK")
os.remove(test_path)
print("\nВсе тесты пройдены!\n")
if __name__ == '__main__':
smoke_test()
generate_maze_files()
run_benchmark()