---
title: Chess
url: 'https://kvc.pl/repositories/chess'
markdown: 'https://kvc.pl/repositories/chess.md'
date: '2026-08-29'
description: 'Modern Chess Engine: competitive C++20 chess engine with pure WinAPI GUI and UCI console engine. Cache-line-aligned mailbox board, lock-free transposition table (Hyatt XOR-key, 4-way 64B buckets, prefetch), PVS, singular extensions, ProbCut, aspiration windows, staged move picker with lazy SEE, tapered hand-crafted evaluation, Lazy SMP parallel search. 200-500 KB, zero dependencies, runs even in WinRE.'
---

[ Download Chess.7z](https://kvc.pl/repositories/chess/Chess.7z) [ Source on GitHub](https://github.com/wesmar/Chess) [ Latest Release](https://github.com/wesmar/Chess/releases/latest) 🔐 ARCHIVE PASSWORD: `github.com`

> **2026-07-11 (late) — Batch 6: Lazy SMP — +147 Elo at 4 threads (LOS 100%)**
> 
> Root-parallel search replaced by true **Lazy SMP with a persistent thread pool**: helper threads search the same root position at staggered depths and coordinate purely through the shared lock-free transposition table — no root splitting, no shared alpha, zero spawn cost (helpers sleep on a condition variable between moves). Measured 4-threads-vs-4-threads against the previous build: **69.4% over 116 games = +147 Elo ±61, LOS 100%**, zero time losses. NPS 420k → 1.73M (×4.1), one extra ply at equal time. Day total across all validated batches: **~+550 Elo**; with 4 threads the engine plays at roughly **~2300 on the Stockfish UCI\_Elo scale**.
> 
> **2026-07-11 — From educational toy to measured competitor: ~+400 Elo in validated batches**
> 
> The engine went through a scientific improvement campaign: every batch of search changes validated with cutechess-cli SPRT matches (fixed openings, tc=8+0.08, level 10). Batch 1 (PVS at all nodes, aspiration widening, history malus, SEE pruning): **~+200 Elo**. Batch 2 (lazy legality, lock-free 4-way cache-line TT buckets with prefetch, AVX2): **~+120 Elo**, NPS +38%. Batch 3+4 (staged move picker with lazy SEE, TT in quiescence, timeout-latch abort, endgame mop-up and drawish scaling, O(1) occupancy restore): **+35 Elo** (LOS 98.7%). Batch 5 (continuation history, TT generation aging): **+8 Elo**, search tree −15% at equal depth. Absolute calibration vs Stockfish 17 at fast time control: **~2160 Elo** on the SF UCI\_Elo scale — holds SF 2100 at 80% score. Next stop: small self-trained NNUE net and Texel tuning.

# ♔ Modern Chess Engine

![Chess Engine Screenshot](https://raw.githubusercontent.com/wesmar/Chess/main/Images/chess.gif)

A competitive chess engine written in modern C++20 with pure WinAPI interface. Built on a deliberately contrarian architecture — a cache-line-aligned mailbox board instead of magic bitboards — and optimized with HFT-style engineering: lock-free data structures, cache-conscious memory layout, and latency hiding via prefetch. Small enough to read, strong enough to compete.

[![Windows](https://img.shields.io/badge/Windows-10%20-blue.svg)](https://www.microsoft.com/windows)
[![C++](https://img.shields.io/badge/C%20%20-20-orange.svg)](https://isocpp.org/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/wesmar/Chess/blob/main/LICENSE.md)
[![Build](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/wesmar/Chess/releases)

## Why This Project?

Most chess engines are either too simple (lacking modern techniques) or too complex (thousands of files, external dependencies). This project implements the full modern search arsenal — PVS, singular extensions, ProbCut, aspiration windows, lock-free transposition table — in clean, readable code, while refusing to copy the standard bitboard blueprint.

This is a case study in building a high-performance chess system using **Data-Oriented Design (DOD)** principles, maximizing computational throughput while drastically reducing binary size and eliminating all external library dependencies. Every strength-affecting change is validated the scientific way: engine-vs-engine matches under cutechess-cli with fixed openings and time controls.

## Key Features

### 🎯 Extreme Optimization

- **No CRT version**: ~ 200 KB
- **With CRT version**: ~ 500 KB
- **Zero external dependencies** - no Qt, SDL, or .NET
- **Portable**: Even runs in Windows Recovery Environment (WinRE)!

### 🧠 Advanced Search Algorithms

#### Core Search Framework

- **Principal Variation Search (PVS) at every node** - first move searched with a full window, all others with a null-window scout; re-search only on fail-high
- **Iterative Deepening** with adaptive time management and a timeout latch (gated clock check + per-node abort flag, bounded overshoot)
- **Aspiration Windows with progressive widening** - each iteration starts with a ±30cp window around the previous score; doubled on fail-low/fail-high
- **Quiescence Search** with TT probing/stores - eliminates horizon effect
- **Lazy Legality Checking** - interior nodes search pseudo-legal moves and verify king safety only when a move is actually made

#### Pruning & Extensions

- **Null Move Pruning (NMP)** - gated on `staticEval >= beta`, hoisted before move generation, disabled in endgames (zugzwang)
- **ProbCut** - captures-only shallow search at raised beta with SEE filter
- **Late Move Reduction (LMR)** - logarithmic formula `log(depth) × log(moveIndex) / 2.25`, re-search on alpha improvement
- **Late Move Pruning, Futility Pruning, Reverse Futility Pruning, Delta Pruning, Mate Distance Pruning**
- **SEE Pruning in Main Search** - losing captures skipped at shallow depths
- **Check Extensions** (capped) and **Singular Extensions** - TT move extended when a reduced search proves it is the only good move

#### Lock-Free Transposition Table

- **Hyatt XOR-key validation** - 16-byte entries with `(keyXorData, data)` atomic pair; zero mutexes in the hot path
- **4-way cache-line buckets** - `alignas(64)` groups of four entries; any probe touches exactly one cache line
- **TT Prefetch (HFT-style latency hiding)** - `_mm_prefetch` issued on the child's Zobrist key immediately after making a move
- **Generation aging** - stale entries from previous searches evicted first
- **TT reuse across moves** - table preserved within a game; only `ucinewgame` resets

#### Move Ordering

- **Staged move picker** - cheap SEE-free scoring plus lazy selection; SEE computed only for a capture actually about to be searched (NPS +20%)
- **TT move, MVV-LVA, killers (two per ply), countermoves, history with malus** - misordered quiets sink fast via `-depth²` penalty
- **Continuation history** - quality of a (piece,to) reply to the opponent's previous (piece,to); much sharper signal than from/to history alone

#### Parallel Search (Lazy SMP)

- **Lazy SMP with a persistent thread pool** - helpers search the same root at staggered depths, coordinating purely through the shared lock-free TT; no root splitting, no shared alpha. **+147 Elo at 4 threads**, NPS ×4.1
- **Zero spawn cost** - helper threads live inside the engine and sleep on a condition variable between moves
- **Thread-Local Heuristics** - separate killer tables per thread; history tables shared atomics

### ⚡ High-Performance Memory Architecture

- **64-byte Mailbox (Cache-Aligned)** - entire board state in a single L1 cache line
- **Bitboards for occupancy only** - fast sliding piece queries without magic-bitboard lookup tables (~800 KB saved)
- **Stack-allocated MoveList** - fixed 256-move array, zero malloc() in the hot path
- **PieceList per color** - O(1) piece iteration, swap-with-last removal
- **Incremental everything** - Zobrist key, MG/EG scores, pawn bitboards; O(1) occupancy snapshot-restore in UndoMove

### 📊 Hand-Crafted Evaluation (HCE)

- **Tapered evaluation** - separate MG/EG piece-square tables, interpolated by material phase
- **King safety** - castling bonus, pawn shield, open-file penalty (O(1) via pawn bitboards)
- **Piece activity** - mobility, center control, tropism, exposed-queen penalty
- **Pawn structure** - isolated, doubled, backward; passed pawns with king-distance and rook-behind bonuses
- **Endgame knowledge** - mop-up evaluation for bare-king conversion, dead-draw detection, opposite-colored-bishop scaling

### 🤖 NNUE Infrastructure (Prepared)

Complete NNUE (Efficiently Updatable Neural Network) infrastructure is on board: HybridEvaluator (Classical/NNUE/Auto), inference engine with incremental accumulators, HalfKP feature extraction, SIMD dense layers, and a `.nnue` weight loader. Currently runs in Classical mode; a small self-trained net is the next roadmap item.

## Measured Strength

Every batch of search changes is validated with cutechess-cli matches (fixed opening set, tc=8+0.08, 1 thread, level 10). The SPRT harness ships with the repo (`testing/run_match.ps1`).

| Batch | Changes | Result |
|---|---|---|
| 1 | PVS at all nodes, TT-probe-before-pruning, NMP eval gate, aspiration widening, history malus, SEE pruning | **~+200 Elo** (76% over 194 games) |
| 2 | Lazy legality, 4-way cache-line TT buckets, TT prefetch, NMP before movegen, AVX2 codegen | **~+120 Elo**; NPS +38% |
| 3+4 | Staged move picker with lazy SEE, TT in quiescence, 50-move rule in search, timeout-latch abort, endgame knowledge, O(1) occupancy restore | **+35 Elo** (LOS 98.7%, 410 games) |
| 5 | Continuation history, TT generation aging, killers ply+2 clearing | **+8 Elo**; search tree −15% at equal depth |
| 6 | Lazy SMP: persistent helper pool, whole-root search at staggered depths, TT-only coordination | **+147 Elo at 4 threads** (69.4% over 116 games, LOS 100%) |

Absolute calibration (single thread): **~2160 Elo** on the Stockfish UCI\_Elo scale (200-game match vs SF 17 @ 2200, plus a descending ladder — holds SF 2100 at 80%). With 4 threads: roughly **~2300** on the same scale.

Batch 3 taught the most valuable lesson of the project: three consecutive test matches showed a "regression" that turned out to be time forfeits, not chess. A gated clock check let the search overrun its budget by hundreds of milliseconds after timeout. Moral: **check the match logs for `loses on time` before touching your evaluation.**

## Quick Start

Download [chess.zip](https://kvc.pl/repositories/chess/chess.zip) or grab the [latest GitHub release](https://github.com/wesmar/Chess/releases/tag/latest) (Chess.7z, password: `github.com`):

- `Chess_x64.exe` - 64-bit GUI version (~500 KB)
- `Chess_x64_minSize.exe` - 64-bit minimal (~200 KB)
- `Chess_x86.exe` / `Chess_x86_minSize.exe` - 32-bit versions
- `ChessEngineUCI_x64.exe` - UCI console engine for Arena / Cutechess / Fritz

Just download and run - no installation needed!

### Building from Source

Requirements: Windows 10+, Visual Studio 2022 or newer with C++20 support (tested with VS 2026, v145 toolset).

```batch
git clone https://github.com/wesmar/Chess.git
cd Chess
build_all.bat
```

Binaries land in `bin\`. Builds are reproducible (`/BREPRO`). `build_uci.bat` builds just the UCI engine (x64 Release).

## UCI Engine (Arena / Cutechess / Fritz)

`ChessEngineUCI_x64.exe` is a standard UCI console engine — drop it into any UCI-compatible GUI.

| Option | Range | Description |
|---|---|---|
| `Threads` | 1..64 | Parallel root-search workers |
| `Hash` | 1..4096 MB | Transposition table size; 128-256 MB recommended |
| `Level` | 1..10 | AI strength; use **10** for tournament play |
| `Move Overhead` | 0..5000 ms | Safety margin for GUI/network latency |

The engine emits live `info depth/score/nodes/nps/time/pv` after every completed iteration. Full Arena setup walkthrough: [arena.txt](https://github.com/wesmar/Chess/blob/main/arena.txt).

## GUI Features

- **Unicode rendering** - clean chess pieces (♔♕♖♗♘♙) using native WinAPI vector rendering
- **Full chess rules** - castling, en passant, promotion; PGN save/load; undo/redo
- **Game modes** - Human vs Human, Human vs AI, AI vs AI; 10 difficulty levels
- Keyboard shortcuts: **Ctrl+N** new game, **Ctrl+Z/Y** undo/redo, **F** flip board, **L** legal moves, **C** coordinates

## Architecture Decisions

**Why mailbox instead of bitboards?** A deliberate architectural bet. Raw move generation is somewhat slower than magic bitboards, but the entire board state lives in one L1 cache line, make/unmake is trivially cheap, and the engine wins the time back where it matters more: move ordering, pruning quality, and a cache-conscious transposition table. Strength is validated by measurement, not by copying the standard blueprint.

**Why 1-byte pieces?** No polymorphism, no v-tables, bit masking for properties, predictable layout — the whole board fits in L1.

**Why hand-crafted evaluation (for now)?** Good strength at minimal size, fast per-node cost, easy to understand and modify. NNUE comes next, on the engine's own terms.

## Roadmap

- Small self-trained NNUE net (HalfKP-style, quantized, ~1-4 MB)
- Texel tuning for PST and eval weights
- Per-thread history tables (kill the last false sharing)
- Syzygy tablebase support, MultiPV, real pondering

## License & Author

MIT License — see [LICENSE](https://github.com/wesmar/Chess/blob/main/LICENSE.md).

**Marek Wesołowski** (WESMAR)
📧 <marek@wesolowski.eu.org>
🌐 [kvc.pl](https://kvc.pl)

---

*Made with ♟️ in C++20 | AVE!*

### Add a comment

---

## Navigation

- Parent: [Repositories](https://kvc.pl/repositories.md)
- Previous: [Notepad](https://kvc.pl/repositories/notepad.md)
- Next: [Tetris](https://kvc.pl/repositories/tetris.md)
