forked from UNN/2026-rff_mp
93 lines
3.1 KiB
Python
93 lines
3.1 KiB
Python
|
|
"""
|
||
|
|
maze_solver/model.py - модель лабиринта (этап 1, без паттернов).
|
||
|
|
"""
|
||
|
|
|
||
|
|
class Cell:
|
||
|
|
"""Клетка лабиринта.
|
||
|
|
|
||
|
|
Атрибуты:
|
||
|
|
x, y - координаты
|
||
|
|
is_wall - стена ли
|
||
|
|
is_start - стартовая клетка
|
||
|
|
is_exit - клетка выхода
|
||
|
|
weight - стоимость прохода (по умолчанию 1, для взвешенного режима >1)
|
||
|
|
"""
|
||
|
|
__slots__ = ("x", "y", "is_wall", "is_start", "is_exit", "weight")
|
||
|
|
|
||
|
|
def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False, weight=1):
|
||
|
|
self.x = x
|
||
|
|
self.y = y
|
||
|
|
self.is_wall = is_wall
|
||
|
|
self.is_start = is_start
|
||
|
|
self.is_exit = is_exit
|
||
|
|
self.weight = weight
|
||
|
|
|
||
|
|
def is_passable(self):
|
||
|
|
return not self.is_wall
|
||
|
|
|
||
|
|
def __repr__(self):
|
||
|
|
return f"Cell({self.x},{self.y},wall={self.is_wall})"
|
||
|
|
|
||
|
|
|
||
|
|
class Maze:
|
||
|
|
"""Лабиринт как двумерный массив клеток.
|
||
|
|
|
||
|
|
Атрибуты:
|
||
|
|
width, height - размеры
|
||
|
|
grid - список списков клеток [y][x]
|
||
|
|
start, exit_ - ссылки на клетки старта и выхода (могут быть None при ошибке)
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self, width, height):
|
||
|
|
self.width = width
|
||
|
|
self.height = height
|
||
|
|
self.grid = [[Cell(x, y, is_wall=True) for x in range(width)]
|
||
|
|
for y in range(height)]
|
||
|
|
self.start = None
|
||
|
|
self.exit_ = None
|
||
|
|
|
||
|
|
def get_cell(self, x, y):
|
||
|
|
if 0 <= x < self.width and 0 <= y < self.height:
|
||
|
|
return self.grid[y][x]
|
||
|
|
return None
|
||
|
|
|
||
|
|
def get_neighbors(self, cell):
|
||
|
|
"""Соседи (вверх, вниз, влево, вправо), только проходимые и в пределах поля."""
|
||
|
|
out = []
|
||
|
|
for dx, dy in ((0, -1), (0, 1), (-1, 0), (1, 0)):
|
||
|
|
nb = self.get_cell(cell.x + dx, cell.y + dy)
|
||
|
|
if nb is not None and nb.is_passable():
|
||
|
|
out.append(nb)
|
||
|
|
return out
|
||
|
|
|
||
|
|
def render_text(self, path=None, player=None):
|
||
|
|
"""Возвращает текстовое представление лабиринта.
|
||
|
|
|
||
|
|
'#' стена, ' ' проход, 'S' старт, 'E' выход,
|
||
|
|
'.' клетка пути, '@' игрок.
|
||
|
|
"""
|
||
|
|
path_set = set()
|
||
|
|
if path:
|
||
|
|
for c in path:
|
||
|
|
path_set.add((c.x, c.y))
|
||
|
|
|
||
|
|
lines = []
|
||
|
|
for y in range(self.height):
|
||
|
|
row = []
|
||
|
|
for x in range(self.width):
|
||
|
|
cell = self.grid[y][x]
|
||
|
|
ch = ' '
|
||
|
|
if cell.is_wall:
|
||
|
|
ch = '#'
|
||
|
|
elif cell.is_start:
|
||
|
|
ch = 'S'
|
||
|
|
elif cell.is_exit:
|
||
|
|
ch = 'E'
|
||
|
|
elif (x, y) in path_set:
|
||
|
|
ch = '.'
|
||
|
|
if player is not None and player.x == x and player.y == y:
|
||
|
|
ch = '@'
|
||
|
|
row.append(ch)
|
||
|
|
lines.append("".join(row))
|
||
|
|
return "\n".join(lines)
|