VeryChess 0.3.0

 ·  Release

Download

Overview

This release covers two areas: search efficiency and time management.

The late move reduction (LMR) scheme — the heuristic that decides how much cheaper to search moves that are unlikely to be best — has been rebuilt from a crude fixed cap into a proper depth- and move-number-scaled formula, with history and principal-variation awareness. The engine now reaches noticeably greater depth in the same amount of time.

The second area is how the engine spends its clock. Previously it burned most of its time in the opening and middlegame and was left playing on the increment by around move 25–30 — occasionally losing games on time outright. Time allocation has been reworked so the clock now lasts the whole game, and the previously dead `Move Overhead` option is now actually honored.

There are no changes to board representation, move generation, or evaluation in this release.

Strength

Every change to the reduction scheme was gated by a sequential probability ratio test (SPRT) against the build immediately preceding it, played at 10s + 0.1s and 120s + 2s with paired openings, one thread, and a 64 MB hash. Measured directly against 0.2.0.

Approximately strength improvement 46 ± 5 ELO.

What's new

Rebuilt late move reductions

Previously, late quiet moves were reduced by a flat 1–2 plies regardless of how deep the search was or how late the move appeared. That cap wasted most of the available savings at higher depths. It has been replaced with a precomputed reduction table indexed by depth and move number. The reduction now grows smoothly with both depth and move number — reaching 4–6 plies deep in the tree, where the savings compound — instead of stopping at 2.

Two refinements sit on top of the table:

  • History-aware reductions. Quiet moves with a strong history score are reduced one ply less. Measurement showed these moves are systematically undervalued by reduction: moves that had to be re-searched carried a median history score roughly two orders of magnitude above a typical reduced move.
  • Principal-variation reductions. LMR now applies inside PV nodes as well, but cautiously: reductions there are one ply smaller than in non-PV nodes, and the first five legal moves of a PV node are never reduced at all. The first move of every PV node is still searched at full depth in a full window.

Reworked time management

The engine was exhausting its clock far too early. The root cause was that the "soft" time limit was never actually a spending cap — it only decided whether to *start* another search iteration. Because each iteration roughly doubles the time of the previous one, the real spend per move came out at one-and-a-half to four times the intended budget, draining the clock by the middlegame.

  • Iteration-completion prediction. The engine now starts a new deepening iteration only when it predicts it can finish it within the budget, rather than starting one whenever any time remains. This is the core fix: it turns the soft limit into a real per-move budget. On its own it eliminated the clock collapse — median time remaining at the engine's 40th move rose from under a second to over a minute (of a three-minute clock).
  • More realistic game-length assumption. When the GUI does not say how many moves remain until the next time control, the engine now assumes 50 rather than 30, matching measured game lengths and making early moves less expensive.
  • "Move Overhead" is now functional. The option was previously declared but never applied. The engine now subtracts the configured reserve (default 10 ms) from its available time so a move reliably reaches the GUI or arbiter before the flag falls.

A threading robustness fix

A latent race in the worker-thread startup could, in rare timing, cause the engine to accept a "go" command and then never reply — no "info", no "bestmove" — while the UCI loop itself stayed responsive. It required a "go" to arrive within microseconds of the engine process starting, so ordinary GUIs (which perform a full handshake first) never triggered it, but automated tooling that streams commands in one burst could. The worker now finishes parking before the constructor returns, closing the window.

Full principal variation in "info" output

"info" lines now report the complete principal variation rather than only the best move. The line is reconstructed from the transposition table between iterations on the main thread, off the search hot path, so it costs no search speed. Occasionally the reported line is shorter than the search depth, when transposition table entries have been overwritten — this is cosmetic and does not affect play.

VeryChess 0.2.0

 ·  Release

Download

VeryChess 0.2.0 introduces multi-threaded search based on the Lazy SMP approach, with support for 1 to 256 search threads and a shared lock-free transposition table.

Each worker thread performs its own iterative deepening search from the same root position. Threads cooperate exclusively through the shared transposition table, without split points or locking in performance-critical search paths.

Every worker maintains its own board copy, history table, and node counters. To improve search diversity, helper threads selectively skip certain depths and explore the position using slightly different search trajectories.

Only the main thread is responsible for time management and UCI output, including info and bestmove. The final move is selected through a voting mechanism across all worker threads. Priority is given to the move from the deepest completed iteration, with the evaluation score used as a tie-breaker.

Internal testing indicates that VeryChess 0.2.0 running with four threads is approximately 100 Elo stronger than VeryChess 0.1.0.

VeryChess 0.1.0

 ·  Beta

Initial public development release of VeryChess. This version establishes the core engine architecture, UCI compatibility, and a basic but functional search and evaluation. Strength is experimental and will improve in future versions.

VeryChess is a UCI chess engine written in C++20, targeting native compiled binaries for macOS (ARM64 primary), Linux, and Windows. It's a classical alpha-beta engine with hand-crafted evaluation — no neural networks, no third-party dependencies, standard library only.

Architecture / Board representation

  • Bitboards - one 64-bit integer per [color][piece-type], plus per-color and total occupancy.
  • Incremental Zobrist hashing updated on every make/unmake.
  • Compact 32-bit move encoding: from | to<<6 | flag<<12, with flags for quiet/capture/double-push/en passant/castling/promotion.
  • Attack tables precomputed at startup: knight/king/pawn lookups; sliding pieces (rook/bishop/queen) use a classical fill algorithm over rank/file/diagonal masks — not magic bitboards.

Move generation

  • Pseudo-legal generation with separate capture-only generation for quiescence.
  • Legality enforced lazily: moves are made, then rejected if they leave the own king in check.
  • Validated via perft — exposed both as a CLI subcommand and a UCI debug command, with Kiwipete and other standard positions in the bench set.

Search algorithms

  • PVS (Principal Variation Search): full window on first move, null-window scout on the rest.
  • Transposition table: probe for cutoffs (non-PV), best-move ordering; depth+age replacement.
  • Null-move pruning: R=2–3, disabled in PV / in check / zugzwang-risk (no non-pawn material).
  • Late move reductions: reduces late quiet moves, re-searches if they beat alpha.
  • Quiescence search: captures-only with stand-pat, avoids the horizon effect.
  • Check extensions: +1 ply when a move gives check.
  • Mate-distance pruning: tightens the alpha/beta window.
  • Move ordering: TT move → MVV-LVA captures → 2 killer moves → history heuristic.
  • Draw detection in search: 50-move rule + repetition via the hash history.

Evaluation

Hand-crafted, integer (centipawn), symmetric, returned from the side-to-move's perspective (eval.cpp):

  • Material + piece-square tables.
  • Phase awareness — separate king PST for middlegame vs endgame, switched on non-pawn material; endgame adds king-centralization and a king-driving term for K+piece vs K mates.
  • Bishop pair bonus, simple knight mobility.
  • King safety — open-file penalties near a castled king plus a non-linear attacker-weight table over inner/outer king zones.

UCI / functionality

  • Commands: uci, isready, ucinewgame, position (startpos/fen + moves), go (depth/movetime/wtime-btime-inc/movestogo/infinite), stop, quit, plus debug perft.
  • Time management with soft/hard limits derived from the clock; time checked every 2048 nodes for low overhead.
  • Hash option: configurable TT size, default 64 MB, 1 MB–64 GB.
  • Standard UCI info output (depth, seldepth, score cp/mate, nodes, nps, time, pv).

Characteristics summary

  • Style: classical alpha-beta engine, correctness-first, performance-conscious.
  • Strengths: complete modern search-pruning toolkit, clean cache-friendly bitboard design, zero dependencies, fully cross-platform, interruptible threaded search.
  • Current limitations / growth areas: single-threaded search (no SMP), classical (non-magic) sliding attacks, untapered hand-crafted eval, no opening book or endgame tablebases, no NNUE.