diff --git a/BudakovIS/docs/data/2-nd-exercize/main.py b/BudakovIS/docs/data/2-nd-exercize/main.py new file mode 100644 index 0000000..f702f83 --- /dev/null +++ b/BudakovIS/docs/data/2-nd-exercize/main.py @@ -0,0 +1,213 @@ +import sys +from collections import deque + + +class Cell: + def __init__(self, x, y): + self._x = x + self._y = y + self._is_wall = False + self._is_start = False + self._is_exit = False + + @property + def x(self): + return self._x + + @property + def y(self): + return self._y + + @property + def is_wall(self): + return self._is_wall + + @is_wall.setter + def is_wall(self, value): + self._is_wall = value + + @property + def is_start(self): + return self._is_start + + @is_start.setter + def is_start(self, value): + self._is_start = value + + @property + def is_exit(self): + return self._is_exit + + @is_exit.setter + def is_exit(self, value): + self._is_exit = value + + def is_passable(self): + return not self._is_wall + + +class Maze: + def __init__(self, width, height): + self._width = width + self._height = height + self._cells = [[Cell(x, y) for x in range(width)] for y in range(height)] + self._start = None + self._exit = None + + @property + def width(self): + return self._width + + @property + def height(self): + return self._height + + @property + def start(self): + return self._start + + @property + def exit(self): + return self._exit + + def get_cell(self, x, y): + if 0 <= x < self._width and 0 <= y < self._height: + return self._cells[y][x] + return None + + def set_cell(self, x, y, cell_type): + cell = self.get_cell(x, y) + if cell is None: + return + + if cell_type == 'wall': + cell.is_wall = True + elif cell_type == 'start': + if self._start: + self._start.is_start = False + cell.is_start = True + cell.is_wall = False + self._start = cell + elif cell_type == 'exit': + if self._exit: + self._exit.is_exit = False + cell.is_exit = True + cell.is_wall = False + self._exit = cell + elif cell_type == 'path': + cell.is_wall = False + + def get_neighbors(self, cell): + neighbors = [] + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + for dx, dy in directions: + nx, ny = cell.x + dx, cell.y + dy + neighbor = self.get_cell(nx, ny) + if neighbor and neighbor.is_passable(): + neighbors.append(neighbor) + return neighbors + + +class MazeBuilder: + def build_from_file(self, filename): + raise NotImplementedError("Need to realise in calss") + +class TextFileMazeBuilder(MazeBuilder): + def build_from_file(self, filename): + with open(filename, 'r') as f: + lines = [line.rstrip('\n')for line in f.readlines()] + height = len(lines) + width = max(len(line) for line in lines) if height > 0 else 0 + start_en = 0 + exit_en = 0 + maze = Maze(width, height) + + for y,line in enumerate(lines): + for x, ch in enumerate(line): + if ch == "#": + maze.set_cell(x,y,"wall") + elif ch == "S": + maze.set_cell(x,y,"start") + start_en+=1 + elif ch == "E": + maze.set_cell(x,y,"exit") + exit_en+=1 + else: + maze.set_cell(x, y, 'path') + if start_en > 1 or exit_en > 1 or start_en==0 or exit_en ==0: + sys.exit("Error while reading file(you have too many or no match start and exits)") + return maze + + + + +class BFSStrategy: + def find_path(self, maze, start, exit): + queue = deque() + queue.append(start) + came_from={} + came_from[start]=None + visited = set() + visited.add(start) + while queue: + current = queue.popleft() + if current == exit: + return self._reconstruct_path(came_from,start,exit) + for neighbors in maze.get_neighbors(current): + if neighbors not in visited: + visited.add(neighbors) + came_from[neighbors] = current + queue.append(neighbors) + return [] + def _reconstruct_path(self, came_from, start, exit_cell): + path = [] + current = exit_cell + while current is not None: + path.append(current) + current = came_from.get(current) + + path.reverse() + return path +class DFSStrategy: + def find_path(self,maze,start,exit): + stack =[] + stack.append(start) + came_from={} + came_from[start]=None + visited = set() + visited.add(start) + while stack: + current = stack.pop() + if current == exit: + return self._reconstruct_path(came_from,start,exit) + for neighbors in maze.get_neighbors(current): + if neighbors not in visited: + visited.add(neighbors) + came_from[neighbors]= current + stack.append(neighbors) + return [] + + + def _reconstruct_path(self, came_from, start, exit_cell): + path = [] + current = exit_cell + while current is not None: + path.append(current) + current = came_from.get(current) + + path.reverse() + return path + + +if __name__ == "__main__": + builder = TextFileMazeBuilder() + maze = builder.build_from_file("maze1.txt") + print(f"Лабиринт {maze.width}x{maze.height}") + print(f"Старт: ({maze.start.x}, {maze.start.y})") + print(f"Выход: ({maze.exit.x}, {maze.exit.y})") + bfs = BFSStrategy() + path = bfs.find_path(maze, maze.start, maze.exit) + print(f"BFS: путь найден, длина = {len(path)}") + dfs = DFSStrategy() + path = dfs.find_path(maze, maze.start, maze.exit) + print(f"DFS: путь найден, длинна = {len(path)}") diff --git a/BudakovIS/docs/data/2-nd-exercize/maze1.txt b/BudakovIS/docs/data/2-nd-exercize/maze1.txt new file mode 100644 index 0000000..1e9e1c6 --- /dev/null +++ b/BudakovIS/docs/data/2-nd-exercize/maze1.txt @@ -0,0 +1,6 @@ +########## +# S# +# # +# ##### +# E# +##########