diff --git a/soldatkinao/lab1/.~lock.otchet.docx# b/soldatkinao/lab1/.~lock.otchet.docx# deleted file mode 100644 index 0704726..0000000 --- a/soldatkinao/lab1/.~lock.otchet.docx# +++ /dev/null @@ -1 +0,0 @@ -,ASSO/ASSO,Asso,18.05.2026 23:53,file:///C:/Users/ASSO/AppData/Roaming/LibreOffice/4; \ No newline at end of file diff --git a/soldatkinao/lab1/otchet.docx b/soldatkinao/lab1/otchet.docx index e31109e..c8fafdf 100644 Binary files a/soldatkinao/lab1/otchet.docx and b/soldatkinao/lab1/otchet.docx differ diff --git a/soldatkinao/lab2/empty.txt b/soldatkinao/lab2/empty.txt new file mode 100644 index 0000000..6d694a2 --- /dev/null +++ b/soldatkinao/lab2/empty.txt @@ -0,0 +1 @@ +S E \ No newline at end of file diff --git a/soldatkinao/lab2/labirint.py b/soldatkinao/lab2/labirint.py new file mode 100644 index 0000000..ac64b5e --- /dev/null +++ b/soldatkinao/lab2/labirint.py @@ -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Это было долго, но вроде бы все готово. ") #можно конечно сделать многофайловую программу чтобы использовать классы как блоки длч строительства \ No newline at end of file diff --git a/soldatkinao/lab2/large.txt b/soldatkinao/lab2/large.txt new file mode 100644 index 0000000..06e2275 --- /dev/null +++ b/soldatkinao/lab2/large.txt @@ -0,0 +1,100 @@ +#################################################################################################### +#S################################################################################################## +# ######## ############################### # ## ################################## ############## ## +# ################################## ############################### ########## +# ############################################################### +## ####### ###################### ####################################### ### ################### +##### ########## ################### ############ ######## ########### ############################# +##### ############################## ############ ################################################## +##### #################### ######### ################################### #### ###################### +##### ######################## ####################################### +####### ######################## ######## ###### ######################### ## ###################### +####### ##################### ######## ###### ################################## ################ +######## # ############## ##### ############## ################################################### +######## ## ############# ##### ############# ################# ################################## +######## ## ############ ###### ############# #################################### ################ +######## ### ### ####### #### ###### ################ ######################## +######## ### ## ############################# ########### ################################### ##### +######## #### ############################# ########### ######################################### +######## ############################ ########### ######################################### +######## ######## ############################ ######################## +####### ######## ############################ ############################ ####################### +####### ######### ########################## ############################# ####### +####### ########### ########### ########### ############################## ### ################# +####### #### ###### ## # ############################### #################### +####################### ################### #### ############# ############ ######### ######### +######################## # ########### #### ################################# ## ############# +################ ############ ######## ########## ####################### ############# +######## ########################### ##################### ###### ############# +############# ########### ############ ################# ######################### #### +##### ########## #################### ########### ######### ######################### ######## #### +##################################### ############# ######## ######## #### +######################## ############ ######################## ############################### ## +############################## #### ######################### ############ #### ### ########## ## +######## ########################## ########################### ### ### ################## ## +######################## ########## ############### ################### ## +########### ######## ## ##### ##### ################## #### ################# #### #### ######### ## +################################### ###### ############################# #### ################### ## +################################ ## ######################################### ######### ####### ### +################################### ######################################### ############### #### +##### #################### ######## ########################################### ############### #### +################ ################## ################ ### ###################### ######### ### #### +#### #### #################### ###### ####### ###################### ##### +################## ################################ ## ################### ###### ######## #### ## +###################################################### ########################## ###### ######### +############ ################### #################### ######################## ### ##### ######### +############################ ######################### ############################# ## ######### +################# #################################### ################################ ## ######### +###### ################### ############## ############ ################################ ####### +###################################################### ########################### ######### ###### +###################################################### ########## ########################### ## ## +###### ################################# ########### # ##################### ################# ##### +#### ############# ######################## ############## ### +#### ####### ####### ################ # ############# ################### ############ ######## ## +#### ########### ####################### ############# ########################################## # +#### ##### ############### ######## #### ########## ## ##################### ##################### # +#### ################################ # ######################################## # +#### ################################################# ######### #################### ########### # +##### ################################ ###### ####### ############################################ # +##### ####### ################### ############# ## ############################################### # +##### ############ ######################################### #################################### # +###### ########################################################## ###### ######################### # +###### ################## ############ ######### ############ ########## ######################### # +###### ######################### ##################### ########################################### # +###### ############################## ############################## ###### # +######## ################ ###### ######### ######################### ########## ################## # +######## ############# #################################################################### ### # +######## ################################# ############################## ################## ##### # +######## ################################################### ##################################### # +### #### #################### # # ################################################################ # +######## ### ####################################### ########################################## ## # +###### # ########################## ############## ################################ ########### # # +######### ############## ################## ########## # +##### ### ################################# ################################## ################### # +######## ########## #### ######### ######## ################### # +################## ####### ############### #### ####### ###### ####### ###### ################### # +############ # # #################### ##### ######################## ######### ################ # +##### ###### ####### ## ############## ## ########## #### ############### ##### ################ # +####### ###### ########## ################# ##################################### ################ # +############## ################# ################ #### ####### # +######################### ################# ####### ##################### ########### ############ # +##### ######## ########## ############### # ######### ################### ######################## # +######################### ################# ################ ########### ######################### # +###### ###################### ####################### # # +###### ### ### ################################ ####################### ######################### # +###### ######################################### ########### ########### ######################### # +### ## ######################################## ############### ####### ############### ######### # +####### ######## ######## ################### ## ######################### # +####### ###### ############################################## ############# #################### # # +####### ################# ############## ## ################# ######################### ########## # +####### ############################ ###### ################# ########################## ######### # +####### ########### ######## ########### ######### ################################### # +####### ######### ####################### ###################### ############ # +###################### ############# # ###### #################################### #### ######### # +###################################### ########################## ################################ # +##### ################################ ################## ######################################## # +########## ############### #### ######### ####### ####### # +########## ####### ################################################ ############################## # +########## # +##################################################################################################E# +#################################################################################################### diff --git a/soldatkinao/lab2/medium.txt b/soldatkinao/lab2/medium.txt new file mode 100644 index 0000000..3802000 --- /dev/null +++ b/soldatkinao/lab2/medium.txt @@ -0,0 +1,50 @@ +################################################## +#S ############################################### +## ############################################## +### ############################################## +### ############################################ +##### ############################################ +##### ## ############### ######################### +##### ############### ######################### +######## ############## ######################### +######### ####### ######################### +########## ########## #################### +############ ################ #################### +#### ################ #################### +############ ############### #################### +############# ########## +############# ########### ############ ########## +############ ############ ############ ########## +############# ############ ########### ########## +############# ################# ############ +############# ## # ######### ############# +################ ##### ## ############# +################ ####### ########## ############# +################ ######## ##### ######## +################ ######## ######### ############# +################ ######## ######### ############# +######################## ##################### +####################### ### #################### +###################### ##### ################### +##################### ####### ######### +############################### ################## +############################### ################## +######### ############### +####################### ######### ########### +####################### ############ # ########## +####################### ############### ########## +####################### ############### ######### +####################### ############### ####### +###################################### ## ####### +###################################### ### ### +###################################### ####### # +###################################### ######## # +################################################ # +################################################ # +################################################ # +################################################ # +##################################### # +################################################ # +################################################ # +################################################E# +################################################## diff --git a/soldatkinao/lab2/no_exit.txt b/soldatkinao/lab2/no_exit.txt new file mode 100644 index 0000000..54e8bea --- /dev/null +++ b/soldatkinao/lab2/no_exit.txt @@ -0,0 +1,6 @@ +####### +#S # +# ### # +# # # +### ### +#####E# \ No newline at end of file diff --git a/soldatkinao/lab2/results.csv b/soldatkinao/lab2/results.csv new file mode 100644 index 0000000..381ab67 --- /dev/null +++ b/soldatkinao/lab2/results.csv @@ -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 diff --git a/soldatkinao/lab2/small.txt b/soldatkinao/lab2/small.txt new file mode 100644 index 0000000..f11ba38 --- /dev/null +++ b/soldatkinao/lab2/small.txt @@ -0,0 +1,10 @@ +########## +#S # +# # +# # +# # +# # +# # +# # +# # +#######E## \ No newline at end of file