Добавлен паттерн Observer. Подготовлены лабиринты и выполнены замеры

This commit is contained in:
yanyaevaa 2026-05-21 02:17:21 +03:00
parent e77bf45914
commit 06a8a01c7f
7 changed files with 332 additions and 17 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,16 @@
лабиринт,стратегия,время_мс,посещено_клеток,длина_пути
10x10.txt,BFS,0.02810000005410984,30.0,29.0
10x10.txt,DFS,0.038610000046901405,43.0,29.0
10x10.txt,AStar,0.03273000111221336,30.0,29.0
50x50.txt,BFS,0.7084800003212877,799.0,316.0
50x50.txt,DFS,0.48563999953330494,562.0,350.0
50x50.txt,AStar,0.6310500000836328,539.0,316.0
100x100.txt,BFS,3.024820000428008,3576.0,196.0
100x100.txt,DFS,0.44655999954557046,595.0,364.0
100x100.txt,AStar,0.5645899997034576,522.0,196.0
empty.txt,BFS,0.2849799988325685,324.0,35.0
empty.txt,DFS,0.1592799999343697,324.0,171.0
empty.txt,AStar,0.4022000000986736,324.0,35.0
without_exit.txt,BFS,0.041259999125031754,48.0,0.0
without_exit.txt,DFS,0.040809998608892784,48.0,0.0
without_exit.txt,AStar,0.052090000826865435,48.0,0.0
1 лабиринт стратегия время_мс посещено_клеток длина_пути
2 10x10.txt BFS 0.02810000005410984 30.0 29.0
3 10x10.txt DFS 0.038610000046901405 43.0 29.0
4 10x10.txt AStar 0.03273000111221336 30.0 29.0
5 50x50.txt BFS 0.7084800003212877 799.0 316.0
6 50x50.txt DFS 0.48563999953330494 562.0 350.0
7 50x50.txt AStar 0.6310500000836328 539.0 316.0
8 100x100.txt BFS 3.024820000428008 3576.0 196.0
9 100x100.txt DFS 0.44655999954557046 595.0 364.0
10 100x100.txt AStar 0.5645899997034576 522.0 196.0
11 empty.txt BFS 0.2849799988325685 324.0 35.0
12 empty.txt DFS 0.1592799999343697 324.0 171.0
13 empty.txt AStar 0.4022000000986736 324.0 35.0
14 without_exit.txt BFS 0.041259999125031754 48.0 0.0
15 without_exit.txt DFS 0.040809998608892784 48.0 0.0
16 without_exit.txt AStar 0.052090000826865435 48.0 0.0

View File

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

View File

@ -1,17 +1,20 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from collections import deque from collections import deque
import heapq import heapq
import time
import os
import csv
#Этап 1 #Этап 1
class Cell: class Cell:
def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False): def __init__(self, x, y, isWall=False, isStart=False, isExit=False):
self.x = x self.x = x
self.y = y self.y = y
self.is_wall = is_wall self.isWall = isWall
self.is_start = is_start self.isStart = isStart
self.is_exit = is_exit self.isExit = isExit
def isPassable(self): def isPassable(self):
return not self.is_wall return not self.isWall
class Maze: class Maze:
def __init__(self, cells, width, height, start, exit): def __init__(self, cells, width, height, start, exit):
@ -59,15 +62,15 @@ class TextFileMazeBuilder(MazeBuilder):
for x in range(width): for x in range(width):
char=lines[y][x] char=lines[y][x]
is_wall = (char == '#') isWall = (char == '#')
is_start = (char == 'S') isStart = (char == 'S')
is_exit = (char == 'E') isExit = (char == 'E')
cell=Cell(x, y, is_wall, is_start, is_exit) cell=Cell(x, y, isWall, isStart, isExit)
if is_start: if isStart:
start_cell =cell start_cell =cell
if is_exit: if isExit:
exit_cell =cell exit_cell =cell
row.append(cell) row.append(cell)
grid.append(row) grid.append(row)
@ -135,22 +138,30 @@ class AStar(PathFindingStrategy):
if neighbor not in g_score or g_score_new < g_score[neighbor]: if neighbor not in g_score or g_score_new < g_score[neighbor]:
traveled_path[neighbor] = current traveled_path[neighbor] = current
g_score[neighbor] = g_score_new g_score[neighbor] = g_score_new
f_score = tentative_g_score + abs(neighbor.x - exit.x) + abs(neighbor.y - exit.y) f_score = g_score_new + abs(neighbor.x - exit.x) + abs(neighbor.y - exit.y)
count += 1 count += 1
heapq.heappush(open_set, (f_score, count, neighbor)) heapq.heappush(open_set, (f_score, count, neighbor))
return [],len(traveled_path) return [],len(traveled_path)
#Этап 4 #Этап 4
class SearchStats:
def __init__(self, time, visited_cells, path_length):
self.time = time
self.visited_cells = visited_cells
self.path_length = path_length
class MazeSolver: class MazeSolver:
def __init__(self, maze, strategy): def __init__(self, maze, strategy):
self.maze = maze self.maze = maze
self.strategy = strategy self.strategy = strategy
self.observers = []
def addObserver(self, observer):
self.observers.append(observer)
def setStrategy(self, strategy): def setStrategy(self, strategy):
self.strategy = strategy self.strategy = strategy
def solve(self): def solve(self):
start_cell = self.maze.getStart() start_cell = self.maze.start
exit_cell = self.maze.getExit() exit_cell = self.maze.exit
start_time = time.perf_counter() start_time = time.perf_counter()
path, visited_cells = self.strategy.findPath(self.maze, start_cell, exit_cell) path, visited_cells = self.strategy.findPath(self.maze, start_cell, exit_cell)
@ -158,7 +169,98 @@ class MazeSolver:
time_ms = (end_time - start_time) * 1000 time_ms = (end_time - start_time) * 1000
path_length = len(path) path_length = len(path)
stats=SearchStats(time_ms, visited_cells, path_length)
event = Event("path_found", data=stats)
for observer in self.observers:
observer.update(event)
return time_ms, visited_cells, path_length return stats
#Этап 5 #Этап 5
#5.1
class Event:
def __init__(self, event_type, data=None):
self.event_type = event_type
self.data = data
class Observer(ABC):
@abstractmethod
def update(self, event):
pass
class ConsoleView(Observer):
def update(self, event):
if event.event_type == "path_found":
stats=event.data
print("Путь найден:")
print("Время выполнения:", stats.time)
print("Количество посещённых клеток:", stats.visited_cells)
print("Длина найденного пути:", stats.path_length)
if event.event_type == "move":
x, y = event.data
print(f"Игрок переместился в ячейку: {x}, {y}")
if event.event_type == "maze_loaded":
print("Загружен новый лабиринт")
def render(self, maze, path):
for y in range(maze.height):
row_str=""
for x in range(maze.width):
cell=maze.getCell(x, y)
if cell == maze.start:
row_str += "S"
elif cell == maze.exit:
row_str += "E"
elif cell in path:
row_str += "·"
elif cell.isWall:
row_str += "#"
else:
row_str += " "
print(row_str)
#Этап 6
mazes = ["10x10.txt","50x50.txt","100x100.txt","empty.txt","without_exit.txt"]
results =[["лабиринт",
"стратегия",
"время_мс",
"посещено_клеток",
"длина_пути"]]
strategies = {
"BFS": BFS(),
"DFS": DFS(),
"AStar": AStar()
}
builder = TextFileMazeBuilder()
n=10
directory = os.path.join("docs", "data")
for maze_name in mazes:
print(maze_name)
file_name=os.path.join(directory, maze_name)
maze = builder.buildFromFile(file_name)
viewer=ConsoleView()
for strategy_name, strategy in strategies.items():
total_time = 0.0
total_visited = 0
total_path_length = 0
solver = MazeSolver(maze, strategy)
for _ in range(n):
stats = solver.solve()
total_time += stats.time
total_visited += stats.visited_cells
total_path_length += stats.path_length
avg_time = total_time/n
avg_visited = total_visited/n
avg_path_length = total_path_length/n
print(f"{maze_name} стратегия: {strategy_name} время_мс: {avg_time} посещено_клеток: {avg_visited} длина_пути: {avg_path_length}")
results.append([maze_name, strategy_name, avg_time, avg_visited, avg_path_length])
path, _ = strategy.findPath(maze, maze.start, maze.exit)
path=path[1:-1]
viewer.render(maze, path)
csv_filename = os.path.join(directory, "maze_results.csv")
with open(csv_filename, "w", newline="", encoding="utf-8-sig") as f:
writer = csv.writer(f)
writer.writerows(results)