from enum import IntEnum, auto type Coordinate = tuple[int, int] class PieceType(IntEnum): T_JUNCTION = auto() # Direction is the piece at the "stem" of the T STRAIGHT = auto() CORNER = auto() # Direction is the more counter-clockwise connection NODE = auto() class Direction(IntEnum): UP = 0 RIGHT = auto() DOWN = auto() LEFT = auto() @staticmethod def from_offset(dx: int, dy: int) -> Direction: if (dx != 0 and dy != 0) or abs(dx + dy) != 1: raise ValueError(f"({dx}, {dy}) is not a valid direction offset") if dx != 0: return Direction(dx % 4) else: return Direction(dy + 1) def flip(self) -> Direction: return Direction((self + 2) % 4) class Piece: type: PieceType direction: Direction locked: bool = False def __init__(self, type: PieceType, direction: Direction = Direction.UP) -> None: self.type = type self.direction = direction def connected_directions(self) -> list[Direction]: match self.type: case PieceType.NODE: return [self.direction] case PieceType.CORNER: return [self.direction, Direction((self.direction + 1) % 4)] case PieceType.STRAIGHT: return [self.direction, Direction((self.direction + 2) % 4)] case PieceType.T_JUNCTION: return [ self.direction, Direction((self.direction + 1) % 4), Direction((self.direction - 1) % 4), ] def turn_cw(self) -> None: if self.locked: return self.direction = Direction((self.direction + 1) % 4) def turn_ccw(self) -> None: if self.locked: return self.direction = Direction((self.direction - 1) % 4)