<feed xmlns='http://www.w3.org/2005/Atom'>
<title>typhoon.git/src/board_representation/MIGRATION.md, branch master</title>
<subtitle>The typhoon chess playing engine.
</subtitle>
<id>https://git.acknak.org/cgit/typhoon.git/atom?h=master</id>
<link rel='self' href='https://git.acknak.org/cgit/typhoon.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/'/>
<updated>2026-09-04T16:55:15Z</updated>
<entry>
<title>Add seescores diagnostic command, verify zero SEE-value drift</title>
<updated>2026-09-04T16:55:15Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-09-04T16:55:15Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=550ea81a5a2ee2561c3feb91dc55686f4d3cb872'/>
<id>urn:sha1:550ea81a5a2ee2561c3feb91dc55686f4d3cb872</id>
<content type='text'>
Board-representation migration section 4 item 4: seescores &lt;filename&gt;
(command.c, registered alongside script/sd) reads setboard lines from
an EPD file (same convention tests/ecm*.ep_ already use), generates
legal moves per position, and prints (FEN, SAN move, SEE value) for
every capture -- meant to be run once per GetAttacksBB toggle state
and diffed, closing a gap TestGetAttacks's attacker-list comparison
can't: whether _GetAttacksBB's attacker lists, though set-identical to
asm GetAttacks, still produce identical SEE() output once fed through
_MinLegalPiece's exchange simulation.

Run against all three curated suites (747 captures total: 51 + 351 +
345), same-commit asm-vs-GETATTACKS_BITBOARD=1 A/B build (same pair
used for the earlier sd10 comparison) -- output byte-identical, zero
diff, on all three. Confirms _GetAttacksBB is correct all the way
through to the final SEE() score every move-ordering decision actually
uses, not just at the raw attacker-list level.

precommit_check.sh clean. Default (no flag) release binary restored
after testing.

Only match_play.py remains unmet before full retirement of the old
mailbox GetAttacks implementation (section 7) -- deliberately deferred,
not run this pass.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2
</content>
</entry>
<entry>
<title>Record whole-engine sd10 results: zero solve regression, +8.38% NPS</title>
<updated>2026-09-04T16:50:57Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-09-04T16:50:57Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=5c3e541b3bf62704eb8950441646deacaea6f887'/>
<id>urn:sha1:5c3e541b3bf62704eb8950441646deacaea6f887</id>
<content type='text'>
Board-representation migration section 4 item 5 / section 5 item 2 /
section 7: ran all three curated suites (ecm_ringers,
ecm_confident_quick, ecm_hard_quick) at sd10, same commit built twice
(default asm GetAttacks vs. GETATTACKS_BITBOARD=1), rather than against
the checked-in head_reference/ binary -- that binary predates this
branch's sections 1-6 by a dozen-plus unrelated commits, so diffing
against it would have conflated this change with everything else on
the branch. Isolating the single variable (same commit, one flag
flipped) is the correct comparison here.

Results: solve counts bit-identical on all three suites (10/11, 83/90,
25/90) -- zero regression. Node counts up slightly (+0.36% to +1.24%),
the expected "same attacker set, not necessarily same order" effect on
move-ordering tie-breaking already flagged in this document; didn't
cost a single solve. Aggregate (total nodes / total script time across
all three suites): +8.38% wall-clock NPS (1,164,842 -&gt; 1,262,490),
comfortably absorbing the extra nodes -- confirms section 3's isolated
cycles/call benchmark reflects a real end-to-end win, not an artifact
of the isolated harness.

match_play.py (the remaining section 7 criterion) deliberately
deferred, not run this pass.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2
</content>
</entry>
<entry>
<title>Add GETATTACKS_BITBOARD toggle, wiring _GetAttacksBB into real search</title>
<updated>2026-09-04T16:37:45Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-09-04T16:37:45Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=1f638f87d8afb0334bf05dda10dc13b4c7a60b62'/>
<id>urn:sha1:1f638f87d8afb0334bf05dda10dc13b4c7a60b62</id>
<content type='text'>
Board-representation migration section 6: a GNUmakefile build flag
(-DGETATTACKS_BITBOARD) makes chess.h's GetAttacks macro resolve to
_GetAttacksBB instead of the real asm implementation (or SlowGetAttacks
under CROUTINES) -- a three-way choice at the same spot the existing
CROUTINES switch already lived. _GetAttacksBB is now reachable from
every real call site (generate.c's check-detection call, see.c's
SEE(), searchsup.c), not just the test/bench harness.

Found and fixed while verifying this: testsee.c's TestGetAttacks and
its benchmark call the identifier GetAttacks meaning "the real
asm/CROUTINES baseline" -- once the macro could resolve to
_GetAttacksBB, those calls would silently compare the new
implementation against itself, turning both the correctness sweep and
the benchmark into false-positive no-ops. Fixed with a local #undef
GetAttacks right after #include "chess.h" in testsee.c, so the harness
always validates against the true baseline regardless of which
implementation is live in production.

Verified: gmake TEST=1 GETATTACKS_BITBOARD=1 passes (self-test suite,
corrected benchmark still reporting real asm vs. _GetAttacksBB
correctly, and a real Search() call exercising _GetAttacksBB live).
precommit_check.sh GETATTACKS_BITBOARD=1 clean for both the TEST=1
self-test and DEBUG=1 smoke test. Default (no flag) build confirmed
unaffected -- GetAttacks still resolves to the real asm function.

See board_representation/MIGRATION.md section 6 for the full writeup.
Sections 4/5/7's remaining items (curated-suite sd10 comparison,
match_play.py gate) are now unblocked but not yet run.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2
</content>
</entry>
<entry>
<title>Drop CountKingSafetyDefects from board-representation migration plan</title>
<updated>2026-09-04T16:27:35Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-09-04T16:27:35Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=cc83e8d355c7adadfbd09228b76eecbaf1c6d53c'/>
<id>urn:sha1:cc83e8d355c7adadfbd09228b76eecbaf1c6d53c</id>
<content type='text'>
Descope CountKingSafetyDefects entirely, per discussion after landing
GetAttacks's half of section 3: the two functions no longer share
enough to justify one plan. CountKingSafetyDefects (eval.c:2325) turns
out to do no ray-walk/blocker check at all -- it's an unblocked
CHECK_VECTOR proximity heuristic, not a true attack query -- so
_WhoAttacksSquareBB's blocker-aware result isn't a value-identical
drop-in for it; making it bitboard-backed would be a real behavior
change (needing eval re-tuning/re-gating), not a reimplementation, and
a materially different, riskier project than this one.

eval.c is untouched. If CountKingSafetyDefects work happens later, it
should be a new, separate migration document starting from its actual
(unblocked heuristic) behavior, not a resumption of this one.

Also updates section 4-7 status notes to reflect what's actually done
vs. still blocked on section 6's toggle (GetAttacks alone, no longer
entangled with a king-safety timeline).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2
</content>
</entry>
<entry>
<title>Add bitboard-backed GetAttacks (section 2/3), verified faster than asm</title>
<updated>2026-09-04T16:22:46Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-09-04T16:22:46Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=be420bb8d1d5d16a4e24ab6fd706a5ae898eaa85'/>
<id>urn:sha1:be420bb8d1d5d16a4e24ab6fd706a5ae898eaa85</id>
<content type='text'>
Board-representation migration, sections 2-3 (GetAttacks half):

- board.c: VerifyPositionConsistency's bbPieces consistency check
  (migration section 2), verified clean via gmake TEST=1 with the
  assert live.
- POSITION.bbPawns[2]: new incrementally-maintained per-color pawn
  location bitboard (chess.h), maintained at the same 6 move.c sites
  as bbPieces, populated from scratch in fen.c. Distinct from the
  pawn-hash-keyed bbPawnLocations; this one needs no
  SEARCHER_THREAD_CONTEXT, so it's reachable from GetAttacks's actual
  call sites (which only ever have a POSITION*).
- data.c/chess.h/main.c: g_RookRayAll/g_BishopRayAll (all 4 per-square
  ray directions pre-ORed) and g_PawnAttackOriginBB[2][128] startup
  tables, plus FastFirstBit/FastLastBit (static inline bsf/bsr
  wrappers, chess.h) -- supporting tables/helpers for the primitive
  below.
- see.c: _WhoAttacksSquareBB (bitboard "who attacks square X" query)
  and _GetAttacksBB (SEE_LIST-populating PoC wrapping it), side by
  side with the existing SlowGetAttacks/asm GetAttacks -- not wired
  into the GetAttacks macro yet (section 6), pure addition.
- testsee.c: SeeListsAreEqual made order-independent (SEE() sorts the
  list right after GetAttacks returns, so order was never semantically
  significant); TestGetAttacks extended to run _GetAttacksBB as a
  third comparison across the existing 20,000-random-position sweep;
  added an interleaved asm/Slow/BB cycles-per-call benchmark across
  opening/middlegame/endgame positions.
- testsup.c: fixed GenerateRandomLegalPosition (used by the sweep
  above) to maintain bbPieces/bbPawns at its two hand-placement sites
  -- a latent gap since section 1 that made its own
  VerifyPositionConsistency legality gate almost always reject
  generated positions, causing large, variable retry-loop slowdowns.

Verified: 20,000-position x every-square x both-colors correctness
sweep passes (gmake TEST=1), precommit_check.sh clean (self-test +
DEBUG smoke test). Benchmark: _GetAttacksBB is ~0.53-0.55x asm
GetAttacks's cycles/call (opening/middlegame) and ~0.89x (endgame) --
faster, not just equivalent, primarily from replacing bbOccupied's
up-to-16-iteration pawn loop with two bbPawns ORs, plus a
g_PawnAttackOriginBB table lookup replacing per-call pawn-delta
arithmetic and per-direction/per-side-group early-outs in the slider
walk. See board_representation/MIGRATION.md section 3 for the full
writeup, including a reverted approach that measured slower and why,
and the CountKingSafetyDefects half's re-scoped (not yet implemented)
design.

Also confirmed (not caused by this work, not fixed here): a
pre-existing non-deterministic MP-race assertion in util.c:1093's PV
printing, reproduced independently on a clean HEAD checkout.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2
</content>
</entry>
<entry>
<title>Add bbPieces incremental piece-location bitboards (migration plan section 1)</title>
<updated>2026-09-04T08:27:59Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-09-04T08:27:59Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=6c045be8a37a8eae1ea6aed250944e22af2335a1'/>
<id>urn:sha1:6c045be8a37a8eae1ea6aed250944e22af2335a1</id>
<content type='text'>
Board-representation migration, section 1: add POSITION.bbPieces[2][8]
(per-color, per-piece-type location bitboards, indexed like the
existing uNonPawnCount) as incrementally-maintained state, not a
per-Eval()-call rebuild -- the structural fix for why the earlier
attack-presence-bitboard work measured slower, not faster.

- chess.h: bbPieces[2][8] field; extern decls for data.c's
  g_RookRayToEdge/g_BishopRayToEdge/g_KnightAttacksBB ray tables and
  their Initialize* functions (needed by the planned bitboard-backed
  GetAttacks/CountKingSafetyDefects primitive, section 3).
- fen.c: populate bbPieces during piece placement; zeroing is free via
  the existing memset(p, 0, sizeof(POSITION)).
- move.c: maintain bbPieces at all 6 non-pawn piece-movement functions
  (SlidePiece/LiftPiece/PlacePiece and their WithoutSigs siblings used
  by UnmakeMove) -- covers every move type: normal moves, captures,
  both-side castling, promotion with/without capture, en passant, and
  every undo.
- board.c: extend VerifyPositionConsistency's existing non-pawn
  piece-list walk with a parallel bbPieces reconstruction-and-compare,
  rather than a separate bespoke check.
- data.c/main.c: pulled ray-to-edge/knight-attack tables from stash
  (needed by section 3, not section 1 itself, but zero-risk to land
  now).

Also, while verifying: COOR_TO_BB was a table lookup (BBSQUARE[idx])
measured ~5-7% slower than the pure-ALU shift already sitting unused in
SLOWCOOR_TO_BB (whose "SLOW" name reflects a stale assumption about
variable shifts never actually tested on this hardware). Switched
COOR_TO_BB to the shift; fixed testbitboard.c's existing but broken
(dead-code-eliminated, silently reporting "0 cycles/op") comparison
benchmark for both while at it.

Verified via gmake TEST=1 (including TestMakeUnmakeMove's explicit
en-passant/promotion-with-capture/both-castling coverage) and
debug_smoke_test.sh, both clean; release build clean and runs normally.
Nothing reads bbPieces yet -- pure addition, zero behavioral risk.

See board_representation/MIGRATION.md for the full plan.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2
</content>
</entry>
</feed>
