Snake and Ladder is a classic turn-based board game played by two or more players on a grid, typically numbered from 1 to 100. Each player starts at cell 1 and takes turns rolling a dice to determine how many steps to move forward.
The game includes:
The first player to land exactly on the final cell (e.g., cell 100) is declared the winner.
In this chapter, we will explore the low-level design of a snake and ladder game in detail.
Lets start by clarifying the requirements:
Before starting the design, it's important to ask thoughtful questions to uncover hidden assumptions and better define the scope of the system.
Here is an example of how a conversation between the candidate and the interviewer might unfold:
Candidate: Should the game support a standard 10x10 board with 100 cells, or should the board size be configurable?
Interviewer: For this version, let’s stick with the standard 10x10 board.
Candidate: Should the number and positions of snakes and ladders be fixed, or should they be configurable?
Interviewer: They should be configurable. The board should allow us to define the number and positions of snakes and ladders at initialization.
Candidate: How many players should the game support? Should it be limited to two, or should we support multiple players?
Interviewer: The game should support multiple players—at least two, but potentially more. Player turns should rotate in order.
Candidate: How should dice rolls be handled? Should we simulate a dice roll in the code or take it as input?
Interviewer: Let’s simulate dice rolls using random number generation from 1 to 6. No need for user input for the roll itself.
Candidate: What should happen if a player rolls a 6? Should they get another turn?
Interviewer: Yes, if a player rolls a 6, they get an extra turn immediately.
Candidate: Should a player roll exact number to land on cell 100, or can they overshoot and still win?
Interviewer: A player must land exactly on 100 to win. If the roll takes them beyond 100, their turn is skipped.
Candidate: Can multiple players occupy the same square at the same time?
Interviewer: Yes, more than one player can land on the same square. There's no interaction or conflict when this happens—no "bumping" or penalties.
After gathering the details, we can summarize the key system requirements.
After the requirements are clear, lets identify the core entities/objects we will have in our system.
Core entities are the fundamental building blocks of our system. We derive them by analyzing the functional requirements and extracting key nouns and responsibilities that naturally map to object-oriented abstractions such as classes, enums, or interfaces.
Let’s go through the functional requirements and identify the relevant entities:
This clearly suggests the need for a Board entity that maintains the overall structure and layout of the game. The board should internally manage the mapping of special cells (snakes and ladders) and allow querying for cell transitions.
This indicates two distinct entities: Snake and Ladder, each with a start and end position. These entities define how a player's position changes if they land on a particular cell.
This calls for a Player entity to encapsulate information like the player’s name, ID, and current position on the board.
We need a Dice entity to simulate random rolls between 1 and 6. The dice logic can also handle special behavior like giving an extra turn for a 6.
This behavior should be managed by a Game entity that acts as the central controller. It will handle player turns, dice rolls, player movement, snake/ladder transitions, win condition checks, and game state updates.
Board: Represents the 10x10 grid and manages snakes, ladders, and board navigation.Snake: Represents a snake with a head (start) and tail (end). If a player lands on the head, they are sent back to the tail.Ladder: Represents a ladder with a base (start) and top (end). If a player lands at the base, they move up to the top.Player: Represents a participant in the game, maintaining their current position and identifier (e.g., name or ID).Dice: Simulates dice rolls with random values between 1 and 6. Can include logic for handling an extra turn on rolling a 6.Game: Acts as the central controller. Manages game state, player turns, board movement, snake/ladder activation, and win condition.These core entities define the key abstractions of the game and will guide the structure of our low-level design and class diagrams.
GameStatusRepresents the lifecycle state of the game.

NOT_STARTED: The initial state before the game loop begins.RUNNING: The state when players are actively taking turns.FINISHED: The terminal state after a winner has been determined.PlayerEncapsulates all relevant information about a player

name: String: Name or identifier of the player.position: int: The current position of the player on the board (typically from 1 to 100).SnakeA specific type of BoardEntity that represents a snake. It holds a start and end position.
LadderA specific type of BoardEntity that represents a ladder. It holds a start and end position.
DiceA utility class responsible for simulating a dice roll.

BoardRepresents the game board's logic.

BoardEntityCan be introduced to generalize Snake and Ladder
GameThe central engine that orchestrates the entire game.

The relationships between classes define the overall architecture and how different components collaborate.
This relationship implies that an object is an integral part of another.
This relationship implies that an object contains other objects, but the contained objects can exist independently.
This is a more general relationship where one class uses another.
This relationship defines a hierarchy between classes.
The Game class acts as the central entry point. It serves as a Facade, providing a simplified interface (createGame, playGame) that hides the complex interactions between the game, board, players, and dice.
This is the most prominent design pattern used in the system. The Game class uses a nested static Builder class (Game.Builder) to construct Game objects.
The BoardEntity abstract class and its subclasses (Snake, Ladder) implicitly follow the structure of this pattern. The base class constructor handles the common logic of storing start and end positions, while the subclasses' constructors are responsible for the specific validation logic (e.g., start > end for Snake), effectively "filling in" a step of the creation template.
Defines the different states of the game:
NOT_STARTED: The game is initialized but not yet started.RUNNING: The game is actively being played.FINISHED: A player has won the game.Encapsulates the behavior of a dice roll. The dice can be customized with a configurable minimum and maximum value (e.g., 1–6). The roll() method simulates a random roll.
Represents a player in the game. Each player has a name and a position on the board, starting from 0. The position is updated after every move.
BoardEntity (Abstract Base Class)Represents either a Snake or a Ladder. Each entity has a start and end position, and both subclasses (Snake and Ladder) impose validation on these.
SnakeRepresents a snake on the board. The head of the snake (start) must be positioned after the tail (end), enforcing a downward movement.
LadderRepresents a ladder on the board. The bottom (start) must be before the top (end), enforcing an upward jump.
Represents the game board.
size: Number of squares (typically 100).snakesAndLadders: Maps positions that trigger snakes or ladders to their destination square.getFinalPosition(): Returns the adjusted position after hitting a snake or ladder, if applicable.The main controller class that manages the gameplay loop, player turns, game rules, and winning condition.
play() MethodControls the game loop:
takeTurn() MethodHandles the actual gameplay mechanics for each player's move:
Builder Inner ClassImplements the Builder pattern to construct a game instance in a flexible and readable way. Each component (board, players, dice) must be set before calling build().
Demonstrates how to use the Game class to create and play a full game:
Builder API.