Katkat

Model a Turn-Based Cats and Rabbits Board Game

AsanaSoftware Engineer · Onsite

Last updated

Design the object model, game state invariants, and move-validation engine for an asymmetric turn-based grid game played on a 7x7 board.

Scenario

Design an object-oriented model and validation engine for a turn-based board game called Cats and Rabbits, played on a 7 x 7 grid. Two players take alternating turns:

  • Rabbit Player (RABBIT): Controls 6 rabbits starting at row 6 (indices (6, 1) through (6, 6)). Rabbits move first.
  • Cat Player (CAT): Controls 2 cats starting at row 0 (indices (0, 2) and (0, 4)).

Game Rules

  1. Rabbit Movement:
    • A rabbit moves exactly 1 cell orthogonally (up, down, left, or right) into an unoccupied cell.
    • Rabbits cannot capture or jump over pieces.
  2. Cat Movement:
    • Walk: A cat moves 1 cell orthogonally into an unoccupied cell.
    • Capture Hop: If a rabbit is directly adjacent orthogonally and the cell immediately past the rabbit in the same direction is empty, the cat can jump over the rabbit onto that empty cell. The jumped rabbit is permanently removed from the board. Only one hop is allowed per turn.
  3. Win Conditions:
    • RABBIT wins if any rabbit reaches row 0, or if the Cats have no valid moves on their turn.
    • CAT wins if fewer than 2 rabbits remain, or if Rabbits have no valid moves on their turn.

Interface

Implement a class representing the game session:

class PieceType(Enum):
    RABBIT = "RABBIT"
    CAT = "CAT"

class Position:
    row: int
    col: int

class GameStatus(Enum):
    IN_PROGRESS = "IN_PROGRESS"
    RABBIT_WON = "RABBIT_WON"
    CAT_WON = "CAT_WON"

class CatsAndRabbitsGame:
    def __init__(self):
        """Initializes a 7x7 board with starting pieces and sets RABBIT as the starting player."""
        pass

    def get_valid_moves(self, player: PieceType) -> list[tuple[Position, Position]]:
        """Returns all valid (from_pos, to_pos) moves for the given player in the current state."""
        pass

    def make_move(self, from_pos: Position, to_pos: Position) -> GameStatus:
        """Validates and executes the move for the current active player.
        Raises ValueError if the move is invalid or not the player's turn.
        Updates game status and toggles the active player.
        """
        pass

Constraints

  • Board coordinates are 0 <= row < 7 and 0 <= col < 7.
  • Pieces cannot move outside the board.
  • Moves must be executed in O(1) time relative to board size; get_valid_moves should run in O(P) where P is the number of active pieces.

Hints

Hint 1

Separate piece representation and coordinate logic from game-state validation to keep classes decoupled and testable.

Hint 2

For cat captures, calculate the midpoint between start and destination coordinates to verify the jumped piece is an opponent.

Hint 3

Evaluate terminal win conditions immediately after applying piece movement and removal, but before switching the active player.

Follow-up questions

  • How would you refactor your design to support multi-hop captures for cats in a single turn without duplicating validation logic?
  • How would you implement an undo/redo feature without serializing the full board state on every move?
  • If this game were served over an HTTP or WebSocket API to two remote players, where would validation run and how would you prevent race conditions?