Case Studies

Snake and Ladder

Design the classic board game with multiple players, dice, snakes, and ladders.

3 min readDesigns · LLD & Patterns

Interview practice: try designing this yourself before reading. Go to the exercise ↓

Problem Statement

Design a Snake and Ladder game where:

  • N players take turns
  • Each turn rolls a die and moves forward
  • Landing on a snake's head moves down to its tail
  • Landing on a ladder's bottom moves up to its top
  • First player to reach 100 (or last cell) wins

Requirements

Functional

  • Configurable board size (default 100 cells)
  • Configurable snakes and ladders
  • N players (≥ 2)
  • Roll a 6-sided die
  • Validate moves (can't go past last cell)
  • Detect winner

Non-Functional

  • Deterministic given a seed (for testing/replay)
  • Extensible: support multiple dice, custom rules

Class Diagram


Core Classes

public class Player {
    private final String name;
    private int position = 0;

    public Player(String name) { this.name = name; }

    public int getPosition() { return position; }
    public void setPosition(int p) { this.position = p; }
    public String getName() { return name; }
}

public class Snake {
    public final int head, tail;
    public Snake(int head, int tail) {
        if (head <= tail) throw new IllegalArgumentException("head must be > tail");
        this.head = head; this.tail = tail;
    }
}

public class Ladder {
    public final int bottom, top;
    public Ladder(int bottom, int top) {
        if (bottom >= top) throw new IllegalArgumentException("top must be > bottom");
        this.bottom = bottom; this.top = top;
    }
}

Board

public class Board {
    private final int size;
    private final Map<Integer, Integer> jumps = new HashMap<>();   // snake heads + ladder bottoms

    public Board(int size, List<Snake> snakes, List<Ladder> ladders) {
        this.size = size;
        for (Snake s : snakes) {
            if (jumps.containsKey(s.head))
                throw new IllegalArgumentException("Cell " + s.head + " has multiple jumps");
            jumps.put(s.head, s.tail);
        }
        for (Ladder l : ladders) {
            if (jumps.containsKey(l.bottom))
                throw new IllegalArgumentException("Cell " + l.bottom + " has multiple jumps");
            jumps.put(l.bottom, l.top);
        }
    }

    public int getSize() { return size; }

    /** Returns the new position after applying snakes/ladders. */
    public int nextPosition(int current, int roll) {
        int target = current + roll;
        if (target > size) return current;   // can't go past, stay put
        return jumps.getOrDefault(target, target);
    }
}

A single map for snakes & ladders simplifies lookup. We validate that no cell has both.


Dice (Strategy Pattern)

public interface Dice {
    int roll();
}

public class StandardDice implements Dice {
    private final Random rng;
    private final int sides;
    private final int count;

    public StandardDice(int sides, int count, Random rng) {
        this.sides = sides; this.count = count; this.rng = rng;
    }

    @Override
    public int roll() {
        int total = 0;
        for (int i = 0; i < count; i++) total += rng.nextInt(sides) + 1;
        return total;
    }
}

Inject a seeded Random for tests.


Game (Round-Robin Loop)

public class Game {
    private final Board board;
    private final Dice dice;
    private final Deque<Player> players;
    private Player winner;

    public Game(Board board, Dice dice, List<Player> players) {
        if (players.size() < 2) throw new IllegalArgumentException("Need ≥2 players");
        this.board = board;
        this.dice = dice;
        this.players = new ArrayDeque<>(players);
    }

    public Player play() {
        while (winner == null) {
            playTurn();
        }
        return winner;
    }

    private void playTurn() {
        Player p = players.pollFirst();
        int roll = dice.roll();
        int newPos = board.nextPosition(p.getPosition(), roll);
        p.setPosition(newPos);

        log(p, roll, newPos);

        if (newPos == board.getSize()) {
            winner = p;
        } else {
            players.offerLast(p);   // back of queue
        }
    }

    private void log(Player p, int roll, int pos) {
        System.out.printf("%s rolled %d -> %d%n", p.getName(), roll, pos);
    }
}

A Deque rotates players naturally: poll front, push back unless they win.


Sequence


Variants & Extensibility

VariantHow to add
Multiple dice (sum)Already supported via count in StandardDice
Roll again on 6Override playTurn — don't push back if roll == 6
Must land exactly on 100Already enforced (target > size returns current)
Snake bites you back to 1Strategy on landing — chain of LandingEffect objects
2D variants (Chutes & Ladders)Same logic; visualization changes

Edge Cases

CaseHandling
Roll exceeds last cellPlayer stays put (must roll exact)
Cell has both snake & ladderForbidden by Board constructor validation
Player on snake tail / ladder top initiallyDisallowed at config time
Single player gameThrow at construction (players.size() < 2)
All players stuck (rare)Add iteration cap, declare draw or rotate

Design Patterns Used

PatternWhere
StrategyDice (standard, weighted, multi-dice)
BuilderBoard configuration with snakes/ladders lists
ObserverGame broadcasts moves to UI listeners
Template methodGame.play() skeleton, subclass overrides for variants

Interview Tips

  • Clarify rules: roll-again-on-6? Exact landing? Multiple dice?
  • The state is small — board + queue of players + dice. Don't over-design.
  • Validate snake/ladder configurations at construction (no overlap, valid directions).
  • Mention testability: inject a seeded RNG and you can replay any game.

Practice

Try it yourself

Design the classes for a snake and ladder game with several players.

Your design should cover

  • Board with configurable snakes and ladders
  • Players take turns rolling dice and moving
  • Win when exactly reaching the last square (or a configurable rule)
  • Support one or more dice and custom dice
  • Easy to add new rules or special squares
0 / 8,000 characters · saved in this browser

Finished reading?

Mark it done to track your progress in Designs.