Since you’re here...

We hope you will consider supporting us today. We need your support to continue to exist, because good entries are more and more work time. Every reader contribution, however big or small, is so valuable. Support "Chess Engines Diary" even a small amount– and it only takes a minute. Thank you.
============================== My email: jotes@go2.pl



Facón 1.2 - Rojo Vivo, new version chess engine


Facón is a chess engine built from scratch in C++17, designed as a learning project and long-term development platform. The name comes from the facón — a traditional Argentine gaucho knife, forged by hand, raw and functional.
Each version carries a codename that follows the knife-making process: from rough rusty iron to a sharp, precise blade.
Author: Carlos M. Canavessi

Facón 1.2 - Rojo Vivo what's new?
+330 Elo over 1.1 (Ordo ~1690, confirmed across two gauntlets totaling 2080 games at 2min+1sec)

Pre-work bug fixes
unmake_move() hash corruption: hash = st.hash was placed before the piece operations, which XOR the hash incrementally. The restored hash was immediately re-corrupted after every unmake. Latent bug since 1.0 — affected TT hit rates, repetition detection, and PV display. Fixed by moving hash = st.hash to the last line of unmake_move().
make_null_move() full-move counter corruption: unmake_null_move() decremented full_move_number when Black made a null move, but make_null_move() never incremented it. Fixed.
Double generate_all_moves() in TT probe path: eliminated by moving a single generation before the TT probe and reusing it. ~2-5% nps improvement.
Search
Null Move Pruning (NMP): if the side to move can pass their turn and the resulting reduced-depth search still exceeds beta, prune immediately. Guards: not in check, ply > 0, non-pawn material present (zugzwang guard), depth >= 3. Reduction R = 3. Largest single search improvement in Facon's history: +5.6 average depth over 1.1 at long time controls.
Triangular PV array: replaced TT-based PV retrieval with an explicit pv_table_[MAX_PLY][MAX_PLY] updated on every alpha raise. Eliminates stale PV lines and the "PV continues after threefold repetition" GUI warning.
PV repetition detection: the PV walk seeds a seen[] array with game history hashes and stops if any resulting position was seen before.
Evaluation
Mopup evaluation: in pawnless endings with a decisive advantage (≥300cp), rewards pushing the losing king toward corners and keeping the winning king close. Guides conversion of technically won positions that standard PSTs cannot resolve.
Infrastructure
UCI threading: go now launches the search in a dedicated thread. The UCI loop returns immediately and can process stop while searching. Previously stop was silently ignored during search.
isatty()-gated output: startup banner, TT info, and interactive prompt are suppressed when launched by a GUI or automated tool.
TT silent constructor: no output is emitted during static initialization; print_info() is called explicitly from main() after the banner.
Time Management
Time forfeit fix: engine was losing games on time. Fixed: HARD_FACTOR 3.0 → 2.0, SAFETY_FACTOR 0.95 → 0.90, OVERHEAD_MS = 100 subtracted upfront, hard limit capped at remaining/3, 100ms grace buffer before expiry. Zero time forfeit losses across 2080 gauntlet games.
extend_time() reason parameter: time extension events are logged with a human-readable reason string ("PV change", "score drop").
start() allocation report: soft and hard limits for each move are emitted as info string for TM diagnostics at long time controls.
Observability
currmove/currmovenumber: each root move emits a standard UCI info currmove line as it begins searching.
New-best SAN info string: when the best move at the root changes relative to the previous iteration, emits a human-readable info string with move in SAN, score, depth, and timestamp.
Heartbeat: if no output has been emitted for 5 minutes, a standard info line plus a status string are emitted. Distinguishes a deep search from a crash at long time controls.
Code audit fixes


Comments