# Этап 1. Модель лабиринта

В первом этапе разработки необходимо создать базовые классы `Cell` и `Maze`, которые представляют карту лабиринта. Паттерны на этом этапе не применяются — только чистые классы.

## Класс `Cell`

Клетка — минимальная единица лабиринта. Хранит координаты и тип: стена, старт, выход или пустая.

По условию задания клетка должна иметь флаги `isWall`, `isStart`, `isExit` и метод `isPassable()`. В реализации флаги оформлены как **свойства** (`@property`) с сеттерами — это позволяет автоматически сбрасывать остальные флаги при установке нового типа.

```python
cell = Cell(1, 1)
cell.is_wall = True
```

Типы клетки взаимоисключают друг друга — клетка не может быть одновременно стеной и стартом. Логика сброса вынесена в приватный метод `_clear_flags()`.

### Символьное представление

Для вывода лабиринта в консоль каждая клетка возвращает символ через `__str__`. Символы берутся из `cell_mapping` в `source/settings.py`, что позволяет менять отображение без правки классов:

| Тип    | Символ по умолчанию   |
|--------|-----------------------|
| Стена  | `#`                   |
| Старт  | `S`                   |
| Выход  | `E`                   |
| Пустая |                       |

## Класс `Maze`

Лабиринт хранит двумерный список клеток и предоставляет методы для работы с ними.

По условию задания требовались методы `getCell(x, y)` и `getNeighbors(cell)`. В реализации добавлено несколько вещей сверх задания:

### Именование методов

Задание написано в стиле Java/pseudocode — названия методов и полей используют `camelCase` (`isWall`, `getCell`, `isPassable`). В Python принят другой стандарт именования — **PEP 8**, который предписывает `snake_case` для методов и атрибутов. Поэтому все названия были приведены к Python стилю:

| Задание                   | Реализация                  |
|---------------------------|-----------------------------|
| `isWall`                  | `is_wall`                   |
| `isStart`                 | `is_start`                  |
| `isExit`                  | `is_exit`                   |
| `isPassable()`            | `is_possible()`             |
| `getCell(x, y)`           | `get_cell(x, y)`            |
| `getNeighbors(cell)`      | `get_neighbors(x, y)`       |
| `buildFromFile(filename)` | `build_from_file(filename)` |

Это соответствует стандарту оформления кода на Python и делает API классов идиоматичным для языка.

### Индексация `maze[row, col]`

Вместо явного вызова `get_cell()` реализованы `__getitem__` и `__setitem__`, что позволяет обращаться к клеткам естественным образом:

```python
maze[0, 0] = cell_mapping['wall']   # установить стену
cell = maze[2, 3]                   # получить клетку
```

Обратите внимание: индексация идёт в формате `[row, col]`, то есть сначала строка (Y), потом столбец (X) — аналогично numpy.

### Свойства `start` и `exit`

Добавлены свойства для быстрого получения стартовой и выходной клетки без ручного обхода:

```python
maze.start   # Cell или None
maze.exit    # Cell или None
```

Это оказалось необходимым при реализации алгоритмов поиска пути — стратегии получают `start` и `exit` автоматически из лабиринта.

### Свойство `shape`

По аналогии с numpy добавлено свойство `shape`, возвращающее `(height, width)`:

```python
rows, cols = maze.shape
```

Используется в стратегиях поиска и тестах для итерации по лабиринту.

### `get_neighbors`

Метод возвращает список проходимых соседей клетки по четырём направлениям. Стены и клетки за границей лабиринта исключаются автоматически. Если переданные координаты вне границ — возвращает `None`.

```python
neighbors = maze.get_neighbors(2, 2)  # список Cell
```

Направления обхода: вниз → вправо → вверх → влево (порядок влияет на поведение DFS).
