forked from UNN/2026-rff_mp
сделан лабиринт и подправлен первй отчет
This commit is contained in:
parent
3869ff11ed
commit
bb11731efd
|
|
@ -1 +0,0 @@
|
|||
,ASSO/ASSO,Asso,18.05.2026 23:53,file:///C:/Users/ASSO/AppData/Roaming/LibreOffice/4;
|
||||
Binary file not shown.
1
soldatkinao/lab2/empty.txt
Normal file
1
soldatkinao/lab2/empty.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
S E
|
||||
402
soldatkinao/lab2/labirint.py
Normal file
402
soldatkinao/lab2/labirint.py
Normal 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
100
soldatkinao/lab2/large.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
####################################################################################################
|
||||
#S##################################################################################################
|
||||
# ######## ############################### # ## ################################## ############## ##
|
||||
# ################################## ############################### ##########
|
||||
# ###############################################################
|
||||
## ####### ###################### ####################################### ### ###################
|
||||
##### ########## ################### ############ ######## ########### #############################
|
||||
##### ############################## ############ ##################################################
|
||||
##### #################### ######### ################################### #### ######################
|
||||
##### ######################## #######################################
|
||||
####### ######################## ######## ###### ######################### ## ######################
|
||||
####### ##################### ######## ###### ################################## ################
|
||||
######## # ############## ##### ############## ###################################################
|
||||
######## ## ############# ##### ############# ################# ##################################
|
||||
######## ## ############ ###### ############# #################################### ################
|
||||
######## ### ### ####### #### ###### ################ ########################
|
||||
######## ### ## ############################# ########### ################################### #####
|
||||
######## #### ############################# ########### #########################################
|
||||
######## ############################ ########### #########################################
|
||||
######## ######## ############################ ########################
|
||||
####### ######## ############################ ############################ #######################
|
||||
####### ######### ########################## ############################# #######
|
||||
####### ########### ########### ########### ############################## ### #################
|
||||
####### #### ###### ## # ############################### ####################
|
||||
####################### ################### #### ############# ############ ######### #########
|
||||
######################## # ########### #### ################################# ## #############
|
||||
################ ############ ######## ########## ####################### #############
|
||||
######## ########################### ##################### ###### #############
|
||||
############# ########### ############ ################# ######################### ####
|
||||
##### ########## #################### ########### ######### ######################### ######## ####
|
||||
##################################### ############# ######## ######## ####
|
||||
######################## ############ ######################## ############################### ##
|
||||
############################## #### ######################### ############ #### ### ########## ##
|
||||
######## ########################## ########################### ### ### ################## ##
|
||||
######################## ########## ############### ################### ##
|
||||
########### ######## ## ##### ##### ################## #### ################# #### #### ######### ##
|
||||
################################### ###### ############################# #### ################### ##
|
||||
################################ ## ######################################### ######### ####### ###
|
||||
################################### ######################################### ############### ####
|
||||
##### #################### ######## ########################################### ############### ####
|
||||
################ ################## ################ ### ###################### ######### ### ####
|
||||
#### #### #################### ###### ####### ###################### #####
|
||||
################## ################################ ## ################### ###### ######## #### ##
|
||||
###################################################### ########################## ###### #########
|
||||
############ ################### #################### ######################## ### ##### #########
|
||||
############################ ######################### ############################# ## #########
|
||||
################# #################################### ################################ ## #########
|
||||
###### ################### ############## ############ ################################ #######
|
||||
###################################################### ########################### ######### ######
|
||||
###################################################### ########## ########################### ## ##
|
||||
###### ################################# ########### # ##################### ################# #####
|
||||
#### ############# ######################## ############## ###
|
||||
#### ####### ####### ################ # ############# ################### ############ ######## ##
|
||||
#### ########### ####################### ############# ########################################## #
|
||||
#### ##### ############### ######## #### ########## ## ##################### ##################### #
|
||||
#### ################################ # ######################################## #
|
||||
#### ################################################# ######### #################### ########### #
|
||||
##### ################################ ###### ####### ############################################ #
|
||||
##### ####### ################### ############# ## ############################################### #
|
||||
##### ############ ######################################### #################################### #
|
||||
###### ########################################################## ###### ######################### #
|
||||
###### ################## ############ ######### ############ ########## ######################### #
|
||||
###### ######################### ##################### ########################################### #
|
||||
###### ############################## ############################## ###### #
|
||||
######## ################ ###### ######### ######################### ########## ################## #
|
||||
######## ############# #################################################################### ### #
|
||||
######## ################################# ############################## ################## ##### #
|
||||
######## ################################################### ##################################### #
|
||||
### #### #################### # # ################################################################ #
|
||||
######## ### ####################################### ########################################## ## #
|
||||
###### # ########################## ############## ################################ ########### # #
|
||||
######### ############## ################## ########## #
|
||||
##### ### ################################# ################################## ################### #
|
||||
######## ########## #### ######### ######## ################### #
|
||||
################## ####### ############### #### ####### ###### ####### ###### ################### #
|
||||
############ # # #################### ##### ######################## ######### ################ #
|
||||
##### ###### ####### ## ############## ## ########## #### ############### ##### ################ #
|
||||
####### ###### ########## ################# ##################################### ################ #
|
||||
############## ################# ################ #### ####### #
|
||||
######################### ################# ####### ##################### ########### ############ #
|
||||
##### ######## ########## ############### # ######### ################### ######################## #
|
||||
######################### ################# ################ ########### ######################### #
|
||||
###### ###################### ####################### # #
|
||||
###### ### ### ################################ ####################### ######################### #
|
||||
###### ######################################### ########### ########### ######################### #
|
||||
### ## ######################################## ############### ####### ############### ######### #
|
||||
####### ######## ######## ################### ## ######################### #
|
||||
####### ###### ############################################## ############# #################### # #
|
||||
####### ################# ############## ## ################# ######################### ########## #
|
||||
####### ############################ ###### ################# ########################## ######### #
|
||||
####### ########### ######## ########### ######### ################################### #
|
||||
####### ######### ####################### ###################### ############ #
|
||||
###################### ############# # ###### #################################### #### ######### #
|
||||
###################################### ########################## ################################ #
|
||||
##### ################################ ################## ######################################## #
|
||||
########## ############### #### ######### ####### ####### #
|
||||
########## ####### ################################################ ############################## #
|
||||
########## #
|
||||
##################################################################################################E#
|
||||
####################################################################################################
|
||||
50
soldatkinao/lab2/medium.txt
Normal file
50
soldatkinao/lab2/medium.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
##################################################
|
||||
#S ###############################################
|
||||
## ##############################################
|
||||
### ##############################################
|
||||
### ############################################
|
||||
##### ############################################
|
||||
##### ## ############### #########################
|
||||
##### ############### #########################
|
||||
######## ############## #########################
|
||||
######### ####### #########################
|
||||
########## ########## ####################
|
||||
############ ################ ####################
|
||||
#### ################ ####################
|
||||
############ ############### ####################
|
||||
############# ##########
|
||||
############# ########### ############ ##########
|
||||
############ ############ ############ ##########
|
||||
############# ############ ########### ##########
|
||||
############# ################# ############
|
||||
############# ## # ######### #############
|
||||
################ ##### ## #############
|
||||
################ ####### ########## #############
|
||||
################ ######## ##### ########
|
||||
################ ######## ######### #############
|
||||
################ ######## ######### #############
|
||||
######################## #####################
|
||||
####################### ### ####################
|
||||
###################### ##### ###################
|
||||
##################### ####### #########
|
||||
############################### ##################
|
||||
############################### ##################
|
||||
######### ###############
|
||||
####################### ######### ###########
|
||||
####################### ############ # ##########
|
||||
####################### ############### ##########
|
||||
####################### ############### #########
|
||||
####################### ############### #######
|
||||
###################################### ## #######
|
||||
###################################### ### ###
|
||||
###################################### ####### #
|
||||
###################################### ######## #
|
||||
################################################ #
|
||||
################################################ #
|
||||
################################################ #
|
||||
################################################ #
|
||||
##################################### #
|
||||
################################################ #
|
||||
################################################ #
|
||||
################################################E#
|
||||
##################################################
|
||||
6
soldatkinao/lab2/no_exit.txt
Normal file
6
soldatkinao/lab2/no_exit.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#######
|
||||
#S #
|
||||
# ### #
|
||||
# # #
|
||||
### ###
|
||||
#####E#
|
||||
16
soldatkinao/lab2/results.csv
Normal file
16
soldatkinao/lab2/results.csv
Normal 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
|
||||
|
10
soldatkinao/lab2/small.txt
Normal file
10
soldatkinao/lab2/small.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
##########
|
||||
#S #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
#######E##
|
||||
Loading…
Reference in New Issue
Block a user