154 lines
4.9 KiB
Python
154 lines
4.9 KiB
Python
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()
|