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.3 - Yunque, 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.3 - Yunque what's new?

+200 Elo over 1.2 (Ordo ~1900, gauntlet 1040 games at 2min+1sec)

Pre-work bug fixes

  • NMP depth floor (search.cpp): at depth == NMP_MIN_DEPTH (3), the NMP recursive call produced depth -1. With the corrected depth == 0 quiescence entry condition, this caused infinite recursion. Fixed: std::max(0, depth - 1 - NMP_REDUCTION).
  • depth <= 0 to depth == 0 (search.cpp): prerequisite for LMR. Negative depths from buggy reductions are now immediately detectable instead of silently entering quiescence.

Search

  • Late Move Reductions (LMR): quiet moves searched after the first 3 legal moves at depth >= 3 are searched at reduced depth. Formula: log(depth) * log(move_number) / 2.25, floored at 1. Re-searched at full depth if the reduced search raises alpha. Skipped for: captures, en passant, promotions, killer moves, in check.
  • History heuristichistory_[color][from][to] incremented by depth^2 on beta cutoffs. Replaces the flat ORDER_QUIET=0 score for quiet move ordering, improving LMR accuracy. Capped at 50,000 (below ORDER_KILLER2). Reset each search.
  • Aspiration windows: iterative deepening searches with a +/-50cp window around the previous score from depth 4+. On fail-low or fail-high, widens only in the failing direction and doubles delta. Full window used for depth < 4 and mate scores.

Evaluation

  • Pawn structure: five terms via bitboard operations -- isolated (-15cp), doubled (-15cp), backward (-12cp), passed (rank-scaled: 0/0/10/20/35/55/80/0cp), connected (+8cp). All computed symmetrically for both colors.
  • Mopup insufficient material guard: K+B vs K and K+N vs K are theoretical draws. Both exceed MOPUP_THRESHOLD (300cp) and previously activated corner-chasing. mopup_eval() now returns 0 when the strong side has exactly one minor piece.

Time Management

  • Quadratic extension scalingextend_time() factors pre-scaled by (depth^2 / EXTENSION_FULL_DEPTH^2). PV changes at depth 2-9 have near-zero effect; extensions at the engine's operating depth (14+) apply the full factor. EXTENSION_FULL_DEPTH = 18.
  • accumulated_ext_ cap removed: the 2.0x cap consumed the budget at low depths before real extensions at depth 14+ could fire. The soft limit is now bounded only by the hard limit.
  • Easy move reduction (reduce_time): mate found (x0.05, one-shot), forced move (x0.1), PV+score stable >= 7 iterations at depth > 12 (x0.40, one-shot). Cancelled before extensions so they act on the full soft limit.
  • Emergency hard limit: when depth >= 25 and the extended soft would exceed hard, hard is raised to match (capped at 50% of raw remaining clock). Both limits rise together on subsequent extensions. Only triggered by real instability -- stable positions at depth 25+ would have already fired easy-move reduction.

Infrastructure

  • Centralized version systemPROJECT_VERSION and FACON_CODENAME in CMakeLists.txt control the binary name, startup banner, UCI id, and Windows version resource. To release: change codename from "dev" to "Yunque" and recompile.
  • perft commandperft N counts leaf nodes, perft divide N gives per-move breakdown. Bulk-counting at depth 1. Verified: startpos depth 5 = 4,865,609.
  • bitboard.cpp init message gated: suppressed when launched by GUI or automated tool.

Bug fixes

  • Aspiration window fail-low: the old handler set beta_asp = (alpha_asp + beta_asp) / 2, squeezing the upper bound. On re-search via TT/LMR interactions, this triggered artificial fail-highs (yo-yo effect). Fixed: widen only in the failing direction.
  • Mate reduction one-shotis_mate_score() is true on every iteration after a mate is found. reduce_time(0.05) firing repeatedly collapsed the soft limit exponentially (x0.05^N). Fixed: mate_reduction_applied_ one-shot guard.
  • Race condition in cmd_ucinewgame()TT.clear() could race with TT.probe()/TT.store() in the search thread. Fixed: join the search thread first.
  • Castling SAN check/matemove_to_san() returned immediately for castling without checking if it delivers check or mate. Fixed: castling now falls through to the check/mate detection block.
  • seen[] guard mismatch: array enlarged to 1154 slots in 1.2, but the insertion guard still stopped at 1152. Updated to match.
Facón 1.3 - Yunque download from page


Comments