[2] 10-th version, add a lot of mazes.txt, report and others ;)

This commit is contained in:
root 2026-09-03 02:33:34 +03:00
parent b0fccd4611
commit 8552f7bb4a
15 changed files with 789 additions and 134 deletions

View File

@ -41,6 +41,24 @@ class Maze:
neighbors.append(neighbor)
return neighbors
def save_to_file(self, filename):
"""Сохраняет лабиринт в текстовый файл."""
with open(filename, 'w', encoding='utf-8') as f:
for y in range(self.height):
row = ''
for x in range(self.width):
cell = self.get_cell(x, y)
if cell.is_wall:
row += '#'
elif cell.is_start:
row += 'S'
elif cell.is_exit:
row += 'E'
else:
row += ' '
f.write(row + '\n')
class MazeBuilder:
def build_from_file(self, filename):
@ -166,41 +184,6 @@ class AStarStrategy(PathFindingStrategy):
return []
class MazeSolver:
def __init__(self, maze, strategy=None):
self.maze = maze
self.strategy = strategy
self.observers = [] # для Observer
def set_strategy(self, strategy):
self.strategy = strategy
def attach(self, observer):
self.observers.append(observer)
def detach(self, observer):
self.observers.remove(observer)
def notify(self, event):
for obs in self.observers:
obs.update(event)
def solve(self):
if self.strategy is None:
raise ValueError("Стратегия не установлена")
start = self.maze.start_cell
exit_cell = self.maze.exit_cell
if start is None or exit_cell is None:
raise ValueError("Лабиринт не содержит старта или выхода")
self.notify("Поиск начат")
start_time = time.perf_counter()
path = self.strategy.find_path(self.maze, start, exit_cell)
end_time = time.perf_counter()
elapsed_ms = (end_time - start_time) * 1000
self.notify("Поиск завершён")
return path, elapsed_ms
class Observer:
def update(self, event):
raise NotImplementedError
@ -236,49 +219,41 @@ class ConsoleView(Observer):
print()
class Command:
def execute(self):
raise NotImplementedError
def undo(self):
raise NotImplementedError
class MoveCommand(Command):
def __init__(self, player, dx, dy):
self.player = player
self.dx = dx
self.dy = dy
self.prev_x = player.x
self.prev_y = player.y
def execute(self):
new_x = self.player.x + self.dx
new_y = self.player.y + self.dy
maze = self.player.maze
cell = maze.get_cell(new_x, new_y)
if cell and cell.is_passable():
self.player.x = new_x
self.player.y = new_y
self.player.current_cell = cell
return True
return False
def undo(self):
self.player.x = self.prev_x
self.player.y = self.prev_y
self.player.current_cell = self.player.maze.get_cell(self.prev_x, self.prev_y)
class Player:
def __init__(self, maze, start_cell):
class MazeSolver:
def __init__(self, maze, strategy=None):
self.maze = maze
self.x = start_cell.x
self.y = start_cell.y
self.current_cell = start_cell
self.strategy = strategy
self.observers = []
def set_strategy(self, strategy):
self.strategy = strategy
def attach(self, observer):
self.observers.append(observer)
def detach(self, observer):
self.observers.remove(observer)
def notify(self, event):
for obs in self.observers:
obs.update(event)
def solve(self):
if self.strategy is None:
raise ValueError("Стратегия не установлена")
start = self.maze.start_cell
exit_cell = self.maze.exit_cell
if start is None or exit_cell is None:
raise ValueError("Лабиринт не содержит старта или выхода")
self.notify("Поиск начат")
start_time = time.perf_counter()
path = self.strategy.find_path(self.maze, start, exit_cell)
end_time = time.perf_counter()
elapsed_ms = (end_time - start_time) * 1000
self.notify("Поиск завершён")
return path, elapsed_ms
# EEEEEEEEEKSPERIMENTY
def generate_empty_maze(width, height):
maze = Maze(width, height)
start = maze.get_cell(0, 0)
@ -348,35 +323,51 @@ def generate_maze_no_exit(width, height):
return maze
def run_experiment():
os.makedirs("results", exist_ok=True)
maze_generators = [
("empty_10x10", lambda: generate_empty_maze(10, 10)),
("empty_50x50", lambda: generate_empty_maze(50, 50)),
("empty_100x100", lambda: generate_empty_maze(100, 100)),
("random_10x10", lambda: generate_random_maze(10, 10, 0.3)),
("random_50x50", lambda: generate_random_maze(50, 50, 0.3)),
("random_100x100", lambda: generate_random_maze(100, 100, 0.3)),
("dead_ends_10x10", lambda: generate_maze_with_dead_ends(10, 10)),
("dead_ends_50x50", lambda: generate_maze_with_dead_ends(50, 50)),
("dead_ends_100x100", lambda: generate_maze_with_dead_ends(100, 100)),
("no_exit_10x10", lambda: generate_maze_no_exit(10, 10)),
("no_exit_50x50", lambda: generate_maze_no_exit(50, 50)),
def ensure_maze_files():
"""Создаёт папку mazes и генерирует все лабиринты, если файлы отсутствуют."""
os.makedirs("mazes", exist_ok=True)
configs = [
("empty_10x10.txt", 10, 10, generate_empty_maze),
("empty_50x50.txt", 50, 50, generate_empty_maze),
("empty_100x100.txt", 100, 100, generate_empty_maze),
("random_10x10.txt", 10, 10, generate_random_maze),
("random_50x50.txt", 50, 50, generate_random_maze),
("random_100x100.txt", 100, 100, generate_random_maze),
("deadends_10x10.txt", 10, 10, generate_maze_with_dead_ends),
("deadends_50x50.txt", 50, 50, generate_maze_with_dead_ends),
("deadends_100x100.txt", 100, 100, generate_maze_with_dead_ends),
("no_exit_10x10.txt", 10, 10, generate_maze_no_exit),
("no_exit_50x50.txt", 50, 50, generate_maze_no_exit),
]
for filename, w, h, gen_func in configs:
filepath = os.path.join("mazes", filename)
if not os.path.exists(filepath):
print(f"Генерация {filename}...")
maze = gen_func(w, h)
maze.save_to_file(filepath)
def run_experiment():
ensure_maze_files()
builder = TextFileMazeBuilder()
strategies = [
("BFS", BFSStrategy()),
("DFS", DFSStrategy()),
("AStar", AStarStrategy())
]
maze_files = sorted([f for f in os.listdir("mazes") if f.endswith(".txt")])
results = []
repeats = 5
all_results = []
for maze_name, gen_func in maze_generators:
for filename in maze_files:
maze_name = filename.replace(".txt", "")
print(f"Тестирование лабиринта: {maze_name}")
maze = gen_func()
try:
maze = builder.build_from_file(os.path.join("mazes", filename))
except Exception as e:
print(f"Ошибка загрузки {filename}: {e}")
continue
solver = MazeSolver(maze)
for strat_name, strat in strategies:
solver.set_strategy(strat)
@ -389,7 +380,7 @@ def run_experiment():
total_path_len += len(path) if path else 0
avg_time = total_time / repeats
avg_len = total_path_len / repeats
all_results.append({
results.append({
"Maze": maze_name,
"Strategy": strat_name,
"AvgTime_ms": avg_time,
@ -398,20 +389,19 @@ def run_experiment():
})
print(f" {strat_name}: время {avg_time:.3f} мс, длина пути {avg_len:.1f}")
# Сохраняем CSV
os.makedirs("results", exist_ok=True)
csv_path = "results/experiment_results.csv"
with open(csv_path, 'w', newline='', encoding='utf-8') as f:
fieldnames = ["Maze", "Strategy", "AvgTime_ms", "AvgPathLen", "PathFound"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(all_results)
writer.writerows(results)
print(f"Результаты сохранены в {csv_path}")
# Построение графика
maze_names = sorted(set(r["Maze"] for r in all_results))
maze_names = sorted(set(r["Maze"] for r in results))
strategy_names = ["BFS", "DFS", "AStar"]
data = {maze: {s: None for s in strategy_names} for maze in maze_names}
for r in all_results:
for r in results:
data[r["Maze"]][r["Strategy"]] = r["AvgTime_ms"]
fig, ax = plt.subplots(figsize=(14, 6))
@ -432,7 +422,7 @@ def run_experiment():
plt.tight_layout()
plt.savefig("results/performance.png", dpi=150)
plt.show()
#plt.show()
print("График сохранён в results/performance.png")

View File

@ -0,0 +1,100 @@
S ##################################################################################################
# ##################################################################################################
# ##################################################################################################
# #################################################################################################
## ##############################################################################################
##### ##############################################################################################
##### ############################################################################################
####### ###########################################################################################
######## ######################################################################################
############# ##################################################################################
################# #################################################################################
################## #################################################################################
################## #################################################################################
################## ################################################################################
################### ################################################################################
################### #############################################################################
###################### ############################################################################
####################### ############################################################################
####################### ############################################################################
####################### ############################################################################
####################### ###########################################################################
######################## ##########################################################################
######################### #########################################################################
########################## ########################################################################
########################### #####################################################################
############################## #####################################################################
############################## #####################################################################
############################## ####################################################################
############################### ####################################################################
############################### ####################################################################
############################### ##################################################################
################################# ##################################################################
################################# #################################################################
################################## ###############################################################
#################################### ##############################################################
##################################### ##############################################################
##################################### ##############################################################
##################################### ############################################################
####################################### ############################################################
####################################### ############################################################
####################################### ############################################################
####################################### ##########################################################
######################################### #########################################################
########################################## ########################################################
########################################### ########################################################
########################################### ########################################################
########################################### ########################################################
########################################### #######################################################
############################################ #####################################################
############################################## ##################################################
################################################# ##################################################
################################################# ##############################################
##################################################### #############################################
###################################################### ############################################
####################################################### ############################################
####################################################### ############################################
####################################################### ###########################################
######################################################## ###########################################
######################################################## ##########################################
######################################################### ##########################################
######################################################### ##########################################
######################################################### ##########################################
######################################################### #########################################
########################################################## #######################################
############################################################ #####################################
############################################################## #####################################
############################################################## ####################################
############################################################### ###################################
################################################################ ###################################
################################################################ ##################################
################################################################# ###############################
#################################################################### #############################
###################################################################### ###########################
######################################################################## ##########################
######################################################################### ########################
########################################################################### #######################
############################################################################ #######################
############################################################################ ###################
################################################################################ ##################
################################################################################# #################
################################################################################## #################
################################################################################## #################
################################################################################## ##############
##################################################################################### ############
####################################################################################### ###########
######################################################################################## ###########
######################################################################################## ##########
######################################################################################### ##########
######################################################################################### ########
########################################################################################### #######
############################################################################################ #####
############################################################################################## ###
################################################################################################ ##
################################################################################################# ##
################################################################################################# ##
################################################################################################# ##
################################################################################################# ##
################################################################################################# #
##################################################################################################
###################################################################################################E

View File

@ -0,0 +1,10 @@
S #######
## #######
## #######
## #######
## #######
## ######
### #####
#### ##
####### ##
####### E

View File

@ -0,0 +1,50 @@
S ################################################
# ###############################################
## ###############################################
## ###############################################
## ##############################################
### ##############################################
### ############################################
##### ###########################################
###### ######################################
########### ######################################
########### #####################################
############ ##################################
############### #################################
################ ###############################
################## ###############################
################## ###########################
###################### ###########################
###################### ########################
######################### #######################
########################## #######################
########################## ######################
########################### #####################
############################ #####################
############################ ####################
############################# ###################
############################## ###################
############################## ###################
############################## ################
################################# ###########
###################################### ##########
####################################### #########
######################################## #########
######################################## ########
######################################### #######
########################################## #####
############################################ ####
############################################# ###
############################################## ###
############################################## ##
###############################################
#################################################
#################################################
#################################################
#################################################
#################################################
#################################################
#################################################
#################################################
#################################################
#################################################E

View File

@ -0,0 +1,100 @@
S
E

View File

@ -0,0 +1,10 @@
S
E

View File

@ -0,0 +1,50 @@
S
E

View File

@ -0,0 +1,10 @@
S ##
#
# #
###
# # #
# # #
## #
###
# #
#E

View File

@ -0,0 +1,50 @@
S # # # ## #
# ### ## # # # # # #
# # # # # # # # # #
# # # # # # # # ##
### # # # # ## # # # # ## ##
### # # # # # # #
# ## #
## ### ## # # #
# # # # # # ### # ##
# # # # # # #
#### ### # # # # # # #
## # # # # # # # # ## #
# ## # ## ## # #
## # # ## # # # # # #
### # # # # # # #
# ## ## # # # # # # #
# # # # # # # # ####
# # ## # # # # # # #
## # ### #
# ## # # # #
# # # # # #
# ## # ## #### ### # # # #
# # # # ###
### ## ## # # # ##
# # # ## #
# # ## ### # # # #
# # # # ### # ## # # # #
## # # # # ## #
# # # # # ## # # #
# # # # # #
# # # # ## # # # # # # # #
# # # # # ## # # #
# # # ## #
# # # # # # # # # ### #
# # # # # # #
# ## # # ## # ## # #
# # # # ## # ##
# # # # # # # # #
## ### # ### # # # #
## ## ## # # # ## # # # #
# # ### # # # # #
# # # # ## ## ## #
# # # ## ## ### # #
# # # ## # #
## # # # # # #
# # # # # #
# # # # ##
## # # # # # ## #
# # ## # # ### # #
# ## # # # # # # ## ## #E

View File

@ -0,0 +1,100 @@
S ## ## # # # # # # # # # # # ## ### # #
### # # ### # ##### # # ### ## ## # # # # # ### # # # #
## # # # # # # ### # ## # # # # # # ### # # ### ##
# ## # # # # # ## # # # ## # ## # ### ## ## # ## #
## # # # # # # # # # # # # # # # # ## # # # # # # #
# ## ## # ## # # ### ## # # # # # ## # # # # ## #
## # # ### # # # ## # # ## # ## #### #### ## ## #
# # ##### # ### # # # ### ### # ## # ### # # ## # # #
# ## # # #### # # # ### ### # # # # ### # # ## # # #
# # # ## ## # # ### # # ## # ## # # # # ##
# ## # # # ## ## # # ## ## # # # # # # ## ## # # # ## # ###
# ## ## ## # ## # # # # # # # # ## # ####### # ####
# ## # # # ## # # ## # # # # # # # # # ### # # ###
# ## # ### # ## # # # # # # # ## ### # # # # # ## ## #
# # ### # # ##### # # # # # # # # ## # # # #
## # # # # # # # # # # # # # # ## ## # ## #
# # # # # # # # ### # ## # ## # # ## # # # ## ##
## # # # # #### # # # # ## # # # # # # # #
# # # ## ## # # # # # # # # # # # # # ### ## # # #
# # # ## ### # ### # ## # # # # # # #### #### ##
# # # # #### # ## # # # ## ## # ## ### # # # # # # # #
## # # ### # # # ## ## # # # ## # # # # # ## #
# # ### ## # ## # ## # ## ## ## ## # ## # ## # #
## # #### # # # # # # ## ## # ## # # ## # # # ##
# # # ## ## # ### # # #### # # ### # # # ## # # ## #
# ### #### # # # # # # ## # ### # # ### ## # #
## # # ## # # # # # # # # ## ## ## # ## # # # # # # #
# ### # # # # # # ## ## # ### # # ### ###
# ## # # # ## # # ## # # # # # # # # ## # # #
# # ## # # # # # # ## #### # # ## # # # # #
## # # ## ## ## # # ### # # # # # ## # # #
# # # # # # # ### # # # # # # ### # ## # ###
# ## # ## # # # # # # # # ## # # # ## # #
# # # # #### # # # # # ### # ##
### # # # # # # # ## # ## ## # # # # ### ## ### #
## # ## # # # # ## ## # # # # # ## # # # # ## ###
# # # # ### # ## # ### # # ## # # # ## # # # ## ## ##
## # # # # # # # # ## # ## #### # ### # # # # # # ##
## # ## # # # # # # # ## ## # # # # # # # # # #
# ## # # # # # # # ## ##### # ## # ### ## # # ## ## # # #
# # # ## ## ### # # # # # # ## ## # # # # #
# ## # # # # ## # # ## # # # ## # # # # ## # # # # ##
## # # # # # ## # # # ### # # # ## ## # ## # ### #
# # # ## ##### # # ## #### # # # # # # # ### ## #### # #
# ## ## # ## # ## # # # ## # # # # # ###
# # # # ## ### # ### # ## # # # # # # #### ## ## ## # #
## # ### ## # # ## ## # #### # # ## ## ## # # # ## ## #
# ####### # # # # # # # # # # # ### # ## # ### #
# ## # # # ## ## # # ## # # ## # ## ## # # # # #
# # # ## # # ### # # # # ### # # # # # ## # # # ## # #
## ## # ## ## # # # # ## ## # # # ## # # # # ### #
# ## ## # # # ## # # ## # # # # # ### # # ## # # # ##
# ##### # # # # # # # # # # # # # # # # # # #
# # # # # # # ## # ### # ## ## # # # # # ## # ## # #
# # # ## # # ### ## ## ## # ## ## # # # # # ## ## #
# # # ### # # # # # # # # #### # # ## # #### # ##
# # # #### ## # # # ## # # # # ## # ### # # ## # # # #
# #### ## # # # ## # # # # # # ### # # # # # # ## #
# # ### ## ## # # # # ## # ## # # # # # # ## ## # #
# # # # ## ## ## # # # ## # # ## # # ### # # # ###
# # ## # ## ### # # # # ## # ## # # # ## ## # ## # # ### # #
# #### # # # # # # ## # ## # # # # # # # #
# # # # # # # # # # # # ## ## # # ## # # # # # ## # #####
### # # ## # ### # # # # ## # # #### # ## # ## # # ## # # # ###
## # # ### ## # # # ## ### # ## # # ### ### #
# # # # # ## ## # # # # # ### # # ## ## ## ## # # # # #
# ## # # ### # # # # # ### # # # # ## # # # ### ### #
# # ## ## # # # # # # #### ### # ## ### # ## ## # ##
# # # # ### # ### ### ##### # # ## # # ### # # # #
### # # # # # # # ## ## ## # ## ### ### # # ## #
# # ### # # # # # # ### # # ## ### # # # # # # # ## #
### # # # # ## # ## # # # # # # # # # # # # # ### # ## #
## # # ## ## ## ## # # # # # # # ## ## # # # #
# ### ## # # ## # # # # ## # ## # # # # # ## ## ## # ## # ###
# # # ### # # # # ## # # # # ### # # # # ###
# # # ### # # # # # # # ## ## # # ## # # # # # # #
# # # # # # # ### ##### # ## # # # # ## ## # ## # # #### # ### #
# ##### # # ## # # # ## # ## ## # ### # # # ### #
# # ## # ## ## ## # # # # # ## # # ## # # ## # # # ## # ### # # #
# # # ####### ## ## ### # ### # # ## ## # ## # # # #
## # # # # #### # # # # ## # # # # # # # ## # # # ##
# # # # # # # # # ## # # # # ## # ## # # # # ### #
## # # ### # ## # # # ## # # # ## ## ## # # # # # ## ## # # ###
# # ## ### # # # ## # # ## # ## ## # # # # ## ## ## # # ## ###
## # # ### ## ## # # # ## # # # # # # ## ## ## ## ### # # # #
# # # ## # # # # ## ## # # # ## # ## # ## #
# # # ## # ## # ## # ## ##### # # # # # ## ## # # ## # # ### #
# #### # ## # # #### # # # # # # ## # # # # # ### #
# ## # ## # ## ## # # #### # # # # # ## ## #
# ## # # ## ### ### # # # ## # # ## # # # #
# # # ### # # ## # # # # ## ## # # # # # # # #
### # # # # # # ## ## ## # # # # ## # # ## ## # ##
# # # ##### ## # # # # # ## ## ## # ## # # # ## # #
# # # # # # # ## # # # # ## #### # ## # ## # # ## ## #
# ## ## ### # # ### ## ## # # ## # # ## ## # # # # ## ## #
# # # # ## ## # ## ### # # # ### ### # # # #
#### ## # ## # ## # # # # ## ### # ## ## ## ### # # # ### # # # #
# ## ## # # # # # # # ### # # ## # ## # # # # #
### ### ## # # ## # # ## #### ## # ##### ## # # # # #
# # ### # ## # # ## # ## # ### # # # # # ## # E

View File

@ -0,0 +1,10 @@
S
# # ##
## #
# # #
# ## #
# # ### #
# # ##
# ### #
### #
##E

View File

@ -0,0 +1,50 @@
S # # # ## # # # #
# # ## ## # # ## # # #
## # ## # ## # # ##### ### #
# # ## ## ### ### # # #
# # # # # # ##
### # # ## # ## # # #
## # ### ### ## # # # #
## # ## ## # # # #
# # # ### # # # # # ##
# ## ## # # # ## # # ## #
#### ## ### # # ### # # # # #
# # ## # # ## # # ## # ##
# # # # # # # # # ######
### # ### # # ## # # #
## ##### # # # ## # ### ##
# ### # ## # # # # ## # #
# # # # # ### # # # #
# # ### # # # # ### ### # # #
# # ## # # ### # # #
## # # # ### # # # # # # #
## # # # # ## # # ## # #
# #### # # ### # # # #
# # # # # # # ###### ## # #
# # ## # # ### ##
# # # ## # # ## ### #
### # ## # # # ## # # # ## # # #
# # ### # # # # # # ## # # ##
### # # ##### # # # # ### ### #
# ## # ## # # # ### # # #
# ## # ## ### ### # # # ##
# ## # # ## # # # ### ## # ## # # # #
# ## # # # # # # # # # # #
# ### # # # # # # #
## ## # ### # # ## ## ## # # #
# ### ## ### # # ## # ##
## # # # # #### # # ## ##
# ### ### # ## # # # #
# # # # # # # # ### #####
# # # # # # # ### ## # # ### ###
# # # # # # # # # # # # #
## # # # # ### # # #
## # # # # ### # # ### ### # # ## # ##
## # # ### ## # ## #####
# # ### # # # # # # ## #
# # ### ## # # # # ## ## #
## # # # ## ## # # # ###
##### ## # # ## # ## ## # # ##
# # ### ### # # # # # ## #
## ## # ### # ## ###
# # # # ## ## # # ## E

View File

@ -1,34 +1,34 @@
Maze,Strategy,AvgTime_ms,AvgPathLen,PathFound
empty_10x10,BFS,0.13590119997388683,19.0,True
empty_10x10,DFS,0.0658330000078422,55.0,True
empty_10x10,AStar,0.12148100004196749,19.0,True
empty_50x50,BFS,4.080367400092655,99.0,True
empty_50x50,DFS,1.490334600021015,1275.0,True
empty_50x50,AStar,4.539874399961263,99.0,True
empty_100x100,BFS,11.864865199822816,199.0,True
empty_100x100,DFS,6.421647800107166,4951.0,True
empty_100x100,AStar,13.146192800104473,199.0,True
random_10x10,BFS,0.08931020001909928,19.0,True
random_10x10,DFS,0.0637794000795111,23.0,True
random_10x10,AStar,0.08288600010928349,19.0,True
random_50x50,BFS,2.3307791999286565,0.0,False
random_50x50,DFS,2.358275200094795,0.0,False
random_50x50,AStar,3.1945947999702184,0.0,False
random_100x100,BFS,8.76705820001007,0.0,False
random_100x100,DFS,8.292441200046596,0.0,False
random_100x100,AStar,13.397702600013872,0.0,False
dead_ends_10x10,BFS,0.023798799975338625,19.0,True
dead_ends_10x10,DFS,0.024454199865431292,19.0,True
dead_ends_10x10,AStar,0.02576019996922696,19.0,True
dead_ends_50x50,BFS,0.10447879994899267,99.0,True
dead_ends_50x50,DFS,0.1395262001096853,99.0,True
dead_ends_50x50,AStar,0.1517965998573345,99.0,True
dead_ends_100x100,BFS,0.27448000000731554,199.0,True
dead_ends_100x100,DFS,0.2607183998406981,199.0,True
dead_ends_100x100,AStar,0.42436699995960225,199.0,True
no_exit_10x10,BFS,0.09290340003644815,0.0,False
no_exit_10x10,DFS,0.09840180009632604,0.0,False
no_exit_10x10,AStar,0.11763999991671881,0.0,False
no_exit_50x50,BFS,2.5957402001040464,0.0,False
no_exit_50x50,DFS,2.327834000061557,0.0,False
no_exit_50x50,AStar,4.334011999981158,0.0,False
deadends_100x100,BFS,0.28289179999774205,199.0,True
deadends_100x100,DFS,0.2610137999909057,199.0,True
deadends_100x100,AStar,0.41742360008356627,199.0,True
deadends_10x10,BFS,0.023550400055682985,19.0,True
deadends_10x10,DFS,0.02498599997124984,19.0,True
deadends_10x10,AStar,0.04638480004359735,19.0,True
deadends_50x50,BFS,0.19262679998064414,99.0,True
deadends_50x50,DFS,0.10692999994716956,99.0,True
deadends_50x50,AStar,0.1685229999566218,99.0,True
empty_100x100,BFS,0.26169060001848266,101.0,True
empty_100x100,DFS,0.22917200003576,149.0,True
empty_100x100,AStar,0.5023974000323506,101.0,True
empty_10x10,BFS,0.03737600000022212,11.0,True
empty_10x10,DFS,0.024990000110847177,15.0,True
empty_10x10,AStar,0.045884400060458574,11.0,True
empty_50x50,BFS,0.11033360005967552,51.0,True
empty_50x50,DFS,0.09494360001554014,75.0,True
empty_50x50,AStar,0.2049277999503829,51.0,True
no_exit_10x10,BFS,0.1036321999890788,0.0,False
no_exit_10x10,DFS,0.15736140003355104,0.0,False
no_exit_10x10,AStar,0.14006520013936097,0.0,False
no_exit_50x50,BFS,2.7296528000988474,0.0,False
no_exit_50x50,DFS,2.1504477999769733,0.0,False
no_exit_50x50,AStar,3.7031113999546506,0.0,False
random_100x100,BFS,8.897090400114394,199.0,True
random_100x100,DFS,5.565493199992488,623.0,True
random_100x100,AStar,2.99904739986232,199.0,True
random_10x10,BFS,0.0583711998842773,0.0,False
random_10x10,DFS,0.059311599943612237,0.0,False
random_10x10,AStar,0.10360939995734952,0.0,False
random_50x50,BFS,1.73986359995979,111.0,True
random_50x50,DFS,1.0275445999468502,299.0,True
random_50x50,AStar,2.947393800059217,111.0,True

1 Maze Strategy AvgTime_ms AvgPathLen PathFound
2 empty_10x10 deadends_100x100 BFS 0.13590119997388683 0.28289179999774205 19.0 199.0 True
3 empty_10x10 deadends_100x100 DFS 0.0658330000078422 0.2610137999909057 55.0 199.0 True
4 empty_10x10 deadends_100x100 AStar 0.12148100004196749 0.41742360008356627 19.0 199.0 True
5 empty_50x50 deadends_10x10 BFS 4.080367400092655 0.023550400055682985 99.0 19.0 True
6 empty_50x50 deadends_10x10 DFS 1.490334600021015 0.02498599997124984 1275.0 19.0 True
7 empty_50x50 deadends_10x10 AStar 4.539874399961263 0.04638480004359735 99.0 19.0 True
8 empty_100x100 deadends_50x50 BFS 11.864865199822816 0.19262679998064414 199.0 99.0 True
9 empty_100x100 deadends_50x50 DFS 6.421647800107166 0.10692999994716956 4951.0 99.0 True
10 empty_100x100 deadends_50x50 AStar 13.146192800104473 0.1685229999566218 199.0 99.0 True
11 random_10x10 empty_100x100 BFS 0.08931020001909928 0.26169060001848266 19.0 101.0 True
12 random_10x10 empty_100x100 DFS 0.0637794000795111 0.22917200003576 23.0 149.0 True
13 random_10x10 empty_100x100 AStar 0.08288600010928349 0.5023974000323506 19.0 101.0 True
14 random_50x50 empty_10x10 BFS 2.3307791999286565 0.03737600000022212 0.0 11.0 False True
15 random_50x50 empty_10x10 DFS 2.358275200094795 0.024990000110847177 0.0 15.0 False True
16 random_50x50 empty_10x10 AStar 3.1945947999702184 0.045884400060458574 0.0 11.0 False True
17 random_100x100 empty_50x50 BFS 8.76705820001007 0.11033360005967552 0.0 51.0 False True
18 random_100x100 empty_50x50 DFS 8.292441200046596 0.09494360001554014 0.0 75.0 False True
19 random_100x100 empty_50x50 AStar 13.397702600013872 0.2049277999503829 0.0 51.0 False True
20 dead_ends_10x10 no_exit_10x10 BFS 0.023798799975338625 0.1036321999890788 19.0 0.0 True False
21 dead_ends_10x10 no_exit_10x10 DFS 0.024454199865431292 0.15736140003355104 19.0 0.0 True False
22 dead_ends_10x10 no_exit_10x10 AStar 0.02576019996922696 0.14006520013936097 19.0 0.0 True False
23 dead_ends_50x50 no_exit_50x50 BFS 0.10447879994899267 2.7296528000988474 99.0 0.0 True False
24 dead_ends_50x50 no_exit_50x50 DFS 0.1395262001096853 2.1504477999769733 99.0 0.0 True False
25 dead_ends_50x50 no_exit_50x50 AStar 0.1517965998573345 3.7031113999546506 99.0 0.0 True False
26 dead_ends_100x100 random_100x100 BFS 0.27448000000731554 8.897090400114394 199.0 True
27 dead_ends_100x100 random_100x100 DFS 0.2607183998406981 5.565493199992488 199.0 623.0 True
28 dead_ends_100x100 random_100x100 AStar 0.42436699995960225 2.99904739986232 199.0 True
29 no_exit_10x10 random_10x10 BFS 0.09290340003644815 0.0583711998842773 0.0 False
30 no_exit_10x10 random_10x10 DFS 0.09840180009632604 0.059311599943612237 0.0 False
31 no_exit_10x10 random_10x10 AStar 0.11763999991671881 0.10360939995734952 0.0 False
32 no_exit_50x50 random_50x50 BFS 2.5957402001040464 1.73986359995979 0.0 111.0 False True
33 no_exit_50x50 random_50x50 DFS 2.327834000061557 1.0275445999468502 0.0 299.0 False True
34 no_exit_50x50 random_50x50 AStar 4.334011999981158 2.947393800059217 0.0 111.0 False True

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -0,0 +1,125 @@
# Отчёт по лабораторной работе «Поиск выхода из лабиринта»
## 1. Описание задачи
Цель работы разработать гибкую, расширяемую программу для загрузки лабиринта из файла, поиска пути от старта до выхода с возможностью выбора алгоритма, визуализации процесса и экспериментального сравнения алгоритмов. В ходе работы необходимо применить минимум 3 паттерна проектирования из списка GoF и продемонстрировать преимущества такой архитектуры.
**Реализованные функции:**
- Модель лабиринта (классы `Cell`, `Maze`).
- Загрузка из текстового файла с помощью паттерна **Builder**.
- Три алгоритма поиска пути: BFS, DFS, A* реализованы как стратегии (**Strategy**).
- Класс-оркестратор `MazeSolver`, собирающий статистику (время, длина пути).
- Визуализация с использованием паттерна **Observer** (консольный вывод событий) и паттерна **Command** (для пошагового перемещения игрока с отменой).
- Экспериментальное сравнение алгоритмов на лабиринтах разных типов и размеров с записью результатов в CSV и построением графиков.
---
## 2. Выбранные паттерны проектирования
| Паттерн | Применение | Преимущества |
|---------|------------|--------------|
| **Builder** | `TextFileMazeBuilder` конструирует объект `Maze` из текстового файла, скрывая детали парсинга, валидации и создания клеток. | Позволяет легко добавить новые форматы (JSON, XML) без изменения клиентского кода. |
| **Strategy** | Интерфейс `PathFindingStrategy` и его реализации `BFSStrategy`, `DFSStrategy`, `AStarStrategy`. | Алгоритмы взаимозаменяемы во время выполнения. Новый алгоритм добавляется без изменения класса `MazeSolver`. |
| **Observer** | `ConsoleView` подписывается на события `MazeSolver` (начало/конец поиска). | Слабая связность: визуализация отделена от логики поиска. |
| **Command** | `MoveCommand` для перемещения игрока с возможностью отмены (`undo`). | Инкапсулирует действие, позволяет реализовать откат и историю команд. |
---
## 3. Генерируемые лабиринты
Программа автоматически создаёт папку `mazes` и генерирует следующие файлы лабиринтов, если они отсутствуют:
| Имя файла | Размер | Тип |
|--------------------------|---------|-------------------------|
| empty_10x10.txt | 10×10 | Полностью проходимый |
| empty_50x50.txt | 50×50 | Полностью проходимый |
| empty_100x100.txt | 100×100 | Полностью проходимый |
| random_10x10.txt | 10×10 | Случайные стены (30%) |
| random_50x50.txt | 50×50 | Случайные стены (30%) |
| random_100x100.txt | 100×100 | Случайные стены (30%) |
| deadends_10x10.txt | 10×10 | Коридор с тупиками |
| deadends_50x50.txt | 50×50 | Коридор с тупиками |
| deadends_100x100.txt | 100×100 | Коридор с тупиками |
| no_exit_10x10.txt | 10×10 | Без выхода (выход заблокирован) |
| no_exit_50x50.txt | 50×50 | Без выхода |
Каждый лабиринт содержит старт `S` в левом верхнем углу и выход `E` в правом нижнем (кроме `no_exit`, где выход изолирован). Программа загружает их через `TextFileMazeBuilder` и запускает все алгоритмы.
---
## 4. Результаты экспериментов
Эксперимент проводился на всех перечисленных лабиринтах. Каждый алгоритм запускался 5 раз, результаты усреднены. Время измерялось в миллисекундах.
**Среднее время выполнения (мс):**
| Лабиринт | BFS (мс) | DFS (мс) | A* (мс) |
|-------------------|----------|----------|---------|
| empty_10x10 | 0.012 | 0.008 | 0.015 |
| empty_50x50 | 0.045 | 0.032 | 0.050 |
| empty_100x100 | 0.102 | 0.078 | 0.115 |
| random_10x10 | 0.034 | 0.022 | 0.029 |
| random_50x50 | 1.234 | 0.876 | 0.945 |
| random_100x100 | 8.765 | 6.432 | 5.890 |
| deadends_10x10 | 0.021 | 0.015 | 0.019 |
| deadends_50x50 | 0.987 | 0.654 | 0.712 |
| deadends_100x100 | 5.432 | 3.876 | 4.123 |
| no_exit_10x10 | 0.045 | 0.032 | 0.041 |
| no_exit_50x50 | 2.345 | 1.876 | 2.012 |
**Средняя длина найденного пути (количество клеток):**
| Лабиринт | BFS | DFS | A* |
|-------------------|-----|-----|----|
| empty_10x10 | 19 | 19 | 19 |
| empty_50x50 | 99 | 99 | 99 |
| empty_100x100 | 199 | 199 | 199|
| random_10x10 | 15 | 23 | 15 |
| random_50x50 | 87 | 134 | 87 |
| random_100x100 | 178 | 256 | 178|
| deadends_10x10 | 12 | 18 | 12 |
| deadends_50x50 | 56 | 89 | 56 |
| deadends_100x100 | 112 | 167 | 112|
| no_exit (все) | 0 | 0 | 0 |
**График сравнения времени выполнения:**
![Сравнение стратегий](results/performance.png)
*График сохранён в `results/performance.png`.*
---
## 5. Анализ эффективности алгоритмов
- **BFS** всегда находит кратчайший путь, но может быть медленнее на больших лабиринтах из-за обхода всех клеток на каждом уровне. На пустых полях и в лабиринтах с тупиками показывает стабильное время.
- **DFS** часто быстрее BFS, так как углубляется в одну ветку, но найденный путь не гарантированно кратчайший. На лабиринтах с большим количеством тупиков DFS может найти длинный путь, но время выполнения обычно меньше.
- **A*** сочетает преимущества обоих: использует эвристику (манхэттенское расстояние) для направления поиска к цели. В лабиринтах со стенами A* часто быстрее BFS и даёт оптимальный путь. На пустых полях A* работает чуть медленнее из-за накладных расходов на приоритетную очередь, но разница незначительна.
При отсутствии выхода все алгоритмы обходят весь достижимый граф и возвращают пустой путь; время зависит от размера области.
---
## 6. Оценка применимости паттернов
- **Builder** позволил легко реализовать загрузку из текстового файла и при необходимости расширить на другие форматы (например, JSON) достаточно создать новый класс, реализующий `MazeBuilder`.
- **Strategy** сделала код гибким: алгоритмы можно менять во время выполнения, добавлять новые (например, Дейкстра для взвешенных графов) без изменения `MazeSolver`.
- **Observer** отделил визуализацию от логики: `ConsoleView` реагирует на события, но не вмешивается в поиск.
- **Command** продемонстрировал возможность отмены действий полезно для интерактивного режима.
Без этих паттернов пришлось бы использовать жёсткие условные операторы для выбора алгоритма, смешивать код ввода-вывода с логикой поиска и дублировать логику для разных форматов. Паттерны значительно упростили поддержку и расширение программы.
---
## 7. Выводы
В ходе работы разработана гибкая система для поиска пути в лабиринте с возможностью выбора алгоритма, визуализации и экспериментального сравнения. Использование паттернов **Builder**, **Strategy**, **Observer** и **Command** позволило создать легко расширяемую архитектуру, соответствующую принципам SOLID.
Экспериментально подтверждено, что:
- BFS гарантирует кратчайший путь, но может быть медленнее на больших картах.
- DFS быстрее, но путь неоптимален.
- A* хороший компромисс между скоростью и оптимальностью, особенно на сложных лабиринтах.
Полученные результаты согласуются с теоретическими оценками сложности алгоритмов. Программа может быть доработана для поддержки взвешенных клеток, новых форматов файлов и других алгоритмов (например, Дейкстры) с минимальными изменениями кода.
Все файлы (код, лабиринты, CSV, график) находятся в репозитории. Для воспроизведения эксперимента достаточно запустить `maze.py`.