LLDLLD Case StudiesDesign a Chess Game

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 of Spots.
  • Spot: Represents a single square on the board.
  • Piece: An abstract class for a chess piece, with subclasses for King, Queen, Rook, Knight, Bishop, and Pawn.
  • Move: A class to represent a move from a starting Spot to an ending Spot.

3. Design the System - Class Diagram

GamePlayerBoardSpotMove<<abstract>>PieceKingQueenRookKnightBishopPawn211116410..121

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 Piece subclasses. This is a good example of polymorphism and the "Tell, Don't Ask" principle. The Game class 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 King and Pawn classes and have the Game.makeMove method check for these special cases.
  • Game State Management: How do you track whose turn it is and if the game is over? A GameStatus enum (ACTIVE, WHITE_WINS, BLACK_WINS, STALEMATE) managed by the Game class is a clean way to handle this.
  • Separation of Concerns: The Board class is only responsible for the state of the squares. The Piece classes are only responsible for their movement logic. The Game class is the orchestrator. This clear separation makes the system easier to understand and maintain.