From d5e0cd8e05e4ce0c99e8e2b8915c41d3839e01e8 Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Wed, 10 Dec 2025 17:27:33 +0700 Subject: [PATCH 01/15] feat(moves): add support for SAN notation parsing and generation - Implement parseSan function to parse Standard Algebraic Notation moves - Add moveToSan function to convert moves to SAN strings - Introduce IllegalMoveException and AmbiguousMoveException for error handling - Refactor code by moving squares_between_bb generation to attacks.cpp - Update parse_square to handle invalid inputs gracefully - Fix copy constructor in position.h and adjust is_castling method - Reorganize and update test cases in tests.cpp - Add new non_core_tests.cpp file for additional tests - Enhance CMakeLists.txt with new test executable - [critical] Hotfix for #29 for implementation-defined global initialization routine This adds comprehensive SAN support, improving move input/output capabilities for better chess engine integration, and fix a UB of the library --- .github/workflows/cmake-multi-platform.yml | 4 +- CMakeLists.txt | 8 +- attacks.cpp | 26 +- movegen.cpp | 51 +- moves_io.cpp | 363 +++- moves_io.h | 24 +- non_core_tests.cpp | 892 ++++++++ position.cpp | 28 +- position.h | 8 +- tests.cpp | 2167 +++++++++----------- types.h | 14 +- 11 files changed, 2260 insertions(+), 1325 deletions(-) create mode 100644 non_core_tests.cpp diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index d2605c9..c0d9094 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -75,7 +75,7 @@ jobs: shell: bash run: | if [[ "${{ matrix.os }}" == "windows-latest" ]]; then - ctest --build-config ${{ matrix.build_type }} --verbose + ctest --build-config ${{ matrix.build_type }} --verbose -j 4 else - ctest --verbose + ctest --verbose -j 4 fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 4355ccb..a3a3c50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,12 @@ FetchContent_MakeAvailable(doctest) add_executable(test_chess tests.cpp ) +add_executable(NonImportantTests + non_core_tests.cpp +) target_link_libraries(test_chess PRIVATE chesslib) target_include_directories(test_chess PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${doctest_SOURCE_DIR}) -add_test(NAME tests COMMAND test_chess) \ No newline at end of file +target_link_libraries(NonImportantTests PRIVATE chesslib) +target_include_directories(NonImportantTests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${doctest_SOURCE_DIR}) +add_test(NAME test_core COMMAND test_chess) +add_test(NAME api_tests COMMAND NonImportantTests) \ No newline at end of file diff --git a/attacks.cpp b/attacks.cpp index 7bf56ae..9c0b1e8 100644 --- a/attacks.cpp +++ b/attacks.cpp @@ -167,4 +167,28 @@ _POSSIBLY_CONSTEXPR std::pair, std::array(); _POSSIBLY_CONSTEXPR std::array RookTable = rookData.first; _POSSIBLY_CONSTEXPR std::array RookAttacks = rookData.second; -} // namespace chess::attacks \ No newline at end of file +} // namespace chess::attacks +namespace chess::movegen{ +inline static Bitboard att(PieceType pt, Square sq, Bitboard occ) { + return (pt == BISHOP) ? chess::_chess::_HyperbolaBishopAttacks(sq, occ) : chess::_chess::_HyperbolaRookAttacks(sq, occ); +} + +inline static std::array, 64> generate_between() { + assert(att(BISHOP, SQ_A1, 0)==9241421688590303744ULL&&"Well... this is a debug message, but this is a landmine that the magic bitboards are NOT initialized before this, wontwork\n"); + std::array, 64> squares_between_bb{}; + + for (int sq1 = 0; sq1 < 64; ++sq1) { + for (PieceType pt : { BISHOP, ROOK }) { + for (int sq2 = 0; sq2 < 64; ++sq2) { + if (att(pt, Square(sq1), 0) & (1ULL << sq2)) { + squares_between_bb[sq1][sq2] = att(pt, Square(sq1), 1ULL << (sq2)) & att(pt, Square(sq2), 1ULL << (sq1)); + } + squares_between_bb[sq1][sq2] |= 1ULL << (sq2); + } + } + } + + return squares_between_bb; +} + std::array, 64> SQUARES_BETWEEN_BB = generate_between(); +} \ No newline at end of file diff --git a/movegen.cpp b/movegen.cpp index 53cf242..64f463b 100644 --- a/movegen.cpp +++ b/movegen.cpp @@ -435,37 +435,28 @@ template Move *chess::_chess::splat_pawn_moves(Move *, Bitboard); Movelist &, \ Bitboard, \ Bitboard, \ - Bitboard); \ - template void chess::movegen::genKnightMoves(const _Position&, Movelist&, Bitboard, Bitboard); \ - template void chess::movegen::genKnightMoves(const _Position&, Movelist&, Bitboard, Bitboard); \ - template void chess::movegen::genKnightMoves(const _Position&, Movelist&, Bitboard, Bitboard); \ - template void chess::movegen::genKnightMoves(const _Position&, Movelist&, Bitboard, Bitboard); \ - template void chess::movegen::genKingMoves(const _Position&, Movelist&); \ - template void chess::movegen::genKingMoves(const _Position&, Movelist&); \ - template void chess::movegen::genKingMoves(const _Position&, Movelist&); \ - template void chess::movegen::genKingMoves(const _Position&, Movelist&); + Bitboard); \ + template void chess::movegen::genKnightMoves(const _Position &, \ + Movelist &, \ + Bitboard, \ + Bitboard); \ + template void chess::movegen::genKnightMoves(const _Position &, \ + Movelist &, \ + Bitboard, \ + Bitboard); \ + template void chess::movegen::genKnightMoves(const _Position &, \ + Movelist &, \ + Bitboard, \ + Bitboard); \ + template void chess::movegen::genKnightMoves(const _Position &, \ + Movelist &, \ + Bitboard, \ + Bitboard); \ + template void chess::movegen::genKingMoves(const _Position &, Movelist &); \ + template void chess::movegen::genKingMoves(const _Position &, Movelist &); \ + template void chess::movegen::genKingMoves(const _Position &, Movelist &); \ + template void chess::movegen::genKingMoves(const _Position &, Movelist &); INSTANTIATE(EnginePiece) INSTANTIATE(PolyglotPiece) INSTANTIATE(ContiguousMappingPiece) -inline static Bitboard att(PieceType pt, Square sq, Bitboard occ) { - return (pt == BISHOP) ? attacks::bishop(sq, occ) : attacks::rook(sq, occ); -} - -inline static std::array, 64> generate_between() { - std::array, 64> squares_between_bb{}; - - for (int sq1 = 0; sq1 < 64; ++sq1) { - for (PieceType pt : { BISHOP, ROOK }) { - for (int sq2 = 0; sq2 < 64; ++sq2) { - if (att(pt, Square(sq1), 0) & (1ULL << sq2)) { - squares_between_bb[sq1][sq2] = att(pt, Square(sq1), 1ULL << (sq2)) & att(pt, Square(sq2), 1ULL << (sq1)); - } - squares_between_bb[sq1][sq2] |= 1ULL << (sq2); - } - } - } - - return squares_between_bb; -} -std::array, 64> movegen::SQUARES_BETWEEN_BB = generate_between(); } // namespace chess \ No newline at end of file diff --git a/moves_io.cpp b/moves_io.cpp index 649828f..1f197fb 100644 --- a/moves_io.cpp +++ b/moves_io.cpp @@ -3,7 +3,13 @@ #include "types.h" #include #include +#include #include +#if defined(__EXCEPTIONS) && defined(_DEBUG) +#define THROW_IF_EXCEPTIONS_ON(stuff) throw stuff +#else +#define THROW_IF_EXCEPTIONS_ON(stuff) ((void)0) +#endif namespace chess { namespace uci { std::string squareToString(Square sq) { @@ -15,7 +21,7 @@ std::string squareToString(Square sq) { }; return std::string{ fileChars[sq] }; } -std::string moveToUci(const Move &mv) { +std::string moveToUci(Move mv) { if (!mv.is_ok()) { // null move static const std::string nullMove = "0000"; @@ -45,9 +51,8 @@ std::string moveToUci(const Move &mv) { default: #if defined(_DEBUG) || !defined(NDEBUG) assert(false && "this isn't chess960"); -#elif defined(__EXCEPTIONS) - throw std::invalid_argument("this isn't chess960"); #else + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("this isn't chess960")); break; #endif } @@ -62,14 +67,9 @@ std::string moveToUci(const Move &mv) { } return move; } -template Move uciToMove(const _Position &pos, std::string uci) { - return uciToMove(pos, std::string_view(uci)); -} template Move uciToMove(const _Position &pos, std::string_view uci) { if (uci.length() < 4) { -#ifdef __EXCEPTIONS - throw std::invalid_argument("example: a2a4"); -#endif + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("example: a2a4 or d7d8q")); return Move::NO_MOVE; } @@ -77,16 +77,13 @@ template Move uciToMove(const _Position &pos, std Square target = parse_square(uci.substr(2, 2)); if (!is_valid(source) || !is_valid(target)) { -#ifdef __EXCEPTIONS - throw std::invalid_argument("source: [a1, h8], target: [a1, h8]"); -#endif + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("source !in [a1, h8], target !in [a1, h8]")); return Move::NO_MOVE; } auto pt = piece_of(pos.at(source)); if (pt == NO_PIECE_TYPE) { -#ifdef __EXCEPTIONS - throw std::invalid_argument("source need to be a existing piece, got nothing"); -#endif + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("source need to be a existing piece, got nothing")); + return Move::NO_MOVE; } if (pt == KING && square_distance(target, source) == 2) { target = make_sq(target > source ? File::FILE_H : File::FILE_A, rank_of(source)); @@ -104,8 +101,8 @@ template Move uciToMove(const _Position &pos, std if (promotion == NO_PIECE_TYPE || promotion == KING || promotion == PAWN) { #if defined(_DEBUG) || !defined(NDEBUG) assert(false && "promotions: NRBQ"); -#elif defined(__EXCEPTIONS) && (defined(_DEBUG) || !defined(NDEBUG)) - throw std::invalid_argument("promotions: NRBQ"); +#else + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("promotions: NRBQ")); #endif return Move::NO_MOVE; } @@ -118,15 +115,341 @@ template Move uciToMove(const _Position &pos, std auto it = std::find(moves.begin(), moves.end(), move); #if defined(_DEBUG) || !defined(NDEBUG) assert(it != moves.end() && "Move is illegal"); -#elif defined(__EXCEPTIONS) +#else if (it == moves.end()) - throw std::invalid_argument("Move is illegal"); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("Move is illegal")); #endif return move; } +template Move parseSan(const _Position &pos, std::string_view raw_san, bool remove_illegals) { + auto do_parse = [&](std::string_view input_san) -> Move { + if (input_san.empty()) + return Move::none(); + Movelist moves; + pos.legals(moves); + + // Make a local mutable copy we can trim safely. + std::string san(input_san); + + // 1) Castling shortcuts + if (san == "O-O" || san == "0-0" || san == "O-O+" || san == "0-0+" || san == "O-O#" || san == "0-0#") { + Move km = chess::Move::make(relative_square(pos.side_to_move(), SQ_E1), + relative_square(pos.side_to_move(), SQ_H1)); + if (std::find(moves.begin(), moves.end(), km) != moves.end()) + return km; + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal O-O")); + return Move::none(); + } + if (san == "O-O-O" || san == "0-0-0" || san == "O-O-O+" || san == "0-0-0+" || san == "O-O-O#" || san == "0-0-0#") { + Move qm = chess::Move::make(relative_square(pos.side_to_move(), SQ_E1), + relative_square(pos.side_to_move(), SQ_A1)); + if (std::find(moves.begin(), moves.end(), qm) != moves.end()) + return qm; + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal O-O-O")); + return Move::none(); + } + // 2) Strip trailing annotations (+, #, !, ?). Repeated occurrences too. + while (!san.empty()) { + char c = san.back(); + if (c == '+' || c == '#' || c == '!' || c == '?') + san.pop_back(); + else + break; + } + if (san.empty()) { + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("empty san")); + return Move::none(); + } + + // 3) Extract promotion if present (e.g. c8=Q or c8Q) + PieceType promotion = NO_PIECE_TYPE; + if (san.size() >= 3) { + // look for "=Q" or similar at the very end, or single letter promotion (historical) + char penult = san[san.size() - 2]; + char last = san.back(); + if (penult == '=') { + promotion = parse_pt(last); + if (promotion == NO_PIECE_TYPE) { + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid promotion piece")); + return Move::none(); + } + san.pop_back(); // remove piece letter + san.pop_back(); // remove '=' + } else if ((last == 'Q' || last == 'R' || last == 'B' || last == 'N' || last == 'q' || last == 'r' || last == 'b' || + last == 'n')) { + // allow c8Q or c8q as shorthand (optional) + promotion = parse_pt(last); + san.pop_back(); + } + } + + // 4) Destination square: always the last [file][rank] + if (san.size() < 2) + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid san (too short)")); + char dfile = san[san.size() - 2]; + char drank = san[san.size() - 1]; + if (!(dfile >= 'a' && dfile <= 'h' && drank >= '1' && drank <= '8')) { + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid destination square")); + return Move::none(); + } + std::string dest_sq_str = san.substr(san.size() - 2, 2); + Square to_square = parse_square(dest_sq_str); + if (to_square == SQ_NONE) { + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid dest square")); + return Move::none(); + } + san.resize(san.size() - 2); // chop off destination + + // 5) Now san contains everything before the dest: + // possible piece letter, possible source square, possible disambiguation, + // optional 'x' capture markers (we will ignore 'x'). + // Remove all 'x' characters (capture indicators) from the remainder + std::string prefix; + prefix.reserve(san.size()); + for (char c : san) + if (c != 'x' && c != 'X' && c != '-') + prefix.push_back(c); + // prefix now holds the pre-destination token (e.g. "Nbd" from "Nbd2" or "Pe2" from "Pe2e4") + + // 6) Detect a fully specified source square at the end of prefix (LAN) + bool has_src_square = false; + Square src_square = SQ_NONE; + if (prefix.size() >= 2) { + char sfile = prefix[prefix.size() - 2]; + char srank = prefix[prefix.size() - 1]; + if (sfile >= 'a' && sfile <= 'h' && srank >= '1' && srank <= '8') { + // consume it + std::string src_sq_str = prefix.substr(prefix.size() - 2, 2); + src_square = parse_square(src_sq_str); + if (src_square == SQ_NONE) + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid source square")); + prefix.resize(prefix.size() - 2); + has_src_square = true; + } + } + + // 7) Detect piece letter at front if present + PieceType piece_type = NO_PIECE_TYPE; + if (!prefix.empty()) { + char front = prefix.front(); + PieceType pt = parse_pt(front); + if (pt != NO_PIECE_TYPE) { + piece_type = pt; + // remove leading piece letter + prefix.erase(prefix.begin()); + } + } + // If no explicit piece letter, it's a pawn move + if (piece_type == NO_PIECE_TYPE) + piece_type = PAWN; + + // 8) The remaining prefix is disambiguation: can be file, rank, or file+rank (rare) + int dis_file = -1; // 0..7 or -1 + int dis_rank = -1; // 0..7 or -1 + for (char c : prefix) { + if (c >= 'a' && c <= 'h') + dis_file = c - 'a'; + else if (c >= '1' && c <= '8') + dis_rank = c - '1'; + else { + // unexpected char in prefix + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid char in SAN prefix")); + return Move::none(); + } + } + + // 9) Build candidate filter and scan legal moves + Move matched = Move::null(); + bool found = false; + Bitboard to_mask = (1ULL << to_square) & ~pos.occ(pos.side_to_move()); // mask excluding own pieces on destination + + // If pawn and no disambiguation file, restrict pawns to dest file (avoid ambiguous pawn non-file forms) + // This matches python-chess behavior described earlier. + Bitboard from_mask = ~0ULL; + if (piece_type == PAWN) { + from_mask &= pos.pieces(PAWN, pos.side_to_move()); + if (dis_file == -1 && !has_src_square) { + // restrict to same file as destination (non-capture pawns must be on same file) + int dest_file = file_of(to_square); + from_mask &= attacks::MASK_FILE[dest_file]; + } + } else { + from_mask &= pos.pieces(piece_type, pos.side_to_move()); + } + + // Additional disambiguation masks: + if (dis_file != -1) + from_mask &= attacks::MASK_FILE[dis_file]; + if (dis_rank != -1) + from_mask &= attacks::MASK_RANK[dis_rank]; + if (has_src_square) { + // If fully specified source given, narrow to that square only. + from_mask &= (1ULL << src_square); + } + + for (Move m : moves) { + // match destination + if (m.to_sq() != to_square) + continue; + + // match promotion + if (promotion != NO_PIECE_TYPE) { + if (m.type_of() != PROMOTION || m.promotion_type() != promotion) + continue; + } else { + // if move is promotion but SAN lacked piece, reject (require explicit promotion) + if (m.type_of() == PROMOTION) + continue; + } + + // match piece type: check the piece that is on m.from_sq() in pos + PieceType src_pt = piece_of(pos.piece_on(m.from_sq())); + if (src_pt != piece_type) + continue; + + // match from_mask (disambiguation and pawn filtering) + if (((1ULL << m.from_sq()) & from_mask) == 0) + continue; + + // Everything matches -> accept candidate + if (found) { + THROW_IF_EXCEPTIONS_ON( + AmbiguousMoveException("ambiguous san: \"" + std::string(raw_san) + "\" in " + pos.fen())); + return Move::none(); + } + matched = m; + found = true; + } + + if (!found) { + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: \"" + std::string(input_san) + "\" in " + pos.fen())); + return Move::none(); + } + + return matched; + }; + + if (remove_illegals) { + std::string trimmed_san(raw_san); + while (!trimmed_san.empty()) { + Move attempt = do_parse(trimmed_san); + if (attempt.is_ok()) + return attempt; + trimmed_san.pop_back(); + } + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: \"" + std::string(raw_san) + "\" in " + pos.fen())); + return Move::none(); + } else { + return do_parse(raw_san); + } +} +template std::string moveToSan(const _Position &pos, Move move, bool long_, bool suffix) { + const char FILE_NAMES[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' }; + + const char RANK_NAMES[] = { '1', '2', '3', '4', '5', '6', '7', '8' }; + constexpr char PieceTypeChar[] = " pnbrqk"; + // Null move. (or none) + if (!move.is_ok()) { + return "--"; + } + + std::string san; + PieceType piece_type = piece_of(pos.at(move.from_sq())); + bool capture = pos.is_capture(move); + // Castling. + if (pos.is_castling(move)) { + if (file_of(move.to_sq()) < file_of(move.from_sq())) { + san = "O-O-O"; + goto appendCheck; + } else { + san = "O-O"; + goto appendCheck; + } + } + if (piece_type == NO_PIECE_TYPE) { + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("san() and lan() expect move to be pseudo-legal or null, but got " + + moveToUci(move) + " in " + pos.fen())); + return ""; + } + + if (piece_type != PAWN) { + san = std::toupper(PieceTypeChar[piece_type]); + } + if (long_) { + san += squareToString(move.from_sq()); + } else if (piece_type != PAWN) { + // Get ambiguous move candidates. + // Relevant candidates: not exactly the current move, + // but to the same square. + Movelist moves; + pos.legals(moves); + Bitboard others = 0; + Bitboard from_mask = pos.pieces(piece_type, pos.side_to_move()); + from_mask &= ~(1ULL << move.from_sq()); + Bitboard to_mask = 1ULL << move.to_sq(); + for (const Move &candidate : moves) { + Bitboard cand_from_bb = 1ULL << candidate.from_sq(); + // Only consider other pieces of same type that can move to the same destination. + if ((cand_from_bb & from_mask) && ((1ULL << candidate.to_sq()) & to_mask)) + others |= cand_from_bb; + } + + // Disambiguate only if there are other candidates that can move to the same square. + if (others) { + bool need_file = false, need_rank = false; + for (Square sq = SQ_A1; sq < SQ_NONE; ++sq) { + if (others & (1ULL << sq)) { + if (file_of(sq) == file_of(move.from_sq())) + need_rank = true; + if (rank_of(sq) == rank_of(move.from_sq())) + need_file = true; + } + } + // If neither shares file nor rank, include file by default. + if (!need_file && !need_rank) + need_file = true; + if (need_file) + san += FILE_NAMES[file_of(move.from_sq())]; + if (need_rank) + san += RANK_NAMES[rank_of(move.from_sq())]; + } + } else if (capture) { + san += FILE_NAMES[file_of(move.from_sq())]; + } + + // Captures. + if (capture) { + san += "x"; + } else if (long_) { + san += "-"; + } + + // Destination square. + san += squareToString(move.to_sq()); + + // Promotion. + if (move.type_of() == PROMOTION) { + san += "=" + std::string(1, std::toupper(PieceTypeChar[move.promotion_type()])); + } +appendCheck: + if (!suffix) + return san; + _Position p = pos; + p.doMove(move); + bool _check = p.is_check(); + Movelist moves; + p.legals(moves); + // Checkmate: no legal moves and in check; Stalemate: no legal moves and not in check + if (moves.size() == 0 && _check) + san += "#"; + else if (_check) + san += "+"; + return san; +} #define INSTANTITATE(PieceC) \ template Move uciToMove(const _Position &, std::string_view); \ - template Move uciToMove(const _Position &, std::string); + template Move parseSan(const _Position &, std::string_view, bool); \ + template std::string moveToSan(const _Position &, Move, bool, bool); INSTANTITATE(PolyglotPiece) INSTANTITATE(EnginePiece) INSTANTITATE(ContiguousMappingPiece) diff --git a/moves_io.h b/moves_io.h index 6e4699b..2418a90 100644 --- a/moves_io.h +++ b/moves_io.h @@ -2,15 +2,35 @@ #include #include #include +#include namespace chess { class Move; enum Square : int8_t; template class _Position; namespace uci { -std::string moveToUci(const Move &move); +std::string moveToUci(Move move); std::string squareToString(Square sq); -template Move uciToMove(const _Position &pos, std::string uci); +class IllegalMoveException : public std::exception{ +public: + IllegalMoveException(const std::string& message) : message_(message) {} + const char* what() const noexcept override { + return message_.c_str(); + } +private: + std::string message_; +}; +class AmbiguousMoveException : public std::exception{ +public: + AmbiguousMoveException(const std::string& message) : message_(message) {} + const char* what() const noexcept override { + return message_.c_str(); + } +private: + std::string message_; +}; template Move uciToMove(const _Position &pos, std::string_view uci); +template Move parseSan(const _Position &pos, std::string_view uci, bool remove_illegals=false); +template std::string moveToSan(const _Position &pos, Move move, bool long_=false, bool suffix=true); } // namespace uci } // namespace chess diff --git a/non_core_tests.cpp b/non_core_tests.cpp new file mode 100644 index 0000000..4707ac6 --- /dev/null +++ b/non_core_tests.cpp @@ -0,0 +1,892 @@ +#define DOCTEST_CONFIG_IMPLEMENT +#ifndef __EXCEPTIONS +#define DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#endif +#include "moves_io.h" +#include "position.h" +#include "printers.h" +#include +#include +using namespace chess; +template struct TestEntry { + InputT input; + CheckInfo info; +}; +void check_moveToUci(std::vector> &tests) { + for (auto &tc : tests) { + REQUIRE(chess::uci::moveToUci(tc.input) == tc.info); + } +} +TEST_CASE("moveToUci") { + std::vector> tests = { + { Move(SQ_A2, SQ_A4), "a2a4" }, + { Move::make(SQ_H1, SQ_G4), "h1g4" }, + { Move::make(SQ_A4, SQ_E6), "a4e6" }, + { Move::make(SQ_D4, SQ_A7), "d4a7" }, + { Move::make(SQ_C5, SQ_E6), "c5e6" }, + { Move::make(SQ_G7, SQ_D2), "g7d2" }, + { Move::make(SQ_A5, SQ_E6), "a5e6" }, + { Move::make(SQ_D3, SQ_F7), "d3f7" }, + { Move::make(SQ_E8, SQ_A4), "e8a4" }, + { Move::make(SQ_B4, SQ_G3), "b4g3" }, + { Move::make(SQ_A6, SQ_C8), "a6c8" }, + { Move::make(SQ_B7, SQ_B2), "b7b2" }, + { Move::make(SQ_F8, SQ_G1), "f8g1" }, + { Move::make(SQ_B2, SQ_B1), "b2b1" }, + { Move::make(SQ_D2, SQ_H8), "d2h8" }, + { Move::make(SQ_B4, SQ_H3), "b4h3" }, + { Move::make(SQ_F7, SQ_E5), "f7e5" }, + { Move::make(SQ_A6, SQ_C2), "a6c2" }, + { Move::make(SQ_C8, SQ_H5), "c8h5" }, + { Move::make(SQ_C3, SQ_G7), "c3g7" }, + { Move::make(SQ_E8, SQ_H8), "e8g8" }, + { Move::make(SQ_B4, SQ_A8), "b4a8" }, + { Move::make(SQ_F3, SQ_G5), "f3g5" }, + { Move::make(SQ_E4, SQ_F6), "e4f6" }, + { Move::make(SQ_D5, SQ_B6), "d5b6" }, + { Move::make(SQ_H2, SQ_G1, BISHOP), "h2g1b" }, + { Move::make(SQ_E5, SQ_C8), "e5c8" }, + { Move::make(SQ_D8, SQ_F1), "d8f1" }, + { Move::make(SQ_H3, SQ_H8), "h3h8" }, + { Move::make(SQ_G6, SQ_A1), "g6a1" }, + { Move::make(SQ_E8, SQ_A8), "e8c8" }, + { Move::make(SQ_E1, SQ_H1), "e1g1" }, + { Move::make(SQ_E8, SQ_H8), "e8g8" }, + { Move::make(SQ_C7, SQ_B1), "c7b1" }, + { Move::make(SQ_E8, SQ_H8), "e8g8" }, + { Move::make(SQ_D8, SQ_A1), "d8a1" }, + { Move::make(SQ_D7, SQ_D8, KNIGHT), "d7d8n" }, + { Move::make(SQ_D8, SQ_E7), "d8e7" }, + { Move::make(SQ_F2, SQ_H3), "f2h3" }, + { Move::make(SQ_B7, SQ_D5), "b7d5" }, + { Move::make(SQ_D1, SQ_F2), "d1f2" }, + { Move::make(SQ_E8, SQ_C4), "e8c4" }, + { Move::make(SQ_D2, SQ_C7), "d2c7" }, + { Move::make(SQ_H1, SQ_C2), "h1c2" }, + { Move::make(SQ_E3, SQ_C1), "e3c1" }, + { Move::make(SQ_H8, SQ_H3), "h8h3" }, + { Move::make(SQ_F2, SQ_F1, QUEEN), "f2f1q" }, + { Move::make(SQ_H2, SQ_D6), "h2d6" }, + { Move::make(SQ_G2, SQ_G1, ROOK), "g2g1r" }, + { Move::make(SQ_H5, SQ_G6), "h5g6" }, + { Move::make(SQ_E8, SQ_E3), "e8e3" }, + { Move::make(SQ_H4, SQ_C3), "h4c3" }, + { Move::make(SQ_E4, SQ_H3), "e4h3" }, + { Move::make(SQ_D2, SQ_A1), "d2a1" }, + { Move::make(SQ_H1, SQ_D2), "h1d2" }, + { Move::make(SQ_B8, SQ_A3), "b8a3" }, + { Move::make(SQ_H5, SQ_A1), "h5a1" }, + { Move::make(SQ_E1, SQ_A1), "e1c1" }, + { Move::make(SQ_A2, SQ_A3), "a2a3" }, + { Move::make(SQ_C7, SQ_G8), "c7g8" }, + { Move::make(SQ_E1, SQ_E6), "e1e6" }, + { Move::make(SQ_E1, SQ_A5), "e1a5" }, + { Move::make(SQ_E6, SQ_A5), "e6a5" }, + { Move::make(SQ_H7, SQ_C8, QUEEN), "h7c8q" }, + { Move::make(SQ_C2, SQ_C1, QUEEN), "c2c1q" }, + { Move::make(SQ_D6, SQ_B7), "d6b7" }, + { Move::make(SQ_D5, SQ_G7), "d5g7" }, + { Move::make(SQ_B6, SQ_F3), "b6f3" }, + { Move::make(SQ_A3, SQ_G1), "a3g1" }, + { Move::make(SQ_D2, SQ_A1, BISHOP), "d2a1b" }, + { Move::make(SQ_H6, SQ_C3), "h6c3" }, + { Move::make(SQ_C7, SQ_C8, KNIGHT), "c7c8n" }, + { Move::make(SQ_A7, SQ_B8, KNIGHT), "a7b8n" }, + { Move::make(SQ_C6, SQ_C5), "c6c5" }, + { Move::make(SQ_H2, SQ_H1, QUEEN), "h2h1q" }, + { Move::make(SQ_G1, SQ_G8), "g1g8" }, + { Move::make(SQ_D1, SQ_H8), "d1h8" }, + { Move::make(SQ_B1, SQ_C6), "b1c6" }, + { Move::make(SQ_E4, SQ_A3), "e4a3" }, + { Move::make(SQ_G5, SQ_F3), "g5f3" }, + { Move::make(SQ_D7, SQ_D8, KNIGHT), "d7d8n" }, + { Move::make(SQ_C4, SQ_E5), "c4e5" }, + { Move::make(SQ_B1, SQ_F7), "b1f7" }, + { Move::make(SQ_B3, SQ_B4), "b3b4" }, + { Move::make(SQ_G7, SQ_G8, BISHOP), "g7g8b" }, + { Move::make(SQ_A1, SQ_E3), "a1e3" }, + { Move::make(SQ_F6, SQ_E3), "f6e3" }, + { Move::make(SQ_B7, SQ_A2), "b7a2" }, + { Move::make(SQ_F7, SQ_D4), "f7d4" }, + { Move::make(SQ_G4, SQ_F6), "g4f6" }, + { Move::make(SQ_E1, SQ_A1), "e1c1" }, + { Move::make(SQ_E1, SQ_A1), "e1a1" }, + { Move::make(SQ_H1, SQ_H8), "h1h8" }, + { Move::make(SQ_A1, SQ_A7), "a1a7" }, + { Move::make(SQ_E5, SQ_A8), "e5a8" }, + { Move::make(SQ_F5, SQ_F8), "f5f8" }, + { Move::make(SQ_E7, SQ_D2), "e7d2" }, + { Move::make(SQ_H2, SQ_E1, BISHOP), "h2e1b" }, + { Move::make(SQ_H4, SQ_F3), "h4f3" }, + { Move::make(SQ_E8, SQ_B6), "e8b6" }, + { Move::make(SQ_H5, SQ_E8), "h5e8" }, + { Move::make(SQ_F2, SQ_F1, ROOK), "f2f1r" }, + }; + check_moveToUci(tests); +} +TEST_CASE("push_uci/parse_uci") { + Position p; + REQUIRE(p.parse_uci("e2e4") == Move(SQ_E2, SQ_E4)); + p.setFEN("rn1qkbnr/pP1ppppp/8/1b6/8/8/PPP1PPPP/RNBQKBNR w KQkq - 1 5"); + REQUIRE(p.parse_uci("b7a8q") == Move::make(SQ_B7, SQ_A8, QUEEN)); +} +template void check_was_into_check(std::vector> &tests) { + for (auto &tc : tests) { + _Position pos(tc.input); + REQUIRE(pos.was_into_check() == tc.info); + } +} +TEST_CASE("was_into_check") { + std::vector> tests = { + { "3K4/1N1Q4/8/2r4k/6r1/8/1q1Q4/r3P3 w q - 24 70", false }, + { "8/8/3b3K/4N3/4k3/7n/4q3/7B w - - 8 9", true }, + { "N7/1B4P1/4B2n/2Kn4/8/3k4/Pp2r1p1/1p5P w - - 29 85", false }, + { "4b3/3n3N/8/2k5/1q6/1B6/4R3/2K1R3 w - g3 37 3", false }, + { "8/r7/1K3p2/2q5/2R5/6N1/3B4/2p4k w q - 2 89", true }, + { "8/1q3Pr1/2b5/2P2r2/7K/5k2/PP1n4/Q2b3p w K g3 28 35", false }, + { "K7/1r6/4B1p1/7p/3P4/4k3/4R3/1np3b1 w - - 16 84", true }, + { "2R2r2/2k2N2/7K/2r2NR1/1n3b2/PP6/3q3b/B7 w q h3 38 21", true }, + { "2Q5/3b4/1b4Rr/4R1K1/7q/2P2R1q/R5Qp/1bn1k3 w - g3 8 76", true }, + { "4k3/bP1r4/n7/8/2PP2K1/4B3/2N1P1q1/7P w q a6 37 18", false }, + { "1P4N1/2Nb4/1K6/5B2/2N3R1/2k1Nn2/5N2/1p3p2 b q - 41 98", false }, + { "Q4rN1/5R2/R5b1/7r/8/r7/kK5B/7B b K c6 37 73", true }, + { "4k2p/r1q5/7n/1p4P1/1P3PQr/N1n2N2/7K/1N1NqB2 b - f6 27 80", true }, + { "7Q/2p2b2/8/3K4/5Q2/N2B1bb1/5b2/5qk1 w K d3 30 68", false }, + { "3b3K/5p2/2Pp4/2n1R3/5Qb1/7k/6n1/R7 b - a3 23 54", false }, + { "1n1PN1N1/3Pn3/3r4/2b5/6K1/7r/5b2/3k4 w q - 15 51", false }, + { "4N3/4kN2/n2p4/4K3/r1P4R/1p4n1/b3r3/3P1n2 b - - 9 43", true }, + { "1Q2q3/k4bBq/5B1P/8/6q1/r1q3p1/1K6/2PP4 w - - 16 90", true }, + { "Kqq1B2b/3R1Q2/8/k7/6P1/8/1P4R1/8 w - e6 33 9", false }, + { "7K/Nn3b2/r1N1pP2/4R3/5q2/kq6/4p2b/8 w - e3 5 11", false }, + { "n3NK1B/B5kn/8/8/6pB/4P3/8/5R2 b k g3 20 41", true }, + { "Kq3Bq1/6p1/4P3/k7/3R4/8/1Npn4/8 b K - 31 84", true }, + { "7N/1RK1p1nb/5n2/3N4/QQ2pkr1/1r6/3P1P2/8 b - - 44 77", false }, + { "1R2RN1q/nn2Q1k1/5b1Q/3n2n1/2qN3Q/1K1R2B1/8/8 w - - 49 2", true }, + { "8/5bQn/3n2B1/1K2B3/4NN1n/6q1/4R3/2q4k w - - 8 100", false }, + { "8/8/1P4P1/7r/1Q1Q4/2R2P1b/6n1/1RbK1Q1k b - - 44 5", false }, + { "2r2p2/1B6/2r5/5p2/8/3b2q1/2R3qK/k1q5 b - - 11 89", true }, + { "1b1Q4/1rk2qP1/8/R1r4q/4p3/2K4p/5P2/R7 b Q - 23 29", true }, + { "qq3B2/2r4n/3n4/r1Q5/2P5/5b2/1b1k1K2/P2n4 w Q - 49 89", false }, + { "B1bn1R1r/1N5k/2p5/4b2r/6n1/K5B1/2n1n3/1P3N2 b q - 6 8", true }, + { "8/6q1/3nr3/3n4/KQ6/1bp2q2/1Bk5/2r2Q2 w - b3 0 89", false }, + { "4r3/p1n4N/8/8/8/4qnP1/6k1/4K3 b K - 12 83", true }, + { "3b1Nk1/4R1nR/3r4/3P4/R7/K2n4/1qB5/4r2R b q - 6 73", true }, + { "6r1/1Q1B2B1/1bK2QR1/1r6/r7/4p2B/8/2r1k1q1 b - - 44 39", true }, + { "5R2/b7/3p2P1/8/2k5/qK2Q3/7p/8 w K - 33 11", true }, + { "1R3Q1Q/p7/8/4B1pq/6k1/2N1Q3/8/6K1 w - - 35 100", false }, + { "Bp6/PQ5q/8/4k3/7b/2q1Nr2/2K5/2n1q2q w K - 26 14", false }, + { "3p4/4k1Q1/5B1b/n1q5/8/2Q4K/3Q4/4B3 b q - 15 33", false }, + { "p7/p5N1/B2n3Q/K4R1P/3n2q1/7k/P3QR2/8 b k e6 16 50", false }, + { "5Pkq/8/7N/2n5/1N4R1/7K/1Q6/3ppP2 w Q - 9 43", true }, + { "6K1/8/Q4B2/1Q6/b1k5/4q1n1/8/1B5b w K - 41 68", true }, + { "1N6/2k4K/2P3r1/8/3R2N1/5b2/5b2/b3p3 w k - 1 50", false }, + { "3r1K2/1R6/p7/8/1qN3q1/1r6/1k5Q/8 w Q - 27 30", true }, + { "p2B2P1/Q1b5/1Q6/K3k3/8/P4P2/8/8 b q - 42 98", false }, + { "BQ5n/5n2/8/7K/8/2B5/1k6/4n1N1 b K - 3 47", false }, + { "8/n3B3/8/R7/3Q2P1/1rQ2B2/5R2/2K1k2r w k - 46 100", true }, + { "1n1N4/2Qr1k1N/1KR3N1/3Pn3/4Q3/4B3/pn2q3/8 w k - 10 9", true }, + { "2b5/1q2Bbq1/5n2/2R3qR/2kN4/6b1/P1r4Q/K3r2B b k h3 41 49", true }, + { "2q5/4br1R/5Q2/5Q2/2k5/Bnp5/7q/3K4 w - - 18 39", false }, + { "8/3q4/7k/5K2/1q2R1N1/3N4/2N5/3P2p1 w K - 17 21", true }, + { "1P1BP1bK/N5r1/7R/1p3B1Q/6n1/3r4/k1B5/2n1P1q1 b K - 35 23", false }, + { "2bP1P2/2p5/3K3r/4Q3/2b5/4kr2/q7/pq5r w - g6 21 63", true }, + { "K1B5/4P1B1/kN3Q1R/3P1B2/2q1QN2/8/8/2P5 w Q - 16 2", true }, + { "7N/2b1p2P/1RK5/Nbqn1P2/3p2p1/2qr4/P1nP2k1/P1p1b3 w - d3 9 95", false }, + { "2B3p1/2R3b1/8/p7/8/Kprk4/3b2b1/2Q5 b - b6 15 77", false }, + { "1r2b3/2R5/1k1p2PQ/7N/3p2R1/P1R1K3/1bq5/R7 w - d6 41 72", false }, + { "3rq3/2p4K/4n3/5nn1/k7/8/2n1Q3/3P1q2 b k - 35 89", true }, + { "K3R3/1P4NB/1q3R2/1k6/1qn2B2/3pr3/3q1B2/4b3 b - - 18 88", false }, + { "N1r5/3nP3/bR2Q3/2RB3N/7k/3K4/b7/nQ5b w k - 31 78", false }, + { "b7/8/3b2P1/3kr3/4R3/6K1/3q2b1/1q2r3 w K - 28 28", false }, + { "2B1p2n/8/P7/Nn3b1K/1q6/N2p1kR1/8/8 b q - 0 36", false }, + { "1RK3p1/2BNr3/6R1/6q1/8/b2Pq3/8/2RR1P1k w K - 24 3", false }, + { "5P2/5Q2/8/2K2rb1/n3p1p1/6b1/2qn4/k4p2 b K - 15 60", true }, + { "2b1p3/5N2/2NNR1R1/2q5/8/8/qNQ4k/1P5K w k - 11 18", true }, + { "5B2/3q3K/1k3n2/R5r1/1Q2bR2/4P1b1/3B1b2/3pR3 w K - 2 22", true }, + { "4K3/8/1r6/3kNQp1/7b/Rr3B2/rP3nq1/1nP1q3 b Q h6 4 85", false }, + { "Q2rKN2/3Pp3/n5k1/4nPN1/3r3Q/1N1r4/5p2/1BBR1B1B w q - 6 18", true }, + { "1NK5/3k1Q2/1B2N1Q1/7p/8/8/5RNN/6Q1 w - g3 16 90", true }, + { "8/4Q3/6QP/3k4/bN2K3/4Q3/5b2/8 w k - 33 38", true }, + { "6K1/6q1/QnRb4/1Np4Q/7R/3Q4/3B1q2/5k2 b q - 29 11", true }, + { "5n2/4q3/4r3/b7/8/1Q5k/5KRB/1q2r3 b - d6 20 39", false }, + { "1R4q1/8/K2B4/5Q2/1N6/Q2qk3/8/8 w - - 10 61", false }, + { "1q1k4/4q3/8/Q1n5/3b3B/2Qp3b/R6K/5n1n b K - 47 62", true }, + { "2PB4/q3BR2/8/N3k3/4P3/4P3/7K/1N2P3 w k c6 22 24", false }, + { "6Pp/5N2/8/3QN3/1B6/p7/6kK/Q7 b K - 29 24", true }, + { "8/R7/4pk2/5R2/1BK3R1/6Q1/1P1Q4/8 w Q - 10 75", true }, + { "8/6p1/b3QN2/5k2/8/p6P/7r/K7 b - f6 18 46", false }, + { "3Q4/5P2/7N/3N2K1/8/3rk1bn/7b/1NQ1Q3 b k - 17 42", true }, + { "5B2/1P2k3/2n3K1/5bn1/5R1P/p3Bp2/3N4/4n3 w - - 6 94", true }, + { "4P3/4n1Q1/6b1/5k2/5N2/3n3B/7p/q2B2K1 w - - 16 65", true }, + { "8/8/1k3r2/Nq6/7n/8/8/3K1b2 b - - 27 10", false }, + { "8/5N2/1K6/8/8/2Bq4/k7/3b2qp b K f3 39 75", true }, + { "kbK1R3/2n2q2/7n/1p6/1r1bP3/2p5/nB5B/2N2b2 w - - 12 68", false }, + { "8/3b4/2k1pn2/2P4n/2qQp3/1nnb4/r7/KB1Q4 b - - 12 11", true }, + { "r3B3/1bb2k2/p7/3K2Q1/8/6bp/6Nb/2p2nB1 b - - 22 61", true }, + { "1b6/4p2k/6p1/1N1Q1n2/1pK1r2B/1q2b3/p3Rp2/8 w k - 30 99", false }, + { "Q2k1B2/8/3rb3/8/2K5/8/1N6/8 w Q - 43 73", true }, + { "8/1r4Nk/2R5/3Q1P2/8/6Q1/7P/6K1 w K - 27 13", false }, + { "5k2/2b5/p7/5B2/1K2n3/6n1/1b4q1/3r1b2 b K - 28 91", false }, + { "5r2/1N6/8/5N1r/4n2k/2B2K2/1RR1NB2/2p1BR2 w - f6 8 12", true }, + { "5N2/8/5K2/8/2B2P2/5nr1/1Q1B2k1/1Qr1n3 b - - 29 100", false }, + { "8/3b4/3p4/1K5n/3Q1Qn1/2n5/k1p1Rq1n/3N4 b Q - 39 12", true }, + { "2Q5/3n4/1Rq1KN2/3P4/7P/1b3B2/3k3q/8 b - - 15 47", true }, + { "3bn3/4Q1p1/2r3q1/2Q2k2/2QKr3/3R4/8/2p2R2 w Q - 28 77", true }, + { "n7/1n4p1/2KB2b1/4q1R1/QR6/1kb3p1/8/2n2b2 b K - 24 73", false }, + { "3R2k1/QpK2R1p/N6P/RP2r3/q4b2/8/1R6/2r5 w q - 7 44", true }, + { "8/k1R2Q2/3r4/2QP3B/8/6B1/3K4/n1b2Q2 b Q - 18 53", true }, + { "p7/2n3PQ/3p1K2/N2b4/2n2bk1/Q7/B1Q5/2q5 b - - 47 54", false }, + { "b2Q1q2/1r6/2R5/B1R3q1/p2K1kR1/4q3/8/1r3b2 b - - 15 92", true }, + { "pB6/4q1nk/7n/4p2B/1N3K2/P7/rn2bRb1/2r5 w - - 7 57", false }, + }; + check_was_into_check(tests); + check_was_into_check(tests); +} +TEST_CASE("Zobrist mapping?") { + REQUIRE(zobrist::RandomPiece[enum_idx()][(int)PolyglotPiece::BPAWN][0] == 0x9D39247E33776D41); +} +struct repetitions_t { + std::string FEN; + std::vector moves; + int repetition; +}; +void check_repetitions(std::vector> &tests) { + for (auto &tc : tests) { + _Position pos(tc.input.FEN); + for (auto &move : tc.input.moves) + pos.doMove(move); + REQUIRE(pos.is_repetition(tc.input.repetition) == tc.info); + } + for (auto &tc : tests) { + _Position pos(tc.input.FEN); + for (auto &move : tc.input.moves) + pos.doMove(move); + REQUIRE(pos.is_repetition(tc.input.repetition) == tc.info); + } +} +TEST_CASE("is_repetition") { + std::vector> tests = { + { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", + { Move(SQ_B1, SQ_C3), + Move(SQ_B8, SQ_C6), + Move(SQ_C3, SQ_B1), + Move(SQ_C6, SQ_B8), + Move(SQ_G1, SQ_F3), + Move(SQ_G8, SQ_F6), + Move(SQ_F3, SQ_G1), + Move(SQ_F6, SQ_G8) }, + 3, true } + }; + check_repetitions(tests); +} + +TEST_SUITE("SAN Parser") { + TEST_CASE("Test ambiguous pawn capture") { + auto b = Position{ "rnbqkbnr/ppp1p1pp/3p1p2/4N3/8/3P4/PPPKPPPP/R1BQ1BNR b kq - 1 7" }; + + Move m = Move::make(Square::SQ_F6, Square::SQ_E5); + + CHECK(uci::moveToSan(b, m) == "fxe5"); + REQUIRE(uci::parseSan(b, "fxe5") == m); + } + + TEST_CASE("Test ambiguous pawn ep capture") { + auto b = Position{ "rnbqkbnr/pppppp1p/8/5PpP/8/8/PPPPP2P/RNBQKBNR w KQkq g6 0 2" }; + + Move m = Move::make(Square::SQ_F5, Square::SQ_G6); + + CHECK(uci::moveToSan(b, m) == "fxg6"); + REQUIRE(uci::parseSan(b, "fxg6") == m); + } + + TEST_CASE("Test ambiguous knight move") { + auto b = Position{ "rnbqkbnr/ppp3pp/3ppp2/8/8/3P1N1N/PPPKPPPP/R1BQ1B1R w kq - 1 8" }; + + Move m = Move::make(Square::SQ_F3, Square::SQ_G5); + + CHECK(uci::moveToSan(b, m) == "Nfg5"); + REQUIRE(uci::parseSan(b, "Nfg5") == m); + } + + TEST_CASE("Test ambiguous rook move with check") { + auto b = Position{ "4k3/8/8/8/8/8/2R3R1/2K5 w - - 0 1" }; + + Move m = Move::make(Square::SQ_C2, Square::SQ_E2); + + CHECK(uci::moveToSan(b, m) == "Rce2+"); + REQUIRE(uci::parseSan(b, "Rce2+") == m); + } + + TEST_CASE("Test ambiguous rook move with checkmate") { + auto b = Position{ "4k3/8/8/8/8/8/2KR1R2/3R1R2 w - - 0 1" }; + + Move m = Move::make(Square::SQ_D2, Square::SQ_E2); + + CHECK(uci::moveToSan(b, m) == "Rde2#"); + REQUIRE(uci::parseSan(b, "Rde2#") == m); + } + + TEST_CASE("Test Knight move") { + auto b = Position{ "rnbqkbnr/ppp1p1pp/3p1p2/8/8/3P1N2/PPPKPPPP/R1BQ1BNR w kq - 0 7" }; + + Move m = Move::make(Square::SQ_F3, Square::SQ_G5); + + CHECK(uci::moveToSan(b, m) == "Ng5"); + REQUIRE(uci::parseSan(b, "Ng5") == m); + } + + TEST_CASE("Test Bishop move") { + auto b = Position{ "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 1" }; + + Move m = Move::make(Square::SQ_F1, Square::SQ_C4); + + CHECK(uci::moveToSan(b, m) == "Bc4"); + REQUIRE(uci::parseSan(b, "Bc4") == m); + } + + TEST_CASE("Test Rook move") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPP1PP/R3KR2 w Qkq - 0 1" }; + + Move m = Move::make(Square::SQ_F1, Square::SQ_F7); + + CHECK(uci::moveToSan(b, m) == "Rxf7"); + REQUIRE(uci::parseSan(b, "Rxf7") == m); + } + + TEST_CASE("Test Queen move") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPP1PP/R3KQ1R w KQkq - 0 1" }; + + Move m = Move::make(Square::SQ_F1, Square::SQ_F7); + + CHECK(uci::moveToSan(b, m) == "Qxf7+"); + REQUIRE(uci::parseSan(b, "Qxf7+") == m); + } + + TEST_CASE("Test King move") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_F1); + + CHECK(uci::moveToSan(b, m) == "Kf1"); + REQUIRE(uci::parseSan(b, "Kf1") == m); + } + + TEST_CASE("Test King Castling Short move") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_H1); + + CHECK(uci::moveToSan(b, m) == "O-O"); + REQUIRE(uci::parseSan(b, "O-O") == m); + } + + TEST_CASE("Test King Castling Long move") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_A1); + + CHECK(uci::moveToSan(b, m) == "O-O-O"); + REQUIRE(uci::parseSan(b, "O-O-O") == m); + } + + TEST_CASE("Test King Castling Short move with Zero") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_H1); + + REQUIRE(uci::parseSan(b, "0-0") == m); + } + + TEST_CASE("Test King Castling Long move with Zero") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_A1); + + REQUIRE(uci::parseSan(b, "0-0-0") == m); + } + // These are removed due to illegal move (annotations aren't allowed strictly) + TEST_CASE("Test King Castling Short move with Annotation") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_H1); + REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0+?!"), "invalid san: '0-0+?!'", chess::uci::IllegalMoveException); + + REQUIRE(uci::parseSan(b, "0-0+?!", true) == m); + } + + TEST_CASE("Test King Castling Long move with Annotation") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_A1); + + REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0-0+?!"), "invalid san: 'O-O-O+!?'", chess::uci::IllegalMoveException); + REQUIRE(uci::parseSan(b, "0-0-0+?!", true) == m); + } + + TEST_CASE("Test Queen Capture Ambiguity") { + auto b = Position{ "3k4/8/4b3/8/2Q3Q1/8/8/3K4 w - - 0 1" }; + + Move m = Move::make(Square::SQ_C4, Square::SQ_E6); + + CHECK(uci::moveToSan(b, m) == "Qcxe6"); + REQUIRE(uci::parseSan(b, "Qcxe6") == m); + } + + TEST_CASE("Test Rook Ambiguity") { + auto b = Position{ "3k4/8/8/R7/8/8/8/R3K3 w - - 0 1" }; + + Move m = Move::make(Square::SQ_A1, Square::SQ_A3); + + CHECK(uci::moveToSan(b, m) == "R1a3"); + REQUIRE(uci::parseSan(b, "R1a3") == m); + } + + TEST_CASE("Test Rook Capture Ambiguity") { + auto b = Position{ "2r3k1/4nn2/pq1p1pp1/3Pp3/1pN1P1P1/1P1Q4/P1r1NP2/1K1R3R b - - 2 19" }; + + Move m = Move::make(Square::SQ_C8, Square::SQ_C4); + + CHECK(uci::moveToSan(b, m) == "R8xc4"); + REQUIRE(uci::parseSan(b, "R8xc4") == m); + } + + TEST_CASE("Test Knight Capture Ambiguity") { + auto b = Position{ "r5k1/5p2/2n2B1p/4P3/p1n3PN/8/P4PK1/1R6 b - - 2 28" }; + + Move m = Move::make(Square::SQ_C6, Square::SQ_E5); + + CHECK(uci::moveToSan(b, m) == "N6xe5"); + REQUIRE(uci::parseSan(b, "N6xe5") == m); + } + + TEST_CASE("Test Pawn Capture Promotion Ambiguity") { + auto b = Position{ "2k2n2/4P1P1/8/8/8/8/8/2K5 w - - 0 1" }; + + Move m = Move::make(Square::SQ_E7, Square::SQ_F8, PieceType::QUEEN); + + CHECK(uci::moveToSan(b, m) == "exf8=Q+"); + REQUIRE(uci::parseSan(b, "exf8=Q+") == m); + } + + TEST_CASE("Test Pawn Push") { + auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" }; + + Move m = Move::make(Square::SQ_E2, Square::SQ_E4); + + CHECK(uci::moveToSan(b, m) == "e4"); + REQUIRE(uci::parseSan(b, "e4") == m); + } + + TEST_CASE("Test Pawn Promotion") { + auto b = Position{ "8/Pk6/8/5p2/8/8/8/2K5 w - - 1 781" }; + + Move m = Move::make(Square::SQ_A7, Square::SQ_A8, PieceType::QUEEN); + + CHECK(uci::moveToSan(b, m) == "a8=Q+"); + REQUIRE(uci::parseSan(b, "a8=Q+") == m); + } + + TEST_CASE("Test Knight Ambiguity") { + auto b = Position{ "8/8/5K2/2N3P1/3N3n/4k3/3N4/7r w - - 59 97" }; + + Move m = Move::make(Square::SQ_D4, Square::SQ_B3); + + CHECK(uci::moveToSan(b, m) == "N4b3"); + REQUIRE(uci::parseSan(b, "N4b3") == m); + } + + TEST_CASE("Test Knight Capture Ambiguity") { + auto b = Position{ "8/8/5K2/2N3P1/3N3n/1b2k3/3N4/7r w - - 59 97" }; + + Move m = Move::make(Square::SQ_D4, Square::SQ_B3); + + CHECK(uci::moveToSan(b, m) == "N4xb3"); + REQUIRE(uci::parseSan(b, "N4xb3") == m); + } + + TEST_CASE("Test Knight Ambiguity 2") { + auto b = Position{ "2N1N3/p7/6k1/1p6/2N1N3/2R5/R3Q1P1/2R3K1 w - - 5 55" }; + + { + Move m = Move::make(Square::SQ_E4, Square::SQ_D6); + + CHECK(uci::moveToSan(b, m) == "Ne4d6"); + REQUIRE(uci::parseSan(b, "Ne4d6") == m); + } + + { + Move m = Move::make(Square::SQ_C4, Square::SQ_D6); + + CHECK(uci::moveToSan(b, m) == "Nc4d6"); + REQUIRE(uci::parseSan(b, "Nc4d6") == m); + } + + { + Move m = Move::make(Square::SQ_C8, Square::SQ_D6); + + CHECK(uci::moveToSan(b, m) == "Nc8d6"); + REQUIRE(uci::parseSan(b, "Nc8d6") == m); + } + + { + Move m = Move::make(Square::SQ_E8, Square::SQ_D6); + + CHECK(uci::moveToSan(b, m) == "Ne8d6"); + REQUIRE(uci::parseSan(b, "Ne8d6") == m); + } + } + + TEST_CASE("Test Knight Capture Check Ambiguity") { + auto b = Position{ "2N1N3/p4k2/3q4/1p6/2N1N3/2R5/R3Q1P1/2R3K1 w - - 0 1" }; + + { + Move m = Move::make(Square::SQ_E4, Square::SQ_D6); + + CHECK(uci::moveToSan(b, m) == "Ne4xd6+"); + REQUIRE(uci::parseSan(b, "Ne4xd6+") == m); + } + } + + TEST_CASE("Test Bishop Ambiguity") { + auto b = Position{ "4k3/8/8/8/2B1B3/8/2B1BK2/8 w - - 0 1" }; + + { + auto m = Move::make(Square::SQ_C2, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Bc2d3"); + REQUIRE(uci::parseSan(b, "Bc2d3") == m); + } + + { + auto m = Move::make(Square::SQ_C4, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Bc4d3"); + REQUIRE(uci::parseSan(b, "Bc4d3") == m); + } + + { + auto m = Move::make(Square::SQ_E2, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Be2d3"); + REQUIRE(uci::parseSan(b, "Be2d3") == m); + } + + { + auto m = Move::make(Square::SQ_E4, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Be4d3"); + REQUIRE(uci::parseSan(b, "Be4d3") == m); + } + } + + TEST_CASE("Test Rook Ambiguity") { + auto b = Position{ "k5r1/8/8/8/2R1R3/8/2R1RK2/8 w - - 0 1" }; + + { + auto m = Move::make(Square::SQ_C2, Square::SQ_C3); + + CHECK(uci::moveToSan(b, m) == "R2c3"); + REQUIRE(uci::parseSan(b, "R2c3") == m); + } + + { + auto m = Move::make(Square::SQ_C2, Square::SQ_D2); + + CHECK(uci::moveToSan(b, m) == "Rcd2"); + REQUIRE(uci::parseSan(b, "Rcd2") == m); + } + + { + auto m = Move::make(Square::SQ_E2, Square::SQ_E3); + + CHECK(uci::moveToSan(b, m) == "R2e3"); + REQUIRE(uci::parseSan(b, "R2e3") == m); + } + + { + auto m = Move::make(Square::SQ_E2, Square::SQ_D2); + + CHECK(uci::moveToSan(b, m) == "Red2"); + REQUIRE(uci::parseSan(b, "Red2") == m); + } + } + + TEST_CASE("Test Queen Ambiguity") { + auto b = Position{ "1k4r1/8/8/8/2Q1Q3/8/2Q1QK2/8 w - - 0 1" }; + + { + auto m = Move::make(Square::SQ_C2, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Qc2d3"); + REQUIRE(uci::parseSan(b, "Qc2d3") == m); + } + + { + auto m = Move::make(Square::SQ_C4, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Qc4d3"); + REQUIRE(uci::parseSan(b, "Qc4d3") == m); + } + + { + auto m = Move::make(Square::SQ_E2, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Qe2d3"); + REQUIRE(uci::parseSan(b, "Qe2d3") == m); + } + + { + auto m = Move::make(Square::SQ_E4, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Qe4d3"); + REQUIRE(uci::parseSan(b, "Qe4d3") == m); + } + } + + TEST_CASE("Test Queen Ambiguity 2") { + auto b = Position{ "5q1k/4P3/7q/1Q1pQ3/3P4/1KN5/8/5q2 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_F8, Square::SQ_F6); + + CHECK(uci::moveToSan(b, m) == "Q8f6"); + REQUIRE(uci::parseSan(b, "Q8f6") == m); + } + } + + TEST_CASE("Test Queen Ambiguity 3") { + auto b = Position{ "5q1k/4P3/7q/1Q1pQ3/3P3q/1KN5/8/5q2 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_H4, Square::SQ_F6); + + CHECK(uci::moveToSan(b, m) == "Q4f6"); + REQUIRE(uci::parseSan(b, "Q4f6") == m); + } + } + + TEST_CASE("Test Queen Ambiguity 4") { + auto b = Position{ "5q1k/4P3/7q/1Q1pQ3/3P1q1q/1KN5/8/5q2 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_H4, Square::SQ_F6); + + CHECK(uci::moveToSan(b, m) == "Qh4f6"); + REQUIRE(uci::parseSan(b, "Qh4f6") == m); + } + + { + auto m = Move::make(Square::SQ_F4, Square::SQ_F6); + + CHECK(uci::moveToSan(b, m) == "Qf4f6"); + REQUIRE(uci::parseSan(b, "Qf4f6") == m); + } + } + + TEST_CASE("Test Rook Ambiguity") { + auto b = Position{ "1r5k/5Rp1/5p1p/4Nb1P/2B5/2P1R1P1/3r1PK1/1r6 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_B1, Square::SQ_B2); + + CHECK(uci::moveToSan(b, m) == "R1b2"); + REQUIRE(uci::parseSan(b, "R1b2") == m); + } + + { + auto m = Move::make(Square::SQ_D2, Square::SQ_B2); + + CHECK(uci::moveToSan(b, m) == "Rdb2"); + REQUIRE(uci::parseSan(b, "Rdb2") == m); + } + } + + TEST_CASE("Test Rook Ambiguity 2") { + auto b = Position{ "1r5k/5Rp1/5p1p/1r2Nb1P/2B5/2P1R1P1/3r1PK1/8 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_B5, Square::SQ_B2); + + CHECK(uci::moveToSan(b, m) == "Rbb2"); + REQUIRE(uci::parseSan(b, "Rbb2") == m); + } + + { + auto m = Move::make(Square::SQ_B5, Square::SQ_B6); + + CHECK(uci::moveToSan(b, m) == "R5b6"); + REQUIRE(uci::parseSan(b, "R5b6") == m); + } + } + + TEST_CASE("Test Rook Ambiguity 3") { + auto b = Position{ "1r5k/5Rp1/5p1p/1r2Nb1P/2B5/2P1R1P1/5PK1/8 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_B5, Square::SQ_B2); + + CHECK(uci::moveToSan(b, m) == "Rb2"); + REQUIRE(uci::parseSan(b, "Rb2") == m); + } + + { + auto m = Move::make(Square::SQ_B5, Square::SQ_B6); + + CHECK(uci::moveToSan(b, m) == "R5b6"); + REQUIRE(uci::parseSan(b, "R5b6") == m); + } + } + + TEST_CASE("Test Bishop Ambiguity 2") { + auto b = Position{ "2Bqkb1r/4p2p/8/8/2B5/p7/4B3/RNBQKBNR w KQk - 0 1" }; + + { + auto m = Move::make(Square::SQ_C4, Square::SQ_A6); + + CHECK(uci::moveToSan(b, m) == "B4a6"); + REQUIRE(uci::parseSan(b, "B4a6") == m); + } + + { + auto m = Move::make(Square::SQ_C4, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Bcd3"); + REQUIRE(uci::parseSan(b, "Bcd3") == m); + } + } + + TEST_CASE("Test Bishop Ambiguity 3") { + auto b = Position{ "3qkb1r/4p2p/8/8/2B5/p7/4B3/RNBQKBNR w KQk - 0 1" }; + + { + auto m = Move::make(Square::SQ_C4, Square::SQ_A6); + + CHECK(uci::moveToSan(b, m) == "Ba6"); + REQUIRE(uci::parseSan(b, "Ba6") == m); + } + + { + auto m = Move::make(Square::SQ_C4, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Bcd3"); + REQUIRE(uci::parseSan(b, "Bcd3") == m); + } + } + + TEST_CASE("Test Bishop Capture Mating Ambiguity") { + auto b = Position{ "7r/4pqbp/5bkp/6nn/2B5/p2r4/4B3/RNBQKBR1 w Q - 0 1" }; + + { + auto m = Move::make(Square::SQ_C4, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Bcxd3#"); + REQUIRE(uci::parseSan(b, "Bcxd3#") == m); + } + } + + TEST_CASE("Test Pinned Queen Ambiguity") { + auto b = Position{ "1Q3q1k/4P3/8/3p1N1q/1Q1P4/2N5/2K5/5q2 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_F1, Square::SQ_F5); + + CHECK(uci::moveToSan(b, m) == "Qfxf5+"); + REQUIRE(uci::parseSan(b, "Qfxf5+") == m); + } + + { + auto m = Move::make(Square::SQ_H5, Square::SQ_F5); + + CHECK(uci::moveToSan(b, m) == "Qhxf5+"); + REQUIRE(uci::parseSan(b, "Qhxf5+") == m); + } + } + + TEST_CASE("Test Pinned Rook Ambiguity") { + auto b = Position{ "1r6/5Rp1/5p1p/1r2Nb1P/2B5/2PR2P1/3r1PK1/3k4 b - - 0 1" }; + + { + auto m = Move::make(Square::SQ_B5, Square::SQ_B2); + + CHECK(uci::moveToSan(b, m) == "Rb2"); + REQUIRE(uci::parseSan(b, "Rb2") == m); + } + + { + auto m = Move::make(Square::SQ_B5, Square::SQ_B6); + + CHECK(uci::moveToSan(b, m) == "R5b6"); + REQUIRE(uci::parseSan(b, "R5b6") == m); + } + } + + TEST_CASE("Test Pinned Bishop Ambiguity") { + auto b = Position{ "2r4r/4pqbp/5bkp/6nn/2B5/p2r4/2K1B3/RNBQ1BR1 w - - 0 1" }; + + { + auto m = Move::make(Square::SQ_E2, Square::SQ_D3); + + CHECK(uci::moveToSan(b, m) == "Bxd3#"); + REQUIRE(uci::parseSan(b, "Bxd3#") == m); + } + } + + TEST_CASE("Test Pinned Knight Ambiguity") { + auto b = Position{ "r1k5/5p2/2n2B1p/2R1P3/p1n3PN/8/P4PK1/1R6 b - - 0 1" }; + + Move m = Move::make(Square::SQ_C4, Square::SQ_E5); + + // CHECK(uci::moveToSan(b, m) == "Nxe5"); + REQUIRE(uci::parseSan(b, "Nxe5") == m); + } + + TEST_CASE("Parse No Move") { + Position b = Position(); + + REQUIRE(uci::parseSan(b, "") == Move::NO_MOVE); + } + + TEST_CASE("Should throw on ambiguous move") { + auto b = Position{ "8/8/6K1/4k3/4N3/p4r2/N3N3/8 w - - 3 82" }; + + Move san = Move::NO_MOVE; + + CHECK_THROWS_AS(san = uci::parseSan(b, "Nec3"), uci::AmbiguousMoveException); + CHECK(san == Move::NO_MOVE); + } + + TEST_CASE("Should throw for illegal move") { + auto b = Position{ "8/8/6K1/4k3/4N3/p4r2/N3N3/8 w - - 3 82" }; + + Move san = Move::NO_MOVE; + + CHECK_THROWS_WITH_AS(san = uci::parseSan(b, "Nec4"), + "illegal san: Nec4 8/8/6K1/4k3/4N3/p4r2/N3N3/8 w - - 3 82", + uci::IllegalMoveException); + CHECK(san == Move::NO_MOVE); + } + + TEST_CASE("Checkmate castle should have #") { + auto b = Position{ "RRR5/8/8/8/8/8/PPPPPP2/k3K2R w K - 0 1" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_H1); + + CHECK(uci::moveToSan(b, m) == "O-O#"); + REQUIRE(uci::parseSan(b, "O-O#") == m); + } + + TEST_CASE("Check castle should have +") { + auto b = Position{ "8/8/8/8/8/8/PPPPPP2/k3K2R w K - 0 1" }; + + Move m = Move::make(Square::SQ_E1, Square::SQ_H1); + + CHECK(uci::moveToSan(b, m) == "O-O+"); + REQUIRE(uci::parseSan(b, "O-O+") == m); + } +} +int main(int argc, char **argv) { + doctest::Context ctx; + ctx.setOption("success", true); + ctx.setOption("no-breaks", true); + return ctx.run(); +} diff --git a/position.cpp b/position.cpp index 28fe48c..0de7816 100644 --- a/position.cpp +++ b/position.cpp @@ -8,6 +8,12 @@ #else #define _POSSIBLY_CONSTEXPR const #endif + +#if defined(__EXCEPTIONS) && defined(_DEBUG) +#define THROW_IF_EXCEPTIONS_ON(stuff) throw stuff +#else +#define THROW_IF_EXCEPTIONS_ON(stuff) ((void)0) +#endif namespace chess { static _POSSIBLY_CONSTEXPR CastlingRights make_clear_mask(Color c, PieceType pt, Square sq) { if (pt == KING) { @@ -80,9 +86,9 @@ template template void _Position void _Position::setFEN(const s assert(file_count == 8 && "Each rank must contain exactly 8 squares"); #elif defined(__EXCEPTIONS) if (file_count != 8) - throw std::invalid_argument("Each rank must contain exactly 8 squares"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Each rank must contain exactly 8 squares")); #endif f = FILE_A; --r; @@ -254,9 +260,9 @@ template void _Position::setFEN(const s assert(chess::is_valid(r, f) && "Invalid file/rank position"); #elif defined(__EXCEPTIONS) if (file_count >= 8) - throw std::invalid_argument("Too many pieces in one rank"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Too many pieces in one rank")); if (!chess::is_valid(r, f)) - throw std::invalid_argument("Invalid file/rank position"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Invalid file/rank position")); #endif switch (c) { case 'p': @@ -299,7 +305,7 @@ template void _Position::setFEN(const s #if defined(_DEBUG) || !defined(NDEBUG) assert(false && "Invalid FEN character"); #elif defined(__EXCEPTIONS) - throw std::invalid_argument("Invalid FEN character"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Invalid FEN character")); #endif break; } @@ -318,10 +324,10 @@ template void _Position::setFEN(const s assert(rank_count == 8 && "FEN must contain exactly 8 ranks"); #elif defined(__EXCEPTIONS) if (file_count != 8) - throw std::invalid_argument("Last rank must have 8 squares"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Last rank must have 8 squares")); rank_count++; if (rank_count != 8) - throw std::invalid_argument("FEN must contain exactly 8 ranks"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("FEN must contain exactly 8 ranks")); #endif } @@ -335,7 +341,7 @@ template void _Position::setFEN(const s #if defined(_DEBUG) || !defined(NDEBUG) assert(false && "Expected white or black, got something else."); #elif defined(__EXCEPTIONS) - throw std::invalid_argument("Expected white or black, got something else."); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Expected white or black, got something else.")); #endif } @@ -366,7 +372,7 @@ template void _Position::setFEN(const s #if defined(_DEBUG) || !defined(NDEBUG) assert(false && "Invalid castling rights, this library doesn't support Chess960"); #elif defined(__EXCEPTIONS) - throw std::invalid_argument("Invalid castling rights, this library doesn't support Chess960"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Invalid castling rights, this library doesn't support Chess960")); #endif break; } @@ -393,7 +399,7 @@ template void _Position::setFEN(const s assert(enpassant == "-" && "Invalid en passant FEN field"); #elif defined(__EXCEPTIONS) if (enpassant != "-") - throw std::invalid_argument("Invalid en passant FEN field"); + THROW_IF_EXCEPTIONS_ON(std::invalid_argument("Invalid en passant FEN field")); #endif current_state.enPassant = SQ_NONE; } diff --git a/position.h b/position.h index cd6a363..26fe44d 100644 --- a/position.h +++ b/position.h @@ -47,7 +47,7 @@ template class HeapAllocatedValueList { inline ~HeapAllocatedValueList() { ::operator delete(values_, std::align_val_t{ALIGNMENT}); } HeapAllocatedValueList(const HeapAllocatedValueList &other) : size_(other.size_) { - ::operator delete(values_, std::align_val_t{ALIGNMENT}); + if (values_) ::operator delete(values_, std::align_val_t{ALIGNMENT}); values_ = reinterpret_cast(::operator new(MaxSize*sizeof(T), std::align_val_t{ALIGNMENT})); assert(values_); std::copy(other.values_, other.values_ + size_, values_); @@ -121,7 +121,7 @@ template class HeapAllocatedValueList { size_type size_ = 0; private: - T *values_; + T *values_=nullptr; }; enum class MoveGenType : uint8_t { ALL, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, CAPTURE }; @@ -419,7 +419,7 @@ template &state() const { return current_state; } uint64_t zobrist() const; __FORCEINLINE PieceC piece_at(Square sq) const { return piece_on(sq); } @@ -538,11 +538,13 @@ template state) { // compatible! current_state = state; + std::copy(std::begin(other.pieces_list), std::end(other.pieces_list), std::begin(pieces_list)); refresh_attacks(); } __FORCEINLINE _Position(const _Position &other) : current_state(other.current_state), history(other.history) // calls HeapAllocatedValueList's copy constructor { + std::copy(std::begin(other.pieces_list), std::end(other.pieces_list), std::begin(pieces_list)); refresh_attacks(); } diff --git a/tests.cpp b/tests.cpp index 139ca21..1d2d96a 100644 --- a/tests.cpp +++ b/tests.cpp @@ -318,20 +318,6 @@ TEST_CASE("Move making and unmaking") { position.undoMove(); REQUIRE(position.fen() == "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); } -TEST_CASE("Perft pawn-only startpos") { - std::string fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; - Position position(fen); - REQUIRE(perft(position, 1) == 16); - REQUIRE(perft(position, 5) == 815968); - REQUIRE(perft(position, 6) == 11515584); -} -TEST_CASE("King walk empty board wking e4 bking f8 depth 6") { - std::string fen = "5k2/8/8/8/3K4/8/8/8 w - - 0 1"; - Position position(fen); - REQUIRE(perft(position, 1) == 8); - REQUIRE(perft(position, 3) == 310); - REQUIRE(perft(position, 6) == 95366); -} TEST_CASE("Pin detection double push movegen") { std::string fen = "rnbqkbnr/1ppppppp/8/p7/Q1P5/8/PP1PPPPP/RNB1KBNR b KQkq - 1 2"; Position position(fen); @@ -353,6 +339,7 @@ TEST_CASE("Move making pin update") { Movelist out; pos.legals(out); auto pin_mask = pos.pin_mask(); + for (auto& mv: out) std::cout<> tests = { - { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 1, 20 }, - { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 2, 400 }, - { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 3, 8902 }, - { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 4, 197281 }, - { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 5, 4865609 }, + { "5k2/8/8/8/3K4/8/8/8 w - - 0 1", 1, 8 }, + { "5k2/8/8/8/3K4/8/8/8 w - - 0 1", 3, 310 }, + { "5k2/8/8/8/3K4/8/8/8 w - - 0 1", 6, 95366 }, + { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 1, 20 }, + { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 2, 400 }, + { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 3, 8902 }, + { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 4, 197281 }, + { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 5, 4865609 }, #if IS_RELEASE == 1 - { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 6, 119060324 }, + { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 6, 119060324 }, #endif - { "rnbqkbnr/pppppppp/8/8/8/3P4/PPP1PPPP/RNBQKBNR b KQkq - 0 1", 4, 328511 }, - { "rnbqkbnr/pp1ppppp/2p5/8/8/3P4/PPP1PPPP/RNBQKBNR w KQkq - 0 2", 3, 15206 }, - { "rnbqkbnr/pp1ppppp/2p5/8/8/3P4/PPPKPPPP/RNBQ1BNR b kq - 1 2", 2, 463 }, - { "rnb1kbnr/pp1ppppp/2p5/q7/8/3P4/PPPKPPPP/RNBQ1BNR w kq - 2 3", 1, 4 } - }; - check_perfts(tests); -} -TEST_CASE("Perft 7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1") { - std::vector> tests = { - { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 1, 8 }, - { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 2, 33 }, - { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 3, 270 }, - { "7k/8/8/8/1p6/P7/1P6/6K1 b - - 0 1", 2, 38 }, - { "7k/8/8/8/8/p7/1P6/6K1 w - - 0 2", 1, 8 }, - { "7k/8/8/8/8/p7/1P6/6K1 w - - 0 2", 2, 36 }, - { "7k/8/8/8/1p6/P7/1P6/6K1 b - - 0 1", 3, 234 }, - { "7k/8/8/8/8/pP6/8/6K1 b - - 0 2", 1, 4 }, - { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 4, 1664 }, - { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 5, 13931 }, - { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 6, 94162 } - }; - check_perfts(tests); -} -TEST_CASE("Massive legal counts") { - std::vector> tests = { - { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 1, 216 }, - { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 2, 95 }, - { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 3, 18138 }, - { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 4, 80766 }, + { "rnbqkbnr/pppppppp/8/8/8/3P4/PPP1PPPP/RNBQKBNR b KQkq - 0 1", 4, 328511 }, + { "rnbqkbnr/pp1ppppp/2p5/8/8/3P4/PPP1PPPP/RNBQKBNR w KQkq - 0 2", 3, 15206 }, + { "rnbqkbnr/pp1ppppp/2p5/8/8/3P4/PPPKPPPP/RNBQ1BNR b kq - 1 2", 2, 463 }, + { "rnb1kbnr/pp1ppppp/2p5/q7/8/3P4/PPPKPPPP/RNBQ1BNR w kq - 2 3", 1, 4 }, + { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 1, 8 }, + { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 2, 33 }, + { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 3, 270 }, + { "7k/8/8/8/1p6/P7/1P6/6K1 b - - 0 1", 2, 38 }, + { "7k/8/8/8/8/p7/1P6/6K1 w - - 0 2", 1, 8 }, + { "7k/8/8/8/8/p7/1P6/6K1 w - - 0 2", 2, 36 }, + { "7k/8/8/8/1p6/P7/1P6/6K1 b - - 0 1", 3, 234 }, + { "7k/8/8/8/8/pP6/8/6K1 b - - 0 2", 1, 4 }, + { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 4, 1664 }, + { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 5, 13931 }, + { "7k/8/8/8/1p6/8/PP6/6K1 w - - 0 1", 6, 94162 }, + { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 1, 216 }, + { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 2, 95 }, + { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 3, 18138 }, + { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 4, 80766 }, #if IS_RELEASE == 1 - { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 5, 11649711 } + { "R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNNK1B1 w - - 0 1", 5, 11649711 }, #endif - }; - check_perfts(tests); -} -TEST_CASE("EP 8/2p5/3p4/KP3k1r/2R1Pp2/6P1/8/8 b - e3 0 1") { - std::vector> tests = { - { "8/2p5/3p4/KP3k1r/2R1Pp2/6P1/8/8 b - e3 0 1", 1, 7 }, - { "8/2p5/3p4/KP3k1r/2R1Pp2/6P1/8/8 b - e3 0 1", 2, 108 } - }; - check_perfts(tests); -} -TEST_CASE("kiwipete") { - std::vector> tests = { - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 1, 48 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 2, 2039 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 3, 97862 }, + { "8/2p5/3p4/KP3k1r/2R1Pp2/6P1/8/8 b - e3 0 1", 1, 7 }, + { "8/2p5/3p4/KP3k1r/2R1Pp2/6P1/8/8 b - e3 0 1", 2, 108 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 1, 48 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 2, 2039 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 3, 97862 }, #if IS_RELEASE == 1 - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 4, 4085603 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 5, 193690690 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/P1N2Q1p/1PPBBPPP/R3K2R b KQkq - 0 1", 4, 4627439 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 4, 4085603 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 5, 193690690 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/P1N2Q1p/1PPBBPPP/R3K2R b KQkq - 0 1", 4, 4627439 }, #endif - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/PpN2Q1p/1PPBBPPP/R3K2R w KQkq - 0 2", 3, 103849 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/PPN2Q1p/1P1BBPPP/R3K2R b KQkq - 0 2", 2, 2098 }, - { "r3k2r/p1ppqpb1/1n2pnp1/3PN3/4P3/PPNb1Q1p/1P1BBPPP/R3K2R w KQkq - 1 3", 1, 46 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/P1p2Q1p/1PPBBPPP/R3K2R w KQkq - 0 2", 3, 98073 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/P1p2Q1p/RPPBBPPP/4K2R b Kkq - 1 2", 2, 1926 }, - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/P4Q1p/RPPpBPPP/4K2R w Kkq - 0 3", 1, 3 } - }; - - check_perfts(tests); -} -TEST_CASE("P[3] (chessprogramming)") { - std::vector> tests = { - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 1, 14 }, - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 2, 191 }, - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 3, 2812 }, - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 4, 43238 }, - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 5, 674624 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/PpN2Q1p/1PPBBPPP/R3K2R w KQkq - 0 2", 3, 103849 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/PPN2Q1p/1P1BBPPP/R3K2R b KQkq - 0 2", 2, 2098 }, + { "r3k2r/p1ppqpb1/1n2pnp1/3PN3/4P3/PPNb1Q1p/1P1BBPPP/R3K2R w KQkq - 1 3", 1, 46 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/P1p2Q1p/1PPBBPPP/R3K2R w KQkq - 0 2", 3, 98073 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/P1p2Q1p/RPPBBPPP/4K2R b Kkq - 1 2", 2, 1926 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/4P3/P4Q1p/RPPpBPPP/4K2R w Kkq - 0 3", 1, 3 }, + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 1, 14 }, + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 2, 191 }, + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 3, 2812 }, + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 4, 43238 }, + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 5, 674624 }, #if IS_RELEASE == 1 - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 6, 11030083 }, - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 7, 178633661 } + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 6, 11030083 }, + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", 7, 178633661 }, #endif - }; - check_perfts(tests); -} -TEST_CASE("P[4] (normal) (chessprogramming)") { - std::vector> tests = { - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 1, 6 }, - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 2, 264 }, - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 3, 9467 }, - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 4, 422333 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 1, 6 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 2, 264 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 3, 9467 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 4, 422333 }, #if IS_RELEASE == 1 - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 5, 15833292 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 5, 15833292 }, //{ "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 6, 706045033 }, - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P1RPP/R2Q2K1 b kq - 1 1", 4, 2703427 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P1RPP/R2Q2K1 b kq - 1 1", 4, 2703427 }, #endif - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/5q2/Pp1P1RPP/R2Q2K1 w kq - 0 2", 3, 58801 }, - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/5q2/Pp1P1RPP/R2Q1K2 b kq - 1 2", 2, 1732 }, - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/5q2/P2P1RPP/Rq1Q1K2 w kq - 0 3", 1, 30 }, - { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/8/Pp1P1RPP/R2q1K2 w kq - 0 3", 1, 2 } - }; - check_perfts(tests); -} -TEST_CASE("P[4] (mirrored) (chessprogramming)") { - std::vector> tests = { - { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 1, 6 }, - { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 2, 264 }, - { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 3, 9467 }, - { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 4, 422333 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/5q2/Pp1P1RPP/R2Q2K1 w kq - 0 2", 3, 58801 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/5q2/Pp1P1RPP/R2Q1K2 b kq - 1 2", 2, 1732 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/5q2/P2P1RPP/Rq1Q1K2 w kq - 0 3", 1, 30 }, + { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/8/Pp1P1RPP/R2q1K2 w kq - 0 3", 1, 2 }, + { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 1, 6 }, + { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 2, 264 }, + { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 3, 9467 }, + { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 4, 422333 }, #if IS_RELEASE == 1 - { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 5, 15833292 }, + { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 5, 15833292 }, //{ "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 6, 706045033 } #endif - }; - check_perfts(tests); -} -TEST_CASE("P[5] (chessprogramming)") { - std::vector> tests = { - { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 1, 44 }, - { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 2, 1486 }, - { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 3, 62379 }, + { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 1, 44 }, + { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 2, 1486 }, + { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 3, 62379 }, #if IS_RELEASE == 1 - { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 4, 2103487 }, - { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 5, 89941194 } + { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 4, 2103487 }, + { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 5, 89941194 }, #endif - }; - check_perfts(tests); -} -TEST_CASE("P[6] (chessprogramming)") { - std::vector> tests = { - { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 1, 46 }, - { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 2, 2079 }, - { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 3, 89890 }, + { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 1, 46 }, + { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 2, 2079 }, + { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 3, 89890 }, #if IS_RELEASE == 1 - { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 4, 3894594 }, - { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 5, 164075551 } + { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 4, 3894594 }, + { "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 5, 164075551 }, #endif - }; - check_perfts(tests); -} -TEST_CASE("Promotion") { - std::vector> tests = { - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 1, 5 }, - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 2, 18 }, - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 3, 176 }, - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 4, 859 }, - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 5, 12510 }, - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 6, 63994 }, - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 7, 1109712 }, - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 8, 5763773 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 1, 5 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 2, 18 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 3, 176 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 4, 859 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 5, 12510 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 6, 63994 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 7, 1109712 }, + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 8, 5763773 }, #if IS_RELEASE == 1 - { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 9, 109424670 } + { "7K/5kP1/8/8/8/8/8/8 w - - 0 1", 9, 109424670 }, #endif - }; - check_perfts(tests); -} -TEST_CASE("Minor position test perft") { - std::vector> tests = { // https://www.chessprogramming.net/perfect-perft/ - { "3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1", 6, 1134888 }, - { "8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1", 6, 1015133 }, - { "8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1", 6, 1440467 }, - { "5k2/8/8/8/8/8/8/4K2R w K - 0 1", 6, 661072 }, - { "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1", 6, 803711 }, - { "r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1", 4, 1274206 }, - { "r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1", 4, 1720476 }, - { "8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1", 5, 1004658 }, - { "4k3/1P6/8/8/8/8/K7/8 w - - 0 1", 6, 217342 }, - { "8/P1k5/K7/8/8/8/8/8 w - - 0 1", 6, 92683 }, - { "K1k5/8/P7/8/8/8/8/8 w - - 0 1", 6, 2217 }, - { "8/k1P5/8/1K6/8/8/8/8 w - - 0 1", 7, 567584 }, - { "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1", 4, 23527 }, + { "3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1", 6, 1134888 }, + { "8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1", 6, 1015133 }, + { "8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1", 6, 1440467 }, + { "5k2/8/8/8/8/8/8/4K2R w K - 0 1", 6, 661072 }, + { "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1", 6, 803711 }, + { "r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1", 4, 1274206 }, + { "r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1", 4, 1720476 }, + { "8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1", 5, 1004658 }, + { "4k3/1P6/8/8/8/8/K7/8 w - - 0 1", 6, 217342 }, + { "8/P1k5/K7/8/8/8/8/8 w - - 0 1", 6, 92683 }, + { "K1k5/8/P7/8/8/8/8/8 w - - 0 1", 6, 2217 }, + { "8/k1P5/8/1K6/8/8/8/8 w - - 0 1", 7, 567584 }, + { "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1", 4, 23527 }, // https://github.com/SebLague/Chess-Coding-Adventure/blob/Chess-V2-Unity/Assets/Scripts/Testing/Perft/Suites/Suite%20Full.txt // converted to [fen, depth, nodes], deduped tests - { "2b1b3/1r1P4/3K3p/1p6/2p5/6k1/1P3p2/4B3 w - - 0 42", 5, 5617302 }, + { "2b1b3/1r1P4/3K3p/1p6/2p5/6k1/1P3p2/4B3 w - - 0 42", 5, 5617302 }, #if IS_RELEASE == 1 - { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -", 6, 11030083 }, - { "r3k2r/pp3pp1/PN1pr1p1/4p1P1/4P3/3P4/P1P2PP1/R3K2R w KQkq - 4 4", 5, 15587335 }, - { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 5, 89941194 }, + { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -", 6, 11030083 }, + { "r3k2r/pp3pp1/PN1pr1p1/4p1P1/4P3/3P4/P1P2PP1/R3K2R w KQkq - 4 4", 5, 15587335 }, + { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 5, 89941194 }, #endif #if IS_RELEASE == 1 - { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -", 5, 193690690 }, + { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -", 5, 193690690 }, #endif - { "r3k1nr/p2pp1pp/b1n1P1P1/1BK1Pp1q/8/8/2PP1PPP/6N1 w kq - 0 1", 4, 497787 }, + { "r3k1nr/p2pp1pp/b1n1P1P1/1BK1Pp1q/8/8/2PP1PPP/6N1 w kq - 0 1", 4, 497787 }, #if IS_RELEASE == 1 - { "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1", 7, 15594314 }, + { "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1", 7, 15594314 }, #endif - { "2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1", 6, 3821001 }, - { "K1k5/8/P7/8/8/8/8/8 w - - 0 1", 10, 5966690 }, - { "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1", 6, 3114998 }, - { "4k2r/1pp1n2p/6N1/K2P2r1/1P2P3/P5P1/3b3P/R7 w k - 1 8", 4, 380429 }, + { "2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1", 6, 3821001 }, + { "K1k5/8/P7/8/8/8/8/8 w - - 0 1", 10, 5966690 }, + { "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1", 6, 3114998 }, + { "4k2r/1pp1n2p/6N1/K2P2r1/1P2P3/P5P1/3b3P/R7 w k - 1 8", 4, 380429 }, #if IS_RELEASE == 1 - { "r1bq2r1/1pppkppp/1b3n2/pP1PP3/2n5/2P5/P3QPPP/RNB1K2R w KQ a6 0 12", 5, 42761834 }, - { "4k2r/1pp1n2p/6N1/1K1P2r1/4P3/P5P1/1Pp4P/R7 w k - 0 6", 5, 10574719 }, + { "r1bq2r1/1pppkppp/1b3n2/pP1PP3/2n5/2P5/P3QPPP/RNB1K2R w KQ a6 0 12", 5, 42761834 }, + { "4k2r/1pp1n2p/6N1/1K1P2r1/4P3/P5P1/1Pp4P/R7 w k - 0 6", 5, 10574719 }, #endif - { "r3k2r/pppqbppp/3p1n1B/1N2p3/1nB1P3/3P3b/PPPQNPPP/R3K2R w KQkq - 11 10", 4, 3050662 }, - { "1Bb3BN/R2Pk2r/1Q5B/4q2R/2bN4/4Q1BK/1p6/1bq1R1rb w - - 0 1", 4, 6871272 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 9, 7618365 }, - { "3r4/2p1p3/8/1P1P1P2/3K4/5k2/8/8 b - - 0 1", 4, 28181 }, - { "8/1p4p1/8/q1PK1P1r/3p1k2/8/4P3/4Q3 b - - 0 1", 5, 6323457 }, + { "r3k2r/pppqbppp/3p1n1B/1N2p3/1nB1P3/3P3b/PPPQNPPP/R3K2R w KQkq - 11 10", 4, 3050662 }, + { "1Bb3BN/R2Pk2r/1Q5B/4q2R/2bN4/4Q1BK/1p6/1bq1R1rb w - - 0 1", 4, 6871272 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 9, 7618365 }, + { "3r4/2p1p3/8/1P1P1P2/3K4/5k2/8/8 b - - 0 1", 4, 28181 }, + { "8/1p4p1/8/q1PK1P1r/3p1k2/8/4P3/4Q3 b - - 0 1", 5, 6323457 }, // http://www.rocechess.ch/perft.html - { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 1, 15 }, - { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 2, 66 }, - { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 3, 1197 }, - { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 4, 7059 }, - { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 5, 133987 }, - { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 6, 764643 }, - { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 1, 16 }, - { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 2, 71 }, - { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 3, 1287 }, - { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 4, 7626 }, - { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 5, 145232 }, - { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 6, 846648 }, - { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 1, 5 }, - { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 2, 75 }, - { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 3, 459 }, - { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 4, 8290 }, - { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 5, 47635 }, - { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 6, 899442 }, - { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 1, 5 }, - { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 2, 80 }, - { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 3, 493 }, - { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 4, 8897 }, - { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 5, 52710 }, - { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 6, 1001523 }, - { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 1, 26 }, - { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 2, 112 }, - { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 3, 3189 }, - { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 4, 17945 }, - { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 5, 532933 }, - { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 6, 2788982 }, - { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 1, 5 }, - { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 2, 130 }, - { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 3, 782 }, - { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 4, 22180 }, - { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 5, 118882 }, - { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 6, 3517770 }, - { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 1, 12 }, - { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 2, 38 }, - { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 3, 564 }, - { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 4, 2219 }, - { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 5, 37735 }, - { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 6, 185867 }, - { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 1, 15 }, - { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 2, 65 }, - { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 3, 1018 }, - { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 4, 4573 }, - { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 5, 80619 }, - { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 6, 413018 }, - { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 1, 3 }, - { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 2, 32 }, - { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 3, 134 }, - { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 4, 2073 }, - { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 5, 10485 }, - { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 6, 179869 }, - { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 1, 4 }, - { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 2, 49 }, - { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 3, 243 }, - { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 4, 3991 }, - { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 5, 20780 }, - { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 6, 367724 }, - { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 1, 26 }, - { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 2, 568 }, - { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 3, 13744 }, - { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 4, 314346 }, - { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 5, 7594526 }, + { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 1, 15 }, + { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 2, 66 }, + { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 3, 1197 }, + { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 4, 7059 }, + { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 5, 133987 }, + { "4k3/8/8/8/8/8/8/4K2R w K - 0 1", 6, 764643 }, + { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 1, 16 }, + { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 2, 71 }, + { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 3, 1287 }, + { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 4, 7626 }, + { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 5, 145232 }, + { "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1", 6, 846648 }, + { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 1, 5 }, + { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 2, 75 }, + { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 3, 459 }, + { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 4, 8290 }, + { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 5, 47635 }, + { "4k2r/8/8/8/8/8/8/4K3 w k - 0 1", 6, 899442 }, + { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 1, 5 }, + { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 2, 80 }, + { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 3, 493 }, + { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 4, 8897 }, + { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 5, 52710 }, + { "r3k3/8/8/8/8/8/8/4K3 w q - 0 1", 6, 1001523 }, + { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 1, 26 }, + { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 2, 112 }, + { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 3, 3189 }, + { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 4, 17945 }, + { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 5, 532933 }, + { "4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1", 6, 2788982 }, + { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 1, 5 }, + { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 2, 130 }, + { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 3, 782 }, + { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 4, 22180 }, + { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 5, 118882 }, + { "r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1", 6, 3517770 }, + { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 1, 12 }, + { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 2, 38 }, + { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 3, 564 }, + { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 4, 2219 }, + { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 5, 37735 }, + { "8/8/8/8/8/8/6k1/4K2R w K - 0 1", 6, 185867 }, + { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 1, 15 }, + { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 2, 65 }, + { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 3, 1018 }, + { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 4, 4573 }, + { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 5, 80619 }, + { "8/8/8/8/8/8/1k6/R3K3 w Q - 0 1", 6, 413018 }, + { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 1, 3 }, + { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 2, 32 }, + { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 3, 134 }, + { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 4, 2073 }, + { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 5, 10485 }, + { "4k2r/6K1/8/8/8/8/8/8 w k - 0 1", 6, 179869 }, + { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 1, 4 }, + { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 2, 49 }, + { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 3, 243 }, + { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 4, 3991 }, + { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 5, 20780 }, + { "r3k3/1K6/8/8/8/8/8/8 w q - 0 1", 6, 367724 }, + { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 1, 26 }, + { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 2, 568 }, + { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 3, 13744 }, + { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 4, 314346 }, + { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 5, 7594526 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 6, 179862938 }, + { "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", 6, 179862938 }, #endif - { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 1, 25 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 2, 567 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 3, 14095 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 4, 328965 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 5, 8153719 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 1, 25 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 2, 567 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 3, 14095 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 4, 328965 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 5, 8153719 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 6, 195629489 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1", 6, 195629489 }, #endif - { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 1, 25 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 2, 548 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 3, 13502 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 4, 312835 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 5, 7736373 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 1, 25 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 2, 548 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 3, 13502 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 4, 312835 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 5, 7736373 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 6, 184411439 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1", 6, 184411439 }, #endif - { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 1, 25 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 2, 547 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 3, 13579 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 4, 316214 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 5, 7878456 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 1, 25 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 2, 547 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 3, 13579 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 4, 316214 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 5, 7878456 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 6, 189224276 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1", 6, 189224276 }, #endif - { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 1, 26 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 2, 583 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 3, 14252 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 4, 334705 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 5, 8198901 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 1, 26 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 2, 583 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 3, 14252 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 4, 334705 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 5, 8198901 }, #if IS_RELEASE == 1 - { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 6, 198328929 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 6, 198328929 }, #endif - { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 1, 25 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 2, 560 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 3, 13592 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 4, 317324 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 5, 7710115 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 1, 25 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 2, 560 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 3, 13592 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 4, 317324 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 5, 7710115 }, #if IS_RELEASE == 1 - { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 6, 185959088 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1", 6, 185959088 }, #endif - { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 1, 25 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 2, 560 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 3, 13607 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 4, 320792 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 5, 7848606 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 1, 25 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 2, 560 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 3, 13607 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 4, 320792 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 5, 7848606 }, #if IS_RELEASE == 1 - { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 6, 190755813 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1", 6, 190755813 }, #endif - { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 1, 5 }, - { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 2, 75 }, - { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 3, 459 }, - { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 4, 8290 }, - { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 5, 47635 }, - { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 6, 899442 }, - { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 1, 5 }, - { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 2, 80 }, - { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 3, 493 }, - { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 4, 8897 }, - { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 5, 52710 }, - { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 6, 1001523 }, - { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 1, 15 }, - { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 2, 66 }, - { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 3, 1197 }, - { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 4, 7059 }, - { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 5, 133987 }, - { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 6, 764643 }, - { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 1, 16 }, - { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 2, 71 }, - { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 3, 1287 }, - { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 4, 7626 }, - { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 5, 145232 }, - { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 6, 846648 }, - { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 1, 5 }, - { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 2, 130 }, - { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 3, 782 }, - { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 4, 22180 }, - { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 5, 118882 }, - { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 6, 3517770 }, - { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 1, 26 }, - { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 2, 112 }, - { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 3, 3189 }, - { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 4, 17945 }, - { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 5, 532933 }, - { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 6, 2788982 }, - { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 1, 3 }, - { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 2, 32 }, - { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 3, 134 }, - { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 4, 2073 }, - { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 5, 10485 }, - { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 6, 179869 }, - { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 1, 4 }, - { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 2, 49 }, - { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 3, 243 }, - { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 4, 3991 }, - { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 5, 20780 }, - { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 6, 367724 }, - { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 1, 12 }, - { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 2, 38 }, - { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 3, 564 }, - { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 4, 2219 }, - { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 5, 37735 }, - { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 6, 185867 }, - { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 1, 15 }, - { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 2, 65 }, - { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 3, 1018 }, - { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 4, 4573 }, - { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 5, 80619 }, - { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 6, 413018 }, - { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 1, 26 }, - { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 2, 568 }, - { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 3, 13744 }, - { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 4, 314346 }, - { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 5, 7594526 }, + { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 1, 5 }, + { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 2, 75 }, + { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 3, 459 }, + { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 4, 8290 }, + { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 5, 47635 }, + { "4k3/8/8/8/8/8/8/4K2R b K - 0 1", 6, 899442 }, + { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 1, 5 }, + { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 2, 80 }, + { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 3, 493 }, + { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 4, 8897 }, + { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 5, 52710 }, + { "4k3/8/8/8/8/8/8/R3K3 b Q - 0 1", 6, 1001523 }, + { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 1, 15 }, + { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 2, 66 }, + { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 3, 1197 }, + { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 4, 7059 }, + { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 5, 133987 }, + { "4k2r/8/8/8/8/8/8/4K3 b k - 0 1", 6, 764643 }, + { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 1, 16 }, + { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 2, 71 }, + { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 3, 1287 }, + { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 4, 7626 }, + { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 5, 145232 }, + { "r3k3/8/8/8/8/8/8/4K3 b q - 0 1", 6, 846648 }, + { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 1, 5 }, + { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 2, 130 }, + { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 3, 782 }, + { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 4, 22180 }, + { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 5, 118882 }, + { "4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1", 6, 3517770 }, + { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 1, 26 }, + { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 2, 112 }, + { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 3, 3189 }, + { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 4, 17945 }, + { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 5, 532933 }, + { "r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1", 6, 2788982 }, + { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 1, 3 }, + { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 2, 32 }, + { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 3, 134 }, + { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 4, 2073 }, + { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 5, 10485 }, + { "8/8/8/8/8/8/6k1/4K2R b K - 0 1", 6, 179869 }, + { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 1, 4 }, + { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 2, 49 }, + { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 3, 243 }, + { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 4, 3991 }, + { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 5, 20780 }, + { "8/8/8/8/8/8/1k6/R3K3 b Q - 0 1", 6, 367724 }, + { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 1, 12 }, + { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 2, 38 }, + { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 3, 564 }, + { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 4, 2219 }, + { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 5, 37735 }, + { "4k2r/6K1/8/8/8/8/8/8 b k - 0 1", 6, 185867 }, + { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 1, 15 }, + { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 2, 65 }, + { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 3, 1018 }, + { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 4, 4573 }, + { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 5, 80619 }, + { "r3k3/1K6/8/8/8/8/8/8 b q - 0 1", 6, 413018 }, + { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 1, 26 }, + { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 2, 568 }, + { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 3, 13744 }, + { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 4, 314346 }, + { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 5, 7594526 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 6, 179862938 }, + { "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1", 6, 179862938 }, #endif - { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 1, 26 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 2, 583 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 3, 14252 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 4, 334705 }, - { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 5, 8198901 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 1, 26 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 2, 583 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 3, 14252 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 4, 334705 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 5, 8198901 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 6, 198328929 }, + { "r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1", 6, 198328929 }, #endif - { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 1, 25 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 2, 560 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 3, 13592 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 4, 317324 }, - { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 5, 7710115 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 1, 25 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 2, 560 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 3, 13592 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 4, 317324 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 5, 7710115 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 6, 185959088 }, + { "r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1", 6, 185959088 }, #endif - { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 1, 25 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 2, 560 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 3, 13607 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 4, 320792 }, - { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 5, 7848606 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 1, 25 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 2, 560 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 3, 13607 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 4, 320792 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 5, 7848606 }, #if IS_RELEASE == 1 - { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 6, 190755813 }, + { "r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1", 6, 190755813 }, #endif - { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 1, 25 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 2, 567 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 3, 14095 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 4, 328965 }, - { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 5, 8153719 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 1, 25 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 2, 567 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 3, 14095 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 4, 328965 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 5, 8153719 }, #if IS_RELEASE == 1 - { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 6, 195629489 }, + { "1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 6, 195629489 }, #endif - { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 1, 25 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 2, 548 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 3, 13502 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 4, 312835 }, - { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 5, 7736373 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 1, 25 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 2, 548 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 3, 13502 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 4, 312835 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 5, 7736373 }, #if IS_RELEASE == 1 - { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 6, 184411439 }, + { "2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1", 6, 184411439 }, #endif - { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 1, 25 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 2, 547 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 3, 13579 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 4, 316214 }, - { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 5, 7878456 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 1, 25 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 2, 547 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 3, 13579 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 4, 316214 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 5, 7878456 }, #if IS_RELEASE == 1 - { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 6, 189224276 }, + { "r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1", 6, 189224276 }, #endif - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 1, 14 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 2, 195 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 3, 2760 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 4, 38675 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 5, 570726 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 6, 8107539 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 1, 11 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 2, 156 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 3, 1636 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 4, 20534 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 5, 223507 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 6, 2594412 }, - { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 1, 19 }, - { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 2, 289 }, - { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 3, 4442 }, - { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 4, 73584 }, - { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 5, 1198299 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 1, 14 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 2, 195 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 3, 2760 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 4, 38675 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 5, 570726 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1", 6, 8107539 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 1, 11 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 2, 156 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 3, 1636 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 4, 20534 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 5, 223507 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1", 6, 2594412 }, + { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 1, 19 }, + { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 2, 289 }, + { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 3, 4442 }, + { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 4, 73584 }, + { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 5, 1198299 }, #if IS_RELEASE == 1 - { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 6, 19870403 }, + { "8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1", 6, 19870403 }, #endif - { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 1, 3 }, - { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 2, 51 }, - { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 3, 345 }, - { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 4, 5301 }, - { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 5, 38348 }, - { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 6, 588695 }, - { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 1, 17 }, - { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 2, 54 }, - { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 3, 835 }, - { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 4, 5910 }, - { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 5, 92250 }, - { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 6, 688780 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 1, 15 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 2, 193 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 3, 2816 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 4, 40039 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 5, 582642 }, - { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 6, 8503277 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 1, 16 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 2, 180 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 3, 2290 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 4, 24640 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 5, 288141 }, - { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 6, 3147566 }, - { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 1, 4 }, - { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 2, 68 }, - { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 3, 1118 }, - { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 4, 16199 }, - { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 5, 281190 }, - { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 6, 4405103 }, - { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 1, 17 }, - { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 2, 54 }, - { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 3, 835 }, - { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 4, 5910 }, - { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 5, 92250 }, - { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 6, 688780 }, - { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 1, 3 }, - { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 2, 51 }, - { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 3, 345 }, - { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 4, 5301 }, - { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 5, 38348 }, - { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 6, 588695 }, - { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 1, 17 }, - { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 2, 278 }, - { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 3, 4607 }, - { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 4, 76778 }, - { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 5, 1320507 }, + { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 1, 3 }, + { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 2, 51 }, + { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 3, 345 }, + { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 4, 5301 }, + { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 5, 38348 }, + { "K7/8/2n5/1n6/8/8/8/k6N w - - 0 1", 6, 588695 }, + { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 1, 17 }, + { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 2, 54 }, + { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 3, 835 }, + { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 4, 5910 }, + { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 5, 92250 }, + { "k7/8/2N5/1N6/8/8/8/K6n w - - 0 1", 6, 688780 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 1, 15 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 2, 193 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 3, 2816 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 4, 40039 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 5, 582642 }, + { "8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1", 6, 8503277 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 1, 16 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 2, 180 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 3, 2290 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 4, 24640 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 5, 288141 }, + { "8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1", 6, 3147566 }, + { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 1, 4 }, + { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 2, 68 }, + { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 3, 1118 }, + { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 4, 16199 }, + { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 5, 281190 }, + { "8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1", 6, 4405103 }, + { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 1, 17 }, + { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 2, 54 }, + { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 3, 835 }, + { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 4, 5910 }, + { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 5, 92250 }, + { "K7/8/2n5/1n6/8/8/8/k6N b - - 0 1", 6, 688780 }, + { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 1, 3 }, + { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 2, 51 }, + { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 3, 345 }, + { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 4, 5301 }, + { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 5, 38348 }, + { "k7/8/2N5/1N6/8/8/8/K6n b - - 0 1", 6, 588695 }, + { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 1, 17 }, + { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 2, 278 }, + { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 3, 4607 }, + { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 4, 76778 }, + { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 5, 1320507 }, #if IS_RELEASE == 1 - { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 6, 22823890 }, + { "B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1", 6, 22823890 }, #endif - { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 1, 21 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 2, 316 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 3, 5744 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 4, 93338 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 5, 1713368 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 1, 21 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 2, 316 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 3, 5744 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 4, 93338 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 5, 1713368 }, #if IS_RELEASE == 1 - { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 6, 28861171 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1", 6, 28861171 }, #endif - { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 1, 21 }, - { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 2, 144 }, - { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 3, 3242 }, - { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 4, 32955 }, - { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 5, 787524 }, - { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 6, 7881673 }, - { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 1, 7 }, - { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 2, 143 }, - { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 3, 1416 }, - { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 4, 31787 }, - { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 5, 310862 }, - { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 6, 7382896 }, - { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 1, 6 }, - { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 2, 106 }, - { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 3, 1829 }, - { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 4, 31151 }, - { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 5, 530585 }, - { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 6, 9250746 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 1, 17 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 2, 309 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 3, 5133 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 4, 93603 }, - { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 5, 1591064 }, + { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 1, 21 }, + { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 2, 144 }, + { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 3, 3242 }, + { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 4, 32955 }, + { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 5, 787524 }, + { "k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1", 6, 7881673 }, + { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 1, 7 }, + { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 2, 143 }, + { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 3, 1416 }, + { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 4, 31787 }, + { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 5, 310862 }, + { "K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1", 6, 7382896 }, + { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 1, 6 }, + { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 2, 106 }, + { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 3, 1829 }, + { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 4, 31151 }, + { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 5, 530585 }, + { "B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1", 6, 9250746 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 1, 17 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 2, 309 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 3, 5133 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 4, 93603 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 5, 1591064 }, #if IS_RELEASE == 1 - { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 6, 29027891 }, + { "8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1", 6, 29027891 }, #endif - { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 1, 7 }, - { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 2, 143 }, - { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 3, 1416 }, - { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 4, 31787 }, - { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 5, 310862 }, - { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 6, 7382896 }, - { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 1, 21 }, - { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 2, 144 }, - { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 3, 3242 }, - { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 4, 32955 }, - { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 5, 787524 }, - { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 6, 7881673 }, - { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 1, 19 }, - { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 2, 275 }, - { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 3, 5300 }, - { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 4, 104342 }, - { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 5, 2161211 }, + { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 1, 7 }, + { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 2, 143 }, + { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 3, 1416 }, + { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 4, 31787 }, + { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 5, 310862 }, + { "k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1", 6, 7382896 }, + { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 1, 21 }, + { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 2, 144 }, + { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 3, 3242 }, + { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 4, 32955 }, + { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 5, 787524 }, + { "K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1", 6, 7881673 }, + { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 1, 19 }, + { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 2, 275 }, + { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 3, 5300 }, + { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 4, 104342 }, + { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 5, 2161211 }, #if IS_RELEASE == 1 - { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 6, 44956585 }, + { "7k/RR6/8/8/8/8/rr6/7K w - - 0 1", 6, 44956585 }, #endif - { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 1, 36 }, - { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 2, 1027 }, - { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 3, 29215 }, - { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 4, 771461 }, + { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 1, 36 }, + { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 2, 1027 }, + { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 3, 29215 }, + { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 4, 771461 }, #if IS_RELEASE == 1 - { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 5, 20506480 }, - { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 6, 525169084 }, + { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 5, 20506480 }, + { "R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1", 6, 525169084 }, #endif - { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 1, 19 }, - { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 2, 275 }, - { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 3, 5300 }, - { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 4, 104342 }, - { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 5, 2161211 }, + { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 1, 19 }, + { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 2, 275 }, + { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 3, 5300 }, + { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 4, 104342 }, + { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 5, 2161211 }, #if IS_RELEASE == 1 - { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 6, 44956585 }, + { "7k/RR6/8/8/8/8/rr6/7K b - - 0 1", 6, 44956585 }, #endif - { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 1, 36 }, - { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 2, 1027 }, - { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 3, 29227 }, - { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 4, 771368 }, + { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 1, 36 }, + { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 2, 1027 }, + { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 3, 29227 }, + { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 4, 771368 }, #if IS_RELEASE == 1 - { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 5, 20521342 }, - { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 6, 524966748 }, + { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 5, 20521342 }, + { "R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1", 6, 524966748 }, #endif - { "6kq/8/8/8/8/8/8/7K w - - 0 1", 1, 2 }, - { "6kq/8/8/8/8/8/8/7K w - - 0 1", 2, 36 }, - { "6kq/8/8/8/8/8/8/7K w - - 0 1", 3, 143 }, - { "6kq/8/8/8/8/8/8/7K w - - 0 1", 4, 3637 }, - { "6kq/8/8/8/8/8/8/7K w - - 0 1", 5, 14893 }, - { "6kq/8/8/8/8/8/8/7K w - - 0 1", 6, 391507 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 1, 2 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 2, 36 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 3, 143 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 4, 3637 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 5, 14893 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 6, 391507 }, - { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 1, 6 }, - { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 2, 35 }, - { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 3, 495 }, - { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 4, 8349 }, - { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 5, 166741 }, - { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 6, 3370175 }, - { "6qk/8/8/8/8/8/8/7K b - - 0 1", 1, 22 }, - { "6qk/8/8/8/8/8/8/7K b - - 0 1", 2, 43 }, - { "6qk/8/8/8/8/8/8/7K b - - 0 1", 3, 1015 }, - { "6qk/8/8/8/8/8/8/7K b - - 0 1", 4, 4167 }, - { "6qk/8/8/8/8/8/8/7K b - - 0 1", 5, 105749 }, - { "6qk/8/8/8/8/8/8/7K b - - 0 1", 6, 419369 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 1, 2 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 2, 36 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 3, 143 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 4, 3637 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 5, 14893 }, - { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 6, 391507 }, - { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 1, 6 }, - { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 2, 35 }, - { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 3, 495 }, - { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 4, 8349 }, - { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 5, 166741 }, - { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 6, 3370175 }, - { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 1, 3 }, - { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 2, 7 }, - { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 3, 43 }, - { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 4, 199 }, - { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 5, 1347 }, - { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 6, 6249 }, - { "8/8/8/8/8/7K/7P/7k w - - 0 1", 1, 3 }, - { "8/8/8/8/8/7K/7P/7k w - - 0 1", 2, 7 }, - { "8/8/8/8/8/7K/7P/7k w - - 0 1", 3, 43 }, - { "8/8/8/8/8/7K/7P/7k w - - 0 1", 4, 199 }, - { "8/8/8/8/8/7K/7P/7k w - - 0 1", 5, 1347 }, - { "8/8/8/8/8/7K/7P/7k w - - 0 1", 6, 6249 }, - { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 1, 1 }, - { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 2, 3 }, - { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 3, 12 }, - { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 4, 80 }, - { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 5, 342 }, - { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 6, 2343 }, - { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 1, 1 }, - { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 2, 3 }, - { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 3, 12 }, - { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 4, 80 }, - { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 5, 342 }, - { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 6, 2343 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 1, 7 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 2, 35 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 3, 210 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 4, 1091 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 5, 7028 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 6, 34834 }, - { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 1, 1 }, - { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 2, 3 }, - { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 3, 12 }, - { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 4, 80 }, - { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 5, 342 }, - { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 6, 2343 }, - { "8/8/8/8/8/7K/7P/7k b - - 0 1", 1, 1 }, - { "8/8/8/8/8/7K/7P/7k b - - 0 1", 2, 3 }, - { "8/8/8/8/8/7K/7P/7k b - - 0 1", 3, 12 }, - { "8/8/8/8/8/7K/7P/7k b - - 0 1", 4, 80 }, - { "8/8/8/8/8/7K/7P/7k b - - 0 1", 5, 342 }, - { "8/8/8/8/8/7K/7P/7k b - - 0 1", 6, 2343 }, - { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 1, 3 }, - { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 2, 7 }, - { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 3, 43 }, - { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 4, 199 }, - { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 5, 1347 }, - { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 6, 6249 }, - { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 1, 3 }, - { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 2, 7 }, - { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 3, 43 }, - { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 4, 199 }, - { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 5, 1347 }, - { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 6, 6249 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 1, 5 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 2, 35 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 3, 182 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 4, 1091 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 5, 5408 }, - { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 6, 34822 }, - { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 1, 2 }, - { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 2, 8 }, - { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 3, 44 }, - { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 4, 282 }, - { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 5, 1814 }, - { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 6, 11848 }, - { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 1, 2 }, - { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 2, 8 }, - { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 3, 44 }, - { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 4, 282 }, - { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 5, 1814 }, - { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 6, 11848 }, - { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 1, 3 }, - { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 2, 9 }, - { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 3, 57 }, - { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 4, 360 }, - { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 5, 1969 }, - { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 6, 10724 }, - { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 1, 3 }, - { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 2, 9 }, - { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 3, 57 }, - { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 4, 360 }, - { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 5, 1969 }, - { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 6, 10724 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 1, 5 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 2, 25 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 3, 180 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 4, 1294 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 5, 8296 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 6, 53138 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 1, 8 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 2, 61 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 3, 483 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 4, 3213 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 5, 23599 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 6, 157093 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 1, 8 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 2, 61 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 3, 411 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 4, 3213 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 5, 21637 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 6, 158065 }, - { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 1, 4 }, - { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 2, 15 }, - { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 3, 90 }, - { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 4, 534 }, - { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 5, 3450 }, - { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 6, 20960 }, - { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 1, 3 }, - { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 2, 9 }, - { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 3, 57 }, - { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 4, 360 }, - { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 5, 1969 }, - { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 6, 10724 }, - { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 1, 3 }, - { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 2, 9 }, - { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 3, 57 }, - { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 4, 360 }, - { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 5, 1969 }, - { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 6, 10724 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 1, 5 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 2, 25 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 3, 180 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 4, 1294 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 5, 8296 }, - { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 6, 53138 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 1, 8 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 2, 61 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 3, 411 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 4, 3213 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 5, 21637 }, - { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 6, 158065 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 1, 8 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 2, 61 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 3, 483 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 4, 3213 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 5, 23599 }, - { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 6, 157093 }, - { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 1, 4 }, - { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 2, 15 }, - { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 3, 89 }, - { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 4, 537 }, - { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 5, 3309 }, - { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 6, 21104 }, - { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 1, 4 }, - { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 2, 19 }, - { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 3, 117 }, - { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 4, 720 }, - { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 5, 4661 }, - { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 6, 32191 }, - { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 1, 5 }, - { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 2, 19 }, - { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 3, 116 }, - { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 4, 716 }, - { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 5, 4786 }, - { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 6, 30980 }, - { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 1, 5 }, - { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 2, 22 }, - { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 3, 139 }, - { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 4, 877 }, - { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 5, 6112 }, - { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 6, 41874 }, - { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 1, 4 }, - { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 2, 16 }, - { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 3, 101 }, - { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 4, 637 }, - { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 5, 4354 }, - { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 6, 29679 }, - { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 1, 5 }, - { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 2, 22 }, - { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 3, 139 }, - { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 4, 877 }, - { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 5, 6112 }, - { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 6, 41874 }, - { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 1, 4 }, - { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 2, 16 }, - { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 3, 101 }, - { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 4, 637 }, - { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 5, 4354 }, - { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 6, 29679 }, - { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 1, 3 }, - { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 2, 15 }, - { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 3, 84 }, - { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 4, 573 }, - { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 5, 3013 }, - { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 6, 22886 }, - { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 1, 4 }, - { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 2, 16 }, - { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 3, 101 }, - { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 4, 637 }, - { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 5, 4271 }, - { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 6, 28662 }, - { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 1, 5 }, - { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 2, 19 }, - { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 3, 117 }, - { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 4, 720 }, - { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 5, 5014 }, - { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 6, 32167 }, - { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 1, 4 }, - { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 2, 19 }, - { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 3, 117 }, - { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 4, 712 }, - { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 5, 4658 }, - { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 6, 30749 }, - { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 1, 5 }, - { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 2, 22 }, - { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 3, 139 }, - { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 4, 877 }, - { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 5, 6112 }, - { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 6, 41874 }, - { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 1, 4 }, - { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 2, 16 }, - { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 3, 101 }, - { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 4, 637 }, - { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 5, 4354 }, - { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 6, 29679 }, - { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 1, 5 }, - { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 2, 22 }, - { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 3, 139 }, - { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 4, 877 }, - { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 5, 6112 }, - { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 6, 41874 }, - { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 1, 4 }, - { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 2, 16 }, - { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 3, 101 }, - { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 4, 637 }, - { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 5, 4354 }, - { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 6, 29679 }, - { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 1, 5 }, - { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 2, 15 }, - { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 3, 102 }, - { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 4, 569 }, - { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 5, 4337 }, - { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 6, 22579 }, - { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 1, 4 }, - { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 2, 16 }, - { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 3, 101 }, - { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 4, 637 }, - { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 5, 4271 }, - { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 6, 28662 }, - { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 1, 5 }, - { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 2, 22 }, - { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 3, 139 }, - { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 4, 877 }, - { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 5, 6112 }, - { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 6, 41874 }, - { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 1, 4 }, - { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 2, 16 }, - { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 3, 101 }, - { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 4, 637 }, - { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 5, 4354 }, - { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 6, 29679 }, - { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 1, 5 }, - { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 2, 22 }, - { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 3, 139 }, - { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 4, 877 }, - { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 5, 6112 }, - { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 6, 41874 }, - { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 1, 4 }, - { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 2, 16 }, - { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 3, 101 }, - { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 4, 637 }, - { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 5, 4354 }, - { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 6, 29679 }, - { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 1, 5 }, - { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 2, 25 }, - { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 3, 161 }, - { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 4, 1035 }, - { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 5, 7574 }, - { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 6, 55338 }, - { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 1, 5 }, - { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 2, 25 }, - { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 3, 161 }, - { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 4, 1035 }, - { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 5, 7574 }, - { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 6, 55338 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 1, 7 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 2, 49 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 3, 378 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 4, 2902 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 5, 24122 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 6, 199002 }, - { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 1, 5 }, - { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 2, 22 }, - { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 3, 139 }, - { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 4, 877 }, - { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 5, 6112 }, - { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 6, 41874 }, - { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 1, 4 }, - { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 2, 16 }, - { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 3, 101 }, - { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 4, 637 }, - { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 5, 4354 }, - { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 6, 29679 }, - { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 1, 5 }, - { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 2, 22 }, - { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 3, 139 }, - { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 4, 877 }, - { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 5, 6112 }, - { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 6, 41874 }, - { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 1, 4 }, - { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 2, 16 }, - { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 3, 101 }, - { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 4, 637 }, - { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 5, 4354 }, - { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 6, 29679 }, - { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 1, 5 }, - { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 2, 25 }, - { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 3, 161 }, - { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 4, 1035 }, - { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 5, 7574 }, - { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 6, 55338 }, - { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 1, 5 }, - { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 2, 25 }, - { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 3, 161 }, - { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 4, 1035 }, - { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 5, 7574 }, - { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 6, 55338 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 1, 7 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 2, 49 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 3, 378 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 4, 2902 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 5, 24122 }, - { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 6, 199002 }, - { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 1, 11 }, - { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 2, 97 }, - { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 3, 887 }, - { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 4, 8048 }, - { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 5, 90606 }, - { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 6, 1030499 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 1, 24 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 2, 421 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 3, 7421 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 4, 124608 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 5, 2193768 }, + { "6kq/8/8/8/8/8/8/7K w - - 0 1", 1, 2 }, + { "6kq/8/8/8/8/8/8/7K w - - 0 1", 2, 36 }, + { "6kq/8/8/8/8/8/8/7K w - - 0 1", 3, 143 }, + { "6kq/8/8/8/8/8/8/7K w - - 0 1", 4, 3637 }, + { "6kq/8/8/8/8/8/8/7K w - - 0 1", 5, 14893 }, + { "6kq/8/8/8/8/8/8/7K w - - 0 1", 6, 391507 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 1, 2 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 2, 36 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 3, 143 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 4, 3637 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 5, 14893 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 6, 391507 }, + { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 1, 6 }, + { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 2, 35 }, + { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 3, 495 }, + { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 4, 8349 }, + { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 5, 166741 }, + { "K7/8/8/3Q4/4q3/8/8/7k w - - 0 1", 6, 3370175 }, + { "6qk/8/8/8/8/8/8/7K b - - 0 1", 1, 22 }, + { "6qk/8/8/8/8/8/8/7K b - - 0 1", 2, 43 }, + { "6qk/8/8/8/8/8/8/7K b - - 0 1", 3, 1015 }, + { "6qk/8/8/8/8/8/8/7K b - - 0 1", 4, 4167 }, + { "6qk/8/8/8/8/8/8/7K b - - 0 1", 5, 105749 }, + { "6qk/8/8/8/8/8/8/7K b - - 0 1", 6, 419369 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 1, 2 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 2, 36 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 3, 143 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 4, 3637 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 5, 14893 }, + { "6KQ/8/8/8/8/8/8/7k b - - 0 1", 6, 391507 }, + { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 1, 6 }, + { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 2, 35 }, + { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 3, 495 }, + { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 4, 8349 }, + { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 5, 166741 }, + { "K7/8/8/3Q4/4q3/8/8/7k b - - 0 1", 6, 3370175 }, + { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 1, 3 }, + { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 2, 7 }, + { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 3, 43 }, + { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 4, 199 }, + { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 5, 1347 }, + { "8/8/8/8/8/K7/P7/k7 w - - 0 1", 6, 6249 }, + { "8/8/8/8/8/7K/7P/7k w - - 0 1", 1, 3 }, + { "8/8/8/8/8/7K/7P/7k w - - 0 1", 2, 7 }, + { "8/8/8/8/8/7K/7P/7k w - - 0 1", 3, 43 }, + { "8/8/8/8/8/7K/7P/7k w - - 0 1", 4, 199 }, + { "8/8/8/8/8/7K/7P/7k w - - 0 1", 5, 1347 }, + { "8/8/8/8/8/7K/7P/7k w - - 0 1", 6, 6249 }, + { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 1, 1 }, + { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 2, 3 }, + { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 3, 12 }, + { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 4, 80 }, + { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 5, 342 }, + { "K7/p7/k7/8/8/8/8/8 w - - 0 1", 6, 2343 }, + { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 1, 1 }, + { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 2, 3 }, + { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 3, 12 }, + { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 4, 80 }, + { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 5, 342 }, + { "7K/7p/7k/8/8/8/8/8 w - - 0 1", 6, 2343 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 1, 7 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 2, 35 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 3, 210 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 4, 1091 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 5, 7028 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1", 6, 34834 }, + { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 1, 1 }, + { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 2, 3 }, + { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 3, 12 }, + { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 4, 80 }, + { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 5, 342 }, + { "8/8/8/8/8/K7/P7/k7 b - - 0 1", 6, 2343 }, + { "8/8/8/8/8/7K/7P/7k b - - 0 1", 1, 1 }, + { "8/8/8/8/8/7K/7P/7k b - - 0 1", 2, 3 }, + { "8/8/8/8/8/7K/7P/7k b - - 0 1", 3, 12 }, + { "8/8/8/8/8/7K/7P/7k b - - 0 1", 4, 80 }, + { "8/8/8/8/8/7K/7P/7k b - - 0 1", 5, 342 }, + { "8/8/8/8/8/7K/7P/7k b - - 0 1", 6, 2343 }, + { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 1, 3 }, + { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 2, 7 }, + { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 3, 43 }, + { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 4, 199 }, + { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 5, 1347 }, + { "K7/p7/k7/8/8/8/8/8 b - - 0 1", 6, 6249 }, + { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 1, 3 }, + { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 2, 7 }, + { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 3, 43 }, + { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 4, 199 }, + { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 5, 1347 }, + { "7K/7p/7k/8/8/8/8/8 b - - 0 1", 6, 6249 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 1, 5 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 2, 35 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 3, 182 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 4, 1091 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 5, 5408 }, + { "8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1", 6, 34822 }, + { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 1, 2 }, + { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 2, 8 }, + { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 3, 44 }, + { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 4, 282 }, + { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 5, 1814 }, + { "8/8/8/8/8/4k3/4P3/4K3 w - - 0 1", 6, 11848 }, + { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 1, 2 }, + { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 2, 8 }, + { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 3, 44 }, + { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 4, 282 }, + { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 5, 1814 }, + { "4k3/4p3/4K3/8/8/8/8/8 b - - 0 1", 6, 11848 }, + { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 1, 3 }, + { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 2, 9 }, + { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 3, 57 }, + { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 4, 360 }, + { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 5, 1969 }, + { "8/8/7k/7p/7P/7K/8/8 w - - 0 1", 6, 10724 }, + { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 1, 3 }, + { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 2, 9 }, + { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 3, 57 }, + { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 4, 360 }, + { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 5, 1969 }, + { "8/8/k7/p7/P7/K7/8/8 w - - 0 1", 6, 10724 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 1, 5 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 2, 25 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 3, 180 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 4, 1294 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 5, 8296 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1", 6, 53138 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 1, 8 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 2, 61 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 3, 483 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 4, 3213 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 5, 23599 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1", 6, 157093 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 1, 8 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 2, 61 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 3, 411 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 4, 3213 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 5, 21637 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1", 6, 158065 }, + { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 1, 4 }, + { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 2, 15 }, + { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 3, 90 }, + { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 4, 534 }, + { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 5, 3450 }, + { "k7/8/3p4/8/3P4/8/8/7K w - - 0 1", 6, 20960 }, + { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 1, 3 }, + { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 2, 9 }, + { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 3, 57 }, + { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 4, 360 }, + { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 5, 1969 }, + { "8/8/7k/7p/7P/7K/8/8 b - - 0 1", 6, 10724 }, + { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 1, 3 }, + { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 2, 9 }, + { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 3, 57 }, + { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 4, 360 }, + { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 5, 1969 }, + { "8/8/k7/p7/P7/K7/8/8 b - - 0 1", 6, 10724 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 1, 5 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 2, 25 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 3, 180 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 4, 1294 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 5, 8296 }, + { "8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1", 6, 53138 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 1, 8 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 2, 61 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 3, 411 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 4, 3213 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 5, 21637 }, + { "8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1", 6, 158065 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 1, 8 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 2, 61 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 3, 483 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 4, 3213 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 5, 23599 }, + { "8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1", 6, 157093 }, + { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 1, 4 }, + { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 2, 15 }, + { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 3, 89 }, + { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 4, 537 }, + { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 5, 3309 }, + { "k7/8/3p4/8/3P4/8/8/7K b - - 0 1", 6, 21104 }, + { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 1, 4 }, + { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 2, 19 }, + { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 3, 117 }, + { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 4, 720 }, + { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 5, 4661 }, + { "7k/3p4/8/8/3P4/8/8/K7 w - - 0 1", 6, 32191 }, + { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 1, 5 }, + { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 2, 19 }, + { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 3, 116 }, + { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 4, 716 }, + { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 5, 4786 }, + { "7k/8/8/3p4/8/8/3P4/K7 w - - 0 1", 6, 30980 }, + { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 1, 5 }, + { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 2, 22 }, + { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 3, 139 }, + { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 4, 877 }, + { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 5, 6112 }, + { "k7/8/8/7p/6P1/8/8/K7 w - - 0 1", 6, 41874 }, + { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 1, 4 }, + { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 2, 16 }, + { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 3, 101 }, + { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 4, 637 }, + { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 5, 4354 }, + { "k7/8/7p/8/8/6P1/8/K7 w - - 0 1", 6, 29679 }, + { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 1, 5 }, + { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 2, 22 }, + { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 3, 139 }, + { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 4, 877 }, + { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 5, 6112 }, + { "k7/8/8/6p1/7P/8/8/K7 w - - 0 1", 6, 41874 }, + { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 1, 4 }, + { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 2, 16 }, + { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 3, 101 }, + { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 4, 637 }, + { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 5, 4354 }, + { "k7/8/6p1/8/8/7P/8/K7 w - - 0 1", 6, 29679 }, + { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 1, 3 }, + { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 2, 15 }, + { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 3, 84 }, + { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 4, 573 }, + { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 5, 3013 }, + { "k7/8/8/3p4/4p3/8/8/7K w - - 0 1", 6, 22886 }, + { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 1, 4 }, + { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 2, 16 }, + { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 3, 101 }, + { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 4, 637 }, + { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 5, 4271 }, + { "k7/8/3p4/8/8/4P3/8/7K w - - 0 1", 6, 28662 }, + { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 1, 5 }, + { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 2, 19 }, + { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 3, 117 }, + { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 4, 720 }, + { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 5, 5014 }, + { "7k/3p4/8/8/3P4/8/8/K7 b - - 0 1", 6, 32167 }, + { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 1, 4 }, + { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 2, 19 }, + { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 3, 117 }, + { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 4, 712 }, + { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 5, 4658 }, + { "7k/8/8/3p4/8/8/3P4/K7 b - - 0 1", 6, 30749 }, + { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 1, 5 }, + { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 2, 22 }, + { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 3, 139 }, + { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 4, 877 }, + { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 5, 6112 }, + { "k7/8/8/7p/6P1/8/8/K7 b - - 0 1", 6, 41874 }, + { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 1, 4 }, + { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 2, 16 }, + { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 3, 101 }, + { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 4, 637 }, + { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 5, 4354 }, + { "k7/8/7p/8/8/6P1/8/K7 b - - 0 1", 6, 29679 }, + { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 1, 5 }, + { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 2, 22 }, + { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 3, 139 }, + { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 4, 877 }, + { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 5, 6112 }, + { "k7/8/8/6p1/7P/8/8/K7 b - - 0 1", 6, 41874 }, + { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 1, 4 }, + { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 2, 16 }, + { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 3, 101 }, + { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 4, 637 }, + { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 5, 4354 }, + { "k7/8/6p1/8/8/7P/8/K7 b - - 0 1", 6, 29679 }, + { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 1, 5 }, + { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 2, 15 }, + { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 3, 102 }, + { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 4, 569 }, + { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 5, 4337 }, + { "k7/8/8/3p4/4p3/8/8/7K b - - 0 1", 6, 22579 }, + { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 1, 4 }, + { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 2, 16 }, + { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 3, 101 }, + { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 4, 637 }, + { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 5, 4271 }, + { "k7/8/3p4/8/8/4P3/8/7K b - - 0 1", 6, 28662 }, + { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 1, 5 }, + { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 2, 22 }, + { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 3, 139 }, + { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 4, 877 }, + { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 5, 6112 }, + { "7k/8/8/p7/1P6/8/8/7K w - - 0 1", 6, 41874 }, + { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 1, 4 }, + { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 2, 16 }, + { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 3, 101 }, + { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 4, 637 }, + { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 5, 4354 }, + { "7k/8/p7/8/8/1P6/8/7K w - - 0 1", 6, 29679 }, + { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 1, 5 }, + { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 2, 22 }, + { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 3, 139 }, + { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 4, 877 }, + { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 5, 6112 }, + { "7k/8/8/1p6/P7/8/8/7K w - - 0 1", 6, 41874 }, + { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 1, 4 }, + { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 2, 16 }, + { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 3, 101 }, + { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 4, 637 }, + { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 5, 4354 }, + { "7k/8/1p6/8/8/P7/8/7K w - - 0 1", 6, 29679 }, + { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 1, 5 }, + { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 2, 25 }, + { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 3, 161 }, + { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 4, 1035 }, + { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 5, 7574 }, + { "k7/7p/8/8/8/8/6P1/K7 w - - 0 1", 6, 55338 }, + { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 1, 5 }, + { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 2, 25 }, + { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 3, 161 }, + { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 4, 1035 }, + { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 5, 7574 }, + { "k7/6p1/8/8/8/8/7P/K7 w - - 0 1", 6, 55338 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 1, 7 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 2, 49 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 3, 378 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 4, 2902 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 5, 24122 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1", 6, 199002 }, + { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 1, 5 }, + { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 2, 22 }, + { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 3, 139 }, + { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 4, 877 }, + { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 5, 6112 }, + { "7k/8/8/p7/1P6/8/8/7K b - - 0 1", 6, 41874 }, + { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 1, 4 }, + { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 2, 16 }, + { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 3, 101 }, + { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 4, 637 }, + { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 5, 4354 }, + { "7k/8/p7/8/8/1P6/8/7K b - - 0 1", 6, 29679 }, + { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 1, 5 }, + { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 2, 22 }, + { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 3, 139 }, + { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 4, 877 }, + { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 5, 6112 }, + { "7k/8/8/1p6/P7/8/8/7K b - - 0 1", 6, 41874 }, + { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 1, 4 }, + { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 2, 16 }, + { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 3, 101 }, + { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 4, 637 }, + { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 5, 4354 }, + { "7k/8/1p6/8/8/P7/8/7K b - - 0 1", 6, 29679 }, + { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 1, 5 }, + { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 2, 25 }, + { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 3, 161 }, + { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 4, 1035 }, + { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 5, 7574 }, + { "k7/7p/8/8/8/8/6P1/K7 b - - 0 1", 6, 55338 }, + { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 1, 5 }, + { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 2, 25 }, + { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 3, 161 }, + { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 4, 1035 }, + { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 5, 7574 }, + { "k7/6p1/8/8/8/8/7P/K7 b - - 0 1", 6, 55338 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 1, 7 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 2, 49 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 3, 378 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 4, 2902 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 5, 24122 }, + { "3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1", 6, 199002 }, + { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 1, 11 }, + { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 2, 97 }, + { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 3, 887 }, + { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 4, 8048 }, + { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 5, 90606 }, + { "8/Pk6/8/8/8/8/6Kp/8 w - - 0 1", 6, 1030499 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 1, 24 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 2, 421 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 3, 7421 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 4, 124608 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 5, 2193768 }, #if IS_RELEASE == 1 - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 6, 37665329 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1", 6, 37665329 }, #endif - { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 1, 18 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 2, 270 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 3, 4699 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 4, 79355 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 5, 1533145 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 1, 18 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 2, 270 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 3, 4699 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 4, 79355 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 5, 1533145 }, #if IS_RELEASE == 1 - { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 6, 28859283 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1", 6, 28859283 }, #endif - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 1, 24 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 2, 496 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 3, 9483 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 4, 182838 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 5, 3605103 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 1, 24 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 2, 496 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 3, 9483 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 4, 182838 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 5, 3605103 }, #if IS_RELEASE == 1 - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 6, 71179139 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1", 6, 71179139 }, #endif - { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 1, 11 }, - { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 2, 97 }, - { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 3, 887 }, - { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 4, 8048 }, - { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 5, 90606 }, + { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 1, 11 }, + { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 2, 97 }, + { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 3, 887 }, + { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 4, 8048 }, + { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 5, 90606 }, #if IS_RELEASE == 1 - { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 6, 1030499 }, + { "8/Pk6/8/8/8/8/6Kp/8 b - - 0 1", 6, 1030499 }, #endif - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 1, 24 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 2, 421 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 3, 7421 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 4, 124608 }, - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 5, 2193768 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 1, 24 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 2, 421 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 3, 7421 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 4, 124608 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 5, 2193768 }, #if IS_RELEASE == 1 - { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 6, 37665329 }, + { "n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1", 6, 37665329 }, #endif - { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 1, 18 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 2, 270 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 3, 4699 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 4, 79355 }, - { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 5, 1533145 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 1, 18 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 2, 270 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 3, 4699 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 4, 79355 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 5, 1533145 }, #if IS_RELEASE == 1 - { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 6, 28859283 }, + { "8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1", 6, 28859283 }, #endif - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 1, 24 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 2, 496 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 3, 9483 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 4, 182838 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 5, 3605103 }, - { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 6, 71179139 }, - }; - check_perfts(tests); -} -TEST_CASE("Random position perfts") { - std::vector> positions = { - { "6k1/2nNrq2/bb1P2NR/P2bqqN1/qpKQ3n/2Rn2B1/B1r1N3/1Q1Nb3 w - - 0 1", 5, 0 }, // checkmate - { "K7/3n3R/1r4k1/8/8/8/2p5/8 w - - 0 1", 5, 1056215 }, - { "1Qn2n1k/P1K2P2/1pr2nrP/1p2Q1b1/bPP2B2/p2B1q1N/2Rpp1pn/Q3Q1N1 w - - 0 1", 1, 2 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 1, 24 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 2, 496 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 3, 9483 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 4, 182838 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 5, 3605103 }, + { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", 6, 71179139 }, + { "6k1/2nNrq2/bb1P2NR/P2bqqN1/qpKQ3n/2Rn2B1/B1r1N3/1Q1Nb3 w - - 0 1", 5, 0 }, // checkmate + { "K7/3n3R/1r4k1/8/8/8/2p5/8 w - - 0 1", 5, 1056215 }, + { "1Qn2n1k/P1K2P2/1pr2nrP/1p2Q1b1/bPP2B2/p2B1q1N/2Rpp1pn/Q3Q1N1 w - - 0 1", 1, 2 }, #if IS_RELEASE == 1 - { "1Qn2n1k/P1K2P2/1pr2nrP/1p2Q1b1/bPP2B2/p2B1q1N/2Rpp1pn/Q3Q1N1 w - - 0 1", 5, 11921325 }, + { "1Qn2n1k/P1K2P2/1pr2nrP/1p2Q1b1/bPP2B2/p2B1q1N/2Rpp1pn/Q3Q1N1 w - - 0 1", 5, 11921325 }, #endif - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 1, 3 }, - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 2, 57 }, - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 3, 261 }, - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 4, 4897 }, - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 5, 22176 }, - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 6, 413723 }, - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 7, 2109569 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 1, 3 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 2, 57 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 3, 261 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 4, 4897 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 5, 22176 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 6, 413723 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 7, 2109569 }, #if IS_RELEASE == 1 - { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 8, 39470570 }, + { "8/7K/8/8/8/5R2/8/k7 b - - 0 1", 8, 39470570 }, #endif - { "8/5K1p/r7/6q1/2p5/5qk1/8/8 w - - 0 1", 1, 1 }, - { "8/5K1p/r7/6q1/2p5/5qk1/8/8 w - - 0 1", 5, 17218 }, - { "3n2r1/2k2B1q/3B2Q1/N1n1P3/1r1R1NQ1/2brB1r1/PQB5/bK6 b - - 0 1", 1, 1 }, + { "8/5K1p/r7/6q1/2p5/5qk1/8/8 w - - 0 1", 1, 1 }, + { "8/5K1p/r7/6q1/2p5/5qk1/8/8 w - - 0 1", 5, 17218 }, + { "3n2r1/2k2B1q/3B2Q1/N1n1P3/1r1R1NQ1/2brB1r1/PQB5/bK6 b - - 0 1", 1, 1 }, #if IS_RELEASE == 1 - { "3n2r1/2k2B1q/3B2Q1/N1n1P3/1r1R1NQ1/2brB1r1/PQB5/bK6 b - - 0 1", 5, 7037862 }, + { "3n2r1/2k2B1q/3B2Q1/N1n1P3/1r1R1NQ1/2brB1r1/PQB5/bK6 b - - 0 1", 5, 7037862 }, #endif - { "4q2R/BQ1Np2k/4pn2/bK1N4/4p3/1n6/8/8 b - - 0 1", 1, 4 }, + { "4q2R/BQ1Np2k/4pn2/bK1N4/4p3/1n6/8/8 b - - 0 1", 1, 4 }, #if IS_RELEASE == 1 - { "4q2R/BQ1Np2k/4pn2/bK1N4/4p3/1n6/8/8 b - - 0 1", 5, 3945793 }, + { "4q2R/BQ1Np2k/4pn2/bK1N4/4p3/1n6/8/8 b - - 0 1", 5, 3945793 }, #endif - { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 1, 5 }, - { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 5, 188155 }, - { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 6, 5537444 }, + { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 1, 5 }, + { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 5, 188155 }, + { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 6, 5537444 }, #if IS_RELEASE == 1 - { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 7, 33107724 }, + { "1K6/6N1/5Q2/5p2/4Pk2/8/8/8 b - - 0 1", 7, 33107724 }, #endif - { "k2bR1B1/NR3B2/2BR4/1N1p1bN1/N3b3/7r/B2n1KN1/2Q5 w - - 0 1", 1, 64 }, + { "k2bR1B1/NR3B2/2BR4/1N1p1bN1/N3b3/7r/B2n1KN1/2Q5 w - - 0 1", 1, 64 }, #if IS_RELEASE == 1 - { "k2bR1B1/NR3B2/2BR4/1N1p1bN1/N3b3/7r/B2n1KN1/2Q5 w - - 0 1", 4, 2641743 }, + { "k2bR1B1/NR3B2/2BR4/1N1p1bN1/N3b3/7r/B2n1KN1/2Q5 w - - 0 1", 4, 2641743 }, #endif - { "4B3/8/5K2/8/8/3k4/8/5N2 b - - 0 1", 1, 6 }, - { "4B3/8/5K2/8/8/3k4/8/5N2 b - - 0 1", 5, 71831 }, + { "4B3/8/5K2/8/8/3k4/8/5N2 b - - 0 1", 1, 6 }, + { "4B3/8/5K2/8/8/3k4/8/5N2 b - - 0 1", 5, 71831 }, #if IS_RELEASE == 1 - { "4B3/8/5K2/8/8/3k4/8/5N2 b - - 0 1", 6, 1376826 }, + { "4B3/8/5K2/8/8/3k4/8/5N2 b - - 0 1", 6, 1376826 }, #endif - { "3q3B/3Q4/1k1N4/5Q2/6Q1/1B2N2Q/K4bB1/2q2N2 b - - 0 1", 1, 35 }, + { "3q3B/3Q4/1k1N4/5Q2/6Q1/1B2N2Q/K4bB1/2q2N2 b - - 0 1", 1, 35 }, #if IS_RELEASE == 1 - { "3q3B/3Q4/1k1N4/5Q2/6Q1/1B2N2Q/K4bB1/2q2N2 b - - 0 1", 4, 5855605 }, + { "3q3B/3Q4/1k1N4/5Q2/6Q1/1B2N2Q/K4bB1/2q2N2 b - - 0 1", 4, 5855605 }, #endif - { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 1, 8 }, - { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 5, 50950 }, + { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 1, 8 }, + { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 5, 50950 }, #if IS_RELEASE == 1 - { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 7, 3844295 }, + { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 7, 3844295 }, #endif #if IS_RELEASE == 1 - { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 8, 47694794 }, + { "8/1K6/8/8/6n1/1k6/8/8 w - - 0 1", 8, 47694794 }, #endif - { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 1, 63 }, - { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 2, 168 }, - { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 3, 10739 }, - { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 4, 28349 }, + { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 1, 63 }, + { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 2, 168 }, + { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 3, 10739 }, + { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 4, 28349 }, #if IS_RELEASE == 1 - { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 5, 1804208 }, - { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 6, 5073106 }, + { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 5, 1804208 }, + { "8/5qk1/8/2Kb2r1/8/1b5r/2n5/1b6 b - - 0 1", 6, 5073106 }, #endif - { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 1, 13 }, - { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 2, 376 }, - { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 3, 3875 }, - { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 4, 112556 }, - { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 5, 1189238 }, - { "2K2q1q/2n4n/3qb3/1r2qq2/5n2/k4n2/r5Q1/1q6 w - - 0 1", 1, 0 }, // checkmate + { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 1, 13 }, + { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 2, 376 }, + { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 3, 3875 }, + { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 4, 112556 }, + { "2b5/2p5/8/8/5B1k/q7/2K5/8 w - - 0 1", 5, 1189238 }, + { "2K2q1q/2n4n/3qb3/1r2qq2/5n2/k4n2/r5Q1/1q6 w - - 0 1", 1, 0 }, // checkmate // Pins (i noticed an desync of position.h that leaves pins unchanged) - { "8/1Q1pkp1Q/3ppp2/8/1Q2Q2Q/4K3/8/8 w - - 0 1", 5, 6990511 }, - { "8/3pkp2/3ppp2/8/1Q6/4K3/8/8 w - - 0 1", 5, 617665 }, - { "7k/4p3/8/2KP3r/8/8/8/8 b - - 0 1", 5, 197176 } + { "8/1Q1pkp1Q/3ppp2/8/1Q2Q2Q/4K3/8/8 w - - 0 1", 5, 6990511 }, + { "8/3pkp2/3ppp2/8/1Q6/4K3/8/8 w - - 0 1", 5, 617665 }, + { "7k/4p3/8/2KP3r/8/8/8/8 b - - 0 1", 5, 197176 }, + { "rnbqkbnr/1p2pppp/p7/2Pp4/8/8/PPPKPPPP/RNBQ1BNR w kq d6 0 4", 1, 25 }, + { "rnbqkbnr/1p2pppp/p7/2Pp4/8/8/PPPKPPPP/RNBQ1BNR w kq d6 0 4", 2, 701 }, + { "rnbqkbnr/1p2pppp/p7/2Pp4/8/8/PPPKPPPP/RNBQ1BNR w kq d6 0 4", 3, 17762 } }; - check_perfts(positions); + check_perfts(tests); } TEST_CASE("Experienced bugs in this repo") { - std::vector> positions = { - { "rnbqkbnr/1p2pppp/p7/2Pp4/8/8/PPPKPPPP/RNBQ1BNR w kq d6 0 4", 1, 25 }, - { "rnbqkbnr/1p2pppp/p7/2Pp4/8/8/PPPKPPPP/RNBQ1BNR w kq d6 0 4", 2, 701 }, - { "rnbqkbnr/1p2pppp/p7/2Pp4/8/8/PPPKPPPP/RNBQ1BNR w kq d6 0 4", 3, 17762 } - }; - check_perfts(positions); { Position p("rnbqkbnr/pp1p1ppp/8/2pPp3/8/8/PPP1PPPP/RNBQKBNR w KQkq e6 0 3"); REQUIRE(p.zobrist() == p.hash()); @@ -1494,273 +1420,6 @@ TEST_CASE("Captures only?") { }; check_perfts(tests); } -void check_moveToUci(std::vector> &tests) { - for (auto &tc : tests) { - REQUIRE(chess::uci::moveToUci(tc.input) == tc.info); - } -} -TEST_CASE("moveToUci") { - std::vector> tests = { - { Move(SQ_A2, SQ_A4), "a2a4" }, - { Move::make(SQ_H1, SQ_G4), "h1g4" }, - { Move::make(SQ_A4, SQ_E6), "a4e6" }, - { Move::make(SQ_D4, SQ_A7), "d4a7" }, - { Move::make(SQ_C5, SQ_E6), "c5e6" }, - { Move::make(SQ_G7, SQ_D2), "g7d2" }, - { Move::make(SQ_A5, SQ_E6), "a5e6" }, - { Move::make(SQ_D3, SQ_F7), "d3f7" }, - { Move::make(SQ_E8, SQ_A4), "e8a4" }, - { Move::make(SQ_B4, SQ_G3), "b4g3" }, - { Move::make(SQ_A6, SQ_C8), "a6c8" }, - { Move::make(SQ_B7, SQ_B2), "b7b2" }, - { Move::make(SQ_F8, SQ_G1), "f8g1" }, - { Move::make(SQ_B2, SQ_B1), "b2b1" }, - { Move::make(SQ_D2, SQ_H8), "d2h8" }, - { Move::make(SQ_B4, SQ_H3), "b4h3" }, - { Move::make(SQ_F7, SQ_E5), "f7e5" }, - { Move::make(SQ_A6, SQ_C2), "a6c2" }, - { Move::make(SQ_C8, SQ_H5), "c8h5" }, - { Move::make(SQ_C3, SQ_G7), "c3g7" }, - { Move::make(SQ_E8, SQ_H8), "e8g8" }, - { Move::make(SQ_B4, SQ_A8), "b4a8" }, - { Move::make(SQ_F3, SQ_G5), "f3g5" }, - { Move::make(SQ_E4, SQ_F6), "e4f6" }, - { Move::make(SQ_D5, SQ_B6), "d5b6" }, - { Move::make(SQ_H2, SQ_G1, BISHOP), "h2g1b" }, - { Move::make(SQ_E5, SQ_C8), "e5c8" }, - { Move::make(SQ_D8, SQ_F1), "d8f1" }, - { Move::make(SQ_H3, SQ_H8), "h3h8" }, - { Move::make(SQ_G6, SQ_A1), "g6a1" }, - { Move::make(SQ_E8, SQ_A8), "e8c8" }, - { Move::make(SQ_E1, SQ_H1), "e1g1" }, - { Move::make(SQ_E8, SQ_H8), "e8g8" }, - { Move::make(SQ_C7, SQ_B1), "c7b1" }, - { Move::make(SQ_E8, SQ_H8), "e8g8" }, - { Move::make(SQ_D8, SQ_A1), "d8a1" }, - { Move::make(SQ_D7, SQ_D8, KNIGHT), "d7d8n" }, - { Move::make(SQ_D8, SQ_E7), "d8e7" }, - { Move::make(SQ_F2, SQ_H3), "f2h3" }, - { Move::make(SQ_B7, SQ_D5), "b7d5" }, - { Move::make(SQ_D1, SQ_F2), "d1f2" }, - { Move::make(SQ_E8, SQ_C4), "e8c4" }, - { Move::make(SQ_D2, SQ_C7), "d2c7" }, - { Move::make(SQ_H1, SQ_C2), "h1c2" }, - { Move::make(SQ_E3, SQ_C1), "e3c1" }, - { Move::make(SQ_H8, SQ_H3), "h8h3" }, - { Move::make(SQ_F2, SQ_F1, QUEEN), "f2f1q" }, - { Move::make(SQ_H2, SQ_D6), "h2d6" }, - { Move::make(SQ_G2, SQ_G1, ROOK), "g2g1r" }, - { Move::make(SQ_H5, SQ_G6), "h5g6" }, - { Move::make(SQ_E8, SQ_E3), "e8e3" }, - { Move::make(SQ_H4, SQ_C3), "h4c3" }, - { Move::make(SQ_E4, SQ_H3), "e4h3" }, - { Move::make(SQ_D2, SQ_A1), "d2a1" }, - { Move::make(SQ_H1, SQ_D2), "h1d2" }, - { Move::make(SQ_B8, SQ_A3), "b8a3" }, - { Move::make(SQ_H5, SQ_A1), "h5a1" }, - { Move::make(SQ_E1, SQ_A1), "e1c1" }, - { Move::make(SQ_A2, SQ_A3), "a2a3" }, - { Move::make(SQ_C7, SQ_G8), "c7g8" }, - { Move::make(SQ_E1, SQ_E6), "e1e6" }, - { Move::make(SQ_E1, SQ_A5), "e1a5" }, - { Move::make(SQ_E6, SQ_A5), "e6a5" }, - { Move::make(SQ_H7, SQ_C8, QUEEN), "h7c8q" }, - { Move::make(SQ_C2, SQ_C1, QUEEN), "c2c1q" }, - { Move::make(SQ_D6, SQ_B7), "d6b7" }, - { Move::make(SQ_D5, SQ_G7), "d5g7" }, - { Move::make(SQ_B6, SQ_F3), "b6f3" }, - { Move::make(SQ_A3, SQ_G1), "a3g1" }, - { Move::make(SQ_D2, SQ_A1, BISHOP), "d2a1b" }, - { Move::make(SQ_H6, SQ_C3), "h6c3" }, - { Move::make(SQ_C7, SQ_C8, KNIGHT), "c7c8n" }, - { Move::make(SQ_A7, SQ_B8, KNIGHT), "a7b8n" }, - { Move::make(SQ_C6, SQ_C5), "c6c5" }, - { Move::make(SQ_H2, SQ_H1, QUEEN), "h2h1q" }, - { Move::make(SQ_G1, SQ_G8), "g1g8" }, - { Move::make(SQ_D1, SQ_H8), "d1h8" }, - { Move::make(SQ_B1, SQ_C6), "b1c6" }, - { Move::make(SQ_E4, SQ_A3), "e4a3" }, - { Move::make(SQ_G5, SQ_F3), "g5f3" }, - { Move::make(SQ_D7, SQ_D8, KNIGHT), "d7d8n" }, - { Move::make(SQ_C4, SQ_E5), "c4e5" }, - { Move::make(SQ_B1, SQ_F7), "b1f7" }, - { Move::make(SQ_B3, SQ_B4), "b3b4" }, - { Move::make(SQ_G7, SQ_G8, BISHOP), "g7g8b" }, - { Move::make(SQ_A1, SQ_E3), "a1e3" }, - { Move::make(SQ_F6, SQ_E3), "f6e3" }, - { Move::make(SQ_B7, SQ_A2), "b7a2" }, - { Move::make(SQ_F7, SQ_D4), "f7d4" }, - { Move::make(SQ_G4, SQ_F6), "g4f6" }, - { Move::make(SQ_E1, SQ_A1), "e1c1" }, - { Move::make(SQ_E1, SQ_A1), "e1a1" }, - { Move::make(SQ_H1, SQ_H8), "h1h8" }, - { Move::make(SQ_A1, SQ_A7), "a1a7" }, - { Move::make(SQ_E5, SQ_A8), "e5a8" }, - { Move::make(SQ_F5, SQ_F8), "f5f8" }, - { Move::make(SQ_E7, SQ_D2), "e7d2" }, - { Move::make(SQ_H2, SQ_E1, BISHOP), "h2e1b" }, - { Move::make(SQ_H4, SQ_F3), "h4f3" }, - { Move::make(SQ_E8, SQ_B6), "e8b6" }, - { Move::make(SQ_H5, SQ_E8), "h5e8" }, - { Move::make(SQ_F2, SQ_F1, ROOK), "f2f1r" }, - }; - check_moveToUci(tests); -} -TEST_CASE("push_uci/parse_uci") { - Position p; - REQUIRE(p.parse_uci("e2e4") == Move(SQ_E2, SQ_E4)); - p.setFEN("rn1qkbnr/pP1ppppp/8/1b6/8/8/PPP1PPPP/RNBQKBNR w KQkq - 1 5"); - REQUIRE(p.parse_uci("b7a8q") == Move::make(SQ_B7, SQ_A8, QUEEN)); -} -template void check_was_into_check(std::vector> &tests) { - for (auto &tc : tests) { - _Position pos(tc.input); - REQUIRE(pos.was_into_check() == tc.info); - } -} -TEST_CASE("was_into_check") { - std::vector> tests = { - { "3K4/1N1Q4/8/2r4k/6r1/8/1q1Q4/r3P3 w q - 24 70", false }, - { "8/8/3b3K/4N3/4k3/7n/4q3/7B w - - 8 9", true }, - { "N7/1B4P1/4B2n/2Kn4/8/3k4/Pp2r1p1/1p5P w - - 29 85", false }, - { "4b3/3n3N/8/2k5/1q6/1B6/4R3/2K1R3 w - g3 37 3", false }, - { "8/r7/1K3p2/2q5/2R5/6N1/3B4/2p4k w q - 2 89", true }, - { "8/1q3Pr1/2b5/2P2r2/7K/5k2/PP1n4/Q2b3p w K g3 28 35", false }, - { "K7/1r6/4B1p1/7p/3P4/4k3/4R3/1np3b1 w - - 16 84", true }, - { "2R2r2/2k2N2/7K/2r2NR1/1n3b2/PP6/3q3b/B7 w q h3 38 21", true }, - { "2Q5/3b4/1b4Rr/4R1K1/7q/2P2R1q/R5Qp/1bn1k3 w - g3 8 76", true }, - { "4k3/bP1r4/n7/8/2PP2K1/4B3/2N1P1q1/7P w q a6 37 18", false }, - { "1P4N1/2Nb4/1K6/5B2/2N3R1/2k1Nn2/5N2/1p3p2 b q - 41 98", false }, - { "Q4rN1/5R2/R5b1/7r/8/r7/kK5B/7B b K c6 37 73", true }, - { "4k2p/r1q5/7n/1p4P1/1P3PQr/N1n2N2/7K/1N1NqB2 b - f6 27 80", true }, - { "7Q/2p2b2/8/3K4/5Q2/N2B1bb1/5b2/5qk1 w K d3 30 68", false }, - { "3b3K/5p2/2Pp4/2n1R3/5Qb1/7k/6n1/R7 b - a3 23 54", false }, - { "1n1PN1N1/3Pn3/3r4/2b5/6K1/7r/5b2/3k4 w q - 15 51", false }, - { "4N3/4kN2/n2p4/4K3/r1P4R/1p4n1/b3r3/3P1n2 b - - 9 43", true }, - { "1Q2q3/k4bBq/5B1P/8/6q1/r1q3p1/1K6/2PP4 w - - 16 90", true }, - { "Kqq1B2b/3R1Q2/8/k7/6P1/8/1P4R1/8 w - e6 33 9", false }, - { "7K/Nn3b2/r1N1pP2/4R3/5q2/kq6/4p2b/8 w - e3 5 11", false }, - { "n3NK1B/B5kn/8/8/6pB/4P3/8/5R2 b k g3 20 41", true }, - { "Kq3Bq1/6p1/4P3/k7/3R4/8/1Npn4/8 b K - 31 84", true }, - { "7N/1RK1p1nb/5n2/3N4/QQ2pkr1/1r6/3P1P2/8 b - - 44 77", false }, - { "1R2RN1q/nn2Q1k1/5b1Q/3n2n1/2qN3Q/1K1R2B1/8/8 w - - 49 2", true }, - { "8/5bQn/3n2B1/1K2B3/4NN1n/6q1/4R3/2q4k w - - 8 100", false }, - { "8/8/1P4P1/7r/1Q1Q4/2R2P1b/6n1/1RbK1Q1k b - - 44 5", false }, - { "2r2p2/1B6/2r5/5p2/8/3b2q1/2R3qK/k1q5 b - - 11 89", true }, - { "1b1Q4/1rk2qP1/8/R1r4q/4p3/2K4p/5P2/R7 b Q - 23 29", true }, - { "qq3B2/2r4n/3n4/r1Q5/2P5/5b2/1b1k1K2/P2n4 w Q - 49 89", false }, - { "B1bn1R1r/1N5k/2p5/4b2r/6n1/K5B1/2n1n3/1P3N2 b q - 6 8", true }, - { "8/6q1/3nr3/3n4/KQ6/1bp2q2/1Bk5/2r2Q2 w - b3 0 89", false }, - { "4r3/p1n4N/8/8/8/4qnP1/6k1/4K3 b K - 12 83", true }, - { "3b1Nk1/4R1nR/3r4/3P4/R7/K2n4/1qB5/4r2R b q - 6 73", true }, - { "6r1/1Q1B2B1/1bK2QR1/1r6/r7/4p2B/8/2r1k1q1 b - - 44 39", true }, - { "5R2/b7/3p2P1/8/2k5/qK2Q3/7p/8 w K - 33 11", true }, - { "1R3Q1Q/p7/8/4B1pq/6k1/2N1Q3/8/6K1 w - - 35 100", false }, - { "Bp6/PQ5q/8/4k3/7b/2q1Nr2/2K5/2n1q2q w K - 26 14", false }, - { "3p4/4k1Q1/5B1b/n1q5/8/2Q4K/3Q4/4B3 b q - 15 33", false }, - { "p7/p5N1/B2n3Q/K4R1P/3n2q1/7k/P3QR2/8 b k e6 16 50", false }, - { "5Pkq/8/7N/2n5/1N4R1/7K/1Q6/3ppP2 w Q - 9 43", true }, - { "6K1/8/Q4B2/1Q6/b1k5/4q1n1/8/1B5b w K - 41 68", true }, - { "1N6/2k4K/2P3r1/8/3R2N1/5b2/5b2/b3p3 w k - 1 50", false }, - { "3r1K2/1R6/p7/8/1qN3q1/1r6/1k5Q/8 w Q - 27 30", true }, - { "p2B2P1/Q1b5/1Q6/K3k3/8/P4P2/8/8 b q - 42 98", false }, - { "BQ5n/5n2/8/7K/8/2B5/1k6/4n1N1 b K - 3 47", false }, - { "8/n3B3/8/R7/3Q2P1/1rQ2B2/5R2/2K1k2r w k - 46 100", true }, - { "1n1N4/2Qr1k1N/1KR3N1/3Pn3/4Q3/4B3/pn2q3/8 w k - 10 9", true }, - { "2b5/1q2Bbq1/5n2/2R3qR/2kN4/6b1/P1r4Q/K3r2B b k h3 41 49", true }, - { "2q5/4br1R/5Q2/5Q2/2k5/Bnp5/7q/3K4 w - - 18 39", false }, - { "8/3q4/7k/5K2/1q2R1N1/3N4/2N5/3P2p1 w K - 17 21", true }, - { "1P1BP1bK/N5r1/7R/1p3B1Q/6n1/3r4/k1B5/2n1P1q1 b K - 35 23", false }, - { "2bP1P2/2p5/3K3r/4Q3/2b5/4kr2/q7/pq5r w - g6 21 63", true }, - { "K1B5/4P1B1/kN3Q1R/3P1B2/2q1QN2/8/8/2P5 w Q - 16 2", true }, - { "7N/2b1p2P/1RK5/Nbqn1P2/3p2p1/2qr4/P1nP2k1/P1p1b3 w - d3 9 95", false }, - { "2B3p1/2R3b1/8/p7/8/Kprk4/3b2b1/2Q5 b - b6 15 77", false }, - { "1r2b3/2R5/1k1p2PQ/7N/3p2R1/P1R1K3/1bq5/R7 w - d6 41 72", false }, - { "3rq3/2p4K/4n3/5nn1/k7/8/2n1Q3/3P1q2 b k - 35 89", true }, - { "K3R3/1P4NB/1q3R2/1k6/1qn2B2/3pr3/3q1B2/4b3 b - - 18 88", false }, - { "N1r5/3nP3/bR2Q3/2RB3N/7k/3K4/b7/nQ5b w k - 31 78", false }, - { "b7/8/3b2P1/3kr3/4R3/6K1/3q2b1/1q2r3 w K - 28 28", false }, - { "2B1p2n/8/P7/Nn3b1K/1q6/N2p1kR1/8/8 b q - 0 36", false }, - { "1RK3p1/2BNr3/6R1/6q1/8/b2Pq3/8/2RR1P1k w K - 24 3", false }, - { "5P2/5Q2/8/2K2rb1/n3p1p1/6b1/2qn4/k4p2 b K - 15 60", true }, - { "2b1p3/5N2/2NNR1R1/2q5/8/8/qNQ4k/1P5K w k - 11 18", true }, - { "5B2/3q3K/1k3n2/R5r1/1Q2bR2/4P1b1/3B1b2/3pR3 w K - 2 22", true }, - { "4K3/8/1r6/3kNQp1/7b/Rr3B2/rP3nq1/1nP1q3 b Q h6 4 85", false }, - { "Q2rKN2/3Pp3/n5k1/4nPN1/3r3Q/1N1r4/5p2/1BBR1B1B w q - 6 18", true }, - { "1NK5/3k1Q2/1B2N1Q1/7p/8/8/5RNN/6Q1 w - g3 16 90", true }, - { "8/4Q3/6QP/3k4/bN2K3/4Q3/5b2/8 w k - 33 38", true }, - { "6K1/6q1/QnRb4/1Np4Q/7R/3Q4/3B1q2/5k2 b q - 29 11", true }, - { "5n2/4q3/4r3/b7/8/1Q5k/5KRB/1q2r3 b - d6 20 39", false }, - { "1R4q1/8/K2B4/5Q2/1N6/Q2qk3/8/8 w - - 10 61", false }, - { "1q1k4/4q3/8/Q1n5/3b3B/2Qp3b/R6K/5n1n b K - 47 62", true }, - { "2PB4/q3BR2/8/N3k3/4P3/4P3/7K/1N2P3 w k c6 22 24", false }, - { "6Pp/5N2/8/3QN3/1B6/p7/6kK/Q7 b K - 29 24", true }, - { "8/R7/4pk2/5R2/1BK3R1/6Q1/1P1Q4/8 w Q - 10 75", true }, - { "8/6p1/b3QN2/5k2/8/p6P/7r/K7 b - f6 18 46", false }, - { "3Q4/5P2/7N/3N2K1/8/3rk1bn/7b/1NQ1Q3 b k - 17 42", true }, - { "5B2/1P2k3/2n3K1/5bn1/5R1P/p3Bp2/3N4/4n3 w - - 6 94", true }, - { "4P3/4n1Q1/6b1/5k2/5N2/3n3B/7p/q2B2K1 w - - 16 65", true }, - { "8/8/1k3r2/Nq6/7n/8/8/3K1b2 b - - 27 10", false }, - { "8/5N2/1K6/8/8/2Bq4/k7/3b2qp b K f3 39 75", true }, - { "kbK1R3/2n2q2/7n/1p6/1r1bP3/2p5/nB5B/2N2b2 w - - 12 68", false }, - { "8/3b4/2k1pn2/2P4n/2qQp3/1nnb4/r7/KB1Q4 b - - 12 11", true }, - { "r3B3/1bb2k2/p7/3K2Q1/8/6bp/6Nb/2p2nB1 b - - 22 61", true }, - { "1b6/4p2k/6p1/1N1Q1n2/1pK1r2B/1q2b3/p3Rp2/8 w k - 30 99", false }, - { "Q2k1B2/8/3rb3/8/2K5/8/1N6/8 w Q - 43 73", true }, - { "8/1r4Nk/2R5/3Q1P2/8/6Q1/7P/6K1 w K - 27 13", false }, - { "5k2/2b5/p7/5B2/1K2n3/6n1/1b4q1/3r1b2 b K - 28 91", false }, - { "5r2/1N6/8/5N1r/4n2k/2B2K2/1RR1NB2/2p1BR2 w - f6 8 12", true }, - { "5N2/8/5K2/8/2B2P2/5nr1/1Q1B2k1/1Qr1n3 b - - 29 100", false }, - { "8/3b4/3p4/1K5n/3Q1Qn1/2n5/k1p1Rq1n/3N4 b Q - 39 12", true }, - { "2Q5/3n4/1Rq1KN2/3P4/7P/1b3B2/3k3q/8 b - - 15 47", true }, - { "3bn3/4Q1p1/2r3q1/2Q2k2/2QKr3/3R4/8/2p2R2 w Q - 28 77", true }, - { "n7/1n4p1/2KB2b1/4q1R1/QR6/1kb3p1/8/2n2b2 b K - 24 73", false }, - { "3R2k1/QpK2R1p/N6P/RP2r3/q4b2/8/1R6/2r5 w q - 7 44", true }, - { "8/k1R2Q2/3r4/2QP3B/8/6B1/3K4/n1b2Q2 b Q - 18 53", true }, - { "p7/2n3PQ/3p1K2/N2b4/2n2bk1/Q7/B1Q5/2q5 b - - 47 54", false }, - { "b2Q1q2/1r6/2R5/B1R3q1/p2K1kR1/4q3/8/1r3b2 b - - 15 92", true }, - { "pB6/4q1nk/7n/4p2B/1N3K2/P7/rn2bRb1/2r5 w - - 7 57", false }, - }; - check_was_into_check(tests); - check_was_into_check(tests); -} -TEST_CASE("Zobrist mapping?") { - REQUIRE(zobrist::RandomPiece[enum_idx()][(int)PolyglotPiece::BPAWN][0] == 0x9D39247E33776D41); -} -struct repetitions_t { - std::string FEN; - std::vector moves; - int repetition; -}; -void check_repetitions(std::vector> &tests) { - for (auto &tc : tests) { - _Position pos(tc.input.FEN); - for (auto &move : tc.input.moves) - pos.doMove(move); - REQUIRE(pos.is_repetition(tc.input.repetition) == tc.info); - } - for (auto &tc : tests) { - _Position pos(tc.input.FEN); - for (auto &move : tc.input.moves) - pos.doMove(move); - REQUIRE(pos.is_repetition(tc.input.repetition) == tc.info); - } -} -TEST_CASE("is_repetition") { - std::vector> tests = { - { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", - { Move(SQ_B1, SQ_C3), - Move(SQ_B8, SQ_C6), - Move(SQ_C3, SQ_B1), - Move(SQ_C6, SQ_B8), - Move(SQ_G1, SQ_F3), - Move(SQ_G8, SQ_F6), - Move(SQ_F3, SQ_G1), - Move(SQ_F6, SQ_G8) }, - 3, true } - }; - check_repetitions(tests); -} int main(int argc, char **argv) { doctest::Context ctx; ctx.setOption("success", true); diff --git a/types.h b/types.h index 3417514..c6e1b2c 100644 --- a/types.h +++ b/types.h @@ -335,7 +335,19 @@ template class ValueList { using Movelist = ValueList; constexpr int square_distance(Square a, Square b) { return std::max(std::abs(file_of(a) - file_of(b)), std::abs(rank_of(a) - rank_of(b))); } -constexpr Square parse_square(std::string_view sv) { return make_sq(File(sv[0] - 'a'), Rank(sv[1] - '1')); } +constexpr Square parse_square(std::string_view sv) { + if (sv.size() < 2) + return SQ_NONE; + + char f = sv[0]; + char r = sv[1]; + + if (f < 'a' || f > 'h' || r < '1' || r > '8') + return SQ_NONE; + + return make_sq(File(f - 'a'), Rank(r - '1')); +} + constexpr PieceType parse_pt(unsigned char c) { const char a[] = "pnbrqk"; int p = -1; From 6b159d253f0c597a03beb18435a1429164f340ad Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Wed, 10 Dec 2025 23:11:37 +0700 Subject: [PATCH 02/15] Refactor piece output operator and improve piece enum handling - Updated the output operator for pieces to use a switch-case structure for better readability and maintainability. - Removed the previous string_view mapping for piece representation. - Enhanced the template specialization for the output operator to include PieceC directly. - Cleaned up the code in `types.h` by formatting enums for better clarity and consistency. - Added missing includes and ensured proper use of forward declarations. - Removed unnecessary debug output in tests to streamline test results. --- attacks.h | 11 +- fwd_decl.h | 4 +- movegen.h | 29 ++--- moves_io.h | 34 +++--- non_core_tests.cpp | 12 ++ position.cpp | 172 ++++++++++++++++------------ position.h | 276 ++++++++++++++++++++++++++++++++------------- printers.cpp | 48 +++++++- printers.h | 8 +- tests.cpp | 1 - types.h | 157 +++++++++++++++++++------- 11 files changed, 517 insertions(+), 235 deletions(-) diff --git a/attacks.h b/attacks.h index d762d62..32b5e94 100644 --- a/attacks.h +++ b/attacks.h @@ -144,7 +144,8 @@ extern const std::array BishopAttacks; * @return */ template [[nodiscard]] static constexpr Bitboard shift(const Bitboard b) { - ASSUME(direction == NORTH || direction == EAST || direction == SOUTH || direction == WEST || direction == NORTH_EAST || direction == SOUTH_EAST || direction == SOUTH_WEST || direction == NORTH_WEST); + ASSUME(direction == NORTH || direction == EAST || direction == SOUTH || direction == WEST || direction == NORTH_EAST || + direction == SOUTH_EAST || direction == SOUTH_WEST || direction == NORTH_WEST); switch (direction) { case Direction::NORTH: return b << 8; @@ -240,7 +241,9 @@ template [[nodiscard]] constexpr Bitboard pawn(const Bitboard pawns) { * @param occupied * @return */ -[[nodiscard]] constexpr Bitboard bishop(Square sq, Bitboard occupied) { return BishopAttacks[BishopTable[(int)sq].index + BishopTable[(int)sq](occupied)]; } +[[nodiscard]] constexpr Bitboard bishop(Square sq, Bitboard occupied) { + return BishopAttacks[BishopTable[(int)sq].index + BishopTable[(int)sq](occupied)]; +} /** * @brief Returns the rook attacks for a given square @@ -248,7 +251,9 @@ template [[nodiscard]] constexpr Bitboard pawn(const Bitboard pawns) { * @param occupied * @return */ -[[nodiscard]] constexpr Bitboard rook(Square sq, Bitboard occupied) { return RookAttacks[RookTable[(int)sq].index + RookTable[(int)sq](occupied)]; } +[[nodiscard]] constexpr Bitboard rook(Square sq, Bitboard occupied) { + return RookAttacks[RookTable[(int)sq].index + RookTable[(int)sq](occupied)]; +} /** * @brief Returns the queen attacks for a given square diff --git a/fwd_decl.h b/fwd_decl.h index d858c89..7fbf593 100644 --- a/fwd_decl.h +++ b/fwd_decl.h @@ -15,9 +15,9 @@ enum MoveType : uint16_t; enum File : int8_t; enum Rank : int8_t; class Move; -enum class MoveGenType : uint8_t; +enum class MoveGenType : uint16_t; template class _Position; -using Bitboard=uint64_t; +using Bitboard = uint64_t; using Key = uint64_t; template class ValueList; using Movelist = ValueList; diff --git a/movegen.h b/movegen.h index f3568fb..e61bc66 100644 --- a/movegen.h +++ b/movegen.h @@ -1,18 +1,21 @@ #pragma once #include "fwd_decl.h" #include -namespace chess::_chess{ - template extern Move *splat_pawn_moves(Move *moveList, Bitboard to_bb); - extern Move *splat_moves(Move *moveList, Square from, Bitboard to_bb); -} +namespace chess::_chess { +template extern Move *splat_pawn_moves(Move *moveList, Bitboard to_bb); +extern Move *splat_moves(Move *moveList, Square from, Bitboard to_bb); +} // namespace chess::_chess namespace chess::movegen { - - template void genEP(const _Position&, Movelist&); - template void genPawnDoubleMoves(const _Position&, Movelist &, Bitboard, Bitboard); - template void genPawnSingleMoves(const _Position&, Movelist &, Bitboard, Bitboard, Bitboard); - template void genKnightMoves(const _Position&, Movelist &, Bitboard, Bitboard); - template void genKingMoves(const _Position&, Movelist &); - template void genSlidingMoves(const _Position&, Movelist &, Bitboard, Bitboard, Bitboard); - extern std::array, 64> SQUARES_BETWEEN_BB; - [[nodiscard]] inline Bitboard between(Square sq1, Square sq2) noexcept { return SQUARES_BETWEEN_BB[sq1][sq2]; } + +template void genEP(const _Position &, Movelist &); +template void genPawnDoubleMoves(const _Position &, Movelist &, Bitboard, Bitboard); +template +void genPawnSingleMoves(const _Position &, Movelist &, Bitboard, Bitboard, Bitboard); +template +void genKnightMoves(const _Position &, Movelist &, Bitboard, Bitboard); +template void genKingMoves(const _Position &, Movelist &); +template +void genSlidingMoves(const _Position &, Movelist &, Bitboard, Bitboard, Bitboard); +extern std::array, 64> SQUARES_BETWEEN_BB; +[[nodiscard]] inline Bitboard between(Square sq1, Square sq2) noexcept { return SQUARES_BETWEEN_BB[sq1][sq2]; } } // namespace chess::movegen diff --git a/moves_io.h b/moves_io.h index 2418a90..72094e7 100644 --- a/moves_io.h +++ b/moves_io.h @@ -1,8 +1,8 @@ #pragma once #include +#include #include #include -#include namespace chess { class Move; enum Square : int8_t; @@ -11,26 +11,26 @@ namespace uci { std::string moveToUci(Move move); std::string squareToString(Square sq); -class IllegalMoveException : public std::exception{ -public: - IllegalMoveException(const std::string& message) : message_(message) {} - const char* what() const noexcept override { - return message_.c_str(); - } -private: +class IllegalMoveException : public std::exception { + public: + IllegalMoveException(const std::string &message) : message_(message) {} + const char *what() const noexcept override { return message_.c_str(); } + + private: std::string message_; }; -class AmbiguousMoveException : public std::exception{ -public: - AmbiguousMoveException(const std::string& message) : message_(message) {} - const char* what() const noexcept override { - return message_.c_str(); - } -private: +class AmbiguousMoveException : public std::exception { + public: + AmbiguousMoveException(const std::string &message) : message_(message) {} + const char *what() const noexcept override { return message_.c_str(); } + + private: std::string message_; }; template Move uciToMove(const _Position &pos, std::string_view uci); -template Move parseSan(const _Position &pos, std::string_view uci, bool remove_illegals=false); -template std::string moveToSan(const _Position &pos, Move move, bool long_=false, bool suffix=true); +template +Move parseSan(const _Position &pos, std::string_view uci, bool remove_illegals = false); +template +std::string moveToSan(const _Position &pos, Move move, bool long_ = false, bool suffix = true); } // namespace uci } // namespace chess diff --git a/non_core_tests.cpp b/non_core_tests.cpp index 4707ac6..11d19ba 100644 --- a/non_core_tests.cpp +++ b/non_core_tests.cpp @@ -884,6 +884,18 @@ TEST_SUITE("SAN Parser") { REQUIRE(uci::parseSan(b, "O-O+") == m); } } +TEST_CASE("Reconstruction of Position from history entry"){{ + Position p; + Position p2(p.state()); + REQUIRE(p.fen()==p2.fen());} + { + _Position p; + Position p2(p.state()); + _Position p3(p2.state()); + REQUIRE(p.fen()==p3.fen()); + REQUIRE(p.fen()==p2.fen()); + } +} int main(int argc, char **argv) { doctest::Context ctx; ctx.setOption("success", true); diff --git a/position.cpp b/position.cpp index 0de7816..b541b29 100644 --- a/position.cpp +++ b/position.cpp @@ -46,22 +46,6 @@ static _POSSIBLY_CONSTEXPR auto make_castle_masks() { } static _POSSIBLY_CONSTEXPR auto clearCastleMask = make_castle_masks(); -template template void _Position::genEP(Movelist &ep_moves) const { - chess::movegen::genEP(*this, ep_moves); -} -template -template -void _Position::genPawnSingleMoves(Movelist &moves) const { - chess::movegen::genPawnSingleMoves(*this, moves, _rook_pin, _bishop_pin, _check_mask); -} -template template void _Position::genPawnDoubleMoves(Movelist &moves) const { - chess::movegen::genPawnDoubleMoves(*this, moves, _pin_mask, _check_mask); -} -template -template -void _Position::genKingMoves(Movelist &out) const { - chess::movegen::genKingMoves(*this, out); -} template template void _Position::doMove(const Move &move) { assert(move.is_ok() && "doMove called with invalid move"); Square from_sq = move.from_sq(), to_sq = move.to_sq(); @@ -414,10 +398,7 @@ template void _Position::setFEN(const s } template std::string _Position::fen() const { - constexpr std::string_view EnginePieceToChar(" PNBRQK pnbrqk "); - constexpr std::string_view PolyglotPieceToChar("PNBRQKpnbrqk "); - constexpr std::string_view PieceToChar = std::is_same_v ? EnginePieceToChar : PolyglotPieceToChar; - std::string fen; + std::ostringstream ss; // 1) Piece placement for (Rank rank = RANK_8; rank >= RANK_1; --rank) { @@ -430,24 +411,23 @@ template std::string _Position::fen() c emptyCount++; } else { if (emptyCount > 0) { - fen += std::to_string(emptyCount); + ss<< std::to_string(emptyCount); emptyCount = 0; } - fen += PieceToChar[static_cast(piece)]; + ss<< piece; } } if (emptyCount > 0) - fen += std::to_string(emptyCount); + ss<< std::to_string(emptyCount); if (rank > 0) - fen += '/'; + ss<< '/'; } // 2) Side to move - fen += ' '; - fen += (sideToMove() == WHITE) ? 'w' : 'b'; + ss<< ' ' << (sideToMove() == WHITE ? 'w' : 'b'); // 3) Castling availability - fen += ' '; + ss<< ' '; std::string castlingStr; if (castlingRights() & WHITE_OO) castlingStr += 'K'; @@ -457,22 +437,20 @@ template std::string _Position::fen() c castlingStr += 'k'; if (castlingRights() & BLACK_OOO) castlingStr += 'q'; - fen += (castlingStr.empty()) ? "-" : castlingStr; + ss<<(castlingStr.empty() ? "-" : castlingStr); // 4) En passant target square or '-' - fen += ' '; + ss<< ' '; Square ep = ep_square(); - fen += (ep == SQ_NONE) ? "-" : uci::squareToString(ep); + ss<< (ep == SQ_NONE ? "-" : uci::squareToString(ep)); // 5) Halfmove clock - fen += ' '; - fen += std::to_string(halfmoveClock()); + ss<< ' ' <<(int)halfmoveClock(); // 6) Fullmove number - fen += ' '; - fen += std::to_string(fullmoveNumber()); + ss<< ' ' <<(int)fullmoveNumber(); - return fen; + return ss.str(); } template template bool _Position::is_valid() const { if (count() != 1) @@ -542,6 +520,90 @@ template template bool _Position CheckType _Position::givesCheck(Move move) const { + const static auto getSniper = [&](Square ksq, Bitboard oc) { + const auto us_occ = this->us(board->sideToMove()); + const auto bishop = attacks::bishop(ksq, oc) & this->pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; + const auto rook = attacks::rook(ksq, oc) & this->pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; + return (bishop | rook); + }; + + assert(color_of(at(m.from())) == sideToMove()); + + const Square from = m.from(); + const Square to = m.to(); + const Square ksq = kingSq(~sideToMove()); + const Bitboard toBB = 1ULL<<(to); + const PieceType pt = at(from).type(); + + Bitboard fromKing = 0ull; + + if (pt == PieceType::PAWN) { + fromKing = attacks::pawn(~stm_, ksq); + } else if (pt == PieceType::KNIGHT) { + fromKing = attacks::knight(ksq); + } else if (pt == PieceType::BISHOP) { + fromKing = attacks::bishop(ksq, occ()); + } else if (pt == PieceType::ROOK) { + fromKing = attacks::rook(ksq, occ()); + } else if (pt == PieceType::QUEEN) { + fromKing = attacks::queen(ksq, occ()); + } + + if (fromKing & toBB) return CheckType::DIRECT_CHECK; + + // Discovery check + const Bitboard fromBB = Bitboard::fromSquare(from); + const Bitboard oc = occ() ^ fromBB; + + Bitboard sniper = getSniper(this, ksq, oc); + + while (sniper) { + Square sq = sniper.pop(); + return (!(movegen::between(ksq, sq) & toBB) || m.typeOf() == Move::CASTLING) ? CheckType::DISCOVERY_CHECK + : CheckType::NO_CHECK; + } + + switch (m.typeOf()) { + case Move::NORMAL: + return CheckType::NO_CHECK; + + case Move::PROMOTION: { + Bitboard attacks = 0ull; + + switch (m.promotionType()) { + case static_cast(PieceType::KNIGHT): + attacks = attacks::knight(to); + break; + case static_cast(PieceType::BISHOP): + attacks = attacks::bishop(to, oc); + break; + case static_cast(PieceType::ROOK): + attacks = attacks::rook(to, oc); + break; + case static_cast(PieceType::QUEEN): + attacks = attacks::queen(to, oc); + } + + return (attacks & pieces(PieceType::KING, ~stm_)) ? CheckType::DIRECT_CHECK : CheckType::NO_CHECK; + } + + case Move::ENPASSANT: { + Square capSq(to.file(), from.rank()); + return (getSniper(this, ksq, (oc ^ Bitboard::fromSquare(capSq)) | toBB)) ? CheckType::DISCOVERY_CHECK + : CheckType::NO_CHECK; + } + + case Move::CASTLING: { + Square rookTo = Square::castling_rook_square(to > from, stm_); + return (attacks::rook(ksq, occ()) & Bitboard::fromSquare(rookTo)) ? CheckType::DISCOVERY_CHECK + : CheckType::NO_CHECK; + } + } + + assert(false); + return CheckType::NO_CHECK; // Prevent a compiler warning +} template void _Position::refresh_attacks() { Color c = sideToMove(); @@ -600,18 +662,6 @@ template uint64_t _Position::zobrist() } return hash; } - -template -template -void _Position::genKnightMoves(Movelist &list) const { - chess::movegen::genKnightMoves(*this, list, _pin_mask, _check_mask); -} -template -template -void _Position::genSlidingMoves(Movelist &moves) const { - chess::movegen::genSlidingMoves(*this, moves, _rook_pin, _bishop_pin, _check_mask); -} - template _Position::_Position(std::string fen) { setFEN(fen); } template Move _Position::parse_uci(std::string uci) const { @@ -724,34 +774,6 @@ template CastlingRights _Position::clea } // clang-format off #define INSTANTIATE(PieceC) \ -template void _Position::genEP(Movelist &) const; \ -template void _Position::genEP(Movelist &) const; \ -template void _Position::genPawnDoubleMoves(Movelist &) const; \ -template void _Position::genPawnDoubleMoves(Movelist &) const; \ -template void _Position::genPawnSingleMoves(Movelist &) const; \ -template void _Position::genPawnSingleMoves(Movelist &) const; \ -template void _Position::genPawnSingleMoves(Movelist &) const; \ -template void _Position::genPawnSingleMoves(Movelist &) const; \ -template void _Position::genKingMoves(Movelist &) const; \ -template void _Position::genKingMoves(Movelist &) const; \ -template void _Position::genKingMoves(Movelist &) const; \ -template void _Position::genKingMoves(Movelist &) const; \ -template void _Position::genKnightMoves(Movelist &) const; \ -template void _Position::genKnightMoves(Movelist &) const; \ -template void _Position::genKnightMoves(Movelist &) const; \ -template void _Position::genKnightMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ -template void _Position::genSlidingMoves(Movelist &) const; \ template _Position::_Position(std::string); \ template void _Position::setFEN(const std::string &); \ template std::string _Position::fen() const; \ diff --git a/position.h b/position.h index 26fe44d..59e61d7 100644 --- a/position.h +++ b/position.h @@ -1,6 +1,7 @@ #pragma once #include "attacks.h" #include "bitboard.h" +#include "movegen.h" #include "printers.h" #include "types.h" #include "zobrist.h" @@ -9,7 +10,6 @@ #include #include #include -#include "movegen.h" namespace chess { template struct alignas(64) HistoryEntry { @@ -41,23 +41,24 @@ template class HeapAllocatedValueList { public: using size_type = std::size_t; inline HeapAllocatedValueList() { - values_ = reinterpret_cast(::operator new(MaxSize*sizeof(T), std::align_val_t{ALIGNMENT})); + values_ = reinterpret_cast(::operator new(MaxSize * sizeof(T), std::align_val_t{ ALIGNMENT })); assert(values_); } - inline ~HeapAllocatedValueList() { ::operator delete(values_, std::align_val_t{ALIGNMENT}); } + inline ~HeapAllocatedValueList() { ::operator delete(values_, std::align_val_t{ ALIGNMENT }); } HeapAllocatedValueList(const HeapAllocatedValueList &other) : size_(other.size_) { - if (values_) ::operator delete(values_, std::align_val_t{ALIGNMENT}); - values_ = reinterpret_cast(::operator new(MaxSize*sizeof(T), std::align_val_t{ALIGNMENT})); + if (values_) + ::operator delete(values_, std::align_val_t{ ALIGNMENT }); + values_ = reinterpret_cast(::operator new(MaxSize * sizeof(T), std::align_val_t{ ALIGNMENT })); assert(values_); std::copy(other.values_, other.values_ + size_, values_); } HeapAllocatedValueList &operator=(const HeapAllocatedValueList &other) { if (this != &other) { - ::operator delete(values_, std::align_val_t{ALIGNMENT}); + ::operator delete(values_, std::align_val_t{ ALIGNMENT }); // Allocate new memory and copy - T *new_values = reinterpret_cast(::operator new(MaxSize*sizeof(T), std::align_val_t{ALIGNMENT})); + T *new_values = reinterpret_cast(::operator new(MaxSize * sizeof(T), std::align_val_t{ ALIGNMENT })); assert(new_values); std::copy(other.values_, other.values_ + other.size_, new_values); @@ -72,16 +73,16 @@ template class HeapAllocatedValueList { } HeapAllocatedValueList(HeapAllocatedValueList &&other) noexcept : size_(other.size_) { - ::operator delete(values_, std::align_val_t{ALIGNMENT}); - values_ = reinterpret_cast(::operator new(MaxSize*sizeof(T), std::align_val_t{ALIGNMENT})); + ::operator delete(values_, std::align_val_t{ ALIGNMENT }); + values_ = reinterpret_cast(::operator new(MaxSize * sizeof(T), std::align_val_t{ ALIGNMENT })); assert(values_); std::copy(other.values_, other.values_ + size_, values_); } HeapAllocatedValueList &operator=(HeapAllocatedValueList &&other) noexcept { if (this != &other) { - ::operator delete(values_, std::align_val_t{ALIGNMENT}); - values_ = reinterpret_cast(::operator new(MaxSize*sizeof(T), std::align_val_t{ALIGNMENT})); + ::operator delete(values_, std::align_val_t{ ALIGNMENT }); + values_ = reinterpret_cast(::operator new(MaxSize * sizeof(T), std::align_val_t{ ALIGNMENT })); assert(values_); std::copy(other.values_, other.values_ + size_, values_); } @@ -121,64 +122,126 @@ template class HeapAllocatedValueList { size_type size_ = 0; private: - T *values_=nullptr; + T *values_ = nullptr; +}; + +enum class CheckType { NO_CHECK, DIRECT_CHECK, DISCOVERY_CHECK }; +enum class MoveGenType : uint16_t { + NONE = 0, + + // piece selectors + PAWN = 1 << 1, + KNIGHT = 1 << 2, + BISHOP = 1 << 3, + ROOK = 1 << 4, + QUEEN = 1 << 5, + KING = 1 << 6, + + PIECE_MASK = PAWN | KNIGHT | BISHOP | ROOK | QUEEN | KING, + + // move-type selectors + CAPTURE = 1 << 7, + QUIET = 1 << 8, + + ALL = PIECE_MASK | CAPTURE | QUIET }; -enum class MoveGenType : uint8_t { ALL, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, CAPTURE }; +template constexpr MoveGenType operator&(MoveGenType a, MoveGenType b) { + using U = std::underlying_type_t; + return static_cast(static_cast(a) & static_cast(b)); +} +template constexpr MoveGenType operator|(MoveGenType a, MoveGenType b) { + using U = std::underlying_type_t; + return static_cast(static_cast(a) | static_cast(b)); +} template ::value>> class _Position { private: HistoryEntry current_state; // Move history stack - HeapAllocatedValueList, 6144> history; // ahh, but i hope it fulfils before I manages to find the absolute limit of a game + HeapAllocatedValueList, 6144> + history; // ahh, but i hope it fulfils before I manages to find the absolute limit of a game // Move generation functions, but INTERNAL. (they're kind of long so i put them into a source // file) Pawns (fully extensively tested) - template void genEP(Movelist &mv) const; - template void genPawnDoubleMoves(Movelist &mv) const; - template void genPawnSingleMoves(Movelist &mv) const; - template void genKnightMoves(Movelist &list) const; - template void genKingMoves(Movelist &mv) const; - template void genSlidingMoves(Movelist &mv) const; - Bitboard _rook_pin; Bitboard _bishop_pin; Bitboard _checkers; Bitboard _check_mask; Bitboard _pin_mask; - alignas(64) PieceC pieces_list[SQUARE_NB + 1] = { PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, - PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE }; + alignas(64) PieceC pieces_list[SQUARE_NB + 1] = { + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, + PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE + }; public: // Legal move generation functions - template __FORCEINLINE void legals(Movelist &out) const { - if constexpr (type == MoveGenType::ALL) { - // Simple cases - genEP(out); - genPawnSingleMoves(out); - genPawnDoubleMoves(out); - genKnightMoves(out); - genKingMoves(out); - genSlidingMoves(out); - genSlidingMoves(out); - genSlidingMoves(out); - } else if constexpr (type == MoveGenType::PAWN) { - genEP(out); - genPawnDoubleMoves(out); - genPawnSingleMoves(out); - } else if constexpr (type == MoveGenType::KNIGHT) { - genKnightMoves(out); - } else if constexpr (type == MoveGenType::KING) { - genKingMoves(out); - } else if constexpr (type == MoveGenType::CAPTURE) { - genEP(out); - genSlidingMoves(out); - genSlidingMoves(out); - genSlidingMoves(out); - genKnightMoves(out); - genKingMoves(out); - genPawnSingleMoves(out); - } +template +__FORCEINLINE void legals(Movelist &out) const { + + constexpr uint16_t raw = static_cast(type); + constexpr uint16_t pieceBits = raw & static_cast(MoveGenType::PIECE_MASK); + constexpr uint16_t modeBits = raw & (static_cast(MoveGenType::CAPTURE) | + static_cast(MoveGenType::QUIET)); + + // ---------------------------------------- + // Resolve default piece selection + // ---------------------------------------- + constexpr uint16_t effectivePieces = + pieceBits ? pieceBits : + (raw == static_cast(MoveGenType::NONE) + ? 0 + : static_cast(MoveGenType::PIECE_MASK)); + + // ---------------------------------------- + // Resolve default mode selection + // ---------------------------------------- + constexpr bool includeCaps = modeBits == 0 || (modeBits & static_cast(MoveGenType::CAPTURE)); + constexpr bool includeQuiet = modeBits == 0 || (modeBits & static_cast(MoveGenType::QUIET)); + constexpr bool captureOnly = includeCaps && !includeQuiet; + + // Early-out for NONE + if constexpr (effectivePieces == 0 && modeBits != 0) + return; + + // Now your existing piece dispatch logic stays the same: + if constexpr (effectivePieces & static_cast(MoveGenType::PAWN)) { + movegen::genPawnSingleMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + if constexpr (includeQuiet) + movegen::genPawnDoubleMoves(*this, out, _pin_mask, _check_mask); + if constexpr (includeCaps) + movegen::genEP(*this, out); + } + + if constexpr (effectivePieces & static_cast(MoveGenType::KNIGHT)) { + movegen::genKnightMoves(*this, out, _pin_mask, _check_mask); + } + + if constexpr (effectivePieces & static_cast(MoveGenType::KING)) { + movegen::genKingMoves(*this, out); + } + + if constexpr (effectivePieces & static_cast(MoveGenType::BISHOP)) { + movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + } + + if constexpr (effectivePieces & static_cast(MoveGenType::ROOK)) { + movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); } + + if constexpr (effectivePieces & static_cast(MoveGenType::QUEEN)) { + movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + } +} + // Legal move generation functions template __FORCEINLINE void legals(Movelist &out) const { const Color stm = sideToMove(); // Cache it @@ -213,7 +276,6 @@ template && ...)>> [[nodiscard]] __FORCEINLINE Bitboard pieces(PTypes... ptypes) const { return (current_state.pieces[ptypes] | ...); } + template && ...)>> + [[nodiscard]] __FORCEINLINE Bitboard pieces(PTypes... ptypes) const { + return (current_state.pieces[ptypes] | ...); + } - template && ...)>> [[nodiscard]] __FORCEINLINE Bitboard pieces(Color c, PTypes... ptypes) const { return (pieces(ptypes, c) | ...); } + template && ...)>> + [[nodiscard]] __FORCEINLINE Bitboard pieces(Color c, PTypes... ptypes) const { + return (pieces(ptypes, c) | ...); + } /** * @brief Returns the origin squares of pieces of a given color attacking a target square @@ -307,7 +375,9 @@ template (pt, c ? WHITE : BLACK); + break; + } + } + } auto p = pieces_list[s]; - auto p2 = piece_of(p); - if (p2 == ALL_PIECES) - return p; - else { - Bitboard bb = 1ULL << s; - Bitboard _ = pieces(p2, color_of(p)); - Bitboard b = _ & bb; #ifndef __EXCEPTIONS - assert(b && "Inconsistient piece map"); + assert(p == _p2 && "Inconsistient piece map"); #else - if (!b) - throw std::invalid_argument("Inconsistient piece map"); + if (p != _p2) + // throw std::invalid_argument("Inconsistient piece map"); + exit(-1); #endif - } return p; #endif } @@ -410,14 +489,18 @@ template &state() const { return current_state; } @@ -440,7 +523,9 @@ template bool is_valid() const; + CheckType givesCheck(Move move) const; private: template [[nodiscard]] __FORCEINLINE Bitboard pinMask(Color c, Square sq) const { @@ -535,10 +624,24 @@ template state) { + __FORCEINLINE _Position(const HistoryEntry &state) { // compatible! current_state = state; - std::copy(std::begin(other.pieces_list), std::end(other.pieces_list), std::begin(pieces_list)); + for (Square sq = SQ_A1; sq < SQ_NONE; sq++) { + Bitboard mask = (1ULL << sq); + if (((state.occ[WHITE] | state.occ[BLACK]) & mask) == 0) { + pieces_list[sq] = PieceC::NO_PIECE; + continue; + } + bool c = (state.occ[WHITE] & mask) != 0; + for (PieceType pt : { PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }) { + bool is_p = (current_state.pieces[(int)pt] & mask) != 0; + if (is_p) { + pieces_list[sq] = make_piece(pt, c ? WHITE : BLACK); + break; + } + } + } refresh_attacks(); } __FORCEINLINE _Position(const _Position &other) @@ -548,7 +651,9 @@ template || std::is_same_v) && !std::is_same_v, int> = 0> [[deprecated("Incompatible piece method used, you shouldn't call this")]] __FORCEINLINE _Position(HistoryEntry state) { + template ::value && !std::is_same_v, int> = 0> + [[deprecated("Incompatible piece method used, you shouldn't call this")]] __FORCEINLINE + _Position(const HistoryEntry &state) { // incompatible! current_state = HistoryEntry(); current_state.turn = state.turn; @@ -557,9 +662,26 @@ template (type_of(state.pieces_list[s]), color_of(state.pieces_list[s])); + current_state.epIncluded = state.epIncluded; + std::copy(std::begin(state.pieces), std::end(state.pieces), current_state.pieces); + current_state.repetition = state.repetition; + std::copy(std::begin(state.kings), std::end(state.kings), current_state.kings); + std::copy(std::begin(state.occ), std::end(state.occ), current_state.occ); + current_state.pliesFromNull = state.pliesFromNull; + for (Square sq = SQ_A1; sq < SQ_NONE; sq++) { + Bitboard mask = (1ULL << sq); + if (((state.occ[WHITE] | state.occ[BLACK]) & mask) == 0) { + pieces_list[sq] = PieceC::NO_PIECE; + continue; + } + bool c = (state.occ[WHITE] & mask) != 0; + for (PieceType pt : { PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }) { + bool is_p = (current_state.pieces[(int)pt] & mask) != 0; + if (is_p) { + pieces_list[sq] = make_piece(pt, c ? WHITE : BLACK); + break; + } + } } refresh_attacks(); } diff --git a/printers.cpp b/printers.cpp index 6c091d6..aaf00b0 100644 --- a/printers.cpp +++ b/printers.cpp @@ -82,11 +82,53 @@ std::ostream &operator<<(std::ostream &os, const Square &sq) { return os; } template std::ostream &operator<<(std::ostream &os, PieceC p) { - constexpr std::string_view mapping = " PNBRQK..pnbrqk."; - return os << mapping[static_cast(make_piece(piece_of(p), color_of(p)))]; + char c='.'; + switch(p){ + case PieceC::WPAWN: + c='P'; + break; + case PieceC::BPAWN: + c='p'; + break; + case PieceC::WKNIGHT: + c='N'; + break; + case PieceC::BKNIGHT: + c='n'; + break; + case PieceC::WBISHOP: + c='B'; + break; + case PieceC::BBISHOP: + c='b'; + break; + case PieceC::WROOK: + c='R'; + break; + case PieceC::BROOK: + c='r'; + break; + case PieceC::WQUEEN: + c='Q'; + break; + case PieceC::BQUEEN: + c='q'; + break; + case PieceC::WKING: + c='K'; + break; + case PieceC::BKING: + c='k'; + break; + default: + break; + } + return os< &); +#define INSTANTITATE(PieceC) \ + template std::ostream &operator<<(std::ostream &, const _Position &); \ + template std::ostream &operator<<(std::ostream &, PieceC); INSTANTITATE(EnginePiece) INSTANTITATE(PolyglotPiece) diff --git a/printers.h b/printers.h index ef5977b..b1dec11 100644 --- a/printers.h +++ b/printers.h @@ -1,15 +1,17 @@ #pragma once +#include "fwd_decl.h" #include #include #include -#include "fwd_decl.h" namespace chess { std::ostream &operator<<(std::ostream &os, const Move &mv); std::ostream &operator<<(std::ostream &os, const Color &c); std::ostream &operator<<(std::ostream &os, const CastlingRights &cr); -template ::value>> std::ostream &operator<<(std::ostream &os, PieceC p); +template ::value>> +std::ostream &operator<<(std::ostream &os, PieceC p); std::ostream &operator<<(std::ostream &os, const Square &sq); template class _Position; -template ::value>> std::ostream &operator<<(std::ostream &os, const _Position &pos); +template ::value>> +std::ostream &operator<<(std::ostream &os, const _Position &pos); } // namespace chess \ No newline at end of file diff --git a/tests.cpp b/tests.cpp index 1d2d96a..1c3152a 100644 --- a/tests.cpp +++ b/tests.cpp @@ -339,7 +339,6 @@ TEST_CASE("Move making pin update") { Movelist out; pos.legals(out); auto pin_mask = pos.pin_mask(); - for (auto& mv: out) std::cout< #include #include -#include "fwd_decl.h" #if defined(_MSC_VER) #define UNREACHABLE() __assume(false) #elif defined(__clang__) || defined(__GNUC__) @@ -23,17 +23,17 @@ #elif __GNUC__ >= 13 #define ASSUME(cond) __attribute__((assume(cond))) #else -#define ASSUME(cond) \ - do { \ - if (!(cond)) \ - UNREACHABLE(); \ +#define ASSUME(cond) \ + do { \ + if (!(cond)) \ + UNREACHABLE(); \ } while (0) #endif #else -#define ASSUME(cond) \ - do { \ - if (!(cond)) \ - UNREACHABLE(); \ +#define ASSUME(cond) \ + do { \ + if (!(cond)) \ + UNREACHABLE(); \ } while (0) #endif @@ -132,18 +132,18 @@ inline constexpr Direction relative_direction(Color c, Direction d) { return sta inline constexpr Direction pawn_push(Color c) { return c == WHITE ? NORTH : SOUTH; } -#define ENABLE_INCR_OPERATORS_ON(T) \ - constexpr T &operator++(T &d) { return d = T(int(d) + 1); } \ - constexpr T &operator--(T &d) { return d = T(int(d) - 1); } \ - constexpr T operator++(T &d, int) { \ - T old = d; \ - ++d; \ - return old; \ - } \ - constexpr T operator--(T &d, int) { \ - T old = d; \ - --d; \ - return old; \ +#define ENABLE_INCR_OPERATORS_ON(T) \ + constexpr T &operator++(T &d) { return d = T(int(d) + 1); } \ + constexpr T &operator--(T &d) { return d = T(int(d) - 1); } \ + constexpr T operator++(T &d, int) { \ + T old = d; \ + ++d; \ + return old; \ + } \ + constexpr T operator--(T &d, int) { \ + T old = d; \ + --d; \ + return old; \ } ENABLE_INCR_OPERATORS_ON(PieceType) @@ -162,10 +162,55 @@ constexpr Square operator-(Square s, Direction d) { return Square(int(s) - int(d constexpr Square &operator+=(Square &s, Direction d) { return s = s + d; } constexpr Square &operator-=(Square &s, Direction d) { return s = s - d; } // specifically for Polyglot (a.k.a zobrist hashing but use proper hash) -enum class PolyglotPiece : uint8_t { WPAWN = 1, WKNIGHT = 3, WBISHOP = 5, WROOK = 7, WQUEEN = 9, WKING = 11, BPAWN = 0, BKNIGHT = 2, BBISHOP = 4, BROOK = 6, BQUEEN = 8, BKING = 10, NO_PIECE = 12, PIECE_NB = 12 }; +enum class PolyglotPiece : uint8_t { + WPAWN = 1, + WKNIGHT = 3, + WBISHOP = 5, + WROOK = 7, + WQUEEN = 9, + WKING = 11, + BPAWN = 0, + BKNIGHT = 2, + BBISHOP = 4, + BROOK = 6, + BQUEEN = 8, + BKING = 10, + NO_PIECE = 12, + PIECE_NB = 12 +}; // Normal board, you can use ANY! (but comfortable for certain chess engines such as Stockfish) -enum class EnginePiece : uint8_t { NO_PIECE, WPAWN = PAWN + 0, WKNIGHT, WBISHOP, WROOK, WQUEEN, WKING, BPAWN = PAWN + 8, BKNIGHT, BBISHOP, BROOK, BQUEEN, BKING, PIECE_NB = 16 }; -enum class ContiguousMappingPiece : uint8_t { WPAWN = 0, WKNIGHT = 1, WBISHOP = 2, WROOK = 3, WQUEEN = 4, WKING = 5, BPAWN = 6, BKNIGHT = 7, BBISHOP = 8, BROOK = 9, BQUEEN = 10, BKING = 11, NO_PIECE = 12, PIECE_NB = 12 }; +enum class EnginePiece : uint8_t { + NO_PIECE, + WPAWN = PAWN + 0, + WKNIGHT, + WBISHOP, + WROOK, + WQUEEN, + WKING, + BPAWN = PAWN + 8, + BKNIGHT, + BBISHOP, + BROOK, + BQUEEN, + BKING, + PIECE_NB = 16 +}; +enum class ContiguousMappingPiece : uint8_t { + WPAWN = 0, + WKNIGHT = 1, + WBISHOP = 2, + WROOK = 3, + WQUEEN = 4, + WKING = 5, + BPAWN = 6, + BKNIGHT = 7, + BBISHOP = 8, + BROOK = 9, + BQUEEN = 10, + BKING = 11, + NO_PIECE = 12, + PIECE_NB = 12 +}; template constexpr size_t enum_idx() { if constexpr (std::is_same_v) return 0; @@ -176,16 +221,35 @@ template constexpr size_t enum_idx() { return -1; } // clang-format on -constexpr PieceType piece_of(PolyglotPiece p) { return p == decltype(p)::NO_PIECE ? NO_PIECE_TYPE : static_cast(static_cast(p) / 2 + 1); } -constexpr PieceType piece_of(EnginePiece p) { return p == decltype(p)::NO_PIECE ? NO_PIECE_TYPE : static_cast((static_cast(p) - 1) % 8 + 1); } -constexpr PieceType piece_of(ContiguousMappingPiece p) { return p == decltype(p)::NO_PIECE ? NO_PIECE_TYPE : static_cast(static_cast(p) % 6 + 1); } +constexpr PieceType piece_of(PolyglotPiece p) { + return p == decltype(p)::NO_PIECE ? NO_PIECE_TYPE : static_cast(static_cast(p) / 2 + 1); +} +constexpr PieceType piece_of(EnginePiece p) { + return p == decltype(p)::NO_PIECE ? NO_PIECE_TYPE : static_cast((static_cast(p) - 1) % 8 + 1); +} +constexpr PieceType piece_of(ContiguousMappingPiece p) { + return p == decltype(p)::NO_PIECE ? NO_PIECE_TYPE : static_cast(static_cast(p) % 6 + 1); +} constexpr Color color_of(PolyglotPiece pt) { return static_cast((static_cast(pt) + 1) % 2); } -constexpr Color color_of(EnginePiece pt) { return static_cast(static_cast(pt) / static_cast(EnginePiece::BPAWN)); } +constexpr Color color_of(EnginePiece pt) { + return static_cast(static_cast(pt) / static_cast(EnginePiece::BPAWN)); +} constexpr Color color_of(ContiguousMappingPiece pt) { return static_cast(static_cast(pt) / 6); } -template , bool> = 0> constexpr EnginePiece make_piece(PieceType pt, Color c) { return static_cast((c << 3) + pt); } -template , bool> = 0> constexpr PolyglotPiece make_piece(PieceType pt, Color c) { return static_cast(~c + 2 * (pt - 1)); } -template , bool> = 0> constexpr ContiguousMappingPiece make_piece(PieceType pt, Color c) { return static_cast((static_cast(pt) - 1) + 6 * static_cast(c)); } -template ::value>> constexpr PieceType type_of(T p) { return piece_of(p); } +template , bool> = 0> +constexpr EnginePiece make_piece(PieceType pt, Color c) { + return static_cast((c << 3) + pt); +} +template , bool> = 0> +constexpr PolyglotPiece make_piece(PieceType pt, Color c) { + return static_cast(~c + 2 * (pt - 1)); +} +template , bool> = 0> +constexpr ContiguousMappingPiece make_piece(PieceType pt, Color c) { + return static_cast((static_cast(pt) - 1) + 6 * static_cast(c)); +} +template ::value>> constexpr PieceType type_of(T p) { + return piece_of(p); +} enum CastlingRights : int8_t { NO_CASTLING, @@ -202,21 +266,27 @@ enum CastlingRights : int8_t { CASTLING_RIGHT_NB = 16 }; -constexpr CastlingRights operator&(Color c, CastlingRights cr) { return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } +constexpr CastlingRights operator&(Color c, CastlingRights cr) { + return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); +} // Bitwise OR assignment operator inline CastlingRights &operator|=(CastlingRights &a, CastlingRights b) { a = static_cast(static_cast(a) | static_cast(b)); return a; } // Bitwise OR assignment operator -inline CastlingRights operator|(CastlingRights a, CastlingRights b) { return static_cast(static_cast(a) | static_cast(b)); } +inline CastlingRights operator|(CastlingRights a, CastlingRights b) { + return static_cast(static_cast(a) | static_cast(b)); +} // Bitwise OR assignment operator inline CastlingRights &operator&=(CastlingRights &a, CastlingRights b) { a = static_cast(static_cast(a) & static_cast(b)); return a; } -inline CastlingRights operator~(CastlingRights a) { return static_cast(static_cast(a) ^ ANY_CASTLING); } +inline CastlingRights operator~(CastlingRights a) { + return static_cast(static_cast(a) ^ ANY_CASTLING); +} enum MoveType : uint16_t { NORMAL, PROMOTION = 1 << 14, EN_PASSANT = 2 << 14, CASTLING = 3 << 14 }; // A move needs 16 bits to be stored @@ -237,7 +307,10 @@ class Move { constexpr Move(Square from, Square to) : data((static_cast(from) << 6) | static_cast(to)) {} - template static constexpr Move make(Square from, Square to, PieceType pt = PieceType::KNIGHT) { return Move(static_cast(T) | static_cast((static_cast(pt) - static_cast(PieceType::KNIGHT)) << 12) | (static_cast(from) << 6) | static_cast(to)); } + template static constexpr Move make(Square from, Square to, PieceType pt = PieceType::KNIGHT) { + return Move(static_cast(T) | static_cast((static_cast(pt) - static_cast(PieceType::KNIGHT)) << 12) | + (static_cast(from) << 6) | static_cast(to)); + } constexpr Square from_sq() const { assert(is_ok()); @@ -256,7 +329,9 @@ class Move { constexpr MoveType type_of() const { return MoveType(data & (3 << 14)); } constexpr MoveType typeOf() const { return type_of(); } - constexpr PieceType promotion_type() const { return static_cast(((data >> 12) & 3) + static_cast(PieceType::KNIGHT)); } + constexpr PieceType promotion_type() const { + return static_cast(((data >> 12) & 3) + static_cast(PieceType::KNIGHT)); + } constexpr PieceType promotionType() const { return promotion_type(); } constexpr bool is_ok() const { return none().data != data && null().data != data; } @@ -334,7 +409,9 @@ template class ValueList { }; using Movelist = ValueList; -constexpr int square_distance(Square a, Square b) { return std::max(std::abs(file_of(a) - file_of(b)), std::abs(rank_of(a) - rank_of(b))); } +constexpr int square_distance(Square a, Square b) { + return std::max(std::abs(file_of(a) - file_of(b)), std::abs(rank_of(a) - rank_of(b))); +} constexpr Square parse_square(std::string_view sv) { if (sv.size() < 2) return SQ_NONE; @@ -351,7 +428,7 @@ constexpr Square parse_square(std::string_view sv) { constexpr PieceType parse_pt(unsigned char c) { const char a[] = "pnbrqk"; int p = -1; - (c >='A' && c<='Z') ? (c += 32) : (c); // tolower + (c >= 'A' && c <= 'Z') ? (c += 32) : (c); // tolower for (size_t i = 0; i < sizeof(a); i++) { if (c == a[i]) p = i; @@ -360,5 +437,3 @@ constexpr PieceType parse_pt(unsigned char c) { } } // namespace chess - - From b8b8a4f256acd373cf9b135080763fb92f0fdf86 Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Wed, 10 Dec 2025 23:20:38 +0700 Subject: [PATCH 03/15] hotfix compile errors for GCC --- position.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/position.cpp b/position.cpp index b541b29..83b99dd 100644 --- a/position.cpp +++ b/position.cpp @@ -520,7 +520,7 @@ template template bool _Position CheckType _Position::givesCheck(Move move) const { +template CheckType _Position::givesCheck(Move m) const { const static auto getSniper = [&](Square ksq, Bitboard oc) { const auto us_occ = this->us(board->sideToMove()); const auto bishop = attacks::bishop(ksq, oc) & this->pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; @@ -534,7 +534,7 @@ template CheckType _Position::givesChec const Square to = m.to(); const Square ksq = kingSq(~sideToMove()); const Bitboard toBB = 1ULL<<(to); - const PieceType pt = at(from).type(); + const PieceType pt = piece_of(at(from)); Bitboard fromKing = 0ull; @@ -553,13 +553,13 @@ template CheckType _Position::givesChec if (fromKing & toBB) return CheckType::DIRECT_CHECK; // Discovery check - const Bitboard fromBB = Bitboard::fromSquare(from); + const Bitboard fromBB = 1ULL<<(from); const Bitboard oc = occ() ^ fromBB; Bitboard sniper = getSniper(this, ksq, oc); while (sniper) { - Square sq = sniper.pop(); + Square sq = pop_lsb(sniper); return (!(movegen::between(ksq, sq) & toBB) || m.typeOf() == Move::CASTLING) ? CheckType::DISCOVERY_CHECK : CheckType::NO_CHECK; } @@ -589,14 +589,14 @@ template CheckType _Position::givesChec } case Move::ENPASSANT: { - Square capSq(to.file(), from.rank()); - return (getSniper(this, ksq, (oc ^ Bitboard::fromSquare(capSq)) | toBB)) ? CheckType::DISCOVERY_CHECK + Square capSq=make_sq(file_of(to), rank_of(from)); + return (getSniper(this, ksq, (oc ^ (1ULL< from, stm_); - return (attacks::rook(ksq, occ()) & Bitboard::fromSquare(rookTo)) ? CheckType::DISCOVERY_CHECK + Square rookTo = relative_square(side_to_move(), to > from ? SQ_F1 : SQ_D1); + return (attacks::rook(ksq, occ()) & (1ULL<::parse_uci(std::string) const; \ template Move _Position::push_uci(std::string); \ template bool _Position::is_valid() const; \ template bool _Position::is_valid() const; \ +template CheckType _Position::givesCheck(Move) const; \ template bool _Position::is_insufficient_material() const; // clang-format off INSTANTIATE(PolyglotPiece) From d22c67102ff6b798a4ad84a2938531e0f463f1bc Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Wed, 10 Dec 2025 23:22:16 +0700 Subject: [PATCH 04/15] hotfixes --- position.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/position.cpp b/position.cpp index 83b99dd..8fcb108 100644 --- a/position.cpp +++ b/position.cpp @@ -539,7 +539,7 @@ template CheckType _Position::givesChec Bitboard fromKing = 0ull; if (pt == PieceType::PAWN) { - fromKing = attacks::pawn(~stm_, ksq); + fromKing = attacks::pawn(~side_to_move(), ksq); } else if (pt == PieceType::KNIGHT) { fromKing = attacks::knight(ksq); } else if (pt == PieceType::BISHOP) { @@ -572,20 +572,23 @@ template CheckType _Position::givesChec Bitboard attacks = 0ull; switch (m.promotionType()) { - case static_cast(PieceType::KNIGHT): + case KNIGHT: attacks = attacks::knight(to); break; - case static_cast(PieceType::BISHOP): + case BISHOP: attacks = attacks::bishop(to, oc); break; - case static_cast(PieceType::ROOK): + case ROOK: attacks = attacks::rook(to, oc); break; - case static_cast(PieceType::QUEEN): + case QUEEN: attacks = attacks::queen(to, oc); + break; + default: + break; } - return (attacks & pieces(PieceType::KING, ~stm_)) ? CheckType::DIRECT_CHECK : CheckType::NO_CHECK; + return (attacks & pieces(PieceType::KING, ~sideToMove())) ? CheckType::DIRECT_CHECK : CheckType::NO_CHECK; } case Move::ENPASSANT: { From 6463375efdaa4eb2dc930a5c1808dbf8e76a7323 Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Wed, 10 Dec 2025 23:27:57 +0700 Subject: [PATCH 05/15] fix some compile errors --- position.cpp | 8 ++++---- position.h | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/position.cpp b/position.cpp index 8fcb108..715e7a7 100644 --- a/position.cpp +++ b/position.cpp @@ -522,9 +522,9 @@ template template bool _Position CheckType _Position::givesCheck(Move m) const { const static auto getSniper = [&](Square ksq, Bitboard oc) { - const auto us_occ = this->us(board->sideToMove()); - const auto bishop = attacks::bishop(ksq, oc) & this->pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; - const auto rook = attacks::rook(ksq, oc) & this->pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; + const auto us_occ = us(sideToMove()); + const auto bishop = attacks::bishop(ksq, oc) & pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; + const auto rook = attacks::rook(ksq, oc) & pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; return (bishop | rook); }; @@ -559,7 +559,7 @@ template CheckType _Position::givesChec Bitboard sniper = getSniper(this, ksq, oc); while (sniper) { - Square sq = pop_lsb(sniper); + Square sq = (Square)pop_lsb(sniper); return (!(movegen::between(ksq, sq) & toBB) || m.typeOf() == Move::CASTLING) ? CheckType::DISCOVERY_CHECK : CheckType::NO_CHECK; } diff --git a/position.h b/position.h index 59e61d7..a93e30f 100644 --- a/position.h +++ b/position.h @@ -324,12 +324,14 @@ __FORCEINLINE void legals(Movelist &out) const { return current_state.pieces[pt]; } } - template && ...)>> + template && ...)>> [[nodiscard]] __FORCEINLINE Bitboard pieces(PTypes... ptypes) const { - return (current_state.pieces[ptypes] | ...); + return (current_state.pieces[static_cast(ptypes)] | ...); } - template && ...)>> + template && ...)>> [[nodiscard]] __FORCEINLINE Bitboard pieces(Color c, PTypes... ptypes) const { return (pieces(ptypes, c) | ...); } From 24140e1932e9f1a6451eb32d50ca9886454948e1 Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Wed, 10 Dec 2025 23:29:47 +0700 Subject: [PATCH 06/15] fix compiles --- position.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/position.cpp b/position.cpp index 715e7a7..422a9b2 100644 --- a/position.cpp +++ b/position.cpp @@ -521,10 +521,10 @@ template template bool _Position CheckType _Position::givesCheck(Move m) const { - const static auto getSniper = [&](Square ksq, Bitboard oc) { - const auto us_occ = us(sideToMove()); - const auto bishop = attacks::bishop(ksq, oc) & pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; - const auto rook = attacks::rook(ksq, oc) & pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; + const static auto getSniper = [](const _Position* p, Square ksq, Bitboard oc) { + const auto us_occ = p.us(p.sideToMove()); + const auto bishop = attacks::bishop(ksq, oc) & p.pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; + const auto rook = attacks::rook(ksq, oc) & p.pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; return (bishop | rook); }; From f22c9008aa7b76e39e1a8f7937cae0237748f4fa Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Wed, 10 Dec 2025 23:32:00 +0700 Subject: [PATCH 07/15] fix compiles (again) --- position.cpp | 6 +++--- position.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/position.cpp b/position.cpp index 422a9b2..b27c069 100644 --- a/position.cpp +++ b/position.cpp @@ -522,9 +522,9 @@ template template bool _Position CheckType _Position::givesCheck(Move m) const { const static auto getSniper = [](const _Position* p, Square ksq, Bitboard oc) { - const auto us_occ = p.us(p.sideToMove()); - const auto bishop = attacks::bishop(ksq, oc) & p.pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; - const auto rook = attacks::rook(ksq, oc) & p.pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; + const auto us_occ = p->us(p->sideToMove()); + const auto bishop = attacks::bishop(ksq, oc) & p->pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; + const auto rook = attacks::rook(ksq, oc) & p->pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; return (bishop | rook); }; diff --git a/position.h b/position.h index a93e30f..1442bbc 100644 --- a/position.h +++ b/position.h @@ -481,6 +481,7 @@ __FORCEINLINE void legals(Movelist &out) const { return p; #endif } + __FORCEINLINE Bitboard us(Color c) const { return occ(c); } __FORCEINLINE Color sideToMove() const { return current_state.turn; } __FORCEINLINE uint64_t hash() const { return current_state.hash; } __FORCEINLINE uint64_t key() const { return current_state.hash; } From 3a0cad039344c64f96d691048221d52c90923936 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:39:30 +0700 Subject: [PATCH 08/15] Clarify trailing annotations in comment Updated comment to clarify which trailing annotations are stripped. --- moves_io.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moves_io.cpp b/moves_io.cpp index 1f197fb..8aece92 100644 --- a/moves_io.cpp +++ b/moves_io.cpp @@ -148,10 +148,10 @@ template Move parseSan(const _Position &pos, std: THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal O-O-O")); return Move::none(); } - // 2) Strip trailing annotations (+, #, !, ?). Repeated occurrences too. + // 2) Strip trailing annotations (+, #) that aren't required in the standard (except "e.p. "). Repeated occurrences too. while (!san.empty()) { char c = san.back(); - if (c == '+' || c == '#' || c == '!' || c == '?') + if (c == '+' || c == '#') san.pop_back(); else break; From bdcea88f6a70546a21fe6a1d304c9a25fda53ab5 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:51:17 +0700 Subject: [PATCH 09/15] correct the comment of SAN --- moves_io.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moves_io.cpp b/moves_io.cpp index 8aece92..ceb1d3d 100644 --- a/moves_io.cpp +++ b/moves_io.cpp @@ -207,7 +207,7 @@ template Move parseSan(const _Position &pos, std: std::string prefix; prefix.reserve(san.size()); for (char c : san) - if (c != 'x' && c != 'X' && c != '-') + if (c != 'x' && c != 'X') prefix.push_back(c); // prefix now holds the pre-destination token (e.g. "Nbd" from "Nbd2" or "Pe2" from "Pe2e4") From e59851b3e0fa97e9505755816a8cd31be047e392 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:52:56 +0700 Subject: [PATCH 10/15] Update movegen.cpp --- movegen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/movegen.cpp b/movegen.cpp index 64f463b..29a77de 100644 --- a/movegen.cpp +++ b/movegen.cpp @@ -37,7 +37,7 @@ Move *splat_moves(Move *moveList, Square from, Bitboard to_bb) { return moveList; } -template Move *splat_pawn_moves(Move *moveList, Bitboard to_bb) { +template Move *splat_pawn_moves(Move *moveList, Bitboard to_bb) { const auto *table = reinterpret_cast(SPLAT_PAWN_TABLE.data.data()); moveList = write_moves(moveList, static_cast(to_bb >> 0), _mm512_load_si512(table + 0)); moveList = write_moves(moveList, static_cast(to_bb >> 32), _mm512_load_si512(table + 1)); @@ -459,4 +459,4 @@ template Move *chess::_chess::splat_pawn_moves(Move *, Bitboard); INSTANTIATE(EnginePiece) INSTANTIATE(PolyglotPiece) INSTANTIATE(ContiguousMappingPiece) -} // namespace chess \ No newline at end of file +} // namespace chess From 76a38dc2bf64464bd55fd3f9daed5920a02fa399 Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Thu, 11 Dec 2025 11:57:35 +0700 Subject: [PATCH 11/15] fix some tests --- moves_io.cpp | 35 +++++++++++++++++++---------------- non_core_tests.cpp | 6 +++--- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/moves_io.cpp b/moves_io.cpp index 1f197fb..338c51b 100644 --- a/moves_io.cpp +++ b/moves_io.cpp @@ -129,7 +129,7 @@ template Move parseSan(const _Position &pos, std: pos.legals(moves); // Make a local mutable copy we can trim safely. - std::string san(input_san); + std::string san(input_san), _san(raw_san); // 1) Castling shortcuts if (san == "O-O" || san == "0-0" || san == "O-O+" || san == "0-0+" || san == "O-O#" || san == "0-0#") { @@ -137,7 +137,7 @@ template Move parseSan(const _Position &pos, std: relative_square(pos.side_to_move(), SQ_H1)); if (std::find(moves.begin(), moves.end(), km) != moves.end()) return km; - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal O-O")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+san+"' in "+pos.fen())); return Move::none(); } if (san == "O-O-O" || san == "0-0-0" || san == "O-O-O+" || san == "0-0-0+" || san == "O-O-O#" || san == "0-0-0#") { @@ -145,7 +145,7 @@ template Move parseSan(const _Position &pos, std: relative_square(pos.side_to_move(), SQ_A1)); if (std::find(moves.begin(), moves.end(), qm) != moves.end()) return qm; - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal O-O-O")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+san+"' in "+pos.fen())); return Move::none(); } // 2) Strip trailing annotations (+, #, !, ?). Repeated occurrences too. @@ -157,7 +157,7 @@ template Move parseSan(const _Position &pos, std: break; } if (san.empty()) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("empty san")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+san+"' in "+pos.fen())); return Move::none(); } @@ -170,7 +170,7 @@ template Move parseSan(const _Position &pos, std: if (penult == '=') { promotion = parse_pt(last); if (promotion == NO_PIECE_TYPE) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid promotion piece")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); return Move::none(); } san.pop_back(); // remove piece letter @@ -185,17 +185,17 @@ template Move parseSan(const _Position &pos, std: // 4) Destination square: always the last [file][rank] if (san.size() < 2) - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid san (too short)")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); char dfile = san[san.size() - 2]; char drank = san[san.size() - 1]; if (!(dfile >= 'a' && dfile <= 'h' && drank >= '1' && drank <= '8')) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid destination square")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); return Move::none(); } std::string dest_sq_str = san.substr(san.size() - 2, 2); Square to_square = parse_square(dest_sq_str); if (to_square == SQ_NONE) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid dest square")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); return Move::none(); } san.resize(san.size() - 2); // chop off destination @@ -222,7 +222,7 @@ template Move parseSan(const _Position &pos, std: std::string src_sq_str = prefix.substr(prefix.size() - 2, 2); src_square = parse_square(src_sq_str); if (src_square == SQ_NONE) - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid source square")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); prefix.resize(prefix.size() - 2); has_src_square = true; } @@ -253,7 +253,7 @@ template Move parseSan(const _Position &pos, std: dis_rank = c - '1'; else { // unexpected char in prefix - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("invalid char in SAN prefix")); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); return Move::none(); } } @@ -314,7 +314,7 @@ template Move parseSan(const _Position &pos, std: // Everything matches -> accept candidate if (found) { THROW_IF_EXCEPTIONS_ON( - AmbiguousMoveException("ambiguous san: \"" + std::string(raw_san) + "\" in " + pos.fen())); + AmbiguousMoveException("ambiguous san: '" + _san + "' in " + pos.fen())); return Move::none(); } matched = m; @@ -322,7 +322,7 @@ template Move parseSan(const _Position &pos, std: } if (!found) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: \"" + std::string(input_san) + "\" in " + pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + _san + "' in " + pos.fen())); return Move::none(); } @@ -332,12 +332,15 @@ template Move parseSan(const _Position &pos, std: if (remove_illegals) { std::string trimmed_san(raw_san); while (!trimmed_san.empty()) { - Move attempt = do_parse(trimmed_san); - if (attempt.is_ok()) - return attempt; + try{ + Move attempt = do_parse(trimmed_san); + if (attempt.is_ok()) + return attempt; + } + catch(...){} trimmed_san.pop_back(); } - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: \"" + std::string(raw_san) + "\" in " + pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + std::string(raw_san) + "' in " + pos.fen())); return Move::none(); } else { return do_parse(raw_san); diff --git a/non_core_tests.cpp b/non_core_tests.cpp index 11d19ba..7d70421 100644 --- a/non_core_tests.cpp +++ b/non_core_tests.cpp @@ -409,7 +409,7 @@ TEST_SUITE("SAN Parser") { auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17" }; Move m = Move::make(Square::SQ_E1, Square::SQ_H1); - REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0+?!"), "invalid san: '0-0+?!'", chess::uci::IllegalMoveException); + REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0+?!"), "illegal san: '0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17", chess::uci::IllegalMoveException); REQUIRE(uci::parseSan(b, "0-0+?!", true) == m); } @@ -419,7 +419,7 @@ TEST_SUITE("SAN Parser") { Move m = Move::make(Square::SQ_E1, Square::SQ_A1); - REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0-0+?!"), "invalid san: 'O-O-O+!?'", chess::uci::IllegalMoveException); + REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0-0+?!"), "illegal san: '0-0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1", chess::uci::IllegalMoveException); REQUIRE(uci::parseSan(b, "0-0-0+?!", true) == m); } @@ -861,7 +861,7 @@ TEST_SUITE("SAN Parser") { Move san = Move::NO_MOVE; CHECK_THROWS_WITH_AS(san = uci::parseSan(b, "Nec4"), - "illegal san: Nec4 8/8/6K1/4k3/4N3/p4r2/N3N3/8 w - - 3 82", + "illegal san: 'Nec4' in 8/8/6K1/4k3/4N3/p4r2/N3N3/8 w - - 3 82", uci::IllegalMoveException); CHECK(san == Move::NO_MOVE); } From 81b36419dc9dc5dd6527c79aa8333de585f1e755 Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Thu, 11 Dec 2025 12:04:20 +0700 Subject: [PATCH 12/15] fix for non-release builds (i don't throw on hot paths) --- .github/workflows/clang-format.yml | 2 ++ moves_io.cpp | 2 +- non_core_tests.cpp | 5 ++++- position.cpp | 14 +++----------- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 12d8034..20ade0c 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -2,5 +2,7 @@ name: clang-format check uses: jidicula/clang-format-action@v4.16.0 on: + push: + branches: [ "main" ] pull_request: branches: [ "main" ] \ No newline at end of file diff --git a/moves_io.cpp b/moves_io.cpp index 402a3e0..fdcff63 100644 --- a/moves_io.cpp +++ b/moves_io.cpp @@ -5,7 +5,7 @@ #include #include #include -#if defined(__EXCEPTIONS) && defined(_DEBUG) +#if defined(__EXCEPTIONS) #define THROW_IF_EXCEPTIONS_ON(stuff) throw stuff #else #define THROW_IF_EXCEPTIONS_ON(stuff) ((void)0) diff --git a/non_core_tests.cpp b/non_core_tests.cpp index 7d70421..295e360 100644 --- a/non_core_tests.cpp +++ b/non_core_tests.cpp @@ -409,8 +409,9 @@ TEST_SUITE("SAN Parser") { auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17" }; Move m = Move::make(Square::SQ_E1, Square::SQ_H1); + #if defined(_DEBUG) && !defined(NDEBUG) REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0+?!"), "illegal san: '0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17", chess::uci::IllegalMoveException); - + #endif REQUIRE(uci::parseSan(b, "0-0+?!", true) == m); } @@ -419,7 +420,9 @@ TEST_SUITE("SAN Parser") { Move m = Move::make(Square::SQ_E1, Square::SQ_A1); + #if defined(_DEBUG) && !defined(NDEBUG) REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0-0+?!"), "illegal san: '0-0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1", chess::uci::IllegalMoveException); + #endif REQUIRE(uci::parseSan(b, "0-0-0+?!", true) == m); } diff --git a/position.cpp b/position.cpp index b27c069..ec72660 100644 --- a/position.cpp +++ b/position.cpp @@ -9,7 +9,7 @@ #define _POSSIBLY_CONSTEXPR const #endif -#if defined(__EXCEPTIONS) && defined(_DEBUG) +#if defined(__EXCEPTIONS) #define THROW_IF_EXCEPTIONS_ON(stuff) throw stuff #else #define THROW_IF_EXCEPTIONS_ON(stuff) ((void)0) @@ -63,16 +63,8 @@ template template void _Position Date: Thu, 11 Dec 2025 13:13:01 +0700 Subject: [PATCH 13/15] fix the errors of workflow --- .github/workflows/clang-format.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 20ade0c..b5bdb95 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,8 +1,14 @@ name: clang-format check -uses: jidicula/clang-format-action@v4.16.0 on: - push: - branches: [ "main" ] pull_request: - branches: [ "main" ] \ No newline at end of file + branches: [ "main" ] + +jobs: + clang-format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: jidicula/clang-format-action@v4.16.0 + with: + clang-format-version: "18" From 71ab6bc678f9d286689edf27bf1062b2224eb015 Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Thu, 11 Dec 2025 13:17:09 +0700 Subject: [PATCH 14/15] Refactor clang-format workflow for better automation Updated the GitHub Actions workflow for clang-format to include permissions and a new job structure, allowing automatic formatting and committing of changes. --- .github/workflows/clang-format.yml | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index b5bdb95..ce9c419 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,14 +1,30 @@ -name: clang-format check +name: clang-format on: pull_request: branches: [ "main" ] jobs: - clang-format: + format: runs-on: ubuntu-latest + permissions: + contents: write # required to push back into PR + steps: - uses: actions/checkout@v4 - - uses: jidicula/clang-format-action@v4.16.0 with: - clang-format-version: "18" + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run clang-format + run: | + clang-format -i $(git ls-files '*.cpp' '*.hpp' '*.h' '*.c') + + - name: Commit and push changes + run: | + if ! git diff --quiet; then + git config user.email "actions@github.com" + git.config user.name "GitHub Actions" + git add . + git commit -m "Apply clang-format" + git push + fi From dcad7bbb19119df66967ec4ee428987b8e5447da Mon Sep 17 00:00:00 2001 From: winapiadmin Date: Thu, 11 Dec 2025 13:18:15 +0700 Subject: [PATCH 15/15] clang-format --- attacks.cpp | 10 ++-- moves_io.cpp | 25 +++++----- non_core_tests.cpp | 36 +++++++++------ position.cpp | 107 +++++++++++++++++++++--------------------- position.h | 113 ++++++++++++++++++++++----------------------- printers.cpp | 86 +++++++++++++++++----------------- 6 files changed, 189 insertions(+), 188 deletions(-) diff --git a/attacks.cpp b/attacks.cpp index 9c0b1e8..c767a24 100644 --- a/attacks.cpp +++ b/attacks.cpp @@ -168,13 +168,15 @@ _POSSIBLY_CONSTEXPR std::pair, std::array RookTable = rookData.first; _POSSIBLY_CONSTEXPR std::array RookAttacks = rookData.second; } // namespace chess::attacks -namespace chess::movegen{ +namespace chess::movegen { inline static Bitboard att(PieceType pt, Square sq, Bitboard occ) { return (pt == BISHOP) ? chess::_chess::_HyperbolaBishopAttacks(sq, occ) : chess::_chess::_HyperbolaRookAttacks(sq, occ); } inline static std::array, 64> generate_between() { - assert(att(BISHOP, SQ_A1, 0)==9241421688590303744ULL&&"Well... this is a debug message, but this is a landmine that the magic bitboards are NOT initialized before this, wontwork\n"); + assert(att(BISHOP, SQ_A1, 0) == 9241421688590303744ULL && + "Well... this is a debug message, but this is a landmine that the magic bitboards are NOT initialized before this, " + "wontwork\n"); std::array, 64> squares_between_bb{}; for (int sq1 = 0; sq1 < 64; ++sq1) { @@ -190,5 +192,5 @@ inline static std::array, 64> generate_between() { return squares_between_bb; } - std::array, 64> SQUARES_BETWEEN_BB = generate_between(); -} \ No newline at end of file +std::array, 64> SQUARES_BETWEEN_BB = generate_between(); +} // namespace chess::movegen \ No newline at end of file diff --git a/moves_io.cpp b/moves_io.cpp index fdcff63..99069f9 100644 --- a/moves_io.cpp +++ b/moves_io.cpp @@ -137,7 +137,7 @@ template Move parseSan(const _Position &pos, std: relative_square(pos.side_to_move(), SQ_H1)); if (std::find(moves.begin(), moves.end(), km) != moves.end()) return km; - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + san + "' in " + pos.fen())); return Move::none(); } if (san == "O-O-O" || san == "0-0-0" || san == "O-O-O+" || san == "0-0-0+" || san == "O-O-O#" || san == "0-0-0#") { @@ -145,7 +145,7 @@ template Move parseSan(const _Position &pos, std: relative_square(pos.side_to_move(), SQ_A1)); if (std::find(moves.begin(), moves.end(), qm) != moves.end()) return qm; - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + san + "' in " + pos.fen())); return Move::none(); } // 2) Strip trailing annotations (+, #) that aren't required in the standard (except "e.p. "). Repeated occurrences too. @@ -157,7 +157,7 @@ template Move parseSan(const _Position &pos, std: break; } if (san.empty()) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + san + "' in " + pos.fen())); return Move::none(); } @@ -170,7 +170,7 @@ template Move parseSan(const _Position &pos, std: if (penult == '=') { promotion = parse_pt(last); if (promotion == NO_PIECE_TYPE) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + _san + "' in " + pos.fen())); return Move::none(); } san.pop_back(); // remove piece letter @@ -185,17 +185,17 @@ template Move parseSan(const _Position &pos, std: // 4) Destination square: always the last [file][rank] if (san.size() < 2) - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + _san + "' in " + pos.fen())); char dfile = san[san.size() - 2]; char drank = san[san.size() - 1]; if (!(dfile >= 'a' && dfile <= 'h' && drank >= '1' && drank <= '8')) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + _san + "' in " + pos.fen())); return Move::none(); } std::string dest_sq_str = san.substr(san.size() - 2, 2); Square to_square = parse_square(dest_sq_str); if (to_square == SQ_NONE) { - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + _san + "' in " + pos.fen())); return Move::none(); } san.resize(san.size() - 2); // chop off destination @@ -222,7 +222,7 @@ template Move parseSan(const _Position &pos, std: std::string src_sq_str = prefix.substr(prefix.size() - 2, 2); src_square = parse_square(src_sq_str); if (src_square == SQ_NONE) - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + _san + "' in " + pos.fen())); prefix.resize(prefix.size() - 2); has_src_square = true; } @@ -253,7 +253,7 @@ template Move parseSan(const _Position &pos, std: dis_rank = c - '1'; else { // unexpected char in prefix - THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '"+_san+"' in "+pos.fen())); + THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + _san + "' in " + pos.fen())); return Move::none(); } } @@ -313,8 +313,7 @@ template Move parseSan(const _Position &pos, std: // Everything matches -> accept candidate if (found) { - THROW_IF_EXCEPTIONS_ON( - AmbiguousMoveException("ambiguous san: '" + _san + "' in " + pos.fen())); + THROW_IF_EXCEPTIONS_ON(AmbiguousMoveException("ambiguous san: '" + _san + "' in " + pos.fen())); return Move::none(); } matched = m; @@ -332,12 +331,12 @@ template Move parseSan(const _Position &pos, std: if (remove_illegals) { std::string trimmed_san(raw_san); while (!trimmed_san.empty()) { - try{ + try { Move attempt = do_parse(trimmed_san); if (attempt.is_ok()) return attempt; + } catch (...) { } - catch(...){} trimmed_san.pop_back(); } THROW_IF_EXCEPTIONS_ON(IllegalMoveException("illegal san: '" + std::string(raw_san) + "' in " + pos.fen())); diff --git a/non_core_tests.cpp b/non_core_tests.cpp index 295e360..965ce96 100644 --- a/non_core_tests.cpp +++ b/non_core_tests.cpp @@ -409,9 +409,11 @@ TEST_SUITE("SAN Parser") { auto b = Position{ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17" }; Move m = Move::make(Square::SQ_E1, Square::SQ_H1); - #if defined(_DEBUG) && !defined(NDEBUG) - REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0+?!"), "illegal san: '0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17", chess::uci::IllegalMoveException); - #endif +#if defined(_DEBUG) && !defined(NDEBUG) + REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0+?!"), + "illegal san: '0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 17", + chess::uci::IllegalMoveException); +#endif REQUIRE(uci::parseSan(b, "0-0+?!", true) == m); } @@ -420,9 +422,11 @@ TEST_SUITE("SAN Parser") { Move m = Move::make(Square::SQ_E1, Square::SQ_A1); - #if defined(_DEBUG) && !defined(NDEBUG) - REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0-0+?!"), "illegal san: '0-0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1", chess::uci::IllegalMoveException); - #endif +#if defined(_DEBUG) && !defined(NDEBUG) + REQUIRE_THROWS_WITH_AS(uci::parseSan(b, "0-0-0+?!"), + "illegal san: '0-0-0+?!' in rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1", + chess::uci::IllegalMoveException); +#endif REQUIRE(uci::parseSan(b, "0-0-0+?!", true) == m); } @@ -887,16 +891,18 @@ TEST_SUITE("SAN Parser") { REQUIRE(uci::parseSan(b, "O-O+") == m); } } -TEST_CASE("Reconstruction of Position from history entry"){{ - Position p; - Position p2(p.state()); - REQUIRE(p.fen()==p2.fen());} +TEST_CASE("Reconstruction of Position from history entry") { + { + Position p; + Position p2(p.state()); + REQUIRE(p.fen() == p2.fen()); + } { - _Position p; - Position p2(p.state()); - _Position p3(p2.state()); - REQUIRE(p.fen()==p3.fen()); - REQUIRE(p.fen()==p2.fen()); + _Position p; + Position p2(p.state()); + _Position p3(p2.state()); + REQUIRE(p.fen() == p3.fen()); + REQUIRE(p.fen() == p2.fen()); } } int main(int argc, char **argv) { diff --git a/position.cpp b/position.cpp index ec72660..7f8a48d 100644 --- a/position.cpp +++ b/position.cpp @@ -403,23 +403,23 @@ template std::string _Position::fen() c emptyCount++; } else { if (emptyCount > 0) { - ss<< std::to_string(emptyCount); + ss << std::to_string(emptyCount); emptyCount = 0; } - ss<< piece; + ss << piece; } } if (emptyCount > 0) - ss<< std::to_string(emptyCount); + ss << std::to_string(emptyCount); if (rank > 0) - ss<< '/'; + ss << '/'; } // 2) Side to move - ss<< ' ' << (sideToMove() == WHITE ? 'w' : 'b'); + ss << ' ' << (sideToMove() == WHITE ? 'w' : 'b'); // 3) Castling availability - ss<< ' '; + ss << ' '; std::string castlingStr; if (castlingRights() & WHITE_OO) castlingStr += 'K'; @@ -429,18 +429,18 @@ template std::string _Position::fen() c castlingStr += 'k'; if (castlingRights() & BLACK_OOO) castlingStr += 'q'; - ss<<(castlingStr.empty() ? "-" : castlingStr); + ss << (castlingStr.empty() ? "-" : castlingStr); // 4) En passant target square or '-' - ss<< ' '; + ss << ' '; Square ep = ep_square(); - ss<< (ep == SQ_NONE ? "-" : uci::squareToString(ep)); + ss << (ep == SQ_NONE ? "-" : uci::squareToString(ep)); // 5) Halfmove clock - ss<< ' ' <<(int)halfmoveClock(); + ss << ' ' << (int)halfmoveClock(); // 6) Fullmove number - ss<< ' ' <<(int)fullmoveNumber(); + ss << ' ' << (int)fullmoveNumber(); return ss.str(); } @@ -513,20 +513,20 @@ template template bool _Position CheckType _Position::givesCheck(Move m) const { - const static auto getSniper = [](const _Position* p, Square ksq, Bitboard oc) { + const static auto getSniper = [](const _Position *p, Square ksq, Bitboard oc) { const auto us_occ = p->us(p->sideToMove()); const auto bishop = attacks::bishop(ksq, oc) & p->pieces(PieceType::BISHOP, PieceType::QUEEN) & us_occ; - const auto rook = attacks::rook(ksq, oc) & p->pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; + const auto rook = attacks::rook(ksq, oc) & p->pieces(PieceType::ROOK, PieceType::QUEEN) & us_occ; return (bishop | rook); }; assert(color_of(at(m.from())) == sideToMove()); - const Square from = m.from(); - const Square to = m.to(); - const Square ksq = kingSq(~sideToMove()); - const Bitboard toBB = 1ULL<<(to); - const PieceType pt = piece_of(at(from)); + const Square from = m.from(); + const Square to = m.to(); + const Square ksq = kingSq(~sideToMove()); + const Bitboard toBB = 1ULL << (to); + const PieceType pt = piece_of(at(from)); Bitboard fromKing = 0ull; @@ -542,11 +542,12 @@ template CheckType _Position::givesChec fromKing = attacks::queen(ksq, occ()); } - if (fromKing & toBB) return CheckType::DIRECT_CHECK; + if (fromKing & toBB) + return CheckType::DIRECT_CHECK; // Discovery check - const Bitboard fromBB = 1ULL<<(from); - const Bitboard oc = occ() ^ fromBB; + const Bitboard fromBB = 1ULL << (from); + const Bitboard oc = occ() ^ fromBB; Bitboard sniper = getSniper(this, ksq, oc); @@ -557,47 +558,45 @@ template CheckType _Position::givesChec } switch (m.typeOf()) { - case Move::NORMAL: - return CheckType::NO_CHECK; + case Move::NORMAL: + return CheckType::NO_CHECK; - case Move::PROMOTION: { - Bitboard attacks = 0ull; + case Move::PROMOTION: { + Bitboard attacks = 0ull; - switch (m.promotionType()) { - case KNIGHT: - attacks = attacks::knight(to); - break; - case BISHOP: - attacks = attacks::bishop(to, oc); - break; - case ROOK: - attacks = attacks::rook(to, oc); - break; - case QUEEN: - attacks = attacks::queen(to, oc); - break; - default: - break; - } - - return (attacks & pieces(PieceType::KING, ~sideToMove())) ? CheckType::DIRECT_CHECK : CheckType::NO_CHECK; + switch (m.promotionType()) { + case KNIGHT: + attacks = attacks::knight(to); + break; + case BISHOP: + attacks = attacks::bishop(to, oc); + break; + case ROOK: + attacks = attacks::rook(to, oc); + break; + case QUEEN: + attacks = attacks::queen(to, oc); + break; + default: + break; } - case Move::ENPASSANT: { - Square capSq=make_sq(file_of(to), rank_of(from)); - return (getSniper(this, ksq, (oc ^ (1ULL< from ? SQ_F1 : SQ_D1); - return (attacks::rook(ksq, occ()) & (1ULL< from ? SQ_F1 : SQ_D1); + return (attacks::rook(ksq, occ()) & (1ULL << rookTo)) ? CheckType::DISCOVERY_CHECK : CheckType::NO_CHECK; + } } assert(false); - return CheckType::NO_CHECK; // Prevent a compiler warning + return CheckType::NO_CHECK; // Prevent a compiler warning } template void _Position::refresh_attacks() { Color c = sideToMove(); diff --git a/position.h b/position.h index 1442bbc..28f89f3 100644 --- a/position.h +++ b/position.h @@ -130,18 +130,18 @@ enum class MoveGenType : uint16_t { NONE = 0, // piece selectors - PAWN = 1 << 1, + PAWN = 1 << 1, KNIGHT = 1 << 2, BISHOP = 1 << 3, - ROOK = 1 << 4, - QUEEN = 1 << 5, - KING = 1 << 6, + ROOK = 1 << 4, + QUEEN = 1 << 5, + KING = 1 << 6, PIECE_MASK = PAWN | KNIGHT | BISHOP | ROOK | QUEEN | KING, // move-type selectors CAPTURE = 1 << 7, - QUIET = 1 << 8, + QUIET = 1 << 8, ALL = PIECE_MASK | CAPTURE | QUIET }; @@ -184,63 +184,60 @@ template -__FORCEINLINE void legals(Movelist &out) const { - - constexpr uint16_t raw = static_cast(type); - constexpr uint16_t pieceBits = raw & static_cast(MoveGenType::PIECE_MASK); - constexpr uint16_t modeBits = raw & (static_cast(MoveGenType::CAPTURE) | - static_cast(MoveGenType::QUIET)); - - // ---------------------------------------- - // Resolve default piece selection - // ---------------------------------------- - constexpr uint16_t effectivePieces = - pieceBits ? pieceBits : - (raw == static_cast(MoveGenType::NONE) - ? 0 - : static_cast(MoveGenType::PIECE_MASK)); - - // ---------------------------------------- - // Resolve default mode selection - // ---------------------------------------- - constexpr bool includeCaps = modeBits == 0 || (modeBits & static_cast(MoveGenType::CAPTURE)); - constexpr bool includeQuiet = modeBits == 0 || (modeBits & static_cast(MoveGenType::QUIET)); - constexpr bool captureOnly = includeCaps && !includeQuiet; - - // Early-out for NONE - if constexpr (effectivePieces == 0 && modeBits != 0) - return; + template __FORCEINLINE void legals(Movelist &out) const { + + constexpr uint16_t raw = static_cast(type); + constexpr uint16_t pieceBits = raw & static_cast(MoveGenType::PIECE_MASK); + constexpr uint16_t modeBits = + raw & (static_cast(MoveGenType::CAPTURE) | static_cast(MoveGenType::QUIET)); + + // ---------------------------------------- + // Resolve default piece selection + // ---------------------------------------- + constexpr uint16_t effectivePieces = + pieceBits ? pieceBits + : (raw == static_cast(MoveGenType::NONE) ? 0 : static_cast(MoveGenType::PIECE_MASK)); + + // ---------------------------------------- + // Resolve default mode selection + // ---------------------------------------- + constexpr bool includeCaps = modeBits == 0 || (modeBits & static_cast(MoveGenType::CAPTURE)); + constexpr bool includeQuiet = modeBits == 0 || (modeBits & static_cast(MoveGenType::QUIET)); + constexpr bool captureOnly = includeCaps && !includeQuiet; + + // Early-out for NONE + if constexpr (effectivePieces == 0 && modeBits != 0) + return; - // Now your existing piece dispatch logic stays the same: - if constexpr (effectivePieces & static_cast(MoveGenType::PAWN)) { - movegen::genPawnSingleMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); - if constexpr (includeQuiet) - movegen::genPawnDoubleMoves(*this, out, _pin_mask, _check_mask); - if constexpr (includeCaps) - movegen::genEP(*this, out); - } + // Now your existing piece dispatch logic stays the same: + if constexpr (effectivePieces & static_cast(MoveGenType::PAWN)) { + movegen::genPawnSingleMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + if constexpr (includeQuiet) + movegen::genPawnDoubleMoves(*this, out, _pin_mask, _check_mask); + if constexpr (includeCaps) + movegen::genEP(*this, out); + } - if constexpr (effectivePieces & static_cast(MoveGenType::KNIGHT)) { - movegen::genKnightMoves(*this, out, _pin_mask, _check_mask); - } + if constexpr (effectivePieces & static_cast(MoveGenType::KNIGHT)) { + movegen::genKnightMoves(*this, out, _pin_mask, _check_mask); + } - if constexpr (effectivePieces & static_cast(MoveGenType::KING)) { - movegen::genKingMoves(*this, out); - } + if constexpr (effectivePieces & static_cast(MoveGenType::KING)) { + movegen::genKingMoves(*this, out); + } - if constexpr (effectivePieces & static_cast(MoveGenType::BISHOP)) { - movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); - } + if constexpr (effectivePieces & static_cast(MoveGenType::BISHOP)) { + movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + } - if constexpr (effectivePieces & static_cast(MoveGenType::ROOK)) { - movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); - } + if constexpr (effectivePieces & static_cast(MoveGenType::ROOK)) { + movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + } - if constexpr (effectivePieces & static_cast(MoveGenType::QUEEN)) { - movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + if constexpr (effectivePieces & static_cast(MoveGenType::QUEEN)) { + movegen::genSlidingMoves(*this, out, _rook_pin, _bishop_pin, _check_mask); + } } -} // Legal move generation functions template __FORCEINLINE void legals(Movelist &out) const { @@ -324,14 +321,12 @@ __FORCEINLINE void legals(Movelist &out) const { return current_state.pieces[pt]; } } - template && ...)>> + template && ...)>> [[nodiscard]] __FORCEINLINE Bitboard pieces(PTypes... ptypes) const { return (current_state.pieces[static_cast(ptypes)] | ...); } - template && ...)>> + template && ...)>> [[nodiscard]] __FORCEINLINE Bitboard pieces(Color c, PTypes... ptypes) const { return (pieces(ptypes, c) | ...); } diff --git a/printers.cpp b/printers.cpp index aaf00b0..41dc3e7 100644 --- a/printers.cpp +++ b/printers.cpp @@ -82,52 +82,52 @@ std::ostream &operator<<(std::ostream &os, const Square &sq) { return os; } template std::ostream &operator<<(std::ostream &os, PieceC p) { - char c='.'; - switch(p){ - case PieceC::WPAWN: - c='P'; - break; - case PieceC::BPAWN: - c='p'; - break; - case PieceC::WKNIGHT: - c='N'; - break; - case PieceC::BKNIGHT: - c='n'; - break; - case PieceC::WBISHOP: - c='B'; - break; - case PieceC::BBISHOP: - c='b'; - break; - case PieceC::WROOK: - c='R'; - break; - case PieceC::BROOK: - c='r'; - break; - case PieceC::WQUEEN: - c='Q'; - break; - case PieceC::BQUEEN: - c='q'; - break; - case PieceC::WKING: - c='K'; - break; - case PieceC::BKING: - c='k'; - break; - default: - break; + char c = '.'; + switch (p) { + case PieceC::WPAWN: + c = 'P'; + break; + case PieceC::BPAWN: + c = 'p'; + break; + case PieceC::WKNIGHT: + c = 'N'; + break; + case PieceC::BKNIGHT: + c = 'n'; + break; + case PieceC::WBISHOP: + c = 'B'; + break; + case PieceC::BBISHOP: + c = 'b'; + break; + case PieceC::WROOK: + c = 'R'; + break; + case PieceC::BROOK: + c = 'r'; + break; + case PieceC::WQUEEN: + c = 'Q'; + break; + case PieceC::BQUEEN: + c = 'q'; + break; + case PieceC::WKING: + c = 'K'; + break; + case PieceC::BKING: + c = 'k'; + break; + default: + break; } - return os< &); \ +#define INSTANTITATE(PieceC) \ + template std::ostream &operator<<(std::ostream &, const _Position &); \ template std::ostream &operator<<(std::ostream &, PieceC); INSTANTITATE(EnginePiece)