From ead7e650da1dd07a2614ba4d8207470fe921a87b Mon Sep 17 00:00:00 2001 From: anematode Date: Thu, 9 Apr 2026 21:43:44 +0200 Subject: [PATCH] Fix weird indexing bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Passed STC](https://tests.stockfishchess.org/tests/live_elo/69cf6a5d1668971c9da23ae1) LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 51104 W: 13376 L: 13180 D: 24548 Ptnml(0-2): 134, 5555, 13963, 5781, 119 [Passed LTC](https://tests.stockfishchess.org/tests/live_elo/69d00a7ee2b443cb2670b5c6) LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 101256 W: 25867 L: 25732 D: 49657 Ptnml(0-2): 59, 10423, 29520, 10576, 50 When processing a promotion we add/remove nonsensical threats, namely, piece threats of pawns on the 1st or 8th rank. This is not only inefficient but also seems to lead to an obscure bug during a promotion–capture + `double_inc_update` that causes a lingering invalid feature. Currently – as an artifact of the training process – these parts of the net are filled with random values in [-1,1], which is why there is a bench change. @ces42 did a helpful analysis: > checking bench with depth 17 actually shows that the bug in has been there all the time since 8e5392d7 (when threat inputs was merged into master) > i.e. double_inc_update for ThreatFeatureSet has always been slightly bugged After this patch is applied we'll be able to better compress the net by filling the invalid features with 0, w/o changing bench. I expect a 15%-ish size savings. closes https://github.com/official-stockfish/Stockfish/pull/6701 Bench: 2700393 --- src/position.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index d9d57c0b3..fa732836c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -966,13 +966,22 @@ void Position::do_move(Move m, // Move the piece. The tricky Chess960 castling is handled earlier if (m.type_of() != CASTLING) { + Piece toPc = pc; + if (m.type_of() == PROMOTION) + toPc = make_piece(us, m.promotion_type()); + if (captured && m.type_of() != EN_PASSANT) { remove_piece(from, &dts); - swap_piece(to, pc, &dts); + swap_piece(to, toPc, &dts); } - else + else if (pc == toPc) move_piece(from, to, &dts); + else + { + remove_piece(from, &dts); + put_piece(toPc, to, &dts); + } } // If the moving piece is a pawn do some special extra work @@ -1011,8 +1020,6 @@ void Position::do_move(Move m, assert(relative_rank(us, to) == RANK_8); assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN); - swap_piece(to, promotion, &dts); - dp.add_pc = promotion; dp.add_sq = to; dp.to = SQ_NONE;