Добавлен паттерн 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 collections import deque
import heapq
import time
import os
import csv
#Этап 1
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.y = y
self.is_wall = is_wall
self.is_start = is_start
self.is_exit = is_exit
self.isWall = isWall
self.isStart = isStart
self.isExit = isExit
def isPassable(self):
return not self.is_wall
return not self.isWall
class Maze:
def __init__(self, cells, width, height, start, exit):
@ -59,15 +62,15 @@ class TextFileMazeBuilder(MazeBuilder):
for x in range(width):
char=lines[y][x]
is_wall = (char == '#')
is_start = (char == 'S')
is_exit = (char == 'E')
isWall = (char == '#')
isStart = (char == 'S')
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
if is_exit:
if isExit:
exit_cell =cell
row.append(cell)
grid.append(row)
@ -135,22 +138,30 @@ class AStar(PathFindingStrategy):
if neighbor not in g_score or g_score_new < g_score[neighbor]:
traveled_path[neighbor] = current
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
heapq.heappush(open_set, (f_score, count, neighbor))
return [],len(traveled_path)
#Этап 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:
def __init__(self, maze, strategy):
self.maze = maze
self.strategy = strategy
self.observers = []
def addObserver(self, observer):
self.observers.append(observer)
def setStrategy(self, strategy):
self.strategy = strategy
def solve(self):
start_cell = self.maze.getStart()
exit_cell = self.maze.getExit()
start_cell = self.maze.start
exit_cell = self.maze.exit
start_time = time.perf_counter()
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
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)