System Layers

Each layer only knows about the layer below it. The GUI never calls an AI method directly, and the engine never imports a GUI class.

Presentation Layer — GUI

com.chess.gui
Table (JFrame)Table.java
BoardPanelBoardPanel.java
TilePanelTilePanel.java
AnimationManagerAnimationManager.java
GameHistoryPanelGameHistoryPanel.java
TakenPiecesPanelTakenPiecesPanel.java
GameSetupGameSetup.java
▼ calls into Engine for move execution & board state

Domain Layer — Engine

com.chess.engine
Boardboard/Board.java
Tileboard/Tile.java
BoardUtilsboard/BoardUtils.java
Moveboard/Move.java
Piece (abstract)pieces/Piece.java
King / Queen / Rook…pieces/*.java
Playerplayer/Player.java
WhitePlayerplayer/WhitePlayer.java
BlackPlayerplayer/BlackPlayer.java
MoveTransitionplayer/MoveTransition.java
▼ provides Board snapshots to AI for evaluation

Intelligence Layer — AI

com.chess.engine.player.ai
AIThinkTankAIThinkTank.java
MoveStrategy (iface)MoveStrategy.java
StandardBoardEvaluatorStandardBoardEvaluator.java
MoveOrderingMoveOrdering.java
ZobristHasherZobristHasher.java
TranspositionTableTranspositionTable.java
OpeningBookOpeningBook.java
RandomMoveStrategyL1
GreedyStrategyL2
MiniMaxStrategyL3
AlphaBetaStrategyL4
IterativeDeepeningStrategyL5
AdvancedAlphaBetaStrategyL6

Immutable Board State

The engine's core insight: Board is immutable. Every move creates a brand new Board — the old one is never modified.

Why immutability? The AI evaluates thousands of positions per second. With a mutable board, every branch would need an explicit undo step. With an immutable board, the AI simply holds a reference to the original — garbage collection handles cleanup. Guava's ImmutableList and ImmutableMap make this zero-cost.

Board fields (all final)

gameBoardImmutableList<Tile> (64)
whitePiecesImmutableList<Piece>
blackPiecesImmutableList<Piece>
whitePlayerWhitePlayer
blackPlayerBlackPlayer
currentPlayerPlayer (white|black)
enPassantPawnPawn | null
nextMoveMakerAlliance (WHITE|BLACK)

Move execution (no mutation)

move.execute()returns new Board
Builder patterncollects changes
setPiece()adds to Builder map
setMoveMaker()flips alliance
build()constructs new Board
old BoardGC-eligible immediately
undonot needed (hold ref)

Move Execution Flow

Trace of a single move from user click to board update — including the AI's background computation.

User Click
TilePanel
Move Factory
createMove()
Player
makeMove()
MoveTransition
status check
New Board
immutable
Human move path (EDT thread)
↓ if AI's turn, hand off to background thread
AIThinkTank
SwingWorker
OpeningBook
lookup hash
Strategy.execute()
L1–L6
Best Move
returned
BoardPanel
animate + redraw
AI move path (background worker → EDT callback)

Board Evaluation

All AI levels from L2 upward share the same evaluator. It returns centipawns from White's perspective.

Material Score

Piece values (centipawns): Pawn = 100 · Knight = 320 · Bishop = 330 · Rook = 500 · Queen = 900. Summed for White, subtracted for Black.

Piece-Square Tables

Each piece type has a 64-value PST from the Chess Programming Wiki. A pawn on e4 is worth more than one on a2 — the PST captures this positional bonus.

Mobility Bonus

+5 cp per legal move available. A player with more legal moves has more options — rewarded explicitly even before searching them.

Check & Checkmate

+50 cp for delivering check. +10 000 + depth for checkmate — the depth term makes the engine prefer faster mates over slower ones.

Pawn Structure

Penalties for doubled (−30) and isolated (−20) pawns. Bonus for passed pawns. Blocked pawn: −10 per rank it cannot advance.

Rook Files

+25 cp for a rook on an open file (no pawns). +10 cp for a half-open file (only opponent pawns). Rooks belong on open files.

Zobrist Hashing & Transposition Table

Levels 5 and 6 fingerprint every board position with a 64-bit hash — enabling the cache that makes deep search possible.

// At startup: assign a random 64-bit key to every (piece, square) pair static long[12][64] pieceSquareKeys = new long[12][64]; // → 768 random longs, generated once, stored statically // Hash a full board position: long hash = 0L; for (Piece p : board.getAllPieces()) { hash ^= pieceSquareKeys[pieceIndex(p)][p.getPiecePosition()]; } if (board.currentPlayer().getAlliance() == Alliance.BLACK) hash ^= sideToMoveKey; // XOR is reversible: moving a piece = XOR out old square, XOR in new square (O(1)) // Transposition Table probe: TTEntry entry = tt.probe(hash); if (entry != null && entry.depth >= depth) { if (entry.flag == EXACT) return entry.score; else if (entry.flag == LOWER) alpha = Math.max(alpha, entry.score); else if (entry.flag == UPPER) beta = Math.min(beta, entry.score); if (alpha >= beta) return entry.score; // TT cutoff }

Why XOR?

XOR is its own inverse. Moving a piece from e2→e4 is two XOR operations: remove the piece at e2, add it at e4. No rehashing from scratch — O(1) incremental update per move.

TT Entry Flags

EXACT — score is exact, from a fully searched window. LOWER — caused a β-cutoff, score is a lower bound. UPPER — all moves failed low, score is an upper bound.

Threading & Observer Pattern

The GUI stays responsive while the AI thinks by running search on a background SwingWorker thread.

EDT (Swing thread)
renders UI, handles input
never blocked
fires
SwingWorker
done()
callback on EDT
Worker thread
AIThinkTank.doInBackground()
runs search in background
Observer pattern: Table subscribes to move events via a GameObserver interface. When human or AI makes a move, the observer fires — the board redraws, history updates, and the next turn is triggered. Neither the engine nor the AI need to import any GUI class.

Opening Book

The first 10 half-moves use a hand-coded book of 10 openings keyed by Zobrist hash.

Ruy Lopez

1.e4 e5 2.Nf3 Nc6 3.Bb5 — classic open game, white targets e5 pawn.

Sicilian Defence

1.e4 c5 — black fights for the d4 square asymmetrically.

French Defence

1.e4 e6 — solid, leads to closed pawn structures.

Caro-Kann

1.e4 c6 — solid defense without early pawn weaknesses.

Queen's Gambit

1.d4 d5 2.c4 — offers a pawn to gain central control.

King's Indian

1.d4 Nf6 2.c4 g6 — dynamic counterplay, black fianchettoes.

London System

1.d4 2.Nf3 3.Bf4 — solid, non-theoretical white setup.

Italian Game

1.e4 e5 2.Nf3 Nc6 3.Bc4 — central control, rapid development.

English Opening

1.c4 — hypermodern, controls d5 from a distance.

Pirc Defence

1.e4 d6 — flexible defense, black challenges center later.

← Explore the AI algorithms   View Source ↗