A fully-featured chess engine built in Java — demonstrating real-world OOP, GoF Design Patterns, and game engine architecture.
Overview · Design Patterns · Architecture · Features · Run · Structure
Project Chess is a complete, rule-compliant chess engine with an interactive Swing/AWT GUI. What differentiates this from a typical game project is the deliberate application of Gang of Four (GoF) design patterns and SOLID principles — each architectural decision made to maximize modularity, testability, and extensibility.
The engine handles the full complexity of chess rules, a rendering pipeline, and an event-driven input model — structured as a mini game engine, not a monolithic application.
Engineering highlights:
- 4 GoF patterns applied where they solve real design problems — not forced
- Full move validation pipeline with rule isolation per piece type
- Command-based move history enabling unlimited undo/redo
- Observer-driven state propagation — UI never polls, only reacts
- Designed so adding a new piece type requires zero changes to existing classes
Complete Chess Rules Engine
- ♟️ Legal move generation for all 6 piece types
- ♟️ Check and checkmate detection
- ♟️ Stalemate detection
- ♟️ Castling (kingside and queenside, with full precondition validation)
- ♟️ En passant capture
- ♟️ Pawn promotion
GUI & Interaction
- Interactive board rendered via Swing/AWT
- Mouse-driven piece selection and move execution
- Move highlighting — valid squares shown on selection
- Captured pieces panel, move history log, game status indicator
- Undo / Redo via toolbar or keyboard shortcut
Architecture
- Separation of game logic, rendering, and input handling
- Extensible piece model — new piece types require no modifications to existing code
- Clean state management — board state is always consistent and inspectable
This is the core engineering section. Each pattern was chosen to solve a specific design problem — not applied for the sake of it.
Problem: Each chess piece has unique movement logic. Without Strategy, this devolves into a giant switch or instanceof chain inside a single movement method — fragile and closed to extension.
Solution: Each piece type implements a MovementStrategy interface with a getLegalMoves(Board board, Position position) method. The Piece class delegates movement calculation to its assigned strategy.
interface MovementStrategy {
List<Move> getLegalMoves(Board board, Position position);
}
class KnightMovementStrategy implements MovementStrategy {
@Override
public List<Move> getLegalMoves(Board board, Position position) {
// L-shaped logic isolated here
}
}Why it improves design:
- Adding a new piece (e.g., a fairy chess variant) = implement one interface, plug in
- Movement logic is independently testable per piece type
- Zero coupling between
Pieceand movement rules — Open/Closed Principle in action
Problem: Creating pieces during board setup requires conditional construction logic scattered across the codebase. Direct instantiation couples the caller to concrete piece classes.
Solution: A PieceFactory encapsulates piece creation. The caller requests a piece by type and color — the factory returns the correctly configured object with the right strategy assigned.
class PieceFactory {
public static Piece create(PieceType type, Color color) {
return switch (type) {
case KNIGHT -> new Piece(color, new KnightMovementStrategy());
case BISHOP -> new Piece(color, new BishopMovementStrategy());
// ...
};
}
}Why it improves design:
- Board setup and piece creation are fully decoupled
- Strategy assignment is centralized — one place to change piece behavior
- Supports future extension (e.g., loading custom pieces from config)
Problem: Multiple UI components (status panel, move log, captured pieces panel) need to react when game state changes. Directly calling each component from the game logic creates tight coupling and violates SRP.
Solution: Game implements a publisher. UI components register as GameEventListener subscribers. On state change (move executed, check detected, game over), the game notifies all registered observers.
interface GameEventListener {
void onMoveMade(Move move);
void onCheckDetected(Color kingColor);
void onGameOver(GameResult result);
}
class StatusPanel implements GameEventListener {
@Override
public void onCheckDetected(Color kingColor) {
statusLabel.setText(kingColor + " is in check!");
}
}Why it improves design:
- Game logic has zero knowledge of the UI — Dependency Inversion preserved
- Adding a new UI component (e.g., an audio cue system) requires only registering a new listener
- State changes propagate automatically — no polling, no stale UI
Problem: Supporting undo/redo requires storing enough information to reverse any move. Without Command, this means ad-hoc state snapshots or deeply coupled reverse-logic in the board class.
Solution: Every move is encapsulated as a MoveCommand object with execute() and undo() methods. A MoveHistory stack manages the command log.
interface MoveCommand {
void execute();
void undo();
}
class StandardMoveCommand implements MoveCommand {
private final Board board;
private final Move move;
private Piece captured; // saved on execute, restored on undo
@Override
public void execute() {
captured = board.getPieceAt(move.getTo());
board.movePiece(move);
}
@Override
public void undo() {
board.movePiece(move.reversed());
if (captured != null) board.placePiece(captured, move.getTo());
}
}Why it improves design:
- Undo/redo is an O(1) stack operation — no board diffing required
- Complex moves (castling, en passant) are self-contained in their own command subclass
- Move history is a first-class object — trivially serializable for game save/replay
Mouse Input
│
▼
InputHandler
(translates click → board position)
│
▼
MoveValidator
(checks legality: rules + board state)
│
▼
MoveCommand.execute()
(applies move to Board, saves state for undo)
│
▼
Game.notifyObservers()
(broadcasts event to all UI listeners)
│
▼
BoardRenderer + StatusPanel + MoveLog
(each independently re-renders from new state)
Input is fully decoupled from game logic. The flow is:
- Input Layer —
MouseListenercaptures click coordinates, maps toPosition(row, col) - Selection Phase — first click selects a piece and requests legal moves from its
MovementStrategy - Validation Phase —
MoveValidatorfilters moves that would leave the king in check - Execution Phase — confirmed move is wrapped in a
MoveCommandand executed; board state updates atomically - Notification Phase —
Gamefires events; all registeredGameEventListeners react independently
The Board is the single source of truth. It holds:
- An 8×8 grid of
Optional<Piece>— null-safe by design - Active color (whose turn it is)
- En passant target square
- Castling rights (bitmask per side)
State is never mutated speculatively outside of MoveCommand.execute(). Move generation operates on a cloned board to test check conditions — the real board is only modified after validation passes.
Raw candidate move
→ Is destination reachable by piece's MovementStrategy?
→ Does move respect board boundaries?
→ Is destination occupied by own piece?
→ After move, is own king in check? (simulated on clone)
→ Special rule checks (castling path clear? en passant conditions met?)
→ ✅ Legal move
ProjectChess/
├── engine/
│ ├── Board.java # Board state, piece placement
│ ├── Game.java # Game lifecycle, observer management
│ ├── MoveValidator.java # Full legality pipeline
│ └── MoveHistory.java # Command stack (undo/redo)
│
├── model/
│ ├── Piece.java # Piece entity (delegates to strategy)
│ ├── Move.java # Move value object
│ ├── Position.java # (row, col) value object
│ ├── PieceType.java # Enum: KING, QUEEN, ROOK, BISHOP, KNIGHT, PAWN
│ └── Color.java # Enum: WHITE, BLACK
│
├── patterns/
│ ├── strategy/
│ │ ├── MovementStrategy.java # Interface
│ │ ├── KnightMovementStrategy.java
│ │ ├── BishopMovementStrategy.java
│ │ └── ... # One class per piece type
│ ├── factory/
│ │ └── PieceFactory.java
│ ├── observer/
│ │ ├── GameEventListener.java # Interface
│ │ └── GameEventType.java
│ └── command/
│ ├── MoveCommand.java # Interface
│ ├── StandardMoveCommand.java
│ ├── CastlingMoveCommand.java
│ └── EnPassantMoveCommand.java
│
├── gui/
│ ├── BoardRenderer.java # Paints board + pieces
│ ├── InputHandler.java # Mouse events → game actions
│ ├── StatusPanel.java # GameEventListener — shows turn/check
│ ├── MoveLogPanel.java # GameEventListener — move history
│ └── CapturedPiecesPanel.java # GameEventListener — captured display
│
└── Main.java # Entry point — wires everything together
Key design decisions in structure:
patterns/package is explicitly named — communicates intent, not just grouping- Each
MoveCommandsubclass handles its own undo logic — no polymorphic branching - GUI components are only
GameEventListeners — they hold zero game state
- Java 17+
- Any IDE (IntelliJ IDEA recommended) or terminal with
javac
git clone https://github.com/mayankSystems/ProjectChess.git
cd ProjectChessVia IDE:
Open the project → run Main.java
Via Terminal:
# Compile
javac -d out -sourcepath src src/Main.java
# Run
java -cp out Main| Action | Input |
|---|---|
| Select piece | Left click on piece |
| Move piece | Left click on highlighted square |
| Undo last move | Ctrl+Z or Undo button |
| Redo move | Ctrl+Y or Redo button |
| New game | New Game button |
- AI opponent — Minimax with alpha-beta pruning;
MovementStrategyabstraction makes the engine AI-ready without modification - PGN import/export — load/save games in standard Portable Game Notation; Command pattern makes this trivial
- Opening book — preloaded opening tree for hints and AI play
- Network multiplayer — serialize
MoveCommandobjects over sockets for peer-to-peer play - Puzzle mode — load board positions and validate player solutions
- Stockfish integration — pipe moves to/from Stockfish via UCI protocol for analysis mode
Open to: SDE2 / Senior Backend Engineer roles · Java · System Design · Clean Architecture
This project exists to demonstrate that OOP isn't just syntax — it's a design discipline. Every pattern here solves a real problem. Happy to walk through any architectural decision in detail.
⭐ Star this repo if it helped you understand design patterns in a real codebase.
Project Chess — Java OOP + Design Patterns Engine