2026-rff_mp/skorohodovsa/task_2/source/models/base.py
SerKin0 7a84310d5d [2]
- Перемещение models в папку source
- Добавление обращения к Maze как к двумерному списку
2026-05-22 23:11:46 +03:00

202 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from typing import Optional
from source.settings import cell_mapping
class Cell:
"""Класс отвечает за хранение характеристик поля лабиринта"""
def __init__(
self,
x: int,
y: int,
is_wall: bool = False,
is_start: bool = False,
is_exit: bool = False,
):
"""
:param x: Координата поля по оси X
:type x: int
:param y: Координата поля по оси Y
:type y: int
:param is_wall: Является ли поле **стеной**, defaults to False
:type is_wall: bool, optional
:param is_start: Является ли поле **началом**, defaults to False
:type is_start: bool, optional
:param is_exit: Является ли поле **концом**, defaults to False
:type is_exit: bool, optional
"""
self.x = x
self.y = y
self._is_wall = is_wall
self._is_start = is_start
self._is_exit = is_exit
def is_possible(self) -> bool:
"""Проверка возможности перемещения в это поле
:return: Если перемещение возможно, то `True`, иначе `False`
:rtype: bool
"""
return not self.is_wall
@property
def is_wall(self):
return self._is_wall
@property
def is_start(self):
return self._is_start
@property
def is_exit(self):
return self._is_exit
def _clear_flags(self) -> None:
"""Обнуляет все флаги поля"""
self._is_start = False
self._is_exit = False
self._is_wall = False
@is_wall.setter
def is_wall(self, value: bool) -> None:
if value:
self._clear_flags()
self._is_wall = value
@is_start.setter
def is_start(self, value: bool) -> None:
if value:
self._clear_flags()
self._is_start = value
@is_exit.setter
def is_exit(self, value: bool) -> None:
if value:
self._clear_flags()
self._is_exit = value
def _get_type_cell(self) -> str:
if self._is_wall:
type_cell = cell_mapping.get('wall')
elif self._is_start:
type_cell = cell_mapping.get('start')
elif self._is_exit:
type_cell = cell_mapping.get('exit')
else:
type_cell = cell_mapping.get('empty')
return type_cell
def __str__(self) -> str:
return self._get_type_cell()
def __repr__(self):
return f"Cell: (x={self.x}, y={self.y}), '{self._get_type_cell()}'"
class Maze:
def __init__(
self,
size: tuple[int, int] = (10, 10)
):
# Установка размеров лабиринта
self._width = size[0]
self._height = size[1]
# Создание двумерного списка лабиринта
self._map = [
[Cell(x, y) for x in range(self._width)] for y in range(self._height)
]
def _check_point_in_map(self, x: int, y: int) -> bool:
"""Проверка нахождения точки в границах поля
Args:
x (int): Координата точки в оси X
y (int): Координата точки в оси Y
Returns:
bool: True если поля в поле, иначе False
"""
return (0 <= x < self._width) and (0 <= y < self._height)
def get_cell(self, x: int, y: int) -> Optional[Cell]:
"""Получение значения поля по координате в лабиринте
Args:
x (int): Координата точки в оси X
y (int): Координата точки в оси Y
Returns:
Optional[Cell]: Объект поля, при его наличии
"""
if not self._check_point_in_map(x, y):
return None
return self._map[y][x]
def get_neighbors(self, x: int, y: int) -> Optional[list[Cell]]:
"""Получение соседних полей относительно заданного поля
Под соседями поля в лабиринте имеется виду клетки сверху, справа,
снизу и слева относительно её. Если точка находится за границами,
то будет возвращено `None`
Args:
x (int): Координата точки в оси X
y (int): Координата точки в оси Y
Returns:
Optional[list[Cell]]: Список соседних полей
"""
if not self._check_point_in_map(x, y):
return None
list()
vector_x = [0, 1, 0, -1]
vector_y = [1, 0, -1, 0]
neighbors = []
for vec_x, vec_y in zip(vector_x, vector_y):
temp_x, temp_y = x + vec_x, y + vec_y
value = self.get_cell(temp_x, temp_y)
if value is not None and value.is_possible():
neighbors.append(value)
return neighbors
def __getitem__(self, index: tuple[int, int]) -> Cell:
row, col = index
if not self._check_point_in_map(col, row):
raise IndexError(f"Поле с индексом ({row}, {col}) выходит за пределы лабиринта")
return self._map[row][col]
def __setitem__(self, index: tuple[int, int], value: str) -> None:
row, col = index
if not self._check_point_in_map(col, row):
raise IndexError(f"Поле с индексом ({row}, {col}) выходит за пределы лабиринта")
cell = self._map[row][col]
cell_type = None
for type_name, symbol in cell_mapping.items():
if symbol == value:
cell_type = type_name
break
if cell_type is None:
raise ValueError(f"Значение '{value}' не соответствует ни одному типу клетки")
if cell_type == "empty":
cell._clear_flags()
else:
setattr(cell, f"is_{cell_type}", True)
def __str__(self) -> str:
result = ""
for y in range(self._height):
for x in range(self._width):
result += str(self[y, x])
result += '\n'
return result