Chess Game
Chess is the interview prompt people fear because "the rules" feel enormous. The trick is that a design-level answer doesn't implement every rule - it builds a shape where each piece answers one question (can I legally move there?) and the board never has to know the answer itself.
Requirements
Functional
- An 8x8 board holds pieces for two players (White and Black), each piece knowing its own movement rule (pawn, rook, knight, bishop, queen, king).
- A move is only applied if the piece's movement rule allows it and the destination isn't occupied by the mover's own piece.
- After every move, the game can answer "is either king currently in check?" and, from there, "is that check a checkmate?"
- Turns alternate strictly between the two players.
Non-functional
- Adding a new piece type (a custom variant piece, say) should mean one new class, not a
change to
BoardorGame. - Check detection must reuse the same movement logic pieces already have for ordinary moves
- a second, parallel "can this piece threaten this square" implementation would drift from the first the moment either one is patched.
Design
Every concrete piece extends an abstract Piece and implements one method, canMove(board, from, to). That single seam is doing two jobs at once: it's how a normal move gets validated,
and it's how check gets detected - "is the king in check" is just "does any opposing piece's
canMove say yes to the king's square," with no separate checking algorithm to keep in sync.
- 1A player proposes a move; the game is the only entry point.
- 2The game looks up whichever piece is sitting on the source square.
- 3The piece itself, not the board or game, decides whether that path is legal for its type.
- 4If legal, the move is applied and recorded so it can be undone if it turns out to self-check.
- 5Check detection asks every opposing piece the same canMove question, aimed at the king's square.
Game never asks "what kind of piece is this" anywhere in its own code. It asks the piece.
Class diagram
Code
Design decisions
Pieceis an abstract class with one abstract method, not aPieceTypeenum and a switch inBoard. A switch statement over piece type grows a new case every time someone adds a variant piece, and it lives far from the rule it's implementing. Polymorphism puts a rook's rule insideRook, where anyone reading that one file sees the whole rule.- Check detection is not a separate algorithm - it reuses
canMove. "Is the king in check" is answered by asking every opposing piece "can you legally move to the king's square right now," the exact questionGame.makeMovealready asks before any ordinary move. One rule, two callers, instead of two rules that can silently diverge. Moveis its own object rather than two loose coordinates. Once check/checkmate logic needs to try a move, see if it leaves the mover's own king in check, and undo it if so, having aMoveobject (with the captured piece, if any) makes "undo" a single operation instead of reconstructing state by hand.- What's missing for a real system: this design validates raw piece movement and basic check/checkmate but stops short of pins (a move that's otherwise legal but would expose your own king), en passant, castling, draw conditions like threefold repetition, and even a couple of ordinary pawn rules - the two-square opening advance and promotion on reaching the back rank - each is a real rule, but naming them as future extension points is the point of a 45-minute design answer, not implementing all of them.