From 0d5d3362ce25615a857bd2202e6ca2776f885e22 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:29:58 +0700 Subject: [PATCH 01/16] Update position.h --- position.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/position.h b/position.h index 482fd33..3e619eb 100644 --- a/position.h +++ b/position.h @@ -396,16 +396,16 @@ template (mv.from_sq()) == PAWN; } - [[nodiscard]] std::string fen() const; + [[nodiscard]] std::string fen(bool xfen=true) const; [[nodiscard]] inline uint8_t halfmoveClock() const { return current_state.halfMoveClock; } [[nodiscard]] inline uint16_t fullmoveNumber() const { return current_state.fullMoveNumber; } [[nodiscard]] inline uint8_t rule50_count() const { return current_state.halfMoveClock; } @@ -428,9 +428,9 @@ template Date: Wed, 25 Mar 2026 10:30:18 +0000 Subject: [PATCH 02/16] Apply clang-format --- position.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/position.h b/position.h index 3e619eb..d8bd924 100644 --- a/position.h +++ b/position.h @@ -396,16 +396,16 @@ template (mv.from_sq()) == PAWN; } - [[nodiscard]] std::string fen(bool xfen=true) const; + [[nodiscard]] std::string fen(bool xfen = true) const; [[nodiscard]] inline uint8_t halfmoveClock() const { return current_state.halfMoveClock; } [[nodiscard]] inline uint16_t fullmoveNumber() const { return current_state.fullMoveNumber; } [[nodiscard]] inline uint8_t rule50_count() const { return current_state.halfMoveClock; } @@ -429,8 +429,8 @@ template Date: Wed, 25 Mar 2026 18:01:09 +0700 Subject: [PATCH 03/16] implemented (non-)permissive FEN parsers --- position.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/position.cpp b/position.cpp index c8bc9ec..3a7b2e0 100644 --- a/position.cpp +++ b/position.cpp @@ -197,7 +197,7 @@ template template void _Position void _Position::setFEN(const std::string &str, bool chess960) { +template void _Position::setFEN(const std::string &str, bool chess960, FENParsingMode mode) { current_state = HistoryEntry(); history.clear(); _chess960 = chess960; @@ -329,6 +329,8 @@ template void _Position::setFEN(const s } return SQ_NONE; }; + bool allow_xfen = (mode == MODE_XFEN || mode == AUTO); + bool allow_smk = (mode == MODE_SMK || mode == AUTO); auto apply = [&](char c) { Square king_sq = findKing(); if (king_sq == SQ_NONE) @@ -368,24 +370,28 @@ template void _Position::setFEN(const s }; if (c == 'K' && color == WHITE) { + INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); if (rook_ks == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_ks)) return; setKS(rook_ks); } else if (c == 'Q' && color == WHITE) { + INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); if (rook_qs == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_qs)) return; setQS(rook_qs); } else if (c == 'k' && color == BLACK) { + INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); if (rook_ks == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_ks)) return; setKS(rook_ks); } else if (c == 'q' && color == BLACK) { + INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); if (rook_qs == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_qs)) @@ -394,6 +400,7 @@ template void _Position::setFEN(const s } else if (c >= 'A' && c <= 'H' && color == WHITE) { + INVALID_ARG_IF(chess960() && !allow_smk, "xfen into shredder fen parser"); File f = static_cast(c - 'A'); Square rook_sq = make_sq(RANK_1, f); @@ -403,6 +410,7 @@ template void _Position::setFEN(const s (f > file_of(king_sq)) ? setKS(rook_sq) : setQS(rook_sq); } else if (c >= 'a' && c <= 'h' && color == BLACK) { + INVALID_ARG_IF(chess960() && !allow_smk, "xfen into shredder fen parser"); File f = static_cast(c - 'a'); Square rook_sq = make_sq(RANK_8, f); @@ -474,7 +482,7 @@ template void _Position::setFEN(const s current_state.repetition = current_state.pliesFromNull = 0; } -template std::string _Position::fen() const { +template std::string _Position::fen(bool xfen) const { std::ostringstream ss; // 1) Piece placement @@ -508,13 +516,17 @@ template std::string _Position::fen() c std::string castlingStr; if (chess960()) { if (castlingRights() & WHITE_OO) - castlingStr += static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_ks)); + castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_ks==SQ_H1)?"K": + static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_ks)); if (castlingRights() & WHITE_OOO) - castlingStr += static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_qs)); + castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_qs==SQ_A1)?"Q": + static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_qs)); if (castlingRights() & BLACK_OO) - castlingStr += static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_ks)); + castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_ks==SQ_H8)?"k": + static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); if (castlingRights() & BLACK_OOO) - castlingStr += static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); + castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_qs==SQ_A8)?"q": + static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); } else { if (castlingRights() & WHITE_OO) castlingStr += 'K'; @@ -858,7 +870,7 @@ template CastlingRights _Position::clea } // clang-format off #define INSTANTIATE(PieceC) \ -template void _Position::setFEN(const std::string &, bool); \ +template void _Position::setFEN(const std::string &, bool, FENParsingMode); \ template std::string _Position::fen() const; \ template void _Position::doMove(const Move &move); \ template void _Position::doMove(const Move &move); \ From 8da283432d4efce23409d278bf37427f9afca606 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 25 Mar 2026 18:01:22 +0700 Subject: [PATCH 04/16] Update position.h --- position.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/position.h b/position.h index d8bd924..7ac4be6 100644 --- a/position.h +++ b/position.h @@ -36,6 +36,9 @@ template struct alignas(64) HistoryEntry { }; enum class CheckType { NO_CHECK, DIRECT_CHECK, DISCOVERY_CHECK }; + +enum FENParsingMode { MODE_XFEN, MODE_SMK, MODE_AUTO }; + enum class MoveGenType : uint16_t { NONE = 0, @@ -396,7 +399,7 @@ template Date: Wed, 25 Mar 2026 11:01:52 +0000 Subject: [PATCH 05/16] Apply clang-format --- position.cpp | 25 +++++++++++++++---------- position.h | 8 ++++++-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/position.cpp b/position.cpp index 3a7b2e0..d8c77af 100644 --- a/position.cpp +++ b/position.cpp @@ -197,7 +197,8 @@ template template void _Position void _Position::setFEN(const std::string &str, bool chess960, FENParsingMode mode) { +template +void _Position::setFEN(const std::string &str, bool chess960, FENParsingMode mode) { current_state = HistoryEntry(); history.clear(); _chess960 = chess960; @@ -330,7 +331,7 @@ template void _Position::setFEN(const s return SQ_NONE; }; bool allow_xfen = (mode == MODE_XFEN || mode == AUTO); - bool allow_smk = (mode == MODE_SMK || mode == AUTO); + bool allow_smk = (mode == MODE_SMK || mode == AUTO); auto apply = [&](char c) { Square king_sq = findKing(); if (king_sq == SQ_NONE) @@ -516,17 +517,21 @@ template std::string _Position::fen(boo std::string castlingStr; if (chess960()) { if (castlingRights() & WHITE_OO) - castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_ks==SQ_H1)?"K": - static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_ks)); + castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_ks == SQ_H1) + ? "K" + : static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_ks)); if (castlingRights() & WHITE_OOO) - castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_qs==SQ_A1)?"Q": - static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_qs)); + castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_qs == SQ_A1) + ? "Q" + : static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_qs)); if (castlingRights() & BLACK_OO) - castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_ks==SQ_H8)?"k": - static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); + castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_ks == SQ_H8) + ? "k" + : static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); if (castlingRights() & BLACK_OOO) - castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_qs==SQ_A8)?"q": - static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); + castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_qs == SQ_A8) + ? "q" + : static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); } else { if (castlingRights() & WHITE_OO) castlingStr += 'K'; diff --git a/position.h b/position.h index 7ac4be6..cda90d7 100644 --- a/position.h +++ b/position.h @@ -432,8 +432,12 @@ template Date: Wed, 25 Mar 2026 19:07:42 +0700 Subject: [PATCH 06/16] Update movegen.cpp --- movegen.cpp | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/movegen.cpp b/movegen.cpp index 5bdfcc5..38ec463 100644 --- a/movegen.cpp +++ b/movegen.cpp @@ -4,7 +4,43 @@ namespace chess { namespace _chess { -#if defined(__AVX512BW__) + +#if defined(USE_AVX512ICL) + +// clang-format off +const __m512i AllSquares = _mm512_set_epi8( + 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, + 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); +// clang-format on + +template +inline Move* splat_pawn_moves(Move* moveList, Bitboard to_bb) { + assert(popcount(to_bb) <= 8); // <= 8 pawns per side + + const __m128i toSquares = + _mm_cvtepi8_epi16(_mm512_castsi512_si128(_mm512_maskz_compress_epi8(to_bb, AllSquares))); + const __m128i fromSquares = _mm_subs_epi16(toSquares, _mm_set1_epi16(offset)); + const __m128i moves = _mm_or_si128(_mm_slli_epi16(fromSquares, 6), + _mm_slli_epi16(toSquares, 0)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(moveList), moves); + return moveList + popcount(to_bb); +} + +inline Move* splat_moves(Move* moveList, Square from, Bitboard to_bb) { + assert(popcount(to_bb) <= 32); // Q can attack up to 27 squares + + const __m512i fromVec = _mm512_set1_epi16(Move(from, SQUARE_ZERO).raw()); + const __m512i toSquares = + _mm512_cvtepi8_epi16(_mm512_castsi512_si256(_mm512_maskz_compress_epi8(to_bb, AllSquares))); + const __m512i moves = _mm512_or_si512(fromVec, _mm512_slli_epi16(toSquares, Move::ToSqShift)); + + _mm512_storeu_si512(moveList, moves); + return moveList + popcount(to_bb); +} + +#elif defined(__AVX512BW__) template struct alignas(64) SplatTable { std::array data; constexpr int clamp64(int x) { return (x < 0) ? 0 : (x > 63 ? 63 : x); } @@ -213,7 +249,7 @@ void movegen::genPawnSingleMoves( } template void movegen::genKnightMoves(const _Position &pos, Movelist &list, Bitboard _pin_mask, Bitboard _check_mask) { - Bitboard knights = pos.template pieces() & ~_pin_mask; // yes, unconditionally. + Bitboard knights = pos.template pieces() & ~_pin_mask; while (knights) { Square x = static_cast(pop_lsb(knights)); Bitboard moves = attacks::knight(x) & ~pos.occ(c); @@ -253,7 +289,6 @@ void movegen::genKingMoves(const _Position &pos, Movelist &out, Bitboar // Enemy king (adjacent control squares) enemyAttacks |= attacks::king(pos.kingSq(them)); - // Candidate king moves = legal squares not attacked by enemy Bitboard moves = attacks::king(kingSq) & ~myOcc & ~enemyAttacks; if constexpr (capturesOnly) moves &= pos.occ(~c); @@ -289,8 +324,7 @@ void movegen::genSlidingMoves( static_assert(pt == BISHOP || pt == ROOK || pt == QUEEN, "Sliding pieces only."); Bitboard sliders = pos.template pieces(); Bitboard occ_all = pos.occ(); - // Square king_sq = current_state.kings[c]; - Bitboard rook_pinners = _rook_pin; // bitboard of enemy rooks/queens pinning + Bitboard rook_pinners = _rook_pin; Bitboard bishop_pinners = _bishop_pin; if constexpr (pt == BISHOP) sliders &= ~rook_pinners; @@ -305,7 +339,6 @@ void movegen::genSlidingMoves( Bitboard bishop_hit = bishop_pinners & from_bb; Bitboard pin_mask = rook_hit ? rook_pinners : bishop_hit ? bishop_pinners : ~0ULL; - // Bitboard blockers = occ() ^ from_bb; // remove piece temporarily auto func = attacks::queen; if constexpr (pt == BISHOP) func = attacks::bishop; From 47133dd28971eb7aba53897e6047e4dd3767ff20 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 25 Mar 2026 12:08:02 +0000 Subject: [PATCH 07/16] Apply clang-format --- movegen.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/movegen.cpp b/movegen.cpp index 38ec463..d92e78a 100644 --- a/movegen.cpp +++ b/movegen.cpp @@ -14,26 +14,22 @@ const __m512i AllSquares = _mm512_set_epi8( 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); // clang-format on -template -inline Move* splat_pawn_moves(Move* moveList, Bitboard to_bb) { - assert(popcount(to_bb) <= 8); // <= 8 pawns per side +template inline Move *splat_pawn_moves(Move *moveList, Bitboard to_bb) { + assert(popcount(to_bb) <= 8); // <= 8 pawns per side - const __m128i toSquares = - _mm_cvtepi8_epi16(_mm512_castsi512_si128(_mm512_maskz_compress_epi8(to_bb, AllSquares))); + const __m128i toSquares = _mm_cvtepi8_epi16(_mm512_castsi512_si128(_mm512_maskz_compress_epi8(to_bb, AllSquares))); const __m128i fromSquares = _mm_subs_epi16(toSquares, _mm_set1_epi16(offset)); - const __m128i moves = _mm_or_si128(_mm_slli_epi16(fromSquares, 6), - _mm_slli_epi16(toSquares, 0)); + const __m128i moves = _mm_or_si128(_mm_slli_epi16(fromSquares, 6), _mm_slli_epi16(toSquares, 0)); - _mm_storeu_si128(reinterpret_cast<__m128i*>(moveList), moves); + _mm_storeu_si128(reinterpret_cast<__m128i *>(moveList), moves); return moveList + popcount(to_bb); } -inline Move* splat_moves(Move* moveList, Square from, Bitboard to_bb) { - assert(popcount(to_bb) <= 32); // Q can attack up to 27 squares +inline Move *splat_moves(Move *moveList, Square from, Bitboard to_bb) { + assert(popcount(to_bb) <= 32); // Q can attack up to 27 squares const __m512i fromVec = _mm512_set1_epi16(Move(from, SQUARE_ZERO).raw()); - const __m512i toSquares = - _mm512_cvtepi8_epi16(_mm512_castsi512_si256(_mm512_maskz_compress_epi8(to_bb, AllSquares))); + const __m512i toSquares = _mm512_cvtepi8_epi16(_mm512_castsi512_si256(_mm512_maskz_compress_epi8(to_bb, AllSquares))); const __m512i moves = _mm512_or_si512(fromVec, _mm512_slli_epi16(toSquares, Move::ToSqShift)); _mm512_storeu_si512(moveList, moves); From 99453fd2cd36c1f69c264ca0533f78776784d323 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 25 Mar 2026 19:09:43 +0700 Subject: [PATCH 08/16] Update try_compile.yml --- .github/workflows/try_compile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/try_compile.yml b/.github/workflows/try_compile.yml index 730a31e..e436057 100644 --- a/.github/workflows/try_compile.yml +++ b/.github/workflows/try_compile.yml @@ -1,7 +1,7 @@ name: Compilation on: - pull_request: + push: jobs: build: From e885bc13aa9afa6e333ee3814cda22feb5b57896 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 25 Mar 2026 19:15:28 +0700 Subject: [PATCH 09/16] Update position.cpp --- position.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/position.cpp b/position.cpp index d8c77af..a417b1c 100644 --- a/position.cpp +++ b/position.cpp @@ -876,7 +876,7 @@ template CastlingRights _Position::clea // clang-format off #define INSTANTIATE(PieceC) \ template void _Position::setFEN(const std::string &, bool, FENParsingMode); \ -template std::string _Position::fen() const; \ +template std::string _Position::fen(bool) const; \ template void _Position::doMove(const Move &move); \ template void _Position::doMove(const Move &move); \ template void _Position::refresh_attacks(); \ From 7564722f0a445bb25bd961e1e4c3c538a52e5785 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:47:34 +0700 Subject: [PATCH 10/16] Update position.cpp --- position.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/position.cpp b/position.cpp index a417b1c..681850f 100644 --- a/position.cpp +++ b/position.cpp @@ -518,19 +518,19 @@ template std::string _Position::fen(boo if (chess960()) { if (castlingRights() & WHITE_OO) castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_ks == SQ_H1) - ? "K" + ? 'K' : static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_ks)); if (castlingRights() & WHITE_OOO) castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_qs == SQ_A1) - ? "Q" + ? 'Q' : static_cast('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_qs)); if (castlingRights() & BLACK_OO) castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_ks == SQ_H8) - ? "k" + ? 'k' : static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); if (castlingRights() & BLACK_OOO) castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_qs == SQ_A8) - ? "q" + ? 'q' : static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); } else { if (castlingRights() & WHITE_OO) From 4377d002801b1455f6d62231afc6c938ba526e19 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:02:58 +0700 Subject: [PATCH 11/16] Update position.cpp --- position.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/position.cpp b/position.cpp index 681850f..8d161bf 100644 --- a/position.cpp +++ b/position.cpp @@ -330,8 +330,8 @@ void _Position::setFEN(const std::string &str, bool chess960, FENPars } return SQ_NONE; }; - bool allow_xfen = (mode == MODE_XFEN || mode == AUTO); - bool allow_smk = (mode == MODE_SMK || mode == AUTO); + bool allow_xfen = (mode == MODE_XFEN || mode == MODE_AUTO); + bool allow_smk = (mode == MODE_SMK || mode == MODE_AUTO); auto apply = [&](char c) { Square king_sq = findKing(); if (king_sq == SQ_NONE) From fcf18a33a21abb1ca9c7abaf9086a38cfcf30532 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:17:03 +0700 Subject: [PATCH 12/16] Update position.cpp --- position.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/position.cpp b/position.cpp index 8d161bf..adbac4a 100644 --- a/position.cpp +++ b/position.cpp @@ -371,28 +371,28 @@ void _Position::setFEN(const std::string &str, bool chess960, FENPars }; if (c == 'K' && color == WHITE) { - INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); + INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser"); if (rook_ks == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_ks)) return; setKS(rook_ks); } else if (c == 'Q' && color == WHITE) { - INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); + INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser"); if (rook_qs == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_qs)) return; setQS(rook_qs); } else if (c == 'k' && color == BLACK) { - INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); + INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser"); if (rook_ks == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_ks)) return; setKS(rook_ks); } else if (c == 'q' && color == BLACK) { - INVALID_ARG_IF(chess960() && !allow_xfen, "shredder fen into xfen parser"); + INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser"); if (rook_qs == SQ_NONE) return; if (rank_of(king_sq) != rank_of(rook_qs)) @@ -401,7 +401,7 @@ void _Position::setFEN(const std::string &str, bool chess960, FENPars } else if (c >= 'A' && c <= 'H' && color == WHITE) { - INVALID_ARG_IF(chess960() && !allow_smk, "xfen into shredder fen parser"); + INVALID_ARG_IF(chess960 && !allow_smk, "xfen into shredder fen parser"); File f = static_cast(c - 'A'); Square rook_sq = make_sq(RANK_1, f); @@ -411,7 +411,7 @@ void _Position::setFEN(const std::string &str, bool chess960, FENPars (f > file_of(king_sq)) ? setKS(rook_sq) : setQS(rook_sq); } else if (c >= 'a' && c <= 'h' && color == BLACK) { - INVALID_ARG_IF(chess960() && !allow_smk, "xfen into shredder fen parser"); + INVALID_ARG_IF(chess960 && !allow_smk, "xfen into shredder fen parser"); File f = static_cast(c - 'a'); Square rook_sq = make_sq(RANK_8, f); From 723475fde238770d2edf7868fc21110b3f70f79c Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:13:53 +0700 Subject: [PATCH 13/16] Update position.h --- position.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/position.h b/position.h index cda90d7..4fd1fc3 100644 --- a/position.h +++ b/position.h @@ -399,7 +399,7 @@ template Date: Fri, 27 Mar 2026 17:02:19 +0700 Subject: [PATCH 14/16] added MSan because tests kept failing for no reason --- .github/workflows/test.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f80f75c..4e1a665 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,11 +51,18 @@ jobs: - name: Configure CMake shell: bash run: | + if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then + if "${{ matrix.cpp_compiler }}" == "clang++" ]]; then + SANITIZERS="memory,undefined" + else + SANITIZERS="address,undefined" + fi + fi cmake -B "${{ steps.vars.outputs.dir }}" \ -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} \ -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} \ -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ - -DSANITIZERS="address,undefined" \ + -DSANITIZERS=${SANITIZERS} \ -DDART_TESTING_TIMEOUT=0 \ -S "${{ github.workspace }}" From f3d0314854607827078b733129d954a1abc0b3ed Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:39:26 +0000 Subject: [PATCH 15/16] use correct FEN format in test --- non_core_tests.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/non_core_tests.cpp b/non_core_tests.cpp index b9536ac..a5116a7 100644 --- a/non_core_tests.cpp +++ b/non_core_tests.cpp @@ -893,9 +893,13 @@ TEST_SUITE("SAN Parser") { } TEST_SUITE("misc tests") { - TEST_CASE("FEN reconstruction") { + TEST_CASE("FEN reconstruction (Chess960)") { Position pos(Position::START_CHESS960_FEN, true); - REQUIRE(pos.fen() == Position::START_CHESS960_FEN); + REQUIRE(pos.fen(false) == Position::START_CHESS960_FEN); + REQUIRE(pos.fen() == Position::START_FEN); + pos.setFEN(Position::START_CHESS960_FEN, true, chess::MODE_SMK); + REQUIRE(pos.fen(false) == Position::START_CHESS960_FEN); + REQUIRE(pos.fen() == Position::START_FEN); } } int main(int argc, char **argv) { From d9b113a9e799a466cad068e794fda2842e509019 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:52:01 +0000 Subject: [PATCH 16/16] bugfix wrong square --- position.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/position.cpp b/position.cpp index adbac4a..d3bdbeb 100644 --- a/position.cpp +++ b/position.cpp @@ -527,7 +527,7 @@ template std::string _Position::fen(boo if (castlingRights() & BLACK_OO) castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_ks == SQ_H8) ? 'k' - : static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs)); + : static_cast('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_ks)); if (castlingRights() & BLACK_OOO) castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_qs == SQ_A8) ? 'q'