Free preview

Why this matters: snake and ladder's core fits in a hundred lines, so the round's second half is guaranteed to move the problem. Every variation below lands on a seam from lesson 02 — the board's constructor, the die interface, the loop's ignorance of rules — and the grading question is always the same: can you name which seam absorbs the change, and what stays untouched?

Generated boards: the validator becomes the star

The natural next step after "the board is configuration" is "the board is generated" — random snakes and ladders for variety, or difficulty-tuned layouts. The design absorbs this without a new seam: a generator is just another producer of the (size, jumps) config, and the constructor-validator from lesson 02 already stands at the door. But generation raises the validator's stakes. A hand-written board is invalid by mistake; a random generator produces invalid boards by the thousands — jumps touching the end cells, overlapping starts, and now cycles become a live concern rather than a defensive footnote. The senior observation: the generator should generate-and-check in a loop against the same validator the constructor uses — one definition of validity, two callers. Two validity implementations is how a "valid" generated board crashes the resolver.

There's also a playability question hiding here — a board where a snake sits on every high cell is legal but miserable. Worth naming that "valid" and "well-designed" are different predicates, and only the first is the constructor's job.

More dice: a one-line change with distribution consequences

Two dice instead of one looks like the smallest possible variation — and mechanically it is: the Die interface stays, a DicePair implementation sums two rolls, the loop never notices. The interesting part is what you can say about consequences. Rolls now range 2–12 with a triangular distribution peaked at 7 — cells 7 apart become the likeliest hops, minimum movement doubles, and any jump placed within one cell of a player becomes unreachable that turn. Board layouts tuned for one die play differently under two. Interviewers enjoy this variation precisely because the code change is trivial; the credit is entirely in noticing that the game changed even though the program barely did.

Undo and replay: the move log

"Support undo" sounds like it demands memento machinery. The lighter design: the game is deterministic given the sequence of (player, roll) pairs — everything else derives from board and rules. So keep an append-only move log, and implement undo as replay: rebuild from the start, applying all but the last move. For a game whose state is six integers, replaying is instant, and the log doubles as replay-for-free — a saved game, a dispute resolver, a debugging record. The pattern rhymes across this course: mutable state for operation, an append-only record for truth. If replay cost ever mattered, snapshots every N moves bound it — but say that as the known upgrade, not the v1.

The seam that makes this cheap: the loop already funnels every move through one method, so logging is one line in one place.

Bots: the player boundary pays off

v1 players make no decisions — you roll, you move — so a "bot player" seems meaningless. But the moment any choice enters the game (which of two tokens to move, whether to use a variant rule), the question becomes: where do decisions live? The answer worth stating now: behind a player interface — chooseMove(options) -> Move — with humans and bots as implementations, so the game loop asks a player and never knows which kind answered. Designing the boundary when it's trivial is what makes the bot a new class later instead of a rewrite. This is the same dependency-direction discipline the die interface bought you, applied one level up.

Rigged dice: the test story as a design proof

The die interface was justified in lesson 02 by testability; here's the cash-out. A scripted die — new ScriptedDie(3, 5, 6) — lets a test drive the game to any situation: land exactly on a snake, ride a chain of three jumps, sit on 98 and roll past the end, win on an exact roll. Each hard-won rule from lesson 01 becomes a five-line deterministic test. The variation-proofing insight: rigged dice also test the variations — two-dice distributions, bounce-on-overshoot — without touching the loop. When an interviewer asks "how would you test this?", walking through the scripted die is the strongest possible answer, because it demonstrates that the seams you claimed actually exist.

Key takeaway

Every variation lands on an existing seam: generated boards reuse the one constructor-validator (one definition of validity, two callers), more dice swap a Die implementation while quietly reshaping the roll distribution, undo falls out of an append-only move log replayed against a deterministic game, bots are a player-interface question answered before it's needed, and rigged dice prove the seams by driving every rule to a deterministic test. The grade is in naming the seam — and what provably doesn't change.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue