# Модель лабиринта: клетки, карта и загрузка из файла (Builder pattern)

class Cell:
    
    def __init__(self, x, y):
        self._x = x
        self._y = y
        self._is_wall = False
        self._is_start = False
        self._is_exit = False
    
    @property
    def x(self):
        return self._x
    
    @property
    def y(self):
        return self._y
    
    @property
    def is_wall(self):
        return self._is_wall
    
    @is_wall.setter
    def is_wall(self, value):
        self._is_wall = value
    
    @property
    def is_start(self):
        return self._is_start
    
    @is_start.setter
    def is_start(self, value):
        self._is_start = value
    
    @property
    def is_exit(self):
        return self._is_exit
    
    @is_exit.setter
    def is_exit(self, value):
        self._is_exit = value
    
    def is_passable(self):
        return not self._is_wall


class Maze:
    
    def __init__(self, width, height):
        self._width = width
        self._height = height
        self._cells = [[Cell(x, y) for x in range(width)] for y in range(height)]
        self._start = None
        self._exit = None
    
    @property
    def width(self):
        return self._width
    
    @property
    def height(self):
        return self._height
    
    @property
    def start(self):
        return self._start
    
    @property
    def exit(self):
        return self._exit
    
    def get_cell(self, x, y):
        if 0 <= x < self._width and 0 <= y < self._height:
            return self._cells[y][x]
        return None
    
    def set_cell(self, x, y, cell_type):
        cell = self.get_cell(x, y)
        if cell is None:
            return
        
        if cell_type == 'wall':
            cell.is_wall = True
        elif cell_type == 'start':
            if self._start:
                self._start.is_start = False
            cell.is_start = True
            cell.is_wall = False
            self._start = cell
        elif cell_type == 'exit':
            if self._exit:
                self._exit.is_exit = False
            cell.is_exit = True
            cell.is_wall = False
            self._exit = cell
        elif cell_type == 'path':
            cell.is_wall = False
    
    def get_neighbors(self, cell):
        neighbors = []
        directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]  # up, down, left, right
        for dx, dy in directions:
            nx, ny = cell.x + dx, cell.y + dy
            neighbor = self.get_cell(nx, ny)
            if neighbor and neighbor.is_passable():
                neighbors.append(neighbor)
        return neighbors


class MazeBuilder:
    
    def build_from_file(self, filename):
        raise NotImplementedError("Must be implemented in subclass")


class TextFileMazeBuilder(MazeBuilder):
    
    def build_from_file(self, filename):
        with open(filename, 'r') as f:
            lines = [line.rstrip('\n') for line in f.readlines()]
        
        height = len(lines)
        width = max(len(line) for line in lines) if height > 0 else 0
        
        start_count = 0
        exit_count = 0
        maze = Maze(width, height)
        
        for y, line in enumerate(lines):
            for x, ch in enumerate(line):
                if ch == "#":
                    maze.set_cell(x, y, "wall")
                elif ch == "S":
                    maze.set_cell(x, y, "start")
                    start_count += 1
                elif ch == "E":
                    maze.set_cell(x, y, "exit")
                    exit_count += 1
                elif ch == " ":
                    maze.set_cell(x, y, "path")
        
        if start_count != 1 or exit_count != 1:
            raise ValueError(f"Лабиринт должен иметь ровно один вход S и один выход E. Найдено: S={start_count}, E={exit_count}")
        
        return maze