[2] 2-nd #377
430
AgapovaDS/docs/data/2-nd/maze.py
Normal file
430
AgapovaDS/docs/data/2-nd/maze.py
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
import time
|
||||
import random
|
||||
import csv
|
||||
import os
|
||||
from collections import deque
|
||||
import heapq
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
class Cell:
|
||||
def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.is_wall = is_wall
|
||||
self.is_start = is_start
|
||||
self.is_exit = is_exit
|
||||
|
||||
def is_passable(self):
|
||||
return not self.is_wall
|
||||
|
||||
|
||||
class Maze:
|
||||
def __init__(self, width, height):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.grid = [[Cell(x, y) for y in range(height)] for x in range(width)]
|
||||
self.start_cell = None
|
||||
self.exit_cell = None
|
||||
|
||||
def get_cell(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
return self.grid[x][y]
|
||||
return None
|
||||
|
||||
def get_neighbors(self, cell):
|
||||
neighbors = []
|
||||
for dx, dy in [(-1,0), (1,0), (0,-1), (0,1)]:
|
||||
nx, ny = cell.x + dx, cell.y + dy
|
||||
neighbor = self.get_cell(nx, ny)
|
||||
if neighbor and neighbor.is_passable():
|
||||
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):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class TextFileMazeBuilder(MazeBuilder):
|
||||
def build_from_file(self, filename):
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
lines = [line.rstrip('\n') for line in lines if line.strip() != '']
|
||||
if not lines:
|
||||
raise ValueError("Файл пуст")
|
||||
height = len(lines)
|
||||
width = max(len(line) for line in lines)
|
||||
maze = Maze(width, height)
|
||||
for y, line in enumerate(lines):
|
||||
for x, ch in enumerate(line):
|
||||
if x >= width:
|
||||
break
|
||||
cell = maze.get_cell(x, y)
|
||||
if ch == '#':
|
||||
cell.is_wall = True
|
||||
elif ch == 'S':
|
||||
cell.is_start = True
|
||||
maze.start_cell = cell
|
||||
elif ch == 'E':
|
||||
cell.is_exit = True
|
||||
maze.exit_cell = cell
|
||||
if maze.start_cell is None or maze.exit_cell is None:
|
||||
raise ValueError("В лабиринте должны быть S и E")
|
||||
return maze
|
||||
|
||||
|
||||
class PathFindingStrategy:
|
||||
def find_path(self, maze, start, exit):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class BFSStrategy(PathFindingStrategy):
|
||||
def find_path(self, maze, start, exit):
|
||||
if start == exit:
|
||||
return [start]
|
||||
queue = deque([start])
|
||||
visited = {start}
|
||||
parent = {start: None}
|
||||
while queue:
|
||||
current = queue.popleft()
|
||||
if current == exit:
|
||||
break
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
if neighbor not in visited:
|
||||
visited.add(neighbor)
|
||||
parent[neighbor] = current
|
||||
queue.append(neighbor)
|
||||
if exit not in parent:
|
||||
return []
|
||||
path = []
|
||||
step = exit
|
||||
while step is not None:
|
||||
path.append(step)
|
||||
step = parent[step]
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
|
||||
class DFSStrategy(PathFindingStrategy):
|
||||
def find_path(self, maze, start, exit):
|
||||
if start == exit:
|
||||
return [start]
|
||||
stack = [start]
|
||||
visited = {start}
|
||||
parent = {start: None}
|
||||
while stack:
|
||||
current = stack.pop()
|
||||
if current == exit:
|
||||
break
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
if neighbor not in visited:
|
||||
visited.add(neighbor)
|
||||
parent[neighbor] = current
|
||||
stack.append(neighbor)
|
||||
if exit not in parent:
|
||||
return []
|
||||
path = []
|
||||
step = exit
|
||||
while step is not None:
|
||||
path.append(step)
|
||||
step = parent[step]
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
|
||||
class AStarStrategy(PathFindingStrategy):
|
||||
def heuristic(self, a, b):
|
||||
return abs(a.x - b.x) + abs(a.y - b.y)
|
||||
|
||||
def find_path(self, maze, start, exit):
|
||||
if start == exit:
|
||||
return [start]
|
||||
open_set = []
|
||||
heapq.heappush(open_set, (0, id(start), start))
|
||||
came_from = {}
|
||||
g_score = {start: 0}
|
||||
f_score = {start: self.heuristic(start, exit)}
|
||||
while open_set:
|
||||
_, _, current = heapq.heappop(open_set)
|
||||
if current == exit:
|
||||
path = []
|
||||
step = current
|
||||
while step is not None:
|
||||
path.append(step)
|
||||
step = came_from.get(step)
|
||||
path.reverse()
|
||||
return path
|
||||
for neighbor in maze.get_neighbors(current):
|
||||
tentative_g = g_score[current] + 1
|
||||
if neighbor not in g_score or tentative_g < g_score[neighbor]:
|
||||
came_from[neighbor] = current
|
||||
g_score[neighbor] = tentative_g
|
||||
f_score[neighbor] = tentative_g + self.heuristic(neighbor, exit)
|
||||
heapq.heappush(open_set, (f_score[neighbor], id(neighbor), neighbor))
|
||||
return []
|
||||
|
||||
|
||||
class Observer:
|
||||
def update(self, event):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ConsoleView(Observer):
|
||||
def __init__(self, maze):
|
||||
self.maze = maze
|
||||
|
||||
def update(self, event):
|
||||
if event == "Поиск начат":
|
||||
print("=== Поиск начат ===")
|
||||
elif event == "Поиск завершён":
|
||||
print("=== Поиск завершён ===")
|
||||
|
||||
def render(self, path=None):
|
||||
path_set = set(path) if path else set()
|
||||
for y in range(self.maze.height):
|
||||
row = ''
|
||||
for x in range(self.maze.width):
|
||||
cell = self.maze.get_cell(x, y)
|
||||
if cell.is_wall:
|
||||
row += '#'
|
||||
elif cell.is_start:
|
||||
row += 'S'
|
||||
elif cell.is_exit:
|
||||
row += 'E'
|
||||
elif cell in path_set:
|
||||
row += '*'
|
||||
else:
|
||||
row += ' '
|
||||
print(row)
|
||||
print()
|
||||
|
||||
|
||||
class MazeSolver:
|
||||
def __init__(self, maze, strategy=None):
|
||||
self.maze = maze
|
||||
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
|
||||
|
||||
|
||||
def generate_empty_maze(width, height):
|
||||
maze = Maze(width, height)
|
||||
start = maze.get_cell(0, 0)
|
||||
exit_cell = maze.get_cell(width-1, height-1)
|
||||
start.is_start = True
|
||||
exit_cell.is_exit = True
|
||||
maze.start_cell = start
|
||||
maze.exit_cell = exit_cell
|
||||
return maze
|
||||
|
||||
|
||||
def generate_random_maze(width, height, wall_prob=0.3):
|
||||
maze = Maze(width, height)
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
cell = maze.get_cell(x, y)
|
||||
if random.random() < wall_prob:
|
||||
cell.is_wall = True
|
||||
start = maze.get_cell(0, 0)
|
||||
exit_cell = maze.get_cell(width-1, height-1)
|
||||
start.is_wall = False
|
||||
start.is_start = True
|
||||
exit_cell.is_wall = False
|
||||
exit_cell.is_exit = True
|
||||
maze.start_cell = start
|
||||
maze.exit_cell = exit_cell
|
||||
return maze
|
||||
|
||||
|
||||
def generate_maze_with_dead_ends(width, height):
|
||||
maze = Maze(width, height)
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
maze.get_cell(x, y).is_wall = True
|
||||
x, y = 0, 0
|
||||
while x < width and y < height:
|
||||
cell = maze.get_cell(x, y)
|
||||
cell.is_wall = False
|
||||
if x == width-1 and y == height-1:
|
||||
break
|
||||
if y+1 < height and (x == width-1 or random.choice([True, False])):
|
||||
y += 1
|
||||
else:
|
||||
x += 1
|
||||
start = maze.get_cell(0, 0)
|
||||
exit_cell = maze.get_cell(width-1, height-1)
|
||||
start.is_start = True
|
||||
exit_cell.is_exit = True
|
||||
maze.start_cell = start
|
||||
maze.exit_cell = exit_cell
|
||||
return maze
|
||||
|
||||
|
||||
def generate_maze_no_exit(width, height):
|
||||
maze = generate_random_maze(width, height, 0.2)
|
||||
exit_cell = maze.get_cell(width-1, height-1)
|
||||
for dx, dy in [(-1,0), (1,0), (0,-1), (0,1)]:
|
||||
nx, ny = exit_cell.x + dx, exit_cell.y + dy
|
||||
neighbor = maze.get_cell(nx, ny)
|
||||
if neighbor:
|
||||
neighbor.is_wall = True
|
||||
start = maze.get_cell(0, 0)
|
||||
start.is_wall = False
|
||||
start.is_start = True
|
||||
maze.start_cell = start
|
||||
maze.exit_cell = exit_cell
|
||||
return maze
|
||||
|
||||
|
||||
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
|
||||
|
||||
for filename in maze_files:
|
||||
maze_name = filename.replace(".txt", "")
|
||||
print(f"Тестирование лабиринта: {maze_name}")
|
||||
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)
|
||||
total_time = 0
|
||||
total_path_len = 0
|
||||
path = []
|
||||
for rep in range(repeats):
|
||||
path, elapsed_ms = solver.solve()
|
||||
total_time += elapsed_ms
|
||||
total_path_len += len(path) if path else 0
|
||||
avg_time = total_time / repeats
|
||||
avg_len = total_path_len / repeats
|
||||
results.append({
|
||||
"Maze": maze_name,
|
||||
"Strategy": strat_name,
|
||||
"AvgTime_ms": avg_time,
|
||||
"AvgPathLen": avg_len,
|
||||
"PathFound": len(path) > 0 if path else False
|
||||
})
|
||||
print(f" {strat_name}: время {avg_time:.3f} мс, длина пути {avg_len:.1f}")
|
||||
|
||||
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(results)
|
||||
print(f"Результаты сохранены в {csv_path}")
|
||||
|
||||
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 results:
|
||||
data[r["Maze"]][r["Strategy"]] = r["AvgTime_ms"]
|
||||
|
||||
fig, ax = plt.subplots(figsize=(14, 6))
|
||||
x = np.arange(len(maze_names))
|
||||
width = 0.25
|
||||
colors = ['skyblue', 'lightgreen', 'salmon']
|
||||
|
||||
for i, strat in enumerate(strategy_names):
|
||||
times = [data[maze][strat] if data[maze][strat] is not None else 0 for maze in maze_names]
|
||||
ax.bar(x + i*width, times, width, label=strat, color=colors[i])
|
||||
|
||||
ax.set_xlabel('Лабиринт')
|
||||
ax.set_ylabel('Среднее время (мс)')
|
||||
ax.set_title('Сравнение стратегий поиска пути')
|
||||
ax.set_xticks(x + width)
|
||||
ax.set_xticklabels(maze_names, rotation=45, ha='right')
|
||||
ax.legend()
|
||||
|
||||
plt.tight_layout()
|
||||
plt.savefig("results/performance.png", dpi=150)
|
||||
#plt.show()
|
||||
print("График сохранён в results/performance.png")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_experiment()
|
||||
100
AgapovaDS/docs/data/2-nd/mazes/deadends_100x100.txt
Normal file
100
AgapovaDS/docs/data/2-nd/mazes/deadends_100x100.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
S ##################################################################################################
|
||||
# ##################################################################################################
|
||||
# ##################################################################################################
|
||||
# #################################################################################################
|
||||
## ##############################################################################################
|
||||
##### ##############################################################################################
|
||||
##### ############################################################################################
|
||||
####### ###########################################################################################
|
||||
######## ######################################################################################
|
||||
############# ##################################################################################
|
||||
################# #################################################################################
|
||||
################## #################################################################################
|
||||
################## #################################################################################
|
||||
################## ################################################################################
|
||||
################### ################################################################################
|
||||
################### #############################################################################
|
||||
###################### ############################################################################
|
||||
####################### ############################################################################
|
||||
####################### ############################################################################
|
||||
####################### ############################################################################
|
||||
####################### ###########################################################################
|
||||
######################## ##########################################################################
|
||||
######################### #########################################################################
|
||||
########################## ########################################################################
|
||||
########################### #####################################################################
|
||||
############################## #####################################################################
|
||||
############################## #####################################################################
|
||||
############################## ####################################################################
|
||||
############################### ####################################################################
|
||||
############################### ####################################################################
|
||||
############################### ##################################################################
|
||||
################################# ##################################################################
|
||||
################################# #################################################################
|
||||
################################## ###############################################################
|
||||
#################################### ##############################################################
|
||||
##################################### ##############################################################
|
||||
##################################### ##############################################################
|
||||
##################################### ############################################################
|
||||
####################################### ############################################################
|
||||
####################################### ############################################################
|
||||
####################################### ############################################################
|
||||
####################################### ##########################################################
|
||||
######################################### #########################################################
|
||||
########################################## ########################################################
|
||||
########################################### ########################################################
|
||||
########################################### ########################################################
|
||||
########################################### ########################################################
|
||||
########################################### #######################################################
|
||||
############################################ #####################################################
|
||||
############################################## ##################################################
|
||||
################################################# ##################################################
|
||||
################################################# ##############################################
|
||||
##################################################### #############################################
|
||||
###################################################### ############################################
|
||||
####################################################### ############################################
|
||||
####################################################### ############################################
|
||||
####################################################### ###########################################
|
||||
######################################################## ###########################################
|
||||
######################################################## ##########################################
|
||||
######################################################### ##########################################
|
||||
######################################################### ##########################################
|
||||
######################################################### ##########################################
|
||||
######################################################### #########################################
|
||||
########################################################## #######################################
|
||||
############################################################ #####################################
|
||||
############################################################## #####################################
|
||||
############################################################## ####################################
|
||||
############################################################### ###################################
|
||||
################################################################ ###################################
|
||||
################################################################ ##################################
|
||||
################################################################# ###############################
|
||||
#################################################################### #############################
|
||||
###################################################################### ###########################
|
||||
######################################################################## ##########################
|
||||
######################################################################### ########################
|
||||
########################################################################### #######################
|
||||
############################################################################ #######################
|
||||
############################################################################ ###################
|
||||
################################################################################ ##################
|
||||
################################################################################# #################
|
||||
################################################################################## #################
|
||||
################################################################################## #################
|
||||
################################################################################## ##############
|
||||
##################################################################################### ############
|
||||
####################################################################################### ###########
|
||||
######################################################################################## ###########
|
||||
######################################################################################## ##########
|
||||
######################################################################################### ##########
|
||||
######################################################################################### ########
|
||||
########################################################################################### #######
|
||||
############################################################################################ #####
|
||||
############################################################################################## ###
|
||||
################################################################################################ ##
|
||||
################################################################################################# ##
|
||||
################################################################################################# ##
|
||||
################################################################################################# ##
|
||||
################################################################################################# ##
|
||||
################################################################################################# #
|
||||
##################################################################################################
|
||||
###################################################################################################E
|
||||
10
AgapovaDS/docs/data/2-nd/mazes/deadends_10x10.txt
Normal file
10
AgapovaDS/docs/data/2-nd/mazes/deadends_10x10.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
S #######
|
||||
## #######
|
||||
## #######
|
||||
## #######
|
||||
## #######
|
||||
## ######
|
||||
### #####
|
||||
#### ##
|
||||
####### ##
|
||||
####### E
|
||||
50
AgapovaDS/docs/data/2-nd/mazes/deadends_50x50.txt
Normal file
50
AgapovaDS/docs/data/2-nd/mazes/deadends_50x50.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
S ################################################
|
||||
# ###############################################
|
||||
## ###############################################
|
||||
## ###############################################
|
||||
## ##############################################
|
||||
### ##############################################
|
||||
### ############################################
|
||||
##### ###########################################
|
||||
###### ######################################
|
||||
########### ######################################
|
||||
########### #####################################
|
||||
############ ##################################
|
||||
############### #################################
|
||||
################ ###############################
|
||||
################## ###############################
|
||||
################## ###########################
|
||||
###################### ###########################
|
||||
###################### ########################
|
||||
######################### #######################
|
||||
########################## #######################
|
||||
########################## ######################
|
||||
########################### #####################
|
||||
############################ #####################
|
||||
############################ ####################
|
||||
############################# ###################
|
||||
############################## ###################
|
||||
############################## ###################
|
||||
############################## ################
|
||||
################################# ###########
|
||||
###################################### ##########
|
||||
####################################### #########
|
||||
######################################## #########
|
||||
######################################## ########
|
||||
######################################### #######
|
||||
########################################## #####
|
||||
############################################ ####
|
||||
############################################# ###
|
||||
############################################## ###
|
||||
############################################## ##
|
||||
###############################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################
|
||||
#################################################E
|
||||
100
AgapovaDS/docs/data/2-nd/mazes/empty_100x100.txt
Normal file
100
AgapovaDS/docs/data/2-nd/mazes/empty_100x100.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
S
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
E
|
||||
10
AgapovaDS/docs/data/2-nd/mazes/empty_10x10.txt
Normal file
10
AgapovaDS/docs/data/2-nd/mazes/empty_10x10.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
S
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
E
|
||||
50
AgapovaDS/docs/data/2-nd/mazes/empty_50x50.txt
Normal file
50
AgapovaDS/docs/data/2-nd/mazes/empty_50x50.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
S
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
E
|
||||
10
AgapovaDS/docs/data/2-nd/mazes/no_exit_10x10.txt
Normal file
10
AgapovaDS/docs/data/2-nd/mazes/no_exit_10x10.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
S ##
|
||||
#
|
||||
# #
|
||||
###
|
||||
# # #
|
||||
# # #
|
||||
## #
|
||||
###
|
||||
# #
|
||||
#E
|
||||
50
AgapovaDS/docs/data/2-nd/mazes/no_exit_50x50.txt
Normal file
50
AgapovaDS/docs/data/2-nd/mazes/no_exit_50x50.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
S # # # ## #
|
||||
# ### ## # # # # # #
|
||||
# # # # # # # # # #
|
||||
# # # # # # # # ##
|
||||
### # # # # ## # # # # ## ##
|
||||
### # # # # # # #
|
||||
# ## #
|
||||
## ### ## # # #
|
||||
# # # # # # ### # ##
|
||||
# # # # # # #
|
||||
#### ### # # # # # # #
|
||||
## # # # # # # # # ## #
|
||||
# ## # ## ## # #
|
||||
## # # ## # # # # # #
|
||||
### # # # # # # #
|
||||
# ## ## # # # # # # #
|
||||
# # # # # # # # ####
|
||||
# # ## # # # # # # #
|
||||
## # ### #
|
||||
# ## # # # #
|
||||
# # # # # #
|
||||
# ## # ## #### ### # # # #
|
||||
# # # # ###
|
||||
### ## ## # # # ##
|
||||
# # # ## #
|
||||
# # ## ### # # # #
|
||||
# # # # ### # ## # # # #
|
||||
## # # # # ## #
|
||||
# # # # # ## # # #
|
||||
# # # # # #
|
||||
# # # # ## # # # # # # # #
|
||||
# # # # # ## # # #
|
||||
# # # ## #
|
||||
# # # # # # # # # ### #
|
||||
# # # # # # #
|
||||
# ## # # ## # ## # #
|
||||
# # # # ## # ##
|
||||
# # # # # # # # #
|
||||
## ### # ### # # # #
|
||||
## ## ## # # # ## # # # #
|
||||
# # ### # # # # #
|
||||
# # # # ## ## ## #
|
||||
# # # ## ## ### # #
|
||||
# # # ## # #
|
||||
## # # # # # #
|
||||
# # # # # #
|
||||
# # # # ##
|
||||
## # # # # # ## #
|
||||
# # ## # # ### # #
|
||||
# ## # # # # # # ## ## #E
|
||||
100
AgapovaDS/docs/data/2-nd/mazes/random_100x100.txt
Normal file
100
AgapovaDS/docs/data/2-nd/mazes/random_100x100.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
S ## ## # # # # # # # # # # # ## ### # #
|
||||
### # # ### # ##### # # ### ## ## # # # # # ### # # # #
|
||||
## # # # # # # ### # ## # # # # # # ### # # ### ##
|
||||
# ## # # # # # ## # # # ## # ## # ### ## ## # ## #
|
||||
## # # # # # # # # # # # # # # # # ## # # # # # # #
|
||||
# ## ## # ## # # ### ## # # # # # ## # # # # ## #
|
||||
## # # ### # # # ## # # ## # ## #### #### ## ## #
|
||||
# # ##### # ### # # # ### ### # ## # ### # # ## # # #
|
||||
# ## # # #### # # # ### ### # # # # ### # # ## # # #
|
||||
# # # ## ## # # ### # # ## # ## # # # # ##
|
||||
# ## # # # ## ## # # ## ## # # # # # # ## ## # # # ## # ###
|
||||
# ## ## ## # ## # # # # # # # # ## # ####### # ####
|
||||
# ## # # # ## # # ## # # # # # # # # # ### # # ###
|
||||
# ## # ### # ## # # # # # # # ## ### # # # # # ## ## #
|
||||
# # ### # # ##### # # # # # # # # ## # # # #
|
||||
## # # # # # # # # # # # # # # ## ## # ## #
|
||||
# # # # # # # # ### # ## # ## # # ## # # # ## ##
|
||||
## # # # # #### # # # # ## # # # # # # # #
|
||||
# # # ## ## # # # # # # # # # # # # # ### ## # # #
|
||||
# # # ## ### # ### # ## # # # # # # #### #### ##
|
||||
# # # # #### # ## # # # ## ## # ## ### # # # # # # # #
|
||||
## # # ### # # # ## ## # # # ## # # # # # ## #
|
||||
# # ### ## # ## # ## # ## ## ## ## # ## # ## # #
|
||||
## # #### # # # # # # ## ## # ## # # ## # # # ##
|
||||
# # # ## ## # ### # # #### # # ### # # # ## # # ## #
|
||||
# ### #### # # # # # # ## # ### # # ### ## # #
|
||||
## # # ## # # # # # # # # ## ## ## # ## # # # # # # #
|
||||
# ### # # # # # # ## ## # ### # # ### ###
|
||||
# ## # # # ## # # ## # # # # # # # # ## # # #
|
||||
# # ## # # # # # # ## #### # # ## # # # # #
|
||||
## # # ## ## ## # # ### # # # # # ## # # #
|
||||
# # # # # # # ### # # # # # # ### # ## # ###
|
||||
# ## # ## # # # # # # # # ## # # # ## # #
|
||||
# # # # #### # # # # # ### # ##
|
||||
### # # # # # # # ## # ## ## # # # # ### ## ### #
|
||||
## # ## # # # # ## ## # # # # # ## # # # # ## ###
|
||||
# # # # ### # ## # ### # # ## # # # ## # # # ## ## ##
|
||||
## # # # # # # # # ## # ## #### # ### # # # # # # ##
|
||||
## # ## # # # # # # # ## ## # # # # # # # # # #
|
||||
# ## # # # # # # # ## ##### # ## # ### ## # # ## ## # # #
|
||||
# # # ## ## ### # # # # # # ## ## # # # # #
|
||||
# ## # # # # ## # # ## # # # ## # # # # ## # # # # ##
|
||||
## # # # # # ## # # # ### # # # ## ## # ## # ### #
|
||||
# # # ## ##### # # ## #### # # # # # # # ### ## #### # #
|
||||
# ## ## # ## # ## # # # ## # # # # # ###
|
||||
# # # # ## ### # ### # ## # # # # # # #### ## ## ## # #
|
||||
## # ### ## # # ## ## # #### # # ## ## ## # # # ## ## #
|
||||
# ####### # # # # # # # # # # # ### # ## # ### #
|
||||
# ## # # # ## ## # # ## # # ## # ## ## # # # # #
|
||||
# # # ## # # ### # # # # ### # # # # # ## # # # ## # #
|
||||
## ## # ## ## # # # # ## ## # # # ## # # # # ### #
|
||||
# ## ## # # # ## # # ## # # # # # ### # # ## # # # ##
|
||||
# ##### # # # # # # # # # # # # # # # # # # #
|
||||
# # # # # # # ## # ### # ## ## # # # # # ## # ## # #
|
||||
# # # ## # # ### ## ## ## # ## ## # # # # # ## ## #
|
||||
# # # ### # # # # # # # # #### # # ## # #### # ##
|
||||
# # # #### ## # # # ## # # # # ## # ### # # ## # # # #
|
||||
# #### ## # # # ## # # # # # # ### # # # # # # ## #
|
||||
# # ### ## ## # # # # ## # ## # # # # # # ## ## # #
|
||||
# # # # ## ## ## # # # ## # # ## # # ### # # # ###
|
||||
# # ## # ## ### # # # # ## # ## # # # ## ## # ## # # ### # #
|
||||
# #### # # # # # # ## # ## # # # # # # # #
|
||||
# # # # # # # # # # # # ## ## # # ## # # # # # ## # #####
|
||||
### # # ## # ### # # # # ## # # #### # ## # ## # # ## # # # ###
|
||||
## # # ### ## # # # ## ### # ## # # ### ### #
|
||||
# # # # # ## ## # # # # # ### # # ## ## ## ## # # # # #
|
||||
# ## # # ### # # # # # ### # # # # ## # # # ### ### #
|
||||
# # ## ## # # # # # # #### ### # ## ### # ## ## # ##
|
||||
# # # # ### # ### ### ##### # # ## # # ### # # # #
|
||||
### # # # # # # # ## ## ## # ## ### ### # # ## #
|
||||
# # ### # # # # # # ### # # ## ### # # # # # # # ## #
|
||||
### # # # # ## # ## # # # # # # # # # # # # # ### # ## #
|
||||
## # # ## ## ## ## # # # # # # # ## ## # # # #
|
||||
# ### ## # # ## # # # # ## # ## # # # # # ## ## ## # ## # ###
|
||||
# # # ### # # # # ## # # # # ### # # # # ###
|
||||
# # # ### # # # # # # # ## ## # # ## # # # # # # #
|
||||
# # # # # # # ### ##### # ## # # # # ## ## # ## # # #### # ### #
|
||||
# ##### # # ## # # # ## # ## ## # ### # # # ### #
|
||||
# # ## # ## ## ## # # # # # ## # # ## # # ## # # # ## # ### # # #
|
||||
# # # ####### ## ## ### # ### # # ## ## # ## # # # #
|
||||
## # # # # #### # # # # ## # # # # # # # ## # # # ##
|
||||
# # # # # # # # # ## # # # # ## # ## # # # # ### #
|
||||
## # # ### # ## # # # ## # # # ## ## ## # # # # # ## ## # # ###
|
||||
# # ## ### # # # ## # # ## # ## ## # # # # ## ## ## # # ## ###
|
||||
## # # ### ## ## # # # ## # # # # # # ## ## ## ## ### # # # #
|
||||
# # # ## # # # # ## ## # # # ## # ## # ## #
|
||||
# # # ## # ## # ## # ## ##### # # # # # ## ## # # ## # # ### #
|
||||
# #### # ## # # #### # # # # # # ## # # # # # ### #
|
||||
# ## # ## # ## ## # # #### # # # # # ## ## #
|
||||
# ## # # ## ### ### # # # ## # # ## # # # #
|
||||
# # # ### # # ## # # # # ## ## # # # # # # # #
|
||||
### # # # # # # ## ## ## # # # # ## # # ## ## # ##
|
||||
# # # ##### ## # # # # # ## ## ## # ## # # # ## # #
|
||||
# # # # # # # ## # # # # ## #### # ## # ## # # ## ## #
|
||||
# ## ## ### # # ### ## ## # # ## # # ## ## # # # # ## ## #
|
||||
# # # # ## ## # ## ### # # # ### ### # # # #
|
||||
#### ## # ## # ## # # # # ## ### # ## ## ## ### # # # ### # # # #
|
||||
# ## ## # # # # # # # ### # # ## # ## # # # # #
|
||||
### ### ## # # ## # # ## #### ## # ##### ## # # # # #
|
||||
# # ### # ## # # ## # ## # ### # # # # # ## # E
|
||||
10
AgapovaDS/docs/data/2-nd/mazes/random_10x10.txt
Normal file
10
AgapovaDS/docs/data/2-nd/mazes/random_10x10.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
S
|
||||
# # ##
|
||||
## #
|
||||
# # #
|
||||
# ## #
|
||||
# # ### #
|
||||
# # ##
|
||||
# ### #
|
||||
### #
|
||||
##E
|
||||
50
AgapovaDS/docs/data/2-nd/mazes/random_50x50.txt
Normal file
50
AgapovaDS/docs/data/2-nd/mazes/random_50x50.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
S # # # ## # # # #
|
||||
# # ## ## # # ## # # #
|
||||
## # ## # ## # # ##### ### #
|
||||
# # ## ## ### ### # # #
|
||||
# # # # # # ##
|
||||
### # # ## # ## # # #
|
||||
## # ### ### ## # # # #
|
||||
## # ## ## # # # #
|
||||
# # # ### # # # # # ##
|
||||
# ## ## # # # ## # # ## #
|
||||
#### ## ### # # ### # # # # #
|
||||
# # ## # # ## # # ## # ##
|
||||
# # # # # # # # # ######
|
||||
### # ### # # ## # # #
|
||||
## ##### # # # ## # ### ##
|
||||
# ### # ## # # # # ## # #
|
||||
# # # # # ### # # # #
|
||||
# # ### # # # # ### ### # # #
|
||||
# # ## # # ### # # #
|
||||
## # # # ### # # # # # # #
|
||||
## # # # # ## # # ## # #
|
||||
# #### # # ### # # # #
|
||||
# # # # # # # ###### ## # #
|
||||
# # ## # # ### ##
|
||||
# # # ## # # ## ### #
|
||||
### # ## # # # ## # # # ## # # #
|
||||
# # ### # # # # # # ## # # ##
|
||||
### # # ##### # # # # ### ### #
|
||||
# ## # ## # # # ### # # #
|
||||
# ## # ## ### ### # # # ##
|
||||
# ## # # ## # # # ### ## # ## # # # #
|
||||
# ## # # # # # # # # # # #
|
||||
# ### # # # # # # #
|
||||
## ## # ### # # ## ## ## # # #
|
||||
# ### ## ### # # ## # ##
|
||||
## # # # # #### # # ## ##
|
||||
# ### ### # ## # # # #
|
||||
# # # # # # # # ### #####
|
||||
# # # # # # # ### ## # # ### ###
|
||||
# # # # # # # # # # # # #
|
||||
## # # # # ### # # #
|
||||
## # # # # ### # # ### ### # # ## # ##
|
||||
## # # ### ## # ## #####
|
||||
# # ### # # # # # # ## #
|
||||
# # ### ## # # # # ## ## #
|
||||
## # # # ## ## # # # ###
|
||||
##### ## # # ## # ## ## # # ##
|
||||
# # ### ### # # # # # ## #
|
||||
## ## # ### # ## ###
|
||||
# # # # ## ## # # ## E
|
||||
34
AgapovaDS/docs/data/2-nd/results/experiment_results.csv
Normal file
34
AgapovaDS/docs/data/2-nd/results/experiment_results.csv
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
Maze,Strategy,AvgTime_ms,AvgPathLen,PathFound
|
||||
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
|
||||
|
BIN
AgapovaDS/docs/data/2-nd/results/performance.png
Normal file
BIN
AgapovaDS/docs/data/2-nd/results/performance.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
5
AgapovaDS/docs/data/2-nd/test_maze.txt
Normal file
5
AgapovaDS/docs/data/2-nd/test_maze.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#######
|
||||
#S #
|
||||
# ### #
|
||||
# E #
|
||||
#######
|
||||
125
AgapovaDS/docs/report-2-nd.md
Normal file
125
AgapovaDS/docs/report-2-nd.md
Normal 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`.*
|
||||
|
||||
---
|
||||
|
||||
## 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`.
|
||||
Loading…
Reference in New Issue
Block a user