forked from UNN/2026-rff_mp
Загрузить файлы в «SmirnovaVYu/docs/data»
This commit is contained in:
parent
8cb368fdd4
commit
ac4f3924d8
62
SmirnovaVYu/docs/data/commands.py
Normal file
62
SmirnovaVYu/docs/data/commands.py
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import Optional
|
||||||
|
from models import Cell, Maze
|
||||||
|
|
||||||
|
|
||||||
|
class Player:
|
||||||
|
|
||||||
|
def __init__(self, start_cell: Cell):
|
||||||
|
self.current_cell = start_cell
|
||||||
|
|
||||||
|
def move_to(self, new_cell: Cell) -> None:
|
||||||
|
self.current_cell = new_cell
|
||||||
|
|
||||||
|
|
||||||
|
class Command(ABC):
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def execute(self) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def undo(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MoveCommand(Command):
|
||||||
|
|
||||||
|
def __init__(self, player: Player, maze: Maze, direction: str):
|
||||||
|
self.player = player
|
||||||
|
self.maze = maze
|
||||||
|
self.direction = direction
|
||||||
|
self.previous_cell: Optional[Cell] = None
|
||||||
|
self.new_cell: Optional[Cell] = None
|
||||||
|
|
||||||
|
def _get_target_cell(self) -> Optional[Cell]:
|
||||||
|
x, y = self.player.current_cell.x, self.player.current_cell.y
|
||||||
|
|
||||||
|
if self.direction == 'w':
|
||||||
|
y -= 1
|
||||||
|
elif self.direction == 's':
|
||||||
|
y += 1
|
||||||
|
elif self.direction == 'a':
|
||||||
|
x -= 1
|
||||||
|
elif self.direction == 'd':
|
||||||
|
x += 1
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.maze.get_cell(x, y)
|
||||||
|
|
||||||
|
def execute(self) -> bool:
|
||||||
|
self.previous_cell = self.player.current_cell
|
||||||
|
self.new_cell = self._get_target_cell()
|
||||||
|
|
||||||
|
if self.new_cell and self.new_cell.is_passable():
|
||||||
|
self.player.move_to(self.new_cell)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def undo(self) -> None:
|
||||||
|
if self.previous_cell:
|
||||||
|
self.player.move_to(self.previous_cell)
|
||||||
13
SmirnovaVYu/docs/data/experiment_results.csv
Normal file
13
SmirnovaVYu/docs/data/experiment_results.csv
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
maze_file,maze_size,strategy,time_mean,time_min,time_max,visited_mean,path_length_mean,path_found
|
||||||
|
small.txt,10×10,BFS,0.14973321231082082,0.08187501225620508,0.3416250110603869,15.0,15.0,True
|
||||||
|
small.txt,10×10,DFS,0.05074121290817857,0.036958022974431515,0.09620800847187638,21.0,21.0,True
|
||||||
|
small.txt,10×10,A*,0.11340839555487037,0.07800001185387373,0.24145899806171656,15.0,15.0,True
|
||||||
|
medium.txt,20×11,BFS,0.28489179676398635,0.21541700698435307,0.3855000250041485,26.0,26.0,True
|
||||||
|
medium.txt,20×11,DFS,0.22732499055564404,0.16850000247359276,0.396291958168149,90.0,90.0,True
|
||||||
|
medium.txt,20×11,A*,0.2952334121800959,0.290708034299314,0.30733400490134954,26.0,26.0,True
|
||||||
|
large.txt,30×15,BFS,0.5741997971199453,0.4562910180538893,0.8350000134669244,40.0,40.0,True
|
||||||
|
large.txt,30×15,DFS,0.4984830040484667,0.38241699803620577,0.6361660198308527,196.0,196.0,True
|
||||||
|
large.txt,30×15,A*,0.6602250039577484,0.6104999920353293,0.7946669938974082,40.0,40.0,True
|
||||||
|
empty.txt,30×1,BFS,0.06608341354876757,0.04250003257766366,0.11475000064820051,30.0,30.0,True
|
||||||
|
empty.txt,30×1,DFS,0.048741791397333145,0.039041973650455475,0.06312498589977622,30.0,30.0,True
|
||||||
|
empty.txt,30×1,A*,0.06089139496907592,0.055582961067557335,0.07212499622255564,30.0,30.0,True
|
||||||
|
BIN
SmirnovaVYu/docs/data/experiment_results.png
Normal file
BIN
SmirnovaVYu/docs/data/experiment_results.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
94
SmirnovaVYu/docs/data/experiments.py
Normal file
94
SmirnovaVYu/docs/data/experiments.py
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
import csv
|
||||||
|
import time
|
||||||
|
from typing import List, Dict
|
||||||
|
from models import Maze
|
||||||
|
from builders import TextFileMazeBuilder
|
||||||
|
from strategies import BFSStrategy, DFSStrategy, AStarStrategy
|
||||||
|
from solver import MazeSolver
|
||||||
|
|
||||||
|
|
||||||
|
def run_experiment(maze: Maze, strategy_name: str, strategy, repeats: int = 5) -> Dict:
|
||||||
|
times = []
|
||||||
|
visited_counts = []
|
||||||
|
path_lengths = []
|
||||||
|
path_found = True
|
||||||
|
|
||||||
|
for _ in range(repeats):
|
||||||
|
solver = MazeSolver(maze, strategy)
|
||||||
|
path, stats = solver.solve()
|
||||||
|
|
||||||
|
times.append(stats.time_ms)
|
||||||
|
visited_counts.append(stats.visited_cells)
|
||||||
|
path_lengths.append(stats.path_length)
|
||||||
|
path_found = stats.path_found
|
||||||
|
|
||||||
|
return {
|
||||||
|
'strategy': strategy_name,
|
||||||
|
'time_mean': sum(times) / len(times),
|
||||||
|
'time_min': min(times),
|
||||||
|
'time_max': max(times),
|
||||||
|
'visited_mean': sum(visited_counts) / len(visited_counts),
|
||||||
|
'path_length_mean': sum(path_lengths) / len(path_lengths) if path_found else 0,
|
||||||
|
'path_found': path_found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def run_all_experiments(maze_files: List[str], repeats: int = 5) -> List[Dict]:
|
||||||
|
builder = TextFileMazeBuilder()
|
||||||
|
strategies = [
|
||||||
|
('BFS', BFSStrategy()),
|
||||||
|
('DFS', DFSStrategy()),
|
||||||
|
('A*', AStarStrategy())
|
||||||
|
]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for maze_file in maze_files:
|
||||||
|
try:
|
||||||
|
maze = builder.build_from_file(maze_file)
|
||||||
|
except (ValueError, FileNotFoundError) as e:
|
||||||
|
print(f" Ошибка: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f" Размер: {maze.width}×{maze.height}")
|
||||||
|
print(f" Старт: ({maze.start.x}, {maze.start.y})")
|
||||||
|
print(f" Выход: ({maze.exit.x}, {maze.exit.y})")
|
||||||
|
|
||||||
|
for strategy_name, strategy in strategies:
|
||||||
|
print(f" Тестирование: {strategy_name}")
|
||||||
|
result = run_experiment(maze, strategy_name, strategy, repeats)
|
||||||
|
result['maze_file'] = maze_file.split('/')[-1]
|
||||||
|
result['maze_size'] = f"{maze.width}×{maze.height}"
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
status = "ok" if result['path_found'] else "ne ok"
|
||||||
|
print(f" {status} Время: {result['time_mean']:.2f} мс, "
|
||||||
|
f"Посещено: {result['visited_mean']:.0f}, "
|
||||||
|
f"Путь: {result['path_length_mean']:.0f}")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def save_results_to_csv(results: List[Dict], filename: str = "experiment_results.csv") -> None:
|
||||||
|
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
||||||
|
writer = csv.DictWriter(f, fieldnames=[
|
||||||
|
'maze_file', 'maze_size', 'strategy',
|
||||||
|
'time_mean', 'time_min', 'time_max',
|
||||||
|
'visited_mean', 'path_length_mean', 'path_found'
|
||||||
|
])
|
||||||
|
writer.writeheader()
|
||||||
|
writer.writerows(results)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def print_results_table(results: List[Dict]) -> None:
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("РЕЗУЛЬТАТЫ ЭКСПЕРИМЕНТОВ")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
for res in results:
|
||||||
|
print(f"\nЛабиринт: {res['maze_file']}")
|
||||||
|
print(f" Стратегия: {res['strategy']}")
|
||||||
|
print(f" Время (ср): {res['time_mean']:.2f} мс")
|
||||||
|
print(f" Посещено: {res['visited_mean']:.0f} клеток")
|
||||||
|
print(f" Длина пути: {res['path_length_mean']:.0f}")
|
||||||
146
SmirnovaVYu/docs/data/main.py
Normal file
146
SmirnovaVYu/docs/data/main.py
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
import os
|
||||||
|
from builders import TextFileMazeBuilder
|
||||||
|
from strategies import BFSStrategy, DFSStrategy, AStarStrategy
|
||||||
|
from solver import MazeSolver
|
||||||
|
from observers import ConsoleView
|
||||||
|
from commands import Player
|
||||||
|
from experiments import run_all_experiments, save_results_to_csv, print_results_table
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_mazes():
|
||||||
|
os.makedirs("mazes", exist_ok=True)
|
||||||
|
|
||||||
|
small = """##########
|
||||||
|
#S #
|
||||||
|
# ### ## #
|
||||||
|
# # #
|
||||||
|
### # ####
|
||||||
|
# # #
|
||||||
|
# ### # #
|
||||||
|
# # #
|
||||||
|
# # E#
|
||||||
|
##########"""
|
||||||
|
|
||||||
|
medium = """####################
|
||||||
|
#S #
|
||||||
|
# # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # #
|
||||||
|
# E#
|
||||||
|
####################"""
|
||||||
|
|
||||||
|
large = """##############################
|
||||||
|
#S #
|
||||||
|
# # # # # # # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # # # # # # #
|
||||||
|
# #
|
||||||
|
# # # # # # # # # # # # # # #
|
||||||
|
# E#
|
||||||
|
##############################"""
|
||||||
|
|
||||||
|
empty = "S" + " " * 28 + "E"
|
||||||
|
|
||||||
|
no_exit = """#######
|
||||||
|
#S #
|
||||||
|
# ### #
|
||||||
|
# # #
|
||||||
|
#######"""
|
||||||
|
|
||||||
|
with open("mazes/small.txt", "w") as f:
|
||||||
|
f.write(small)
|
||||||
|
with open("mazes/medium.txt", "w") as f:
|
||||||
|
f.write(medium)
|
||||||
|
with open("mazes/large.txt", "w") as f:
|
||||||
|
f.write(large)
|
||||||
|
with open("mazes/empty.txt", "w") as f:
|
||||||
|
f.write(empty)
|
||||||
|
with open("mazes/no_exit.txt", "w") as f:
|
||||||
|
f.write(no_exit)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def demo_maze_solver():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("ДЕМОНСТРАЦИЯ РАБОТЫ MAZE SOLVER")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
builder = TextFileMazeBuilder()
|
||||||
|
view = ConsoleView()
|
||||||
|
|
||||||
|
maze = builder.build_from_file("mazes/small.txt")
|
||||||
|
view.update("maze_loaded", {"maze": maze})
|
||||||
|
|
||||||
|
strategies = [
|
||||||
|
("BFS", BFSStrategy(), "BFS"),
|
||||||
|
("DFS", DFSStrategy(), "DFSs"),
|
||||||
|
("A*", AStarStrategy(), "A*")
|
||||||
|
]
|
||||||
|
|
||||||
|
for name, strategy, description in strategies:
|
||||||
|
solver = MazeSolver(maze, strategy)
|
||||||
|
view.update("search_start", {"algorithm": description})
|
||||||
|
|
||||||
|
path, stats = solver.solve()
|
||||||
|
|
||||||
|
if stats.path_found:
|
||||||
|
view.update("path_found", {"maze": maze, "path": path, "stats": stats})
|
||||||
|
else:
|
||||||
|
view.update("no_path", {"stats": stats})
|
||||||
|
|
||||||
|
|
||||||
|
def demo_player_controls():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("Command + Observer")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
builder = TextFileMazeBuilder()
|
||||||
|
view = ConsoleView()
|
||||||
|
maze = builder.build_from_file("mazes/small.txt")
|
||||||
|
|
||||||
|
player = Player(maze.start)
|
||||||
|
|
||||||
|
view.update("maze_loaded", {"maze": maze})
|
||||||
|
view.render(maze, player_position=player.current_cell)
|
||||||
|
|
||||||
|
|
||||||
|
def run_experiments():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("ЭКСПЕРИМЕНТАЛЬНОЕ СРАВНЕНИЕ АЛГОРИТМОВ")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
maze_files = [
|
||||||
|
"mazes/small.txt",
|
||||||
|
"mazes/medium.txt",
|
||||||
|
"mazes/large.txt",
|
||||||
|
"mazes/empty.txt",
|
||||||
|
"mazes/no_exit.txt"
|
||||||
|
]
|
||||||
|
|
||||||
|
results = run_all_experiments(maze_files, repeats=5)
|
||||||
|
save_results_to_csv(results)
|
||||||
|
print_results_table(results)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Объектно-ориентированная реализация с паттернами")
|
||||||
|
print("Паттерны: Builder, Strategy, Observer, Command")
|
||||||
|
|
||||||
|
create_test_mazes()
|
||||||
|
demo_maze_solver()
|
||||||
|
demo_player_controls()
|
||||||
|
run_experiments()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user