Releases: CMCanavessi/facon
Facón 1.6 - Temple
Approximately +250 Elo over 1.5 (Ordo ~2800, Gauntlet 4 n=1040). Direct self-play vs 1.5: +222.8 Elo (n=10000, +/- 7.0) at 10+0.1.
Unlike 1.5, whose gain came almost entirely from a single critical bug fix, 1.6's improvement is a deliberate, broad evaluation overhaul. Every tunable evaluation weight was centralized into a single flat vector and optimized with Texel tuning; the piece-square tables were made phase-tapered (separate middlegame and endgame values); and three new evaluation feature groups were added: pawn shelter/storm, a second king-safety layer, and a positional refinement group covering tempo, bishop outpost, and passed-pawn play. On the infrastructure side, the magic numbers are now hardcoded, making engine startup effectively instant.
The development was strict and incremental: features were added one at a time (or in small thematic groups), each validated by self-play before the next was included, and only measurable gainers were kept. Three conceptually sound features were implemented, tuned, measured, and rejected (rook-behind-passer, non-linear mobility, material imbalance).
Evaluation -- Tuning and Tapering
- Weight centralization: every tunable evaluation weight collected into a single flat array
eval_weights[NUM_WEIGHTS](934 entries), organized into named groups. Previously weights were scattered as named compile-time constants. The array is non-const so the tuner can mutate it; the eval hot path treats it as read-only by convention. - Texel-tuned weight set: the integrated weights were produced by Texel tuning on a labeled quiet-position dataset. Material was modeled as a separate tunable during tuning and folded back into the PSTs afterward, so
PIECE_VALUEstays fixed at 100/320/330/500/900 while the evaluation reproduces the tuned values. - Tapered piece-square tables: each PST square now holds separate middlegame and endgame values, blended by
game_phase(). Lets the tuner express phase-dependent placement (king centralization bad in the middlegame and good in the endgame, advanced pawns worth progressively more as material comes off).
Evaluation -- New Feature Groups
- Pawn shelter / storm: scores the friendly pawn nearest the king on the king's file and the two adjacent files (shelter, bucketed by rank gap), and enemy pawns advancing on those files (storm, bucketed by advancement). Tapered.
- Second king-safety layer: open/semi-open files toward the king (king's file weighted apart from adjacent files) and safe checks (squares an enemy can check from without being captured, per piece type). Complements the attacker-count king safety from earlier versions.
- Tempo (+19 Elo, n=860, LOS 98.5%): a bonus for the side to move, added per the side to move rather than per colour. The single most valuable feature added in 1.6.
- Bishop outpost (+6.6 Elo, n=3480, LOS 93%): a bishop on relative ranks 4-6 on a square no enemy pawn can challenge, with a larger bonus when pawn-supported. Mirrors the knight outpost.
- Passed-pawn refinement (+10.6 Elo as a group, n=6520, LOS 99.94%): king proximity (own king near is good, enemy king near is bad, endgame-weighted), blockade (enemy piece on the stop square; a minor blockades more effectively than a major), free path to promotion, and pawn protection. Computed in a single pass over passed pawns, no NPS cost.
Evaluation -- Trace and Consistency
trace_evaluate()and thetracecommand:trace_evaluate()produces the linear coefficient decomposition of the evaluation (required for Texel tuning); its dot product with the weight vector reproducesevaluate()within the documented tapered-blend rounding tolerance (<=2cp). The newtraceUCI debug command prints the per-weight coefficients and the engine-vs-trace fidelity check.
Infrastructure
- Hardcoded magic numbers: the bishop/rook magics, previously found at startup by a fixed-seed randomized search, are now baked in as constants. Startup time dropped from ~261 ms to ~11 ms (~96% faster) on the Ryzen 7 1700; the generated attacks are bit-identical (bench unchanged at 618952, depth 8). The randomized search is preserved under
#ifdef FACON_REGENERATE_MAGICSfor offline regeneration; not compiled into the normal build.
Build
- Version bumped to 1.6, codename "Temple": the version-string/binary-name logic distinguishes development codenames (suffix carried) from release codenames (no suffix), and the version-selection comments were generalized so they need no editing between development and release.
Features attempted and rejected
- Rook behind passed pawn (Tarrasch rule): -9 Elo (n=3020, LOS 2.9%). Redundant with the rook PST and existing passed-pawn terms.
- Non-linear mobility (per-count tables): -12 Elo (n=5300). Overfit; the linear mobility from 1.4 is more robust at this strength.
- Material imbalance (Kaufman-style, knight/rook/bishop-pair scaled by pawn count): approximately neutral to -5 Elo. The tuning itself signaled redundancy (two of three terms wrong-signed vs theory, tiny magnitudes, error barely moved, optimizer redistributed existing PST/bishop-pair value); self-play confirmed it.
Known limitations
- Drawn pawnless endings evaluated as material (carried from 1.5): K+B vs K, K+N vs K, K+N+N vs K, and K+B+B same-color vs K return the raw material count rather than 0. An override forcing 0 was attempted in 1.5 and reverted after measuring ~30 Elo regression. Proper resolution requires material-signature endgame recognition or tablebase probing, planned for a future version.
Checksums (SHA1)
b38f845e6de27867c9cf08b2f0f4b6d1d9e8f187 facon-1.6
ac61999b8a482173eef5d206fcfac1590b6e78a8 facon-1.6.exe
Facón 1.5 - Espiga
Approximately +220 Elo over 1.4 (Ordo ~2550, G3+G4 combined n=2080). Gauntlet 3 (low-Ordo field, avg ~2310): 800.5/1040 (77.0%, Ordo ~2550). Gauntlet 4 (high-Ordo field, avg ~2680): 345.5/1040 (33.2%, Ordo ~2545). Cross-validation across the two fields confirms the rating within ~5 Elo.
The bulk of the gain comes from fixing a game_phase() inversion that had silently disabled king-safety evaluation in the middlegame since version 1.1 -- the fix in isolation measured +224 Elo at 10+0.1 self-play. The rest of the release adds search refinements (LMP, SEE-aware ordering, IIR, countermove, razoring, TT aging), evaluation refinements (knight outpost two-tier, mopup guard extended to KNN and KBB same-color), and infrastructure improvements (bench rebalanced and deepened, eval debug command, CLI bench mode, observability output).
Search
- Late Move Pruning (LMP): skip late quiet moves at shallow depths in non-PV nodes when enough alternatives have already been searched without raising alpha.
- SEE-aware capture ordering: captures split into GOOD (SEE >= 0, before quiets) and BAD (SEE < 0, after quiets) tiers. Replaces the single MVV-LVA tier from 1.4.
- Internal Iterative Reductions (IIR): non-PV nodes without a TT move at sufficient depth are reduced by 1 ply before searching; the next visit benefits from move ordering.
- Countermove heuristic: third quiet-move ordering tier after killers; remembers the refutation move per opponent (piece, to-square) pair.
- Razoring: at depth 1-2 in non-PV nodes, drop into qsearch if
eval + 250cp <= alpha.
Evaluation
game_phase()inversion fix (carried over from 1.1): the function had been returning the inverse of its documented contract, silently zeroing king-safety in the middlegame and using the endgame king PST from move 1. +224 Elo measured in isolation. Single largest source of strength gain in 1.5.- Knight outpost refactor: previous outpost detection required only that the square not be attackable by enemy pawns. Refactored to two tiers:
KNIGHT_OUTPOST_REACHABLE(10cp, no friendly pawn support) andKNIGHT_OUTPOST_SUPPORTED(25cp, supported by a friendly pawn). - Knight outpost forward_mask fix: the disqualifying forward mask incorrectly included the knight's own rank, causing false-negatives when an enemy pawn sat on the same rank in an adjacent file. Pawns capture diagonally forward, so such pawns cannot attack the knight. Mask now strictly ahead.
- Mopup insufficient material guard extended: now covers K+N+N vs K and K+B+B same-color vs K, in addition to the K+B vs K and K+N vs K cases from 1.4. K+B+B with opposite-colored bishops continues to trigger mopup correctly.
Transposition Table
- TT aging: global generation counter packed into the entry's bound byte. Replacement compares
(age_in_generations * 4) + (stored_depth - new_depth). Smarter eviction keeps the TT relevant across moves without losing meaningful old data. Entry size unchanged at 16 bytes.
Infrastructure
benchdefault depth raised from 15 to 18: more meaningful per-position measurements. Bench signature: 299,881,540 nodes at depth 18 (deterministic, used as no-regression check).benchposition rebalancing: 6 of 10 positions replaced for better time distribution. Per-position share went from 0.01%-38.85% (1.4 set) to 2.7%-16.7% (much more uniform). Each position now carries a label describing the search feature it stresses.bench verboseflag: when present, full search output is emitted. Default (quiet) mode prints only per-position summary and total.- CLI
benchmode: the binary can now be invoked as./facon-1.5 bench [verbose] [depth N](orfacon-1.5.exe bench ...on Windows) to run the benchmark once and exit, without UCI handshake. Useful for automation. evalUCI command: new debug command that prints a per-component breakdown of the static evaluation for the current position. Callsevaluate_verbose()which reproducesevaluate()exactly but accumulates each term separately.- Final summary on aborted iteration: when the search is interrupted mid-iteration, the engine now emits a final UCI
info depthline and a human-readableinfo stringsummary right beforebestmove, capturing total nodes / time / nps that would otherwise be lost between the last heartbeat and the bestmove. currmoveoutput suppressed for first 2 seconds: UCIinfo currmovelines from the root are gated by elapsed time. At shallow depths each move at the root completes in well under a millisecond, producing hundreds of currmove lines per second; suppressing this volume reduces stdout pressure on GUI pipe readers without losing useful information.
Build
- MSVC support removed from CMakeLists.txt: the previous MSVC branch was non-functional because the source uses GCC/Clang builtins directly without wrappers. CMake now rejects MSVC at configure time with
FATAL_ERROR. Native Windows builds should use MinGW-w64. -fomit-frame-pointeradded to Release builds: frees%rbpas a general-purpose register in the hot search/eval paths. Measured ~+2.3% NPS on Ryzen 7 1700 (Zen 1).
Known limitations
- Drawn pawnless endings evaluated as material: KB vs K, KN vs K, KNN vs K, and KBB same-color vs K are theoretically drawn but
evaluate()returns the raw material count (~+330 to ~+660 cp) rather than 0. An override forcing 0 was attempted during 1.5 development but reverted after extended gauntlet testing measured ~30 Elo regression -- the override was technically correct but demotivated the engine from reaching positions whose drawn final endings propagated back through search. Proper resolution requires material-signature endgame recognition or tablebase probing, planned for a future version.
Checksums (SHA1)
f7627bc8d319610b9d607f8349b955201ca152b0 facon-1.5
705aa911390d15bb819d9b792620cf3456bb6c5e facon-1.5.exe
Facón 1.4 - Hoja
+430 Elo over 1.3 (Ordo ~2330, gauntlet 1040 games at 2min+1sec). NPS: +53% (Linux), +92% (Windows).
Search
- Check extension: when in check, extend search depth by 1. Check evasions are now resolved at full depth instead of dropping into quiescence. +30 Elo.
- Static Exchange Evaluation (SEE): full exchange simulation with x-ray discovery. Losing captures pruned in quiescence search. Shortcut: skip SEE for captures where the victim is worth >= the attacker.
- Reverse futility pruning: at depth 1-3, if the static evaluation already exceeds beta by a margin, prune the node without searching. Like NMP without the null search cost.
- Move-level futility pruning: at depth 1-2, skip quiet moves when the static evaluation plus a margin is still below alpha.
- Make/unmake legality: the per-move board copy in
is_legal()(~700 bytes per pseudo-legal move) replaced with make, check, unmake. NPS: +130%. - Move scores computed once: parallel scoring array eliminates O(n^2)
move_score()calls during selection sort. NPS: +9%. - LMR table precalculated: startup-initialized
LMR_table[MAX_PLY][MAX_MOVES]replaces per-nodelog()calls. - Quiet queen promotions in qsearch: pawn pushing to the 8th rank without capturing is now visible to quiescence search.
- Forced move instant-play: only one legal move = play immediately with zero search time.
Evaluation
- Piece mobility: pseudo-legal squares per piece, excluding own pieces and enemy pawn attacks. Knight 4cp, bishop 5cp, rook 2cp, queen 1cp per square.
- Open/semi-open files: rook bonuses for files with no pawns (+20cp) or no friendly pawns (+10cp).
- Rook on 7th rank: +20cp bonus.
- Bishop pair: +30cp when both bishops present.
- Knight outposts: +20cp for knights on ranks 4-6 that cannot be attacked by enemy pawns.
Transposition Table
- Depth-preferred replacement: shallow entries for different positions no longer evict deeper entries.
- TTEntry::depth int8_t to uint8_t: fixes overflow at MAX_PLY (128).
Time Management
- Base time budget increased (MOVES_TO_GO 30 to 25).
- Progressive easy-move reduction (x0.95 per stable iteration, cumulative, cancellable).
- AW fail-high time extension (proportional to fail-high count, capped at x1.50).
- Time cap relaxed (remaining/3 to remaining*2/5).
- Mate reduction only when winning (no longer triggers when being mated).
- TM extensions now always run before checking soft_stop().
go depth Xwithout clock no longer activates TM.movestogoUCI parameter now parsed and used.
Infrastructure
benchcommand: 10 positions, depth 15 default. Quiet by default,bench verbosefor full output.FACON_DEBUGbuild mode: diagnostic counters compiled only with-DFACON_DEBUG=ON.
Checksums (SHA1)
09f0fba11511470f8b06102a8f118293ef94fe4e facon-1.4
a8815dbc6e952bceee4f5f7c7478f96eb3c7c18b facon-1.4.exe
Facón 1.3 - Yunque
+200 Elo over 1.2 (Ordo ~1900, gauntlet 1040 games at 2min+1sec)
Pre-work bug fixes
- NMP depth floor (
search.cpp): atdepth == NMP_MIN_DEPTH(3), the NMP recursive call produced depth -1. With the correcteddepth == 0quiescence entry condition, this caused infinite recursion. Fixed:std::max(0, depth - 1 - NMP_REDUCTION). depth <= 0todepth == 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 heuristic:
history_[color][from][to]incremented bydepth^2on beta cutoffs. Replaces the flatORDER_QUIET=0score for quiet move ordering, improving LMR accuracy. Capped at 50,000 (belowORDER_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 scaling:
extend_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 system:
PROJECT_VERSIONandFACON_CODENAMEin CMakeLists.txt control the binary name, startup banner, UCI id, and Windows version resource. To release: change codename from"dev"to"Yunque"and recompile. perftcommand:perft Ncounts leaf nodes,perft divide Ngives per-move breakdown. Bulk-counting at depth 1. Verified: startpos depth 5 = 4,865,609.bitboard.cppinit 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-shot:
is_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 withTT.probe()/TT.store()in the search thread. Fixed: join the search thread first. - Castling SAN check/mate:
move_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.
Checksums (SHA1)
a8a681ae3c6129205f9e98bcc86adadf2d33b70a facon-1.3
3d51dc6625f69ca24d62d02d6cd72a67c254bb06 facon-1.3.exe
Facón 1.2 - Rojo Vivo
+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.hashwas 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 movinghash = st.hashto the last line ofunmake_move().make_null_move()full-move counter corruption:unmake_null_move()decrementedfull_move_numberwhen Black made a null move, butmake_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:
gonow launches the search in a dedicated thread. The UCI loop returns immediately and can processstopwhile searching. Previouslystopwas 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 frommain()after the banner.
Time Management
- Time forfeit fix: engine was losing games on time. Fixed:
HARD_FACTOR3.0 → 2.0,SAFETY_FACTOR0.95 → 0.90,OVERHEAD_MS = 100subtracted upfront, hard limit capped atremaining/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 asinfo stringfor TM diagnostics at long time controls.
Observability
- currmove/currmovenumber: each root move emits a standard UCI
info currmoveline 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 stringwith move in SAN, score, depth, and timestamp. - Heartbeat: if no output has been emitted for 5 minutes, a standard
infoline plus a status string are emitted. Distinguishes a deep search from a crash at long time controls.
Code audit fixes
- Quiescence time check:
quiescence()checkedstats_.nodes(negamax-only counter) for its periodic time check. During deep capture sequences the check never fired. Fixed: usesstats_.qnodes. - Nodes / NPS reporting: all UCI output reported only negamax nodes, excluding quiescence. In tactical positions this caused severe underreporting. Fixed: all output now uses
stats_.nodes + stats_.qnodes. - PV
seen[]array size: off-by-one in the theoretical worst case. Fixed:seen[MAX_GAME_HISTORY + MAX_PLY + 2].
Checksums (SHA1)
2b02adc2dee72ada51a35b2c96134e7862d43f71 facon-1.2
c4710908026a479e4fa81ae076699db1c4a4bf78 facon-1.2.exe
Facón 1.1 - Herrumbre
+120 Elo over 1.0 (gauntlet testing vs field Elo ~1358, 1040 games at 2min+1sec)
Search
- Killer move heuristic: quiet moves that cause a beta cutoff are stored per-ply (two slots per node) and tried before other quiet moves in sibling nodes. Improves move ordering in quiet positions where MVV-LVA has no effect.
- Dynamic time management: replaced the fixed time budget with a soft/hard limit model. The soft limit is extended when the PV move changes between iterations (×1.5) or the score drops by ≥30 centipawns (×1.25). The hard limit acts as an absolute ceiling.
- seldepth tracking: maximum depth reached including quiescence search is tracked and reported in the UCI info line each iteration.
Evaluation
- King safety: penalty for enemy pieces attacking the king zone (king square plus adjacent squares). Attack weights: Knight=2, Bishop=2, Rook=3, Queen=5 (queens counted twice — once as diagonal, once as straight attacker). Penalty grows quadratically with total weight and scales with game phase (middlegame only).
Stability
- Abort flag (
abort_search_): when the hard time limit is hit inside the search, a flag is set and every level of the call stack returns immediately. Ensures allunmake_move()calls execute, leaving the board consistent for the next search. - Root best move tracking (
root_best_move_): the best move at ply 0 is saved directly insidenegamax()whenever a new best is found. Eliminatesbestmove 0000outputs. is_legal()piece ownership check: verifies that the from-square contains a piece belonging to the side to move before the expensive board copy. Eliminates ghost moves from stale TT entries.- TT move validation: TT moves are verified against the generated move list before use. Prevents hash collisions from inserting garbage into move ordering.
- TT pollution prevention: if
abort_search_is set when returning from a child node, the result is discarded without storing to the TT. safe_movepre-seed: the first legal move is stored as a fallback before iterative deepening begins. Guaranteesbestmoveis never0000even if depth 1 is aborted.
Cleanup
probe_move()removed fromtt.h/tt.cpp(dead code).- Non-ASCII characters removed from all source files.
- All source file headers updated to
Facon 1.1 — Herrumbre.
Checksums (SHA1)
231d9973d9f1062a40b6b39c4ac3f3ea872efcd6 facon-1.1
028e1671bf4fcad4fe19c1f5876e216709daf924 facon-1.1.exe
Facón 1.0 - Óxido
Changelog
All notable changes to Facón will be documented here.
[1.0] "Óxido" — 2026-03-05
Initial public release.
Engine
- Bitboard board representation with redundant piece array for O(1) square queries
- Magic bitboards for sliding piece attack generation (rooks, bishops, queens)
- Zobrist hashing with incremental updates on make/unmake
- Full make/unmake move stack supporting any game length
- Draw detection: threefold repetition and 50-move rule
Move Generation
- Complete pseudo-legal move generation for all piece types
- Separate capture-only generator for quiescence search
- Handles all special moves: castling, en passant, promotions (all four pieces)
Search
- Negamax alpha-beta with iterative deepening
- Quiescence search at leaf nodes
- Transposition table (Zobrist hash, 16 MB default, configurable via UCI)
- Move ordering: TT move first, then MVV-LVA for captures, then quiet moves
- Time management with Fischer clock support and movetime override
Evaluation
- Material count (P=100, N=320, B=330, R=500, Q=900)
- Piece-square tables for all piece types
- King safety interpolated between middlegame and endgame tables based on remaining material
UCI
- Full UCI protocol support
- Supported commands:
uci,isready,ucinewgame,position,go,stop,setoption,quit - Supported options:
Hash(transposition table size in MB) - Debug command:
d(display current board)
Build
- CMake build system
- Linux native build (GCC/Clang, C++17)
- Windows cross-compilation via MinGW-w64
- Statically linked Windows binary (no DLL dependencies)