forked from UNN/2026-rff_mp
Загрузить файлы в «dyachenkoas/docs/data2»
This commit is contained in:
parent
8353478190
commit
9ef6acffb0
16
dyachenkoas/docs/data2/experiment_results.csv
Normal file
16
dyachenkoas/docs/data2/experiment_results.csv
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
лабиринт,стратегия,время_мс,посещено_клеток,длина_пути
|
||||
Empty,BFS,0.158,162,26
|
||||
Empty,DFS,0.096,162,94
|
||||
Empty,AStar,0.290,162,26
|
||||
Large,BFS,0.194,220,75
|
||||
Large,DFS,0.073,77,75
|
||||
Large,AStar,0.337,216,75
|
||||
Medium,BFS,0.156,179,34
|
||||
Medium,DFS,0.038,44,38
|
||||
Medium,AStar,0.140,85,34
|
||||
No Exit,BFS,0.001,0,0
|
||||
No Exit,DFS,0.000,0,0
|
||||
No Exit,AStar,0.000,0,0
|
||||
Small,BFS,0.022,22,16
|
||||
Small,DFS,0.016,19,16
|
||||
Small,AStar,0.033,21,16
|
||||
|
425
dyachenkoas/docs/data2/main.py
Normal file
425
dyachenkoas/docs/data2/main.py
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
import sys
|
||||
import os
|
||||
import time
|
||||
import csv
|
||||
from collections import deque
|
||||
import heapq
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
# ========== Модель данных ==========
|
||||
class Tile:
|
||||
def __init__(self, x, y):
|
||||
self._x = x
|
||||
self._y = y
|
||||
self._wall = False
|
||||
self._entry = False
|
||||
self._goal = False
|
||||
|
||||
@property
|
||||
def x(self): return self._x
|
||||
@property
|
||||
def y(self): return self._y
|
||||
@property
|
||||
def is_wall(self): return self._wall
|
||||
@is_wall.setter
|
||||
def is_wall(self, value): self._wall = value
|
||||
@property
|
||||
def is_entry(self): return self._entry
|
||||
@is_entry.setter
|
||||
def is_entry(self, value): self._entry = value
|
||||
@property
|
||||
def is_goal(self): return self._goal
|
||||
@is_goal.setter
|
||||
def is_goal(self, value): self._goal = value
|
||||
|
||||
def can_walk(self):
|
||||
return not self._wall
|
||||
|
||||
|
||||
class Labyrinth:
|
||||
def __init__(self, width, height):
|
||||
self._width = width
|
||||
self._height = height
|
||||
self._grid = [[Tile(x, y) for x in range(width)] for y in range(height)]
|
||||
self._start = None
|
||||
self._exit = None
|
||||
|
||||
@property
|
||||
def width(self): return self._width
|
||||
@property
|
||||
def height(self): return self._height
|
||||
@property
|
||||
def start(self): return self._start
|
||||
@property
|
||||
def exit(self): return self._exit
|
||||
|
||||
def tile_at(self, x, y):
|
||||
if 0 <= x < self._width and 0 <= y < self._height:
|
||||
return self._grid[y][x]
|
||||
return None
|
||||
|
||||
def configure_tile(self, x, y, kind):
|
||||
tile = self.tile_at(x, y)
|
||||
if tile is None:
|
||||
return
|
||||
if kind == 'wall':
|
||||
tile.is_wall = True
|
||||
elif kind == 'entry':
|
||||
if self._start:
|
||||
self._start.is_entry = False
|
||||
tile.is_entry = True
|
||||
tile.is_wall = False
|
||||
self._start = tile
|
||||
elif kind == 'goal':
|
||||
if self._exit:
|
||||
self._exit.is_goal = False
|
||||
tile.is_goal = True
|
||||
tile.is_wall = False
|
||||
self._exit = tile
|
||||
elif kind == 'floor':
|
||||
tile.is_wall = False
|
||||
|
||||
def neighbours(self, tile):
|
||||
res = []
|
||||
for dx, dy in ((0, -1), (0, 1), (-1, 0), (1, 0)):
|
||||
nb = self.tile_at(tile.x + dx, tile.y + dy)
|
||||
if nb and nb.can_walk():
|
||||
res.append(nb)
|
||||
return res
|
||||
|
||||
|
||||
# ========== Загрузка из файла ==========
|
||||
class TextLabyrinthBuilder:
|
||||
def build(self, filename):
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
lines = [line.rstrip('\n') for line in f]
|
||||
h = len(lines)
|
||||
w = max(len(l) for l in lines) if h else 0
|
||||
lab = Labyrinth(w, h)
|
||||
for y, row in enumerate(lines):
|
||||
for x, ch in enumerate(row):
|
||||
if ch == '#':
|
||||
lab.configure_tile(x, y, 'wall')
|
||||
elif ch == 'S':
|
||||
lab.configure_tile(x, y, 'entry')
|
||||
elif ch == 'E':
|
||||
lab.configure_tile(x, y, 'goal')
|
||||
elif ch == ' ':
|
||||
lab.configure_tile(x, y, 'floor')
|
||||
return lab
|
||||
|
||||
|
||||
# ========== Алгоритмы поиска ==========
|
||||
class BFS_Pathfinder:
|
||||
def find_path(self, lab, start, goal):
|
||||
if goal is None:
|
||||
self._visited = 0
|
||||
return []
|
||||
q = deque([start])
|
||||
preds = {start: None}
|
||||
seen = {start}
|
||||
while q:
|
||||
cur = q.popleft()
|
||||
if cur == goal:
|
||||
self._visited = len(seen)
|
||||
return self._build_path(preds, start, goal)
|
||||
for nb in lab.neighbours(cur):
|
||||
if nb not in seen:
|
||||
seen.add(nb)
|
||||
preds[nb] = cur
|
||||
q.append(nb)
|
||||
self._visited = len(seen)
|
||||
return []
|
||||
|
||||
def _build_path(self, preds, start, goal):
|
||||
path = []
|
||||
cur = goal
|
||||
while cur is not None:
|
||||
path.append(cur)
|
||||
cur = preds.get(cur)
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
@property
|
||||
def visited_count(self):
|
||||
return getattr(self, '_visited', 0)
|
||||
|
||||
|
||||
class DFS_Pathfinder:
|
||||
def find_path(self, lab, start, goal):
|
||||
if goal is None:
|
||||
self._visited = 0
|
||||
return []
|
||||
stack = [start]
|
||||
preds = {start: None}
|
||||
seen = {start}
|
||||
while stack:
|
||||
cur = stack.pop()
|
||||
if cur == goal:
|
||||
self._visited = len(seen)
|
||||
return self._build_path(preds, start, goal)
|
||||
for nb in lab.neighbours(cur):
|
||||
if nb not in seen:
|
||||
seen.add(nb)
|
||||
preds[nb] = cur
|
||||
stack.append(nb)
|
||||
self._visited = len(seen)
|
||||
return []
|
||||
|
||||
def _build_path(self, preds, start, goal):
|
||||
path = []
|
||||
cur = goal
|
||||
while cur is not None:
|
||||
path.append(cur)
|
||||
cur = preds.get(cur)
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
@property
|
||||
def visited_count(self):
|
||||
return getattr(self, '_visited', 0)
|
||||
|
||||
|
||||
class AStar_Pathfinder:
|
||||
def _heuristic(self, a, b):
|
||||
return abs(a.x - b.x) + abs(a.y - b.y)
|
||||
|
||||
def find_path(self, lab, start, goal):
|
||||
if goal is None:
|
||||
self._visited = 0
|
||||
return []
|
||||
heap = []
|
||||
cnt = 0
|
||||
f_start = self._heuristic(start, goal)
|
||||
heapq.heappush(heap, (f_start, cnt, start))
|
||||
cnt += 1
|
||||
preds = {}
|
||||
g = {start: 0}
|
||||
f = {start: f_start}
|
||||
seen = set()
|
||||
while heap:
|
||||
cur_f, _, cur = heapq.heappop(heap)
|
||||
seen.add(cur)
|
||||
if cur == goal:
|
||||
self._visited = len(seen)
|
||||
return self._build_path(preds, start, goal)
|
||||
if cur_f > f.get(cur, float('inf')):
|
||||
continue
|
||||
for nb in lab.neighbours(cur):
|
||||
tent_g = g[cur] + 1
|
||||
if tent_g < g.get(nb, float('inf')):
|
||||
preds[nb] = cur
|
||||
g[nb] = tent_g
|
||||
new_f = tent_g + self._heuristic(nb, goal)
|
||||
f[nb] = new_f
|
||||
heapq.heappush(heap, (new_f, cnt, nb))
|
||||
cnt += 1
|
||||
self._visited = len(seen)
|
||||
return []
|
||||
|
||||
def _build_path(self, preds, start, goal):
|
||||
path = []
|
||||
cur = goal
|
||||
while cur is not None:
|
||||
path.append(cur)
|
||||
cur = preds.get(cur)
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
@property
|
||||
def visited_count(self):
|
||||
return getattr(self, '_visited', 0)
|
||||
|
||||
|
||||
class LabyrinthSolver:
|
||||
def __init__(self, lab):
|
||||
self._lab = lab
|
||||
self._strategy = None
|
||||
|
||||
def set_strategy(self, strategy):
|
||||
self._strategy = strategy
|
||||
|
||||
def solve(self):
|
||||
start_t = time.perf_counter()
|
||||
path = self._strategy.find_path(self._lab, self._lab.start, self._lab.exit)
|
||||
elapsed = (time.perf_counter() - start_t) * 1000
|
||||
return {
|
||||
'time_ms': elapsed,
|
||||
'visited': self._strategy.visited_count,
|
||||
'length': len(path)
|
||||
}
|
||||
|
||||
|
||||
# ========== Графики ==========
|
||||
def create_charts(results, save_filename='maze_performance.png'):
|
||||
mazes = list(set([r['maze'] for r in results]))
|
||||
strategies = ['BFS', 'DFS', 'AStar']
|
||||
|
||||
data = {s: {m: None for m in mazes} for s in strategies}
|
||||
for r in results:
|
||||
data[r['strategy']][r['maze']] = r
|
||||
|
||||
times = {s: [data[s][m]['time_ms'] for m in mazes] for s in strategies}
|
||||
visited = {s: [data[s][m]['visited_cells'] for m in mazes] for s in strategies}
|
||||
lengths = {s: [data[s][m]['path_length'] for m in mazes] for s in strategies}
|
||||
|
||||
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
|
||||
x = np.arange(len(mazes))
|
||||
width = 0.25
|
||||
|
||||
# Время
|
||||
axes[0].bar(x - width, times['BFS'], width, label='BFS', color='blue', alpha=0.7)
|
||||
axes[0].bar(x, times['DFS'], width, label='DFS', color='green', alpha=0.7)
|
||||
axes[0].bar(x + width, times['AStar'], width, label='A*', color='red', alpha=0.7)
|
||||
axes[0].set_xlabel('Лабиринты')
|
||||
axes[0].set_ylabel('Время (мс)')
|
||||
axes[0].set_title('Время выполнения алгоритмов')
|
||||
axes[0].set_xticks(x)
|
||||
axes[0].set_xticklabels(mazes, rotation=15, ha='right', fontsize=8)
|
||||
axes[0].legend()
|
||||
axes[0].grid(True, alpha=0.3)
|
||||
|
||||
# Посещённые клетки
|
||||
axes[1].bar(x - width, visited['BFS'], width, label='BFS', color='blue', alpha=0.7)
|
||||
axes[1].bar(x, visited['DFS'], width, label='DFS', color='green', alpha=0.7)
|
||||
axes[1].bar(x + width, visited['AStar'], width, label='A*', color='red', alpha=0.7)
|
||||
axes[1].set_xlabel('Лабиринты')
|
||||
axes[1].set_ylabel('Количество клеток')
|
||||
axes[1].set_title('Посещённые клетки')
|
||||
axes[1].set_xticks(x)
|
||||
axes[1].set_xticklabels(mazes, rotation=15, ha='right', fontsize=8)
|
||||
axes[1].legend()
|
||||
axes[1].grid(True, alpha=0.3)
|
||||
|
||||
# Длина пути
|
||||
axes[2].bar(x - width, lengths['BFS'], width, label='BFS', color='blue', alpha=0.7)
|
||||
axes[2].bar(x, lengths['DFS'], width, label='DFS', color='green', alpha=0.7)
|
||||
axes[2].bar(x + width, lengths['AStar'], width, label='A*', color='red', alpha=0.7)
|
||||
axes[2].set_xlabel('Лабиринты')
|
||||
axes[2].set_ylabel('Длина пути')
|
||||
axes[2].set_title('Длина найденного пути')
|
||||
axes[2].set_xticks(x)
|
||||
axes[2].set_xticklabels(mazes, rotation=15, ha='right', fontsize=8)
|
||||
axes[2].legend()
|
||||
axes[2].grid(True, alpha=0.3)
|
||||
|
||||
plt.suptitle('Сравнение алгоритмов поиска пути', fontsize=14, fontweight='bold')
|
||||
plt.tight_layout()
|
||||
plt.savefig(save_filename, dpi=300, bbox_inches='tight')
|
||||
print(f"\nГрафик сохранён в файл: {save_filename}")
|
||||
plt.show()
|
||||
|
||||
|
||||
# ========== Основная программа ==========
|
||||
def main():
|
||||
print('\n' + '=' * 60)
|
||||
print('ПОИСК ВЫХОДА ИЗ ЛАБИРИНТА')
|
||||
print('Сравнение алгоритмов BFS, DFS и A*')
|
||||
print('=' * 60)
|
||||
|
||||
# Находим все txt файлы в текущей директории
|
||||
maze_files = [f for f in os.listdir('.') if f.endswith('.txt') and f.startswith('maze_')]
|
||||
|
||||
if not maze_files:
|
||||
print("\nНет файлов с лабиринтами (maze_*.txt)")
|
||||
return
|
||||
|
||||
print(f"\nНайдено лабиринтов: {len(maze_files)}")
|
||||
for f in maze_files:
|
||||
print(f" - {f}")
|
||||
|
||||
strategies = [
|
||||
('BFS', BFS_Pathfinder()),
|
||||
('DFS', DFS_Pathfinder()),
|
||||
('AStar', AStar_Pathfinder())
|
||||
]
|
||||
|
||||
all_results = []
|
||||
builder = TextLabyrinthBuilder()
|
||||
|
||||
for maze_file in sorted(maze_files):
|
||||
maze_name = maze_file.replace('.txt', '').replace('maze_', '').replace('_', ' ').title()
|
||||
print(f"\nОбработка лабиринта: {maze_name}")
|
||||
|
||||
lab = builder.build(maze_file)
|
||||
|
||||
for sname, strat in strategies:
|
||||
solver = LabyrinthSolver(lab)
|
||||
solver.set_strategy(strat)
|
||||
stats = solver.solve()
|
||||
|
||||
all_results.append({
|
||||
'maze': maze_name,
|
||||
'strategy': sname,
|
||||
'time_ms': stats['time_ms'],
|
||||
'visited_cells': stats['visited'],
|
||||
'path_length': stats['length']
|
||||
})
|
||||
|
||||
status = "Найден" if stats['length'] > 0 else "Не найден"
|
||||
print(f" {sname}: {status} (время: {stats['time_ms']:.3f} мс, посещено: {stats['visited']}, длина: {stats['length']})")
|
||||
|
||||
# Сохранение в CSV
|
||||
print('\n' + '=' * 60)
|
||||
print('СОХРАНЕНИЕ РЕЗУЛЬТАТОВ В CSV')
|
||||
print('=' * 60)
|
||||
|
||||
csv_filename = 'experiment_results.csv'
|
||||
with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile:
|
||||
fieldnames = ['лабиринт', 'стратегия', 'время_мс', 'посещено_клеток', 'длина_пути']
|
||||
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||
|
||||
writer.writeheader()
|
||||
for result in all_results:
|
||||
writer.writerow({
|
||||
'лабиринт': result['maze'],
|
||||
'стратегия': result['strategy'],
|
||||
'время_мс': f"{result['time_ms']:.3f}",
|
||||
'посещено_клеток': result['visited_cells'],
|
||||
'длина_пути': result['path_length']
|
||||
})
|
||||
|
||||
print(f"\nРезультаты сохранены в файл: {csv_filename}")
|
||||
|
||||
# Вывод таблицы в консоль
|
||||
print('\n' + '=' * 100)
|
||||
print('ТАБЛИЦА РЕЗУЛЬТАТОВ')
|
||||
print('=' * 100)
|
||||
print(f"{'Лабиринт':<20} {'Стратегия':<10} {'Время (мс)':<12} {'Посещено':<12} {'Длина пути':<12}")
|
||||
print('-' * 100)
|
||||
for r in all_results:
|
||||
print(f"{r['maze']:<20} {r['strategy']:<10} {r['time_ms']:<12.3f} {r['visited_cells']:<12.0f} {r['path_length']:<12.0f}")
|
||||
print('=' * 100)
|
||||
|
||||
# Создание графика
|
||||
print('\nСОЗДАНИЕ ГРАФИКА...')
|
||||
create_charts(all_results, 'maze_performance.png')
|
||||
|
||||
# Статистика
|
||||
print('\n' + '=' * 60)
|
||||
print('СТАТИСТИКА')
|
||||
print('=' * 60)
|
||||
|
||||
for strategy in ['BFS', 'DFS', 'AStar']:
|
||||
strategy_results = [r for r in all_results if r['strategy'] == strategy and r['path_length'] > 0]
|
||||
if strategy_results:
|
||||
avg_time = sum(r['time_ms'] for r in strategy_results) / len(strategy_results)
|
||||
avg_visited = sum(r['visited_cells'] for r in strategy_results) / len(strategy_results)
|
||||
avg_length = sum(r['path_length'] for r in strategy_results) / len(strategy_results)
|
||||
print(f'\n{strategy}:')
|
||||
print(f' Среднее время: {avg_time:.3f} мс')
|
||||
print(f' Среднее посещено: {avg_visited:.0f} клеток')
|
||||
print(f' Средняя длина пути: {avg_length:.1f}')
|
||||
|
||||
print('\n' + '=' * 60)
|
||||
print('ГОТОВО')
|
||||
print(f'Результаты сохранены в:')
|
||||
print(f' - {csv_filename} (таблица)')
|
||||
print(f' - maze_performance.png (график)')
|
||||
print('=' * 60)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
dyachenkoas/docs/data2/maze_performance.png
Normal file
BIN
dyachenkoas/docs/data2/maze_performance.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
Loading…
Reference in New Issue
Block a user