[1] Лабораторная работа №1 "Структуры данных" #198

Merged
kit8nino merged 18 commits from stepushovgs/2026-rff_mp:stepushovgs into develop 2026-05-30 11:41:24 +00:00
8 changed files with 315 additions and 106 deletions
Showing only changes of commit 5fce1bb8a6 - Show all commits

View File

@ -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()

View File

@ -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
)

View File

@ -17,7 +17,8 @@ class Cell:
"""
Создание клетки лабиринта
`x, y` - координаты клетки в лабиринте
`x` - столбец клетки в лабиринте
`y` - строка клетки в лабиринте
`isWall` - Является ли клетка стеной

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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
))

View File

@ -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,