diff --git a/stepushovgs/labyrinth/source/bububu/observer.py b/stepushovgs/labyrinth/source/bububu/observer.py deleted file mode 100644 index 56314b1..0000000 --- a/stepushovgs/labyrinth/source/bububu/observer.py +++ /dev/null @@ -1,80 +0,0 @@ -from abc import ABC, abstractmethod -import os - -from source.classes.cell import Cell - - -class Event: - def __init__(self, event, maze, player_position, path): - self.event = event - self.maze = maze - self.player_position = player_position - self.path = path - - -class Observer(ABC): - - @abstractmethod - def update(self, event: Event): - pass - - -class ConsoleView(Observer): - - def update(self, event: Event): - if event.event == "path_found": - print("Путь найден:") - self.render( - event.maze, - event.player_position, - event.path - ) - elif event.event == "move": - self.render( - event.maze, - event.player_position, - event.path - ) - elif event.event == "maze_loaded": - print("Загружен лабиринт:") - self.render( - event.maze, - event.player_position, - event.path - ) - else: - pass - - - def render(self, maze, player_position, path): - if path and isinstance(path[0], tuple): - self.render_xy(maze=maze, player_position=player_position, path=path) - return - os.system('cls' if os.name == 'nt' else 'clear') - - path_xy = [cell.getXY() for cell in path] - - for line in maze.cells: - for c in line: - if c.getXY() == player_position: - print('P', end='') - elif c.getXY() in path_xy: - print('*', end='') - else: - print(c.toStr(), end='') - - print() - - def render_xy(self, maze, player_position, path: list[tuple[int, int]]): - os.system('cls' if os.name == 'nt' else 'clear') - # path_xy = [cell.getXY() for cell in path] - - for line in maze.cells: - for c in line: - if c.getXY() == player_position: - print('P', end='') - elif c.getXY() in path: - print('*', end='') - else: - print(c.toStr(), end='') - print() \ No newline at end of file diff --git a/stepushovgs/labyrinth/source/classes/builder.py b/stepushovgs/labyrinth/source/builder/builder.py similarity index 97% rename from stepushovgs/labyrinth/source/classes/builder.py rename to stepushovgs/labyrinth/source/builder/builder.py index 3757511..d819170 100644 --- a/stepushovgs/labyrinth/source/classes/builder.py +++ b/stepushovgs/labyrinth/source/builder/builder.py @@ -25,7 +25,6 @@ class TextFileMazeBuilder(MazeBuilder): for line in data: x = 0 - for c in line.strip(): if c == 'S': cells[y][x] = Cell(x, y, isStart=True) @@ -59,5 +58,5 @@ class TextFileMazeBuilder(MazeBuilder): width=width, height=height, start=start, - exit=c_exit + exit_cell=c_exit ) \ No newline at end of file diff --git a/stepushovgs/labyrinth/source/classes/cell.py b/stepushovgs/labyrinth/source/classes/cell.py index a128510..aea675a 100644 --- a/stepushovgs/labyrinth/source/classes/cell.py +++ b/stepushovgs/labyrinth/source/classes/cell.py @@ -17,7 +17,8 @@ class Cell: """ Создание клетки лабиринта - `x, y` - координаты клетки в лабиринте + `x` - столбец клетки в лабиринте + `y` - строка клетки в лабиринте `isWall` - Является ли клетка стеной diff --git a/stepushovgs/labyrinth/source/classes/maze.py b/stepushovgs/labyrinth/source/classes/maze.py index 2be2594..cffdd47 100644 --- a/stepushovgs/labyrinth/source/classes/maze.py +++ b/stepushovgs/labyrinth/source/classes/maze.py @@ -2,16 +2,16 @@ from source.classes.cell import Cell class Maze: """Лабиринт""" - def __init__(self, cells, width: int, height: int, start: Cell, exit: Cell): + def __init__(self, cells, width: int, height: int, start: Cell, exit_cell: Cell): self.cells = cells self.width = width self.height = height self.start = start - self.exit = exit + self.exit = exit_cell pass - def getCell(self, x, y) -> Cell: - return self.cells[x][y] + def getCell(self, x: int, y: int) -> Cell: + return self.cells[y][x] # строка стобец def getNeighbors(self, cell) -> list[Cell]: """Возвращает список соседних проходимых клеток (вверх, вниз, влево, вправо, если в пределах границ и не стена).""" @@ -19,17 +19,17 @@ class Maze: c_x, c_y = cell.getXY() - if c_x - 1 >= 0 and not self.cells[c_x - 1][c_y].isWall: - neighbors.append(self.cells[c_x - 1][c_y]) + if c_y - 1 >= 0 and not self.cells[c_y - 1][c_x].isWall: + neighbors.append(self.cells[c_y - 1][c_x]) - if c_x + 1 < self.width and not self.cells[c_x + 1][c_y].isWall: - neighbors.append(self.cells[c_x + 1][c_y]) + if c_y + 1 < self.height and not self.cells[c_y + 1][c_x].isWall: + neighbors.append(self.cells[c_y + 1][c_x]) - if c_y - 1 >= 0 and not self.cells[c_x][c_y - 1].isWall: - neighbors.append(self.cells[c_x][c_y - 1]) + if c_x - 1 >= 0 and not self.cells[c_y][c_x - 1].isWall: + neighbors.append(self.cells[c_y][c_x - 1]) - if c_y + 1 < self.height and not self.cells[c_x][c_y + 1].isWall: - neighbors.append(self.cells[c_x][c_y + 1]) + if c_x + 1 < self.width and not self.cells[c_y][c_x + 1].isWall: + neighbors.append(self.cells[c_y][c_x + 1]) return neighbors diff --git a/stepushovgs/labyrinth/source/observer/console_view.py b/stepushovgs/labyrinth/source/observer/console_view.py new file mode 100644 index 0000000..8377f07 --- /dev/null +++ b/stepushovgs/labyrinth/source/observer/console_view.py @@ -0,0 +1,80 @@ +import os + + +from source.observer.observer import Observer, Event +from source.classes.cell import Cell +from source.classes.maze import Maze + +class ConsoleView(Observer): + + def update(self, event: Event): + """Вывод состояния лабиринта на экран + + `maze_loaded` - Лабиринт загружен + + `path_found` - Отображает лабиринт и маршрут в нём (символом `*`) + + `move` - Выводит лабиринт и позицию игрока в нём (символом `P`) + + """ + if event.event == "path_found": + print("Путь найден:") + self.render( + event.maze, + event.player_position, + event.path + ) + elif event.event == "move": + self.render( + event.maze, + event.player_position, + event.path + ) + elif event.event == "maze_loaded": + print("Загружен лабиринт:") + self.render( + event.maze, + event.player_position, + event.path + ) + else: + pass + + + def render(self, maze:Maze, player_position: tuple[int, int], path: list): + os.system('cls' if os.name == 'nt' else 'clear') + + # Если path содержит объекты Cell, преобразуем в координаты + if path and isinstance(path[0], Cell): + path_xy = [cell.getXY() for cell in path] + else: + path_xy = path + + # path_xy = [cell.getXY() for cell in path] + + for line in maze.cells: + for c in line: + if c.getXY() == player_position: + print('P', end='') + elif c.toStr() in ["S", "E"]: + print(c.toStr(), end='') + elif c.getXY() in path_xy: + print('*', end='') + else: + print(c.toStr(), end='') + + print() + + # def render_xy(self, maze: Maze, player_position: tuple[int, int], path: list[tuple[int, int]]): + # os.system('cls' if os.name == 'nt' else 'clear') + # # path_xy = [cell.getXY() for cell in path] + + # for line in maze.cells: + # for c in line: + # if c.getXY() == player_position: + # print('P', end='') + # elif c.getXY() in path: + # print('*', end='') + # else: + # print(c.toStr(), end='') + # print() \ No newline at end of file diff --git a/stepushovgs/labyrinth/source/observer/observer.py b/stepushovgs/labyrinth/source/observer/observer.py new file mode 100644 index 0000000..541a481 --- /dev/null +++ b/stepushovgs/labyrinth/source/observer/observer.py @@ -0,0 +1,22 @@ +from abc import ABC, abstractmethod +# import os + +# from source.classes.cell import Cell +from source.classes.maze import Maze + + +class Event: + def __init__(self, event: str, maze: Maze, player_position: tuple[int, int], path): + self.event = event + self.maze = maze + self.player_position = player_position + self.path = path + + +class Observer(ABC): + + @abstractmethod + def update(self, event: Event): + pass + + diff --git a/stepushovgs/labyrinth/source/strategy/maze_solver.py b/stepushovgs/labyrinth/source/strategy/maze_solver.py index ad90177..bb8b48f 100644 --- a/stepushovgs/labyrinth/source/strategy/maze_solver.py +++ b/stepushovgs/labyrinth/source/strategy/maze_solver.py @@ -2,7 +2,9 @@ import time from source.strategy.strategy import PathFindingStrategy +from source.observer.observer import Observer, Event from source.classes.cell import Cell +from source.classes.maze import Maze class MazeSolver: def __init__(self, maze: Maze, strategy: PathFindingStrategy, observer: Observer): @@ -23,6 +25,7 @@ class MazeSolver: self.observer.update(Event( event="path_found", + maze=self.maze, player_position=self.maze.exit, path=path )) diff --git a/stepushovgs/labyrinth/test.ipynb b/stepushovgs/labyrinth/test.ipynb index 1a04544..3f068c4 100644 --- a/stepushovgs/labyrinth/test.ipynb +++ b/stepushovgs/labyrinth/test.ipynb @@ -46,7 +46,7 @@ } ], "source": [ - "from source.classes.builder import TextFileMazeBuilder\n", + "from source.builder.builder import TextFileMazeBuilder\n", "\n", "builder = TextFileMazeBuilder()\n", "maze = builder.buildFromFile(filename='test_lab.txt')\n", @@ -65,7 +65,7 @@ "output_type": "stream", "text": [ "Загружен лабиринт:\n", - "\u001b[H\u001b[2J**P# ###\n", + "S*P# ###\n", "## # # E\n", "# # #\n", "### ## #\n", @@ -75,7 +75,8 @@ } ], "source": [ - "from source.bububu.observer import ConsoleView, Event\n", + "from source.observer.console_view import ConsoleView\n", + "from source.observer.observer import Event\n", "\n", "view = ConsoleView()\n", "view.update(Event(\n", @@ -88,21 +89,84 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "19840429", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Старт: (0, 0)\n", + "Выход: (7, 1)\n", + "Соседи старта: [(1, 0)]\n", + "для клекти (0, 0) соседи: [(1, 0)]\n", + "для клекти (1, 0) соседи: [(0, 0), (2, 0)]\n", + "для клекти (2, 0) соседи: [(2, 1), (1, 0)]\n", + "для клекти (2, 1) соседи: [(2, 0), (2, 2)]\n", + "для клекти (2, 2) соседи: [(2, 1), (1, 2), (3, 2)]\n", + "для клекти (3, 2) соседи: [(3, 3), (2, 2), (4, 2)]\n", + "для клекти (4, 2) соседи: [(4, 1), (3, 2)]\n", + "для клекти (4, 1) соседи: [(4, 0), (4, 2)]\n", + "для клекти (4, 0) соседи: [(4, 1)]\n", + "для клекти (3, 3) соседи: [(3, 2), (3, 4)]\n", + "для клекти (3, 4) соседи: [(3, 3), (2, 4), (4, 4)]\n", + "для клекти (4, 4) соседи: [(3, 4), (5, 4)]\n", + "для клекти (5, 4) соседи: [(4, 4), (6, 4)]\n", + "для клекти (6, 4) соседи: [(6, 3), (5, 4)]\n", + "для клекти (6, 3) соседи: [(6, 2), (6, 4)]\n", + "для клекти (6, 2) соседи: [(6, 1), (6, 3)]\n", + "для клекти (6, 1) соседи: [(6, 2), (7, 1)]\n", + "Путь найден:\n", + "S**# ###\n", + "##*# #*E\n", + "# ** #*#\n", + "###*##*#\n", + "# ****#\n", + "########\n" + ] + }, + { + "data": { + "text/plain": [ + "([(2, 1), (1, 0)],\n", + " [(0, 0),\n", + " (1, 0),\n", + " (2, 0),\n", + " (2, 1),\n", + " (2, 2),\n", + " (3, 2),\n", + " (3, 3),\n", + " (3, 4),\n", + " (4, 4),\n", + " (5, 4),\n", + " (6, 4),\n", + " (6, 3),\n", + " (6, 2),\n", + " (6, 1),\n", + " (7, 1)])" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from source.strategy.DFS import DFS\n", "from source.strategy.maze_solver import MazeSolver\n", + "from source.classes.cell import Cell\n", "\n", - "strat = MazeSolver(maze, DFS())\n", - "\n" + "\n", + "solver = MazeSolver(maze, DFS(), ConsoleView())\n", + "stats = solver.solve()\n", + "\n", + "[cord.getXY() for cord in maze.getNeighbors(cell=Cell(2, 0))], [cord.getXY() for cord in stats.path]" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "857c5c04", "metadata": {}, "outputs": [ @@ -113,8 +177,9 @@ "0\n", "2\n", "1\n", + "4\n", "3\n", - "4\n" + "3\n" ] }, { @@ -123,7 +188,7 @@ "{'0', '1', '2', '3', '4'}" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -149,6 +214,125 @@ "\n", "dfs(graph, '0')" ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9a5ea5cb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Размер: 8x6\n", + "(0,0): wall=False, start=True, exit=False\n", + "(1,0): wall=False, start=False, exit=False\n", + "(2,0): wall=False, start=False, exit=False\n", + "(3,0): wall=True, start=False, exit=False\n", + "(4,0): wall=False, start=False, exit=False\n", + "(5,0): wall=True, start=False, exit=False\n", + "(6,0): wall=True, start=False, exit=False\n", + "(7,0): wall=True, start=False, exit=False\n", + "(0,1): wall=True, start=False, exit=False\n", + "(1,1): wall=True, start=False, exit=False\n", + "(2,1): wall=False, start=False, exit=False\n", + "(3,1): wall=True, start=False, exit=False\n", + "(4,1): wall=False, start=False, exit=False\n", + "(5,1): wall=True, start=False, exit=False\n", + "(6,1): wall=False, start=False, exit=False\n", + "(7,1): wall=False, start=False, exit=True\n", + "(0,2): wall=True, start=False, exit=False\n", + "(1,2): wall=False, start=False, exit=False\n", + "(2,2): wall=False, start=False, exit=False\n", + "(3,2): wall=False, start=False, exit=False\n", + "(4,2): wall=False, start=False, exit=False\n", + "(5,2): wall=True, start=False, exit=False\n", + "(6,2): wall=False, start=False, exit=False\n", + "(7,2): wall=True, start=False, exit=False\n", + "(0,3): wall=True, start=False, exit=False\n", + "(1,3): wall=True, start=False, exit=False\n", + "(2,3): wall=True, start=False, exit=False\n", + "(3,3): wall=False, start=False, exit=False\n", + "(4,3): wall=True, start=False, exit=False\n", + "(5,3): wall=True, start=False, exit=False\n", + "(6,3): wall=False, start=False, exit=False\n", + "(7,3): wall=True, start=False, exit=False\n", + "(0,4): wall=True, start=False, exit=False\n", + "(1,4): wall=False, start=False, exit=False\n", + "(2,4): wall=False, start=False, exit=False\n", + "(3,4): wall=False, start=False, exit=False\n", + "(4,4): wall=False, start=False, exit=False\n", + "(5,4): wall=False, start=False, exit=False\n", + "(6,4): wall=False, start=False, exit=False\n", + "(7,4): wall=True, start=False, exit=False\n", + "(0,5): wall=True, start=False, exit=False\n", + "(1,5): wall=True, start=False, exit=False\n", + "(2,5): wall=True, start=False, exit=False\n", + "(3,5): wall=True, start=False, exit=False\n", + "(4,5): wall=True, start=False, exit=False\n", + "(5,5): wall=True, start=False, exit=False\n", + "(6,5): wall=True, start=False, exit=False\n", + "(7,5): wall=True, start=False, exit=False\n", + "\n", + "Клетка (2,0) из лабиринта: wall=True\n", + "Соседи (2,0): [(1, 2)]\n", + "Соседи (1,0): [(0, 0)]\n" + ] + } + ], + "source": [ + "# Проверьте структуру лабиринта\n", + "print(f\"Размер: {maze.width}x{maze.height}\")\n", + "\n", + "# Проверьте конкретные клетки\n", + "for y in range(maze.height):\n", + " for x in range(maze.width):\n", + " cell = maze.cells[y][x]\n", + " print(f\"({x},{y}): wall={cell.isWall}, start={cell.isStart}, exit={cell.isExit}\")\n", + "\n", + "# Проверьте соседей конкретной клетки из лабиринта\n", + "cell_from_maze = maze.cells[2][0] # Берём реальную клетку из лабиринта\n", + "print(f\"\\nКлетка (2,0) из лабиринта: wall={cell_from_maze.isWall}\")\n", + "print(f\"Соседи (2,0): {[n.getXY() for n in maze.getNeighbors(cell_from_maze)]}\")\n", + "\n", + "# Проверьте соседей (1,0)\n", + "cell_1_0 = maze.cells[1][0]\n", + "print(f\"Соседи (1,0): {[n.getXY() for n in maze.getNeighbors(cell_1_0)]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "32edf4d1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['S # ###', '## # # E', '# # #', '### ## #', '# #', '########']\n", + "8 6\n" + ] + } + ], + "source": [ + "with open('test_lab.txt') as f:\n", + " data = f.read().splitlines()\n", + " x, y = 0, 0\n", + " width = len(data[0])\n", + " height = len(data)\n", + " print(data)\n", + " print(width, height)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48d20564", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -167,7 +351,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.14.4" + "version": "3.10.6" } }, "nbformat": 4,