сделан лабиринт и подправлен первй отчет

This commit is contained in:
soldatkinao 2026-05-23 13:50:28 +03:00
parent 3869ff11ed
commit bb11731efd
9 changed files with 585 additions and 1 deletions

View File

@ -1 +0,0 @@
,ASSO/ASSO,Asso,18.05.2026 23:53,file:///C:/Users/ASSO/AppData/Roaming/LibreOffice/4;

Binary file not shown.

View File

@ -0,0 +1 @@
S E

View File

@ -0,0 +1,402 @@
import os
import time
import heapq
import csv
from collections import deque
from abc import ABC, abstractmethod
class Cell:
def __init__(self, x, y, wall=False):
self.x = x
self.y = y
self.wall = wall
self.start = False
self.exit = False
def prohodim(self):
return not self.wall
# лабиринт
class Maze:
def __init__(self, w, h):
self.w = w
self.h = h
self.grid = []
for i in range(h):
row = []
for j in range(w):
row.append(Cell(j, i))
self.grid.append(row)
self.start = None
self.exit = None
def get_cell(self, x, y):
if 0 <= x < self.w and 0 <= y < self.h:
return self.grid[y][x]
return None
def set_start(self, x, y):
c = self.get_cell(x, y)
if c:
c.start = True
self.start = (x, y)
def set_exit(self, x, y):
c = self.get_cell(x, y)
if c:
c.exit = True
self.exit = (x, y)
def neighbors(self, x, y):
res = []
for dx, dy in [(0,1),(1,0),(0,-1),(-1,0)]:
nx, ny = x+dx, y+dy
c = self.get_cell(nx, ny)
if c and c.prohodim():
res.append((nx, ny))
return res
class MazeBuilder(ABC):
@abstractmethod
def load(self, filename):
pass
class TextMazeBuilder(MazeBuilder):
def load(self, filename):
f = open(filename, 'r', encoding='utf-8')
lines = []
for line in f:
lines.append(line.rstrip('\n'))
f.close()
if not lines:
raise Exception("Файл пустой")
h = len(lines)
w = max([len(l) for l in lines])
maze = Maze(w, h)
for y in range(h):
line = lines[y]
for x in range(len(line)):
ch = line[x]
if ch == '#':
maze.grid[y][x] = Cell(x, y, wall=True)
elif ch == 'S':
maze.set_start(x, y)
elif ch == 'E':
maze.set_exit(x, y)
return maze
class Strategy(ABC):
@abstractmethod
def find_path(self, maze, start, end):
pass
# BFS
class BFS(Strategy):
def find_path(self, maze, start, end):
if start is None or end is None:
self.visited_count = 0
return None
q = deque()
q.append(start)
parent = {start: None}
while q:
cur = q.popleft()
if cur == end:
break
for nb in maze.neighbors(cur[0], cur[1]):
if nb not in parent:
parent[nb] = cur
q.append(nb)
self.visited_count = len(parent)
if end not in parent:
return None
path = []
c = end
while c is not None:
path.append(c)
c = parent[c]
path.reverse()
return path
# DFS
class DFS(Strategy):
def find_path(self, maze, start, end):
if start is None or end is None:
self.visited_count = 0
return None
stack = [start]
parent = {start: None}
while stack:
cur = stack.pop()
if cur == end:
break
for nb in maze.neighbors(cur[0], cur[1]):
if nb not in parent:
parent[nb] = cur
stack.append(nb)
self.visited_count = len(parent)
if end not in parent:
return None
path = []
c = end
while c is not None:
path.append(c)
c = parent[c]
path.reverse()
return path
# A*
class AStar(Strategy):
def heur(self, a, b):
return abs(a[0]-b[0]) + abs(a[1]-b[1])
def find_path(self, maze, start, end):
if start is None or end is None:
self.visited_count = 0
return None
heap = [(0, start)]
came_from = {}
g = {start: 0}
f = {start: self.heur(start, end)}
visited = set([start])
while heap:
cur = heapq.heappop(heap)[1]
visited.add(cur)
if cur == end:
break
for nb in maze.neighbors(cur[0], cur[1]):
newg = g[cur] + 1
if newg < g.get(nb, 999999):
came_from[nb] = cur
g[nb] = newg
f[nb] = newg + self.heur(nb, end)
heapq.heappush(heap, (f[nb], nb))
visited.add(nb)
self.visited_count = len(visited)
if end not in came_from and end != start:
return None
path = []
c = end
while c in came_from:
path.append(c)
c = came_from[c]
path.append(start)
path.reverse()
return path
# решение и статистика
class MazeSolver:
def __init__(self, maze, strategy):
self.maze = maze
self.strategy = strategy
def solve(self):
if self.maze.start is None or self.maze.exit is None:
return (0, 0, 0, False)
t0 = time.perf_counter()
path = self.strategy.find_path(self.maze, self.maze.start, self.maze.exit)
t = (time.perf_counter() - t0) * 1000
if path is None:
return (t, 0, 0, False)
return (t, self.strategy.visited_count, len(path), True)
# Наблюдатель
class Observer(ABC):
@abstractmethod
def update(self, event, data):
pass
class ConsoleView(Observer):
def __init__(self, maze):
self.maze = maze
self.player_pos = None
self.path_set = None
def update(self, event, data):
if event == 'init':
self.draw()
elif event == 'move':
self.player_pos = data
self.draw()
elif event == 'path':
self.path_set = set(data) if data else None
self.draw()
def clear(self):
os.system('cls' if os.name == 'nt' else 'clear')
def draw(self):
self.clear()
for y in range(self.maze.h):
row = ''
for x in range(self.maze.w):
cell = self.maze.get_cell(x, y)
if self.player_pos and (x,y) == self.player_pos:
row += 'P'
elif cell.start:
row += 'S'
elif cell.exit:
row += 'E'
elif cell.wall:
row += '#'
elif self.path_set and (x,y) in self.path_set:
row += '*'
else:
row += ' '
print(row)
print("WASD - ходить, F - BFS путь, G - A* путь, Z - отмена, Q - выход")
# игрок
class Player:
def __init__(self, maze):
self.maze = maze
self.pos = maze.start
self.history = []
def move(self, new_pos):
cell = self.maze.get_cell(new_pos[0], new_pos[1])
if cell and cell.prohodim():
self.history.append(self.pos)
self.pos = new_pos
return True
return False
def undo(self):
if self.history:
self.pos = self.history.pop()
return True
return False
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
class MoveCommand(Command):
def __init__(self, player, dx, dy):
self.player = player
self.dx = dx
self.dy = dy
self.old = None
def execute(self):
self.old = self.player.pos
nx = self.player.pos[0] + self.dx
ny = self.player.pos[1] + self.dy
return self.player.move((nx, ny))
def undo(self):
if self.old:
return self.player.move(self.old)
return False
# эксперимент
def run_experiment(maze_files, repeats=5):
builder = TextMazeBuilder()
results = []
for fname in maze_files:
print("Обработка", fname)
maze = builder.load(fname)
if maze.start is None or maze.exit is None:
print(f"Предупреждение: в {fname} нет S или E, пропускаем")
continue
for algo_class, name in [(BFS, 'BFS'), (DFS, 'DFS'), (AStar, 'A*')]:
total_time = 0.0
total_visited = 0
path_len = 0
found = False
for _ in range(repeats):
alg = algo_class()
t0 = time.perf_counter()
path = alg.find_path(maze, maze.start, maze.exit)
t = (time.perf_counter() - t0) * 1000
total_time += t
total_visited += alg.visited_count
if path:
found = True
path_len = len(path)
results.append({
'maze': fname,
'algo': name,
'time': total_time / repeats,
'visited': total_visited / repeats,
'length': path_len,
'found': found
})
with open('results.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['maze','algo','time','visited','length','found'])
writer.writeheader()
writer.writerows(results)
print("\nРезультаты:")
for r in results:
print(f"{r['maze']:15} {r['algo']:5} время={r['time']:6.2f}ms посещено={r['visited']:6.1f} длина={r['length']}")
# режим игры
def play_game(maze):
view = ConsoleView(maze)
player = Player(maze)
view.update('init', None)
while True:
cmd = input("> ").strip().upper()
if cmd == 'W':
c = MoveCommand(player, 0, -1)
elif cmd == 'S':
c = MoveCommand(player, 0, 1)
elif cmd == 'A':
c = MoveCommand(player, -1, 0)
elif cmd == 'D':
c = MoveCommand(player, 1, 0)
elif cmd == 'F':
solver = MazeSolver(maze, BFS())
t, v, l, ok = solver.solve()
if ok:
path = BFS().find_path(maze, maze.start, maze.exit)
view.update('path', path)
print(f"BFS: длина={l} время={t:.2f}ms посещено={v}")
else:
print("Путь не найден")
continue
elif cmd == 'G':
astar = AStar()
path = astar.find_path(maze, maze.start, maze.exit)
if path:
view.update('path', path)
print(f"A*: длина={len(path)} посещено={astar.visited_count}")
else:
print("Путь не найден")
continue
elif cmd == 'Z':
if player.undo():
view.update('move', player.pos)
continue
elif cmd == 'Q':
break
else:
print("Неизвестная команда")
continue
if c.execute():
view.update('move', player.pos)
else:
print("Стена!")
def main():
print("1 - Игра\n2 - Эксперимент")
ch = input("> ")
builder = TextMazeBuilder()
if ch == '1':
maze = builder.load('small.txt') #легкая прогулка)
play_game(maze)
else:
files = ['small.txt', 'medium.txt', 'large.txt', 'empty.txt', 'no_exit.txt']
run_experiment(files)
if __name__ == '__main__':
main()
print ("\nЭто было долго, но вроде бы все готово. ") #можно конечно сделать многофайловую программу чтобы использовать классы как блоки длч строительства

100
soldatkinao/lab2/large.txt Normal file
View File

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

View File

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

View File

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

View File

@ -0,0 +1,16 @@
maze,algo,time,visited,length,found
small.txt,BFS,0.10989999282173812,65.0,15,True
small.txt,DFS,0.065619993256405,65.0,31,True
small.txt,A*,0.14332000282593071,65.0,15,True
medium.txt,BFS,0.3859999938867986,254.0,95,True
medium.txt,DFS,0.33629999379627407,252.0,95,True
medium.txt,A*,0.413980009034276,179.0,95,True
large.txt,BFS,1.4565200021024793,950.0,313,True
large.txt,DFS,1.5662399993743747,1079.0,467,True
large.txt,A*,2.138140005990863,819.0,313,True
empty.txt,BFS,0.1598999951966107,102.0,102,True
empty.txt,DFS,0.13713999651372433,102.0,102,True
empty.txt,A*,0.20723999477922916,102.0,102,True
no_exit.txt,BFS,0.049780000699684024,12.0,0,False
no_exit.txt,DFS,0.04159999662078917,12.0,0,False
no_exit.txt,A*,0.06787999300286174,12.0,0,False
1 maze algo time visited length found
2 small.txt BFS 0.10989999282173812 65.0 15 True
3 small.txt DFS 0.065619993256405 65.0 31 True
4 small.txt A* 0.14332000282593071 65.0 15 True
5 medium.txt BFS 0.3859999938867986 254.0 95 True
6 medium.txt DFS 0.33629999379627407 252.0 95 True
7 medium.txt A* 0.413980009034276 179.0 95 True
8 large.txt BFS 1.4565200021024793 950.0 313 True
9 large.txt DFS 1.5662399993743747 1079.0 467 True
10 large.txt A* 2.138140005990863 819.0 313 True
11 empty.txt BFS 0.1598999951966107 102.0 102 True
12 empty.txt DFS 0.13713999651372433 102.0 102 True
13 empty.txt A* 0.20723999477922916 102.0 102 True
14 no_exit.txt BFS 0.049780000699684024 12.0 0 False
15 no_exit.txt DFS 0.04159999662078917 12.0 0 False
16 no_exit.txt A* 0.06787999300286174 12.0 0 False

View File

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