from dataclasses import dataclass from typing import List, Optional @dataclass(frozen=True) class Cell: x: int y: int isWall: bool = False isStart: bool = False isExit: bool = False weight: int = 1 def isPassable(self) -> bool: return not self.isWall class Maze: def __init__(self, grid: List[List[Cell]]): self.grid = grid self.height = len(grid) self.width = len(grid[0]) if self.height else 0 self.start: Optional[Cell] = None self.exit: Optional[Cell] = None for row in grid: for cell in row: if cell.isStart: self.start = cell if cell.isExit: self.exit = cell def getCell(self, x: int, y: int) -> Optional[Cell]: if 0 <= y < self.height and 0 <= x < self.width: return self.grid[y][x] return None def getNeighbors(self, cell: Cell) -> List[Cell]: result = [] for dx, dy in [(0, -1), (0, 1), (-1, 0), (1, 0)]: nxt = self.getCell(cell.x + dx, cell.y + dy) if nxt is not None and nxt.isPassable(): result.append(nxt) return result def render(self, path=None, player_position=None) -> str: path_set = {(c.x, c.y) for c in path} if path else set() player_xy = (player_position.x, player_position.y) if player_position else None lines = [] for y in range(self.height): row = [] for x in range(self.width): c = self.grid[y][x] if player_xy == (x, y): row.append("P") elif c.isStart: row.append("S") elif c.isExit: row.append("E") elif (x, y) in path_set: row.append(".") elif c.isWall: row.append("#") else: row.append(" ") lines.append("".join(row)) return "\n".join(lines)