Back to LLD explorer
OOD / Game• Patterns: Factory Method, Command, Strategy

Chess

Hard

Problem Summary

Design a full-featured Chess game engine supporting standard 8x8 rules, piece movement strategies (Knight jump, Pawn en passant, Castling), check/checkmate detection, and command-based move history with undo/redo.

Functional Scope

  • Standard 8x8 board with 16 White and 16 Black pieces.
  • Polymorphic movement validation per piece type (Pawn, Rook, Knight, Bishop, Queen, King).
  • Special rules: Castling, En Passant, Pawn Promotion.
  • Check, Checkmate, and Stalemate evaluation.
  • Command Pattern for move logging, replay, and undo/redo functionality.

Entity-Relationship (ER) Schema

ChessGame [1] --> [1] Board
Board [1] --> [64] Square
Square [1] --> [0..1] Piece
ChessGame [1] --> [*] MoveCommand
Piece <|-- Pawn
Piece <|-- King
Piece <|-- Knight

Design Approach

Apply the Command pattern to encapsulate player moves into reversible objects, making undo, move history recording, and network replay trivial.

Core Classes & Models

ChessGame (Main orchestrator maintaining turn rotations and command stack)Board (8x8 grid of Squares and piece location indexing)Square (Row, col, occupying piece)Piece (Abstract class with PieceColor and getValidMoves)Pawn, Rook, Knight, Bishop, Queen, King (Concrete pieces)MoveCommand (Command storing fromSquare, toSquare, capturedPiece, execute/undo)
Code Blueprint
75 lines
/**
 * Low-Level Design: Chess Game Engine
 * Design Patterns Applied:
 *  - Factory Method Pattern: Concrete chess piece creation (Pawn, Knight, Bishop, Rook, Queen, King)
 *  - Command Pattern: Move execution, undo, redo, and algebraic notation history
 *  - Strategy Pattern: Move validation per piece type
 */

import java.util.*;

enum Color { WHITE, BLACK }

abstract class Piece {
    protected final Color color;
    public Piece(Color color) { this.color = color; }
    public Color getColor() { return color; }
    public abstract boolean canMove(int fromR, int fromC, int toR, int toC);
}

class Knight extends Piece {
    public Knight(Color color) { super(color); }
    @Override
    public boolean canMove(int fromR, int fromC, int toR, int toC) {
        int dr = Math.abs(fromR - toR);
        int dc = Math.abs(fromC - toC);
        return (dr == 1 && dc == 2) || (dr == 2 && dc == 1);
    }
}

// --- [DESIGN PATTERN: Factory Method] Piece factory ---
class PieceFactory {
    public static Piece createKnight(Color color) { return new Knight(color); }
}

// --- [DESIGN PATTERN: Command] Move command ---
interface MoveCommand {
    boolean execute();
    void undo();
}

class ChessMove implements MoveCommand {
    private final Piece piece;
    private final int fromR, fromC, toR, toC;

    public ChessMove(Piece piece, int fromR, int fromC, int toR, int toC) {
        this.piece = piece;
        this.fromR = fromR; this.fromC = fromC; this.toR = toR; this.toC = toC;
    }

    @Override
    public boolean execute() {
        if (!piece.canMove(fromR, fromC, toR, toC)) {
            System.out.println("❌ Illegal move for " + piece.getClass().getSimpleName());
            return false;
        }
        System.out.printf("♟️ Move executed: (%d,%d) -> (%d,%d)%n", fromR, fromC, toR, toC);
        return true;
    }

    @Override
    public void undo() {
        System.out.printf("↩️ Move undone: back to (%d,%d)%n", fromR, fromC);
    }
}

public class Main {
    public static void main(String[] args) {
        Piece whiteKnight = PieceFactory.createKnight(Color.WHITE);
        ChessMove move1 = new ChessMove(whiteKnight, 0, 1, 2, 2); // Valid L-shape
        move1.execute();

        ChessMove move2 = new ChessMove(whiteKnight, 2, 2, 2, 4); // Invalid
        move2.execute();
    }
}