Design a Chess Game
LLD Case Studies
The Chess Game Problem
Designing a chess game is a fantastic LLD problem because it involves clear rules, a defined state, and a variety of interacting pieces. The interviewer is looking for your ability to model the game's components and enforce its rules in an object-oriented way.
1. Clarify Requirements
- What is the scope? A two-player chess game on a standard 8x8 board.
- How do players interact? Players take turns making moves.
- What are the rules? The system must enforce all the standard rules of chess, including how each piece moves, castling, and check/checkmate conditions.
- Is there a UI? We are designing the backend logic. The UI is a separate concern.
- What happens when the game is over? The system should declare a winner (or a draw) and prevent further moves.
2. Identify the Core Classes and Objects
Game: The main class that manages the board, players, and game state.Player: Represents a player in the game.Board: Represents the 8x8 chessboard and contains a collection ofSpots.Spot: Represents a single square on the board.Piece: An abstract class for a chess piece, with subclasses forKing,Queen,Rook,Knight,Bishop, andPawn.Move: A class to represent a move from a startingSpotto an endingSpot.
3. Design the System - Class Diagram
4. Key Design Decisions & Implementation Details
The Piece Hierarchy:
This is the core of the design. An abstract Piece class is perfect for defining common attributes (color, isKilled) and an abstract method that all pieces must implement.
public abstract class Piece {
private final boolean isWhite;
private boolean isKilled;
public Piece(boolean isWhite) {
this.isWhite = isWhite;
}
// This is the key method for each piece.
public abstract boolean canMove(Board board, Spot start, Spot end);
// ... getters and setters
}
public class King extends Piece {
public King(boolean isWhite) {
super(isWhite);
}
@Override
public boolean canMove(Board board, Spot start, Spot end) {
// 1. Check if the end spot is the same color.
if (end.getPiece() != null && end.getPiece().isWhite() == this.isWhite()) {
return false;
}
// 2. Check if the move is a valid king move (one square in any direction).
int x = Math.abs(start.getX() - end.getX());
int y = Math.abs(start.getY() - end.getY());
return x <= 1 && y <= 1;
}
}
The Game Class:
The Game class orchestrates the entire flow, processing moves and updating the state.
public class Game {
private Board board;
private Player[] players;
private Player currentPlayer;
private GameStatus status;
public Game() {
// Initialize board, players, etc.
}
public boolean makeMove(Move move, Player player) {
if (player != currentPlayer) {
return false; // Not this player's turn.
}
Piece sourcePiece = move.getStart().getPiece();
if (sourcePiece == null) {
return false; // No piece to move.
}
// The core logic: ask the piece if the move is valid.
if (!sourcePiece.canMove(board, move.getStart(), move.getEnd())) {
return false;
}
// 1. Move the piece.
// 2. Check for check/checkmate.
// 3. Update game status.
// 4. Switch to the next player.
return true;
}
}
Key Discussion Points
- Enforcing Rules: Where should the rules logic live? The chosen design places the responsibility on the
Piecesubclasses. This is a good example of polymorphism and the "Tell, Don't Ask" principle. TheGameclass doesn't need to know the rules for every piece; it just "tells" the piece to validate its own move. - Handling Special Moves: How would you handle castling or en passant? These are complex moves that involve multiple pieces or specific game states. You could add special methods to the
KingandPawnclasses and have theGame.makeMovemethod check for these special cases. - Game State Management: How do you track whose turn it is and if the game is over? A
GameStatusenum (ACTIVE,WHITE_WINS,BLACK_WINS,STALEMATE) managed by theGameclass is a clean way to handle this. - Separation of Concerns: The
Boardclass is only responsible for the state of the squares. ThePiececlasses are only responsible for their movement logic. TheGameclass is the orchestrator. This clear separation makes the system easier to understand and maintain.