From fb056b1ecd3ccc7eacaf44d0eb32252b9e7a90a0 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 24 Mar 2023 23:27:55 +0100 Subject: [PATCH] Replace set by PieceSet enum (#602) Simplifies the code and improves performance. No functional change. --- src/apiutil.h | 15 ++- src/bitboard.h | 104 ++++++++++++++++++ src/endgame.cpp | 4 +- src/evaluate.cpp | 29 ++++-- src/material.cpp | 8 +- src/movegen.cpp | 32 ++++-- src/nnue/features/half_ka_v2_variants.cpp | 5 +- src/parser.cpp | 23 ++--- src/position.cpp | 35 ++++--- src/position.h | 21 ++-- src/psqt.cpp | 11 +- src/search.cpp | 2 +- src/types.h | 7 +- src/ucioption.cpp | 5 +- src/variant.cpp | 168 ++++++++++++++-------------- src/variant.h | 92 +++++++++------- 16 files changed, 359 insertions(+), 202 deletions(-) diff --git a/src/apiutil.h b/src/apiutil.h index 34e7729..3cdbf4d 100644 --- a/src/apiutil.h +++ b/src/apiutil.h @@ -375,18 +375,21 @@ inline bool has_insufficient_material(Color c, const Position& pos) { // Restricted pieces Bitboard restricted = pos.pieces(~c, KING); // Atomic kings can not help checkmating - if (pos.extinction_pseudo_royal() && pos.blast_on_capture() && pos.extinction_piece_types().find(COMMONER) != pos.extinction_piece_types().end()) + if (pos.extinction_pseudo_royal() && pos.blast_on_capture() && (pos.extinction_piece_types() & COMMONER)) restricted |= pos.pieces(c, COMMONER); - for (PieceType pt : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); if (pt == KING || !(pos.board_bb(c, pt) & pos.board_bb(~c, KING))) restricted |= pos.pieces(c, pt); else if (is_custom(pt) && pos.count(c, pt) > 0) // to be conservative, assume any custom piece has mating potential return false; + } // Mating pieces for (PieceType pt : { ROOK, QUEEN, ARCHBISHOP, CHANCELLOR, SILVER, GOLD, COMMONER, CENTAUR }) - if ((pos.pieces(c, pt) & ~restricted) || (pos.count(c, pos.promotion_pawn_type(c)) && pos.promotion_piece_types(c).find(pt) != pos.promotion_piece_types(c).end())) + if ((pos.pieces(c, pt) & ~restricted) || (pos.count(c, pos.promotion_pawn_type(c)) && (pos.promotion_piece_types(c) & pt))) return false; // Color-bound pieces @@ -895,7 +898,7 @@ inline std::string get_valid_special_chars(const Variant* v) { // Whether or not '-', '+', '~', '[', ']' are valid depends on the variant being played. if (v->shogiStylePromotions) validSpecialCharactersFirstField += '+'; - if (!v->promotionPieceTypes[WHITE].empty() || !v->promotionPieceTypes[BLACK].empty()) + if (v->promotionPieceTypes[WHITE] || v->promotionPieceTypes[BLACK]) validSpecialCharactersFirstField += '~'; if (!v->freeDrops && (v->pieceDrops || v->seirawanGating)) validSpecialCharactersFirstField += "[-]"; @@ -948,7 +951,7 @@ inline FenValidation validate_fen(const std::string& fen, const Variant* v, bool } // check for number of kings - if (v->pieceTypes.find(KING) != v->pieceTypes.end()) + if (v->pieceTypes & KING) { // we have a royal king in this variant, // ensure that each side has exactly as many kings as in the starting position @@ -1021,7 +1024,7 @@ inline FenValidation validate_fen(const std::string& fen, const Variant* v, bool // check en-passant square if (fenParts.size() >= 4 && !skipCastlingAndEp) { - if (v->doubleStep && v->pieceTypes.find(PAWN) != v->pieceTypes.end()) + if (v->doubleStep && (v->pieceTypes & PAWN)) { if (check_en_passant_square(fenParts[3]) == NOK) return FEN_INVALID_EN_PASSANT_SQ; diff --git a/src/bitboard.h b/src/bitboard.h index b1b6f3d..ce575b5 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -678,6 +678,110 @@ inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); } + +/// popcount() counts the number of non-zero bits in a piece set + +inline int popcount(PieceSet ps) { + +#ifndef USE_POPCNT + + union { uint64_t bb; uint16_t u[4]; } v = { (uint64_t)ps }; + return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]]; + +#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) + + return (int)_mm_popcnt_u64(ps); + +#else // Assumed gcc or compatible compiler + + return __builtin_popcountll(ps); + +#endif +} + +/// lsb() and msb() return the least/most significant bit in a non-zero piece set + +#if defined(__GNUC__) // GCC, Clang, ICC + +inline PieceType lsb(PieceSet ps) { + assert(ps); + return PieceType(__builtin_ctzll(ps)); +} + +inline PieceType msb(PieceSet ps) { + assert(ps); + return PieceType((PIECE_TYPE_NB - 1) ^ __builtin_clzll(ps)); +} + +#elif defined(_MSC_VER) // MSVC + +#ifdef _WIN64 // MSVC, WIN64 + +inline PieceType lsb(PieceSet ps) { + assert(ps); + unsigned long idx; + _BitScanForward64(&idx, ps); + return (PieceType) idx; +} + +inline PieceType msb(PieceSet ps) { + assert(ps); + unsigned long idx; + _BitScanReverse64(&idx, ps); + return (PieceType) idx; +} + +#else // MSVC, WIN32 + +inline PieceType lsb(PieceSet ps) { + assert(ps); + unsigned long idx; + + if (ps & 0xffffffff) { + _BitScanForward(&idx, uint32_t(ps)); + return PieceType(idx); + } else { + _BitScanForward(&idx, uint32_t(ps >> 32)); + return PieceType(idx + 32); + } +} + +inline PieceType msb(PieceSet ps) { + assert(ps); + unsigned long idx; + if (ps >> 32) { + _BitScanReverse(&idx, uint32_t(ps >> 32)); + return PieceType(idx + 32); + } else { + _BitScanReverse(&idx, uint32_t(ps)); + return PieceType(idx); + } +} + +#endif + +#else // Compiler is neither GCC nor MSVC compatible + +#error "Compiler not supported." + +#endif + +/// pop_lsb() and pop_msb() find and clear the least/most significant bit in a non-zero piece set + +inline PieceType pop_lsb(PieceSet& ps) { + assert(ps); + const PieceType pt = lsb(ps); + ps &= PieceSet(ps - 1); + return pt; +} + +inline PieceType pop_msb(PieceSet& ps) { + assert(ps); + const PieceType pt = msb(ps); + ps &= ~piece_set(pt); + return pt; +} + } // namespace Stockfish #endif // #ifndef BITBOARD_H_INCLUDED diff --git a/src/endgame.cpp b/src/endgame.cpp index 186258a..a95ff37 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -185,7 +185,7 @@ Value Endgame::operator()(const Position& pos) const { // Non-standard promotion, evaluation unclear if ( pos.promotion_zone(us) != rank_bb(relative_rank(us, RANK_8, pos.max_rank())) || RANK_MAX != RANK_8 - || pos.promotion_piece_types(us).find(QUEEN) == pos.promotion_piece_types(us).end()) + || !(pos.promotion_piece_types(us) & QUEEN)) { Value result = PawnValueEg + Value(rank_of(strongPawn)); return strongSide == pos.side_to_move() ? result : -result; @@ -939,7 +939,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // it's probably at least a draw even with the pawn. if ( pos.promotion_zone(us) != rank_bb(relative_rank(us, RANK_8, pos.max_rank())) || RANK_MAX != RANK_8 - || pos.promotion_piece_types(us).find(QUEEN) == pos.promotion_piece_types(us).end()) + || !(pos.promotion_piece_types(us) & QUEEN)) return SCALE_FACTOR_NONE; return Bitbases::probe(strongKing, strongPawn, weakKing, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 24ca187..b2986fe 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -694,8 +694,9 @@ namespace { std::function get_attacks = [this](Color c, PieceType pt) { return attackedBy[c][pt] | (pos.piece_drops() && pos.count_in_hand(c, pt) > 0 ? pos.drop_region(c, pt) & ~pos.pieces() : Bitboard(0)); }; - for (PieceType pt : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) { + PieceType pt = pop_lsb(ps); switch (pt) { case QUEEN: @@ -755,7 +756,9 @@ namespace { // Virtual piece drops if (pos.two_boards() && pos.piece_drops()) { - for (PieceType pt : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); if (pos.count_in_hand(Them, pt) <= 0 && (attacks_bb(Us, pt, ksq, pos.pieces()) & safe & pos.drop_region(Them, pt) & ~pos.pieces())) { kingDanger += VirtualCheck * 500 / (500 + PieceValue[MG][pt]); @@ -763,6 +766,7 @@ namespace { if (!(attackedBy[Us][KING] & ~(attackedBy[Them][ALL_PIECES] | pos.pieces(Us)))) kingDanger += 2000; } + } } if (pos.check_counting()) @@ -863,8 +867,9 @@ namespace { if (pos.extinction_value() == -VALUE_MATE) { Bitboard bExt = attackedBy[Us][ALL_PIECES] & pos.pieces(Them); - for (PieceType pt : pos.extinction_piece_types()) + for (PieceSet ps = pos.extinction_piece_types(); ps;) { + PieceType pt = pop_lsb(ps); if (pt == ALL_PIECES) continue; int denom = std::max(pos.count_with_hand(Them, pt) - pos.extinction_piece_count(), 1); @@ -1067,8 +1072,9 @@ namespace { // Scale by maximum promotion piece value Value maxMg = VALUE_ZERO, maxEg = VALUE_ZERO; - for (PieceType pt : pos.promotion_piece_types(Us)) + for (PieceSet ps = pos.promotion_piece_types(Us); ps;) { + PieceType pt = pop_lsb(ps); maxMg = std::max(maxMg, PieceValue[MG][pt]); maxEg = std::max(maxEg, PieceValue[EG][pt]); } @@ -1213,7 +1219,9 @@ namespace { // Extinction if (pos.extinction_value() != VALUE_NONE) { - for (PieceType pt : pos.extinction_piece_types()) + for (PieceSet ps = pos.extinction_piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); if (pt != ALL_PIECES) { // Single piece type extinction bonus @@ -1250,6 +1258,7 @@ namespace { dist = std::min(dist, popcount(pos.pieces(PAWN) & file_bb(f))); score += make_score(70, 70) * pos.count(Them) / (1 + dist * dist) / (pos.pieces(Us, QUEEN) ? 2 : 4); } + } } // Connect-n @@ -1471,14 +1480,20 @@ namespace { // Pieces evaluated first (also populates attackedBy, attackedBy2). // For unused piece types, we still need to set attack bitboard to zero. - for (PieceType pt : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); if (pt != SHOGI_PAWN && pt != PAWN && pt != KING) score += pieces(pt) - pieces(pt); + } // Evaluate pieces in hand once attack tables are complete if (pos.piece_drops() || pos.seirawan_gating()) - for (PieceType pt : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); score += hand(pt) - hand(pt); + } score += (mobility[WHITE] - mobility[BLACK]) * (1 + pos.captures_to_hand() + pos.must_capture() + pos.check_counting()); diff --git a/src/material.cpp b/src/material.cpp index e806093..36f664e 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -69,8 +69,7 @@ namespace { // Helper used to detect a given material distribution bool is_KFsPsK(const Position& pos, Color us) { - return pos.promotion_piece_types(us).size() == 1 - && pos.promotion_piece_types(us).find(FERS) != pos.promotion_piece_types(us).end() + return (pos.promotion_piece_types(us) == piece_set(FERS)) && !more_than_one(pos.pieces(~us)) && (pos.count(us) || pos.count(us)) && !(pos.count(us) - pos.count(us) - pos.count(us) - pos.count(us)); @@ -165,8 +164,11 @@ Entry* probe(const Position& pos) { if (pos.captures_to_hand() || pos.two_boards()) { Value npm2 = VALUE_ZERO; - for (PieceType pt : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); npm2 += pos.count_in_hand(pt) * PieceValue[MG][make_piece(WHITE, pt)]; + } e->gamePhase = Phase(PHASE_MIDGAME * npm / std::max(int(npm + npm2), 1)); int countAll = pos.count_with_hand(WHITE, ALL_PIECES) + pos.count_with_hand(BLACK, ALL_PIECES); e->materialDensity = (npm + npm2 + pos.count() * PawnValueMg) * countAll / (pos.files() * pos.ranks()); diff --git a/src/movegen.cpp b/src/movegen.cpp index e713f8e..60a1efd 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -57,13 +57,19 @@ namespace { // Gating moves if (pos.seirawan_gating() && (pos.gates(us) & from)) - for (PieceType pt_gating : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt_gating = pop_lsb(ps); if (pos.can_drop(us, pt_gating) && (pos.drop_region(us, pt_gating) & from)) *moveList++ = make_gating(from, to, pt_gating, from); + } if (pos.seirawan_gating() && T == CASTLING && (pos.gates(us) & to)) - for (PieceType pt_gating : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt_gating = pop_lsb(ps); if (pos.can_drop(us, pt_gating) && (pos.drop_region(us, pt_gating) & to)) *moveList++ = make_gating(from, to, pt_gating, to); + } return moveList; } @@ -73,9 +79,12 @@ namespace { if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) { - for (PieceType pt : pos.promotion_piece_types(c)) + for (PieceSet promotions = pos.promotion_piece_types(c); promotions;) + { + PieceType pt = pop_msb(promotions); if (!pos.promotion_limit(pt) || pos.promotion_limit(pt) > pos.count(c, pt)) moveList = make_move_and_gating(pos, moveList, pos.side_to_move(), to - D, to, pt); + } PieceType pt = pos.promoted_piece_type(PAWN); if (pt && !(pos.piece_promotion_on_capture() && pos.empty(to))) moveList = make_move_and_gating(pos, moveList, pos.side_to_move(), to - D, to); @@ -213,8 +222,9 @@ namespace { while (promotionPawns) { Square from = pop_lsb(promotionPawns); - for (PieceType pt : pos.promotion_piece_types(Us)) + for (PieceSet ps = pos.promotion_piece_types(Us); ps;) { + PieceType pt = pop_msb(ps); if (pos.promotion_limit(pt) && pos.promotion_limit(pt) <= pos.count(Us, pt)) continue; Bitboard b = ((pos.attacks_from(Us, pt, from) & ~pos.pieces()) | from) & target; @@ -332,10 +342,13 @@ namespace { // Pawn-style promotions if ((Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) && pawnPromotions) - for (PieceType ptP : pos.promotion_piece_types(Us)) + for (PieceSet ps = pos.promotion_piece_types(Us); ps;) + { + PieceType ptP = pop_msb(ps); if (!pos.promotion_limit(ptP) || pos.promotion_limit(ptP) > pos.count(Us, ptP)) for (Bitboard promotions = pawnPromotions; promotions; ) moveList = make_move_and_gating(pos, moveList, pos.side_to_move(), from, pop_lsb(promotions), ptP); + } // En passant captures if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) @@ -378,13 +391,12 @@ namespace { target &= pos.board_bb(); moveList = generate_pawn_moves(pos, moveList, target); - for (PieceType pt : pos.piece_types()) - if (pt != PAWN && pt != KING) - moveList = generate_moves(pos, moveList, pt, target); + for (PieceSet ps = pos.piece_types() & ~(piece_set(PAWN) | KING); ps;) + moveList = generate_moves(pos, moveList, pop_lsb(ps), target); // generate drops if (pos.piece_drops() && Type != CAPTURES && (pos.can_drop(Us, ALL_PIECES) || pos.two_boards())) - for (PieceType pt : pos.piece_types()) - moveList = generate_drops(pos, moveList, pt, target & ~pos.pieces(~Us)); + for (PieceSet ps = pos.piece_types(); ps;) + moveList = generate_drops(pos, moveList, pop_lsb(ps), target & ~pos.pieces(~Us)); // Castling with non-king piece if (!pos.count(Us) && Type != CAPTURES && pos.can_castle(Us & ANY_CASTLING)) diff --git a/src/nnue/features/half_ka_v2_variants.cpp b/src/nnue/features/half_ka_v2_variants.cpp index 0807241..4d23de0 100644 --- a/src/nnue/features/half_ka_v2_variants.cpp +++ b/src/nnue/features/half_ka_v2_variants.cpp @@ -63,9 +63,12 @@ namespace Stockfish::Eval::NNUE::Features { // Indices for pieces in hand if (pos.nnue_use_pockets()) for (Color c : {WHITE, BLACK}) - for (PieceType pt : pos.piece_types()) + for (PieceSet ps = pos.piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); for (int i = 0; i < pos.count_in_hand(c, pt); i++) active.push_back(make_index(perspective, i, make_piece(c, pt), oriented_ksq, pos)); + } } diff --git a/src/parser.cpp b/src/parser.cpp index 90a5406..6ca9385 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -174,7 +174,7 @@ template bool VariantParser::parse_attribute(co char token; size_t idx; std::stringstream ss(it->second); - while (ss >> token && (idx = pieceToChar.find(toupper(token))) != std::string::npos) + while (ss >> token && (idx = token == '*' ? size_t(ALL_PIECES) : pieceToChar.find(toupper(token))) != std::string::npos) set(PieceType(idx), target); if (DoCheck && idx == std::string::npos && token != '-') std::cerr << key << " - Invalid piece type: " << token << std::endl; @@ -433,18 +433,7 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("extinctionPseudoRoyal", v->extinctionPseudoRoyal); parse_attribute("dupleCheck", v->dupleCheck); // extinction piece types - const auto& it_ext = config.find("extinctionPieceTypes"); - if (it_ext != config.end()) - { - v->extinctionPieceTypes = {}; - char token; - size_t idx = 0; - std::stringstream ss(it_ext->second); - while (ss >> token && (idx = token == '*' ? size_t(ALL_PIECES) : v->pieceToChar.find(toupper(token))) != std::string::npos) - v->extinctionPieceTypes.insert(PieceType(idx)); - if (DoCheck && idx == std::string::npos) - std::cerr << "extinctionPieceTypes - Invalid piece type: " << token << std::endl; - } + parse_attribute("extinctionPieceTypes", v->extinctionPieceTypes, v->pieceToChar); parse_attribute("extinctionPieceCount", v->extinctionPieceCount); parse_attribute("extinctionOpponentPieceCount", v->extinctionOpponentPieceCount); parse_attribute("flagPiece", v->flagPiece, v->pieceToChar); @@ -468,8 +457,9 @@ Variant* VariantParser::parse(Variant* v) { if (DoCheck) { // pieces - for (PieceType pt : v->pieceTypes) + for (PieceSet ps = v->pieceTypes; ps;) { + PieceType pt = pop_lsb(ps); for (Color c : {WHITE, BLACK}) if (std::count(v->pieceToChar.begin(), v->pieceToChar.end(), v->pieceToChar[make_piece(c, pt)]) != 1) std::cerr << piece_name(pt) << " - Ambiguous piece character: " << v->pieceToChar[make_piece(c, pt)] << std::endl; @@ -490,8 +480,9 @@ Variant* VariantParser::parse(Variant* v) { while (ss >> token) if (isalpha(token) && v->pieceToChar.find(toupper(token)) == std::string::npos) std::cerr << "pieceToCharTable - Invalid piece type: " << token << std::endl; - for (PieceType pt : v->pieceTypes) + for (PieceSet ps = v->pieceTypes; ps;) { + PieceType pt = pop_lsb(ps); char ptl = tolower(v->pieceToChar[pt]); if (v->pieceToCharTable.find(ptl) == std::string::npos && fenBoard.find(ptl) != std::string::npos) std::cerr << "pieceToCharTable - Missing piece type: " << ptl << std::endl; @@ -513,7 +504,7 @@ Variant* VariantParser::parse(Variant* v) { if (v->pieceDrops && (v->arrowGating || v->duckGating || v->staticGating || v->pastGating)) std::cerr << "pieceDrops and arrowGating/duckGating are incompatible." << std::endl; // Options incompatible with royal kings - if (v->pieceTypes.find(KING) != v->pieceTypes.end()) + if (v->pieceTypes & KING) { if (v->blastOnCapture) std::cerr << "Can not use kings with blastOnCapture." << std::endl; diff --git a/src/position.cpp b/src/position.cpp index 99966b3..a934c6b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -553,8 +553,9 @@ void Position::set_check_info(StateInfo* si) const { // For unused piece types, the check squares are left uninitialized si->nonSlidingRiders = 0; - for (PieceType pt : piece_types()) + for (PieceSet ps = piece_types(); ps;) { + PieceType pt = pop_lsb(ps); si->checkSquares[pt] = ksq != SQ_NONE ? attacks_bb(~sideToMove, pt, ksq, pieces()) : Bitboard(0); // Collect special piece types that require slower check and evasion detection if (AttackRiderTypes[pt] & NON_SLIDING_RIDERS) @@ -568,8 +569,9 @@ void Position::set_check_info(StateInfo* si) const { { si->pseudoRoyalCandidates = 0; si->pseudoRoyals = 0; - for (PieceType pt : extinction_piece_types()) + for (PieceSet ps = extinction_piece_types(); ps;) { + PieceType pt = pop_lsb(ps); si->pseudoRoyalCandidates |= pieces(pt); if (count(sideToMove, pt) <= var->extinctionPieceCount + 1) si->pseudoRoyals |= pieces(sideToMove, pt); @@ -835,8 +837,9 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners } else { - for (PieceType pt : piece_types()) + for (PieceSet ps = piece_types(); ps;) { + PieceType pt = pop_lsb(ps); Bitboard b = sliders & (PseudoAttacks[~c][pt][s] ^ LeaperAttacks[~c][pt][s]) & pieces(c, pt); if (b) { @@ -925,7 +928,9 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied, Color c, Bitboard j } Bitboard b = 0; - for (PieceType pt : piece_types()) + for (PieceSet ps = piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); if (board_bb(c, pt) & s) { PieceType move_pt = pt == KING ? king_type() : pt; @@ -945,6 +950,7 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied, Color c, Bitboard j else b |= attacks_bb(~c, move_pt, s, occupied) & pieces(c, pt); } + } // Janggi palace moves if (diagonal_lines() & s) @@ -1093,7 +1099,7 @@ bool Position::legal(Move m) const { Bitboard pseudoRoyalsTheirs = st->pseudoRoyals & pieces(~sideToMove); if (is_ok(from) && (pseudoRoyals & from)) pseudoRoyals ^= square_bb(from) ^ kto; - if (type_of(m) == PROMOTION && extinction_piece_types().find(promotion_type(m)) != extinction_piece_types().end()) + if (type_of(m) == PROMOTION && (extinction_piece_types() & promotion_type(m))) { if (count(sideToMove, promotion_type(m)) > extinction_piece_count()) // increase in count leads to loss of pseudo-royalty @@ -1121,7 +1127,7 @@ bool Position::legal(Move m) const { Bitboard pseudoRoyalCandidates = st->pseudoRoyalCandidates & pieces(sideToMove); if (is_ok(from) && (pseudoRoyalCandidates & from)) pseudoRoyalCandidates ^= square_bb(from) ^ kto; - if (type_of(m) == PROMOTION && extinction_piece_types().find(promotion_type(m)) != extinction_piece_types().end()) + if (type_of(m) == PROMOTION && (extinction_piece_types() & promotion_type(m))) pseudoRoyalCandidates |= kto; bool allCheck = bool(pseudoRoyalCandidates); while (allCheck && pseudoRoyalCandidates) @@ -2282,7 +2288,7 @@ Value Position::blast_see(Move m) const { while (attackers) { Square s = pop_lsb(attackers); - if (extinction_piece_types().find(type_of(piece_on(s))) == extinction_piece_types().end()) + if (!(extinction_piece_types() & type_of(piece_on(s)))) minAttacker = std::min(minAttacker, blast & s ? VALUE_ZERO : CapturePieceValue[MG][piece_on(s)]); } @@ -2298,7 +2304,7 @@ Value Position::blast_see(Move m) const { while (blast) { Piece bpc = piece_on(pop_lsb(blast)); - if (extinction_piece_types().find(type_of(bpc)) != extinction_piece_types().end()) + if (extinction_piece_types() & type_of(bpc)) return color_of(bpc) == us ? extinction_value() : capture(m) ? -extinction_value() : VALUE_ZERO; @@ -2334,9 +2340,9 @@ bool Position::see_ge(Move m, Value threshold) const { // Extinction if ( extinction_value() != VALUE_NONE && piece_on(to) - && ( ( extinction_piece_types().find(type_of(piece_on(to))) != extinction_piece_types().end() + && ( ( (extinction_piece_types() & type_of(piece_on(to))) && pieceCount[piece_on(to)] == extinction_piece_count() + 1) - || ( extinction_piece_types().find(ALL_PIECES) != extinction_piece_types().end() + || ( (extinction_piece_types() & ALL_PIECES) && count(~sideToMove) == extinction_piece_count() + 1))) return extinction_value() < VALUE_ZERO; @@ -2608,13 +2614,16 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { if (extinction_value() != VALUE_NONE && (!var->extinctionPseudoRoyal || blast_on_capture())) { for (Color c : { ~sideToMove, sideToMove }) - for (PieceType pt : extinction_piece_types()) + for (PieceSet ps = extinction_piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); if ( count_with_hand( c, pt) <= var->extinctionPieceCount && count_with_hand(~c, pt) >= var->extinctionOpponentPieceCount + (extinction_claim() && c == sideToMove)) { result = c == sideToMove ? extinction_value(ply) : -extinction_value(ply); return true; } + } } // capture the flag if ( capture_the_flag_piece() @@ -2687,8 +2696,8 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { if (two_boards() && !checkers()) { int virtualCount = 0; - for (PieceType pt : piece_types()) - virtualCount += std::max(-count_in_hand(~sideToMove, pt), 0); + for (PieceSet ps = piece_types(); ps;) + virtualCount += std::max(-count_in_hand(~sideToMove, pop_lsb(ps)), 0); if (virtualCount > 0) { diff --git a/src/position.h b/src/position.h index fa8ffd6..2c2c94b 100644 --- a/src/position.h +++ b/src/position.h @@ -125,13 +125,13 @@ public: bool two_boards() const; Bitboard board_bb() const; Bitboard board_bb(Color c, PieceType pt) const; - const std::set& piece_types() const; + PieceSet piece_types() const; const std::string& piece_to_char() const; const std::string& piece_to_char_synonyms() const; Bitboard promotion_zone(Color c) const; Square promotion_square(Color c, Square s) const; PieceType promotion_pawn_type(Color c) const; - const std::set >& promotion_piece_types(Color c) const; + PieceSet promotion_piece_types(Color c) const; bool sittuyin_promotion() const; int promotion_limit(PieceType pt) const; PieceType promoted_piece_type(PieceType pt) const; @@ -192,7 +192,7 @@ public: Value checkmate_value(int ply = 0) const; Value extinction_value(int ply = 0) const; bool extinction_claim() const; - const std::set& extinction_piece_types() const; + PieceSet extinction_piece_types() const; bool extinction_single_piece() const; int extinction_piece_count() const; int extinction_opponent_piece_count() const; @@ -408,7 +408,7 @@ inline Bitboard Position::board_bb(Color c, PieceType pt) const { return var->mobilityRegion[c][pt] ? var->mobilityRegion[c][pt] & board_bb() : board_bb(); } -inline const std::set& Position::piece_types() const { +inline PieceSet Position::piece_types() const { assert(var != nullptr); return var->pieceTypes; } @@ -439,7 +439,7 @@ inline PieceType Position::promotion_pawn_type(Color c) const { return var->promotionPawnType[c]; } -inline const std::set >& Position::promotion_piece_types(Color c) const { +inline PieceSet Position::promotion_piece_types(Color c) const { assert(var != nullptr); return var->promotionPieceTypes[c]; } @@ -866,8 +866,11 @@ inline Value Position::checkmate_value(int ply) const { if (two_boards() && var->checkmateValue < VALUE_ZERO) { Value virtualMaterial = VALUE_ZERO; - for (PieceType pt : piece_types()) + for (PieceSet ps = piece_types(); ps;) + { + PieceType pt = pop_lsb(ps); virtualMaterial += std::max(-count_in_hand(~sideToMove, pt), 0) * PieceValue[MG][pt]; + } if (virtualMaterial > 0) return -VALUE_VIRTUAL_MATE + virtualMaterial / 20 + ply; @@ -886,7 +889,7 @@ inline bool Position::extinction_claim() const { return var->extinctionClaim; } -inline const std::set& Position::extinction_piece_types() const { +inline PieceSet Position::extinction_piece_types() const { assert(var != nullptr); return var->extinctionPieceTypes; } @@ -894,9 +897,7 @@ inline const std::set& Position::extinction_piece_types() const { inline bool Position::extinction_single_piece() const { assert(var != nullptr); return var->extinctionValue == -VALUE_MATE - && std::any_of(var->extinctionPieceTypes.begin(), - var->extinctionPieceTypes.end(), - [](PieceType pt) { return pt != ALL_PIECES; }); + && (var->extinctionPieceTypes & ~piece_set(ALL_PIECES)); } inline int Position::extinction_piece_count() const { diff --git a/src/psqt.cpp b/src/psqt.cpp index afa1fde..c753c6a 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -183,8 +183,9 @@ Score psq[PIECE_NB][SQUARE_NB + 1]; void init(const Variant* v) { PieceType strongestPiece = NO_PIECE_TYPE; - for (PieceType pt : v->pieceTypes) + for (PieceSet ps = v->pieceTypes; ps;) { + PieceType pt = pop_lsb(ps); if (is_custom(pt)) { PieceValue[MG][pt] = piece_value(MG, pt); @@ -196,8 +197,8 @@ void init(const Variant* v) { } Value maxPromotion = VALUE_ZERO; - for (PieceType pt : v->promotionPieceTypes[WHITE]) - maxPromotion = std::max(maxPromotion, PieceValue[EG][pt]); + for (PieceSet ps = v->promotionPieceTypes[WHITE]; ps;) + maxPromotion = std::max(maxPromotion, PieceValue[EG][pop_lsb(ps)]); for (PieceType pt = PAWN; pt <= KING; ++pt) { @@ -261,7 +262,7 @@ void init(const Variant* v) { // In variants such as horde where all pieces need to be captured, weak pieces such as pawns are more useful if ( v->extinctionValue == -VALUE_MATE && v->extinctionPieceCount == 0 - && v->extinctionPieceTypes.find(ALL_PIECES) != v->extinctionPieceTypes.end()) + && (v->extinctionPieceTypes & ALL_PIECES)) score += make_score(0, std::max(KnightValueEg - PieceValue[EG][pt], VALUE_ZERO) / 20); // The strongest piece of a variant usually has some dominance, such as rooks in Makruk and Xiangqi. @@ -311,7 +312,7 @@ void init(const Variant* v) { : pt == KING ? KingBonus[std::clamp(Rank(r - pawnRank + 1), RANK_1, RANK_8)][std::min(f, FILE_D)] * (1 + v->capturesToHand) : pt <= QUEEN ? Bonus[pc][std::min(r, RANK_8)][std::min(f, FILE_D)] * (1 + v->blastOnCapture) : pt == HORSE ? Bonus[KNIGHT][std::min(r, RANK_8)][std::min(f, FILE_D)] - : pt == COMMONER && v->extinctionValue == -VALUE_MATE && v->extinctionPieceTypes.find(COMMONER) != v->extinctionPieceTypes.end() ? KingBonus[std::clamp(Rank(r - pawnRank + 1), RANK_1, RANK_8)][std::min(f, FILE_D)] + : pt == COMMONER && v->extinctionValue == -VALUE_MATE && (v->extinctionPieceTypes & COMMONER) ? KingBonus[std::clamp(Rank(r - pawnRank + 1), RANK_1, RANK_8)][std::min(f, FILE_D)] : isSlider ? make_score(5, 5) * (2 * f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile - 1) : isPawn ? make_score(5, 5) * (2 * f - v->maxFile) : make_score(10, 10) * (1 + isSlowLeaper) * (f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile / 2)); diff --git a/src/search.cpp b/src/search.cpp index 67ee805..e1c34c9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1646,7 +1646,7 @@ moves_loop: // When in check, search starts from here && !givesCheck && !( pos.extinction_value() == -VALUE_MATE && pos.piece_on(to_sq(move)) - && pos.extinction_piece_types().find(type_of(pos.piece_on(to_sq(move)))) != pos.extinction_piece_types().end()) + && (pos.extinction_piece_types() & type_of(pos.piece_on(to_sq(move))))) && futilityBase > -VALUE_KNOWN_WIN && type_of(move) != PROMOTION) { diff --git a/src/types.h b/src/types.h index fbf7367..ef99c4a 100644 --- a/src/types.h +++ b/src/types.h @@ -419,7 +419,9 @@ enum Piece { PIECE_NB = 2 * PIECE_TYPE_NB }; -enum PieceSet : uint64_t {}; +enum PieceSet : uint64_t { + NO_PIECE_SET = 0 +}; enum RiderType : int { NO_RIDER = 0, @@ -629,11 +631,14 @@ constexpr PieceSet piece_set(PieceType pt) { return PieceSet(1ULL << pt); } +constexpr PieceSet operator~ (PieceSet ps) { return (PieceSet)~(uint64_t)ps; } constexpr PieceSet operator| (PieceSet ps1, PieceSet ps2) { return (PieceSet)((uint64_t)ps1 | (uint64_t)ps2); } +constexpr PieceSet operator| (PieceSet ps, PieceType pt) { return ps | piece_set(pt); } constexpr PieceSet operator& (PieceSet ps1, PieceSet ps2) { return (PieceSet)((uint64_t)ps1 & (uint64_t)ps2); } constexpr PieceSet operator& (PieceSet ps, PieceType pt) { return ps & piece_set(pt); } inline PieceSet& operator|= (PieceSet& ps1, PieceSet ps2) { return (PieceSet&)((uint64_t&)ps1 |= (uint64_t)ps2); } inline PieceSet& operator|= (PieceSet& ps, PieceType pt) { return ps |= piece_set(pt); } +inline PieceSet& operator&= (PieceSet& ps1, PieceSet ps2) { return (PieceSet&)((uint64_t&)ps1 &= (uint64_t)ps2); } static_assert(piece_set(PAWN) & PAWN); static_assert(piece_set(KING) & KING); diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 2d24c0f..0326e04 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -92,7 +92,7 @@ void on_variant_change(const Option &o) { // Do not send setup command for known variants if (standard_variants.find(o) != standard_variants.end()) return; - int pocketsize = v->pieceDrops ? (v->pocketSize ? v->pocketSize : v->pieceTypes.size()) : 0; + int pocketsize = v->pieceDrops ? (v->pocketSize ? v->pocketSize : popcount(v->pieceTypes)) : 0; if (CurrentProtocol == XBOARD) { // Overwrite setup command for Janggi variants @@ -115,8 +115,9 @@ void on_variant_change(const Option &o) { << sync_endl; // Send piece command with Betza notation // https://www.gnu.org/software/xboard/Betza.html - for (PieceType pt : v->pieceTypes) + for (PieceSet ps = v->pieceTypes; ps;) { + PieceType pt = pop_lsb(ps); string suffix = pt == PAWN && v->doubleStep ? "ifmnD" : pt == KING && v->cambodianMoves ? "ismN" : pt == FERS && v->cambodianMoves ? "ifD" diff --git a/src/variant.cpp b/src/variant.cpp index cb2ea69..c29ce1e 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -161,8 +161,8 @@ namespace { v->startFen = "rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w - - 0 1"; v->promotionRegion[WHITE] = Rank6BB | Rank7BB | Rank8BB; v->promotionRegion[BLACK] = Rank3BB | Rank2BB | Rank1BB; - v->promotionPieceTypes[WHITE] = {MET}; - v->promotionPieceTypes[BLACK] = {MET}; + v->promotionPieceTypes[WHITE] = piece_set(MET); + v->promotionPieceTypes[BLACK] = piece_set(MET); v->doubleStep = false; v->castling = false; v->nMoveRule = 0; @@ -206,8 +206,8 @@ namespace { v->add_piece(KHON, 'b'); v->add_piece(MET, 'q'); v->startFen = "rnbqkbnr/8/pppppppp/8/8/PPPPPPPP/8/RNBQKBNR w - - 0 1"; - v->promotionPieceTypes[WHITE] = {ROOK, KNIGHT, KHON, MET}; - v->promotionPieceTypes[BLACK] = {ROOK, KNIGHT, KHON, MET}; + v->promotionPieceTypes[WHITE] = piece_set(ROOK) | KNIGHT | KHON | MET; + v->promotionPieceTypes[BLACK] = piece_set(ROOK) | KNIGHT | KHON | MET; v->doubleStep = false; v->castling = false; v->countingRule = ASEAN_COUNTING; @@ -221,8 +221,8 @@ namespace { v->remove_piece(MET); v->add_piece(AIWOK, 'a'); v->startFen = "rnsaksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKASNR w - - 0 1"; - v->promotionPieceTypes[WHITE] = {AIWOK}; - v->promotionPieceTypes[BLACK] = {AIWOK}; + v->promotionPieceTypes[WHITE] = piece_set(AIWOK); + v->promotionPieceTypes[BLACK] = piece_set(AIWOK); return v; } // Shatranj @@ -237,13 +237,13 @@ namespace { v->add_piece(ALFIL, 'b'); v->add_piece(FERS, 'q'); v->startFen = "rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w - - 0 1"; - v->promotionPieceTypes[WHITE] = {FERS}; - v->promotionPieceTypes[BLACK] = {FERS}; + v->promotionPieceTypes[WHITE] = piece_set(FERS); + v->promotionPieceTypes[BLACK] = piece_set(FERS); v->doubleStep = false; v->castling = false; v->extinctionValue = -VALUE_MATE; v->extinctionClaim = true; - v->extinctionPieceTypes = {ALL_PIECES}; + v->extinctionPieceTypes = piece_set(ALL_PIECES); v->extinctionPieceCount = 1; v->extinctionOpponentPieceCount = 2; v->stalemateValue = -VALUE_MATE; @@ -269,8 +269,8 @@ namespace { v->remove_piece(QUEEN); v->add_piece(AMAZON, 'a'); v->startFen = "rnbakbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBAKBNR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {AMAZON, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {AMAZON, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(AMAZON) | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(AMAZON) | ROOK | BISHOP | KNIGHT; return v; } // Nightrider chess @@ -280,8 +280,8 @@ namespace { Variant* v = chess_variant_base()->init(); v->remove_piece(KNIGHT); v->add_piece(CUSTOM_PIECES, 'n', "NN"); - v->promotionPieceTypes[WHITE] = {QUEEN, ROOK, BISHOP, CUSTOM_PIECES}; - v->promotionPieceTypes[BLACK] = {QUEEN, ROOK, BISHOP, CUSTOM_PIECES}; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | ROOK | BISHOP | CUSTOM_PIECES; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | ROOK | BISHOP | CUSTOM_PIECES; return v; } // Grasshopper chess @@ -289,8 +289,8 @@ namespace { Variant* grasshopper_variant() { Variant* v = chess_variant_base()->init(); v->add_piece(CUSTOM_PIECES, 'g', "gQ"); - v->promotionPieceTypes[WHITE].insert(CUSTOM_PIECES); - v->promotionPieceTypes[BLACK].insert(CUSTOM_PIECES); + v->promotionPieceTypes[WHITE] |= CUSTOM_PIECES; + v->promotionPieceTypes[BLACK] |= CUSTOM_PIECES; v->startFen = "rnbqkbnr/gggggggg/pppppppp/8/8/PPPPPPPP/GGGGGGGG/RNBQKBNR w KQkq - 0 1"; v->doubleStep = false; return v; @@ -304,8 +304,8 @@ namespace { v->remove_piece(BISHOP); v->add_piece(KNIBIS, 'n'); v->add_piece(BISKNI, 'b'); - v->promotionPieceTypes[WHITE] = {QUEEN, ROOK, BISKNI, KNIBIS}; - v->promotionPieceTypes[BLACK] = {QUEEN, ROOK, BISKNI, KNIBIS}; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | ROOK | BISKNI | KNIBIS; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | ROOK | BISKNI | KNIBIS; return v; } // New Zealand @@ -317,8 +317,8 @@ namespace { v->add_piece(ROOKNI, 'r'); v->add_piece(KNIROO, 'n'); v->castlingRookPiece = ROOKNI; - v->promotionPieceTypes[WHITE] = {QUEEN, ROOKNI, BISHOP, KNIROO}; - v->promotionPieceTypes[BLACK] = {QUEEN, ROOKNI, BISHOP, KNIROO}; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | ROOKNI | BISHOP | KNIROO; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | ROOKNI | BISHOP | KNIROO; return v; } // King of the Hill @@ -353,8 +353,8 @@ namespace { v->startFen = "rmbqkbmr/pppppppp/8/8/8/8/PPPPPPPP/RMBQKBMR w KQkq - 0 1"; v->kingType = KNIGHT; v->castlingKingPiece = KING; - v->promotionPieceTypes[WHITE] = {COMMONER, QUEEN, ROOK, BISHOP}; - v->promotionPieceTypes[BLACK] = {COMMONER, QUEEN, ROOK, BISHOP}; + v->promotionPieceTypes[WHITE] = piece_set(COMMONER) | QUEEN | ROOK | BISHOP; + v->promotionPieceTypes[BLACK] = piece_set(COMMONER) | QUEEN | ROOK | BISHOP; return v; } // Losers chess @@ -364,7 +364,7 @@ namespace { v->checkmateValue = VALUE_MATE; v->stalemateValue = VALUE_MATE; v->extinctionValue = VALUE_MATE; - v->extinctionPieceTypes = {ALL_PIECES}; + v->extinctionPieceTypes = piece_set(ALL_PIECES); v->extinctionPieceCount = 1; v->mustCapture = true; return v; @@ -378,11 +378,11 @@ namespace { v->remove_piece(KING); v->add_piece(COMMONER, 'k'); v->castlingKingPiece = COMMONER; - v->promotionPieceTypes[WHITE] = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(COMMONER) | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(COMMONER) | QUEEN | ROOK | BISHOP | KNIGHT; v->stalemateValue = VALUE_MATE; v->extinctionValue = VALUE_MATE; - v->extinctionPieceTypes = {ALL_PIECES}; + v->extinctionPieceTypes = piece_set(ALL_PIECES); v->mustCapture = true; v->nnueAlias = "antichess"; return v; @@ -409,9 +409,9 @@ namespace { // http://www.binnewirtz.com/Schlagschach1.htm Variant* codrus_variant() { Variant* v = giveaway_variant()->init(); - v->promotionPieceTypes[WHITE] = {QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {QUEEN, ROOK, BISHOP, KNIGHT}; - v->extinctionPieceTypes = {COMMONER}; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | ROOK | BISHOP | KNIGHT; + v->extinctionPieceTypes = piece_set(COMMONER); return v; } // Extinction chess @@ -421,19 +421,19 @@ namespace { v->remove_piece(KING); v->add_piece(COMMONER, 'k'); v->castlingKingPiece = COMMONER; - v->promotionPieceTypes[WHITE] = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(COMMONER) | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(COMMONER) | QUEEN | ROOK | BISHOP | KNIGHT; v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT, PAWN}; + v->extinctionPieceTypes = piece_set(COMMONER) | QUEEN | ROOK | BISHOP | KNIGHT | PAWN; return v; } // Kinglet // https://en.wikipedia.org/wiki/V._R._Parton#Kinglet_chess Variant* kinglet_variant() { Variant* v = extinction_variant()->init(); - v->promotionPieceTypes[WHITE] = {COMMONER}; - v->promotionPieceTypes[BLACK] = {COMMONER}; - v->extinctionPieceTypes = {PAWN}; + v->promotionPieceTypes[WHITE] = piece_set(COMMONER); + v->promotionPieceTypes[BLACK] = piece_set(COMMONER); + v->extinctionPieceTypes = piece_set(PAWN); return v; } // Three Kings Chess @@ -445,7 +445,7 @@ namespace { v->castlingKingPiece = COMMONER; v->startFen = "knbqkbnk/pppppppp/8/8/8/8/PPPPPPPP/KNBQKBNK w - - 0 1"; v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {COMMONER}; + v->extinctionPieceTypes = piece_set(COMMONER); v->extinctionPieceCount = 2; return v; } @@ -457,7 +457,7 @@ namespace { v->doubleStepRegion[WHITE] |= Rank1BB; v->enPassantRegion = Rank3BB | Rank6BB; // exclude en passant on second rank v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {ALL_PIECES}; + v->extinctionPieceTypes = piece_set(ALL_PIECES); return v; } // Atomic chess without checks (ICC rules) @@ -469,7 +469,7 @@ namespace { v->add_piece(COMMONER, 'k'); v->castlingKingPiece = COMMONER; v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {COMMONER}; + v->extinctionPieceTypes = piece_set(COMMONER); v->blastOnCapture = true; v->nnueAlias = "atomic"; return v; @@ -489,7 +489,7 @@ namespace { v->add_piece(COMMONER, 'k'); v->castlingKingPiece = COMMONER; v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {COMMONER}; + v->extinctionPieceTypes = piece_set(COMMONER); v->duckGating = true; v->stalemateValue = VALUE_MATE; return v; @@ -607,7 +607,7 @@ namespace { v->mustDrop = true; v->mustDropType = COMMONER; v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {COMMONER}; + v->extinctionPieceTypes = piece_set(COMMONER); v->extinctionOpponentPieceCount = 2; // own all kings/commoners return v; } @@ -676,8 +676,8 @@ namespace { v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[HEhe] w KQBCDFGkqbcdfg - 0 1"; v->gating = true; v->seirawanGating = true; - v->promotionPieceTypes[WHITE] = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN | ROOK | BISHOP | KNIGHT; return v; } // S-House @@ -715,8 +715,8 @@ namespace { Variant *v = chess_variant_base()->init(); v->remove_piece(BISHOP); v->add_piece(CUSTOM_PIECES, 'b', "BnN"); - v->promotionPieceTypes[WHITE] = {QUEEN, CUSTOM_PIECES, ROOK, KNIGHT}; - v->promotionPieceTypes[BLACK] = {QUEEN, CUSTOM_PIECES, ROOK, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | CUSTOM_PIECES | ROOK | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | CUSTOM_PIECES | ROOK | KNIGHT; return v; } // Base used for most shogi variants @@ -931,8 +931,8 @@ namespace { v->startFen = "rnqknr/pppppp/6/6/PPPPPP/RNQKNR w - - 0 1"; v->promotionRegion[WHITE] = Rank6BB; v->promotionRegion[BLACK] = Rank1BB; - v->promotionPieceTypes[WHITE] = {QUEEN, ROOK, KNIGHT}; - v->promotionPieceTypes[BLACK] = {QUEEN, ROOK, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | ROOK | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | ROOK | KNIGHT; v->doubleStep = false; v->castling = false; return v; @@ -959,8 +959,8 @@ namespace { v->remove_piece(QUEEN); v->add_piece(CHANCELLOR, 'c'); v->startFen = "rnbckbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBCKBNR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {CHANCELLOR, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {CHANCELLOR, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(CHANCELLOR) | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(CHANCELLOR) | ROOK | BISHOP | KNIGHT; return v; } // Chigorin chess @@ -971,8 +971,8 @@ namespace { v->pieceToCharTable = "PNBR............CKpnbrq............k"; v->add_piece(CHANCELLOR, 'c'); v->startFen = "rbbqkbbr/pppppppp/8/8/8/8/PPPPPPPP/RNNCKNNR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {CHANCELLOR, ROOK, KNIGHT}; - v->promotionPieceTypes[BLACK] = {QUEEN, ROOK, BISHOP}; + v->promotionPieceTypes[WHITE] = piece_set(CHANCELLOR) | ROOK | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | ROOK | BISHOP; return v; } // Spartan chess @@ -988,7 +988,7 @@ namespace { v->promotionPawnType[BLACK] = CUSTOM_PIECES; v->promotionPawnTypes[BLACK] = piece_set(CUSTOM_PIECES); v->nMoveRuleTypes[BLACK] = piece_set(CUSTOM_PIECES); - v->promotionPieceTypes[BLACK] = {COMMONER, DRAGON, ARCHBISHOP, CUSTOM_PIECES + 1, CUSTOM_PIECES + 2}; + v->promotionPieceTypes[BLACK] = piece_set(COMMONER) | DRAGON | ARCHBISHOP | (CUSTOM_PIECES + 1) | (CUSTOM_PIECES + 2); v->promotionLimit[COMMONER] = 2; v->enPassantRegion = 0; v->extinctionPieceCount = 0; @@ -1004,12 +1004,12 @@ namespace { v->remove_piece(QUEEN); v->add_piece(BERS, 'j'); v->startFen = "rnbjkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBJKBNR w - - 0 1"; - v->promotionPieceTypes[WHITE] = {BERS}; - v->promotionPieceTypes[BLACK] = {BERS}; + v->promotionPieceTypes[WHITE] = piece_set(BERS); + v->promotionPieceTypes[BLACK] = piece_set(BERS); v->doubleStep = false; v->castling = false; v->extinctionValue = VALUE_DRAW; // Robado - v->extinctionPieceTypes = {ALL_PIECES}; + v->extinctionPieceTypes = piece_set(ALL_PIECES); v->extinctionPieceCount = 1; v->shatarMateRule = true; return v; @@ -1020,7 +1020,7 @@ namespace { Variant* coregal_variant() { Variant* v = chess_variant_base()->init(); v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {QUEEN}; + v->extinctionPieceTypes = piece_set(QUEEN); v->extinctionPseudoRoyal = true; v->extinctionPieceCount = 64; // no matter how many queens, all are royal return v; @@ -1169,7 +1169,7 @@ namespace { v->promotedPieceType[CUSTOM_PIECES] = COMMONER; v->castlingKingPiece = COMMONER; v->extinctionValue = -VALUE_MATE; - v->extinctionPieceTypes = {COMMONER}; + v->extinctionPieceTypes = piece_set(COMMONER); v->extinctionPseudoRoyal = true; v->extinctionPieceCount = 0; return v; @@ -1239,8 +1239,8 @@ namespace { v->add_piece(ARCHBISHOP, 'a'); v->add_piece(CHANCELLOR, 'c'); v->startFen = "rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN | ROOK | BISHOP | KNIGHT; return v; } // Capahouse @@ -1283,8 +1283,8 @@ namespace { v->castlingQueensideFile = FILE_B; v->add_piece(ARCHBISHOP, 'j'); v->startFen = "rjnbkqbnjr/pppppppppp/10/10/10/10/PPPPPPPPPP/RJNBKQBNJR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {ARCHBISHOP, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {ARCHBISHOP, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(ARCHBISHOP) | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(ARCHBISHOP) | QUEEN | ROOK | BISHOP | KNIGHT; return v; } // Modern chess @@ -1303,8 +1303,8 @@ namespace { v->castlingQueensideFile = FILE_C; v->add_piece(ARCHBISHOP, 'm'); v->startFen = "rnbqkmbnr/ppppppppp/9/9/9/9/9/PPPPPPPPP/RNBMKQBNR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {ARCHBISHOP, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {ARCHBISHOP, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(ARCHBISHOP) | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(ARCHBISHOP) | QUEEN | ROOK | BISHOP | KNIGHT; return v; } // Chancellor chess @@ -1323,8 +1323,8 @@ namespace { v->castlingQueensideFile = FILE_C; v->add_piece(CHANCELLOR, 'c'); v->startFen = "rnbqkcnbr/ppppppppp/9/9/9/9/9/PPPPPPPPP/RNBQKCNBR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(CHANCELLOR) | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(CHANCELLOR) | QUEEN | ROOK | BISHOP | KNIGHT; return v; } // Embassy chess @@ -1350,8 +1350,8 @@ namespace { v->castlingQueensideFile = FILE_C; v->add_piece(CENTAUR, 'c'); v->startFen = "rcnbqkbncr/pppppppppp/10/10/10/10/PPPPPPPPPP/RCNBQKBNCR w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {CENTAUR, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {CENTAUR, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(CENTAUR) | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(CENTAUR) | QUEEN | ROOK | BISHOP | KNIGHT; return v; } // Gustav III chess @@ -1366,8 +1366,8 @@ namespace { v->castlingQueensideFile = FILE_D; v->add_piece(AMAZON, 'a'); v->startFen = "arnbqkbnra/*pppppppp*/*8*/*8*/*8*/*8*/*PPPPPPPP*/ARNBQKBNRA w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = {AMAZON, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {AMAZON, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(AMAZON) | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(AMAZON) | QUEEN | ROOK | BISHOP | KNIGHT; return v; } // Jeson mor @@ -1402,13 +1402,13 @@ namespace { v->add_piece(COMMONER, 'm'); v->add_piece(WAZIR, 'w'); v->startFen = "rnebmk1wbenr/1ppppp1pppp1/6f5/p5p4p/P5P4P/6F5/1PPPPP1PPPP1/RNEBMK1WBENR w - - 0 1"; - v->promotionPieceTypes[WHITE] = {FERS}; - v->promotionPieceTypes[BLACK] = {FERS}; + v->promotionPieceTypes[WHITE] = piece_set(FERS); + v->promotionPieceTypes[BLACK] = piece_set(FERS); v->doubleStep = false; v->castling = false; v->extinctionValue = -VALUE_MATE; v->extinctionClaim = true; - v->extinctionPieceTypes = {ALL_PIECES}; + v->extinctionPieceTypes = piece_set(ALL_PIECES); v->extinctionPieceCount = 1; v->extinctionOpponentPieceCount = 2; v->stalemateValue = -VALUE_MATE; @@ -1426,8 +1426,8 @@ namespace { v->add_piece(ARCHBISHOP, 'a'); v->add_piece(CHANCELLOR, 'c'); v->startFen = "r8r/1nbqkcabn1/pppppppppp/10/10/10/10/PPPPPPPPPP/1NBQKCABN1/R8R w - - 0 1"; - v->promotionPieceTypes[WHITE] = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN | ROOK | BISHOP | KNIGHT; v->promotionRegion[WHITE] = Rank8BB | Rank9BB | Rank10BB; v->promotionRegion[BLACK] = Rank3BB | Rank2BB | Rank1BB; v->promotionLimit[ARCHBISHOP] = 1; @@ -1454,10 +1454,10 @@ namespace { v->add_piece(CUSTOM_PIECES + 1, 'w', "CF"); v->add_piece(CUSTOM_PIECES + 2, 'l', "FDH"); v->startFen = "rw6wr/clbnqknbla/pppppppppp/10/10/10/10/PPPPPPPPPP/CLBNQKNBLA/RW6WR w - - 0 1"; - v->promotionPieceTypes[WHITE].erase(KNIGHT); - v->promotionPieceTypes[WHITE].insert(CUSTOM_PIECES); - v->promotionPieceTypes[WHITE].insert(CUSTOM_PIECES + 1); - v->promotionPieceTypes[WHITE].insert(CUSTOM_PIECES + 2); + v->promotionPieceTypes[WHITE] &= ~piece_set(KNIGHT); + v->promotionPieceTypes[WHITE] |= CUSTOM_PIECES; + v->promotionPieceTypes[WHITE] |= CUSTOM_PIECES + 1; + v->promotionPieceTypes[WHITE] |= CUSTOM_PIECES + 2; v->promotionPieceTypes[BLACK] = v->promotionPieceTypes[WHITE]; v->promotionLimit[CUSTOM_PIECES] = 2; v->promotionLimit[CUSTOM_PIECES + 1] = 2; @@ -1476,8 +1476,8 @@ namespace { v->add_piece(CHANCELLOR, 'm'); v->add_piece(CUSTOM_PIECES, 'c', "DAW"); // Champion v->add_piece(CUSTOM_PIECES + 1, 'w', "CF"); // Wizard - v->promotionPieceTypes[WHITE] = {ARCHBISHOP, CHANCELLOR, QUEEN}; - v->promotionPieceTypes[BLACK] = {ARCHBISHOP, CHANCELLOR, QUEEN}; + v->promotionPieceTypes[WHITE] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN; + v->promotionPieceTypes[BLACK] = piece_set(ARCHBISHOP) | CHANCELLOR | QUEEN; v->promotionRegion[WHITE] = Rank10BB; v->promotionRegion[BLACK] = Rank1BB; v->doubleStepRegion[WHITE] = Rank3BB; @@ -1501,8 +1501,8 @@ namespace { v->castlingRank = RANK_2; v->promotionRegion[WHITE] = Rank9BB | Rank10BB; v->promotionRegion[BLACK] = Rank2BB | Rank1BB; - v->promotionPieceTypes[WHITE] = {CUSTOM_PIECES + 1, CUSTOM_PIECES, QUEEN, ROOK, BISHOP, KNIGHT}; - v->promotionPieceTypes[BLACK] = {CUSTOM_PIECES + 1, CUSTOM_PIECES, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionPieceTypes[WHITE] = piece_set(CUSTOM_PIECES + 1) | CUSTOM_PIECES | QUEEN | ROOK | BISHOP | KNIGHT; + v->promotionPieceTypes[BLACK] = piece_set(CUSTOM_PIECES + 1) | CUSTOM_PIECES | QUEEN | ROOK | BISHOP | KNIGHT; v->doubleStepRegion[WHITE] = Rank3BB; v->doubleStepRegion[BLACK] = Rank8BB; return v; @@ -1535,8 +1535,8 @@ namespace { v->startFen = "qwfrbbnk/pssppssp/1pp2pp1/8/8/8/8/1PP2PP1/PSSPPSSP/KNBBRFWQ w - - 0 1"; v->promotionPawnType[WHITE] = v->promotionPawnType[BLACK] = PAWN; v->promotionPawnTypes[WHITE] = v->promotionPawnTypes[BLACK] = piece_set(PAWN) | piece_set(CUSTOM_PIECES); - v->promotionPieceTypes[WHITE] = {QUEEN, CHANCELLOR, ARCHBISHOP, ROOK, BISHOP}; - v->promotionPieceTypes[BLACK] = {QUEEN, CHANCELLOR, ARCHBISHOP, ROOK, BISHOP}; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | CHANCELLOR | ARCHBISHOP | ROOK | BISHOP; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | CHANCELLOR | ARCHBISHOP | ROOK | BISHOP; v->promotedPieceType[PAWN] = CUSTOM_PIECES + 2; v->promotionRegion[WHITE] = Rank10BB; v->promotionRegion[BLACK] = Rank1BB; @@ -1558,8 +1558,8 @@ namespace { v->add_piece(FERS_ALFIL, 'e'); v->add_piece(CANNON, 'c'); v->startFen = "c8c/ernbqkbnre/pppppppppp/10/10/10/10/PPPPPPPPPP/ERNBQKBNRE/C8C w KQkq - 0 1"; - v->promotionPieceTypes[WHITE] = { QUEEN, ROOK, BISHOP, KNIGHT, CANNON, FERS_ALFIL }; - v->promotionPieceTypes[BLACK] = { QUEEN, ROOK, BISHOP, KNIGHT, CANNON, FERS_ALFIL }; + v->promotionPieceTypes[WHITE] = piece_set(QUEEN) | ROOK | BISHOP | KNIGHT | CANNON | FERS_ALFIL ; + v->promotionPieceTypes[BLACK] = piece_set(QUEEN) | ROOK | BISHOP | KNIGHT | CANNON | FERS_ALFIL ; v->promotionRegion[WHITE] = Rank10BB; v->promotionRegion[BLACK] = Rank1BB; v->castlingKingsideFile = FILE_H; diff --git a/src/variant.h b/src/variant.h index 2a9d277..3af6138 100644 --- a/src/variant.h +++ b/src/variant.h @@ -19,6 +19,7 @@ #ifndef VARIANT_H_INCLUDED #define VARIANT_H_INCLUDED +#include #include #include #include @@ -44,7 +45,7 @@ struct Variant { bool twoBoards = false; int pieceValue[PHASE_NB][PIECE_TYPE_NB] = {}; std::string customPiece[CUSTOM_PIECES_NB] = {}; - std::set pieceTypes = { PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }; + PieceSet pieceTypes = piece_set(PAWN) | KNIGHT | BISHOP | ROOK | QUEEN | KING; std::string pieceToChar = " PNBRQ" + std::string(KING - QUEEN - 1, ' ') + "K" + std::string(PIECE_TYPE_NB - KING - 1, ' ') + " pnbrq" + std::string(KING - QUEEN - 1, ' ') + "k" + std::string(PIECE_TYPE_NB - KING - 1, ' '); std::string pieceToCharSynonyms = std::string(PIECE_NB, ' '); @@ -53,8 +54,8 @@ struct Variant { Bitboard promotionRegion[COLOR_NB] = {Rank8BB, Rank1BB}; PieceType promotionPawnType[COLOR_NB] = {PAWN, PAWN}; PieceSet promotionPawnTypes[COLOR_NB] = {piece_set(PAWN), piece_set(PAWN)}; - std::set > promotionPieceTypes[COLOR_NB] = {{ QUEEN, ROOK, BISHOP, KNIGHT }, - { QUEEN, ROOK, BISHOP, KNIGHT }}; + PieceSet promotionPieceTypes[COLOR_NB] = {piece_set(QUEEN) | ROOK | BISHOP | KNIGHT, + piece_set(QUEEN) | ROOK | BISHOP | KNIGHT}; bool sittuyinPromotion = false; int promotionLimit[PIECE_TYPE_NB] = {}; // 0 means unlimited PieceType promotedPieceType[PIECE_TYPE_NB] = {}; @@ -135,7 +136,7 @@ struct Variant { bool extinctionClaim = false; bool extinctionPseudoRoyal = false; bool dupleCheck = false; - std::set extinctionPieceTypes = {}; + PieceSet extinctionPieceTypes = NO_PIECE_SET; int extinctionPieceCount = 0; int extinctionOpponentPieceCount = 0; PieceType flagPiece = NO_PIECE_TYPE; @@ -170,7 +171,7 @@ struct Variant { pieceToChar[make_piece(BLACK, pt)] = tolower(c); pieceToCharSynonyms[make_piece(WHITE, pt)] = toupper(c2); pieceToCharSynonyms[make_piece(BLACK, pt)] = tolower(c2); - pieceTypes.insert(pt); + pieceTypes |= pt; // Add betza notation for custom piece if (is_custom(pt)) customPiece[pt - CUSTOM_PIECES] = betza; @@ -185,19 +186,19 @@ struct Variant { pieceToChar[make_piece(BLACK, pt)] = ' '; pieceToCharSynonyms[make_piece(WHITE, pt)] = ' '; pieceToCharSynonyms[make_piece(BLACK, pt)] = ' '; - pieceTypes.erase(pt); + pieceTypes &= ~piece_set(pt); // erase from promotion types to ensure consistency - promotionPieceTypes[WHITE].erase(pt); - promotionPieceTypes[BLACK].erase(pt); + promotionPieceTypes[WHITE] &= ~piece_set(pt); + promotionPieceTypes[BLACK] &= ~piece_set(pt); } void reset_pieces() { pieceToChar = std::string(PIECE_NB, ' '); pieceToCharSynonyms = std::string(PIECE_NB, ' '); - pieceTypes.clear(); + pieceTypes = NO_PIECE_SET; // clear promotion types to ensure consistency - promotionPieceTypes[WHITE].clear(); - promotionPieceTypes[BLACK].clear(); + promotionPieceTypes[WHITE] = NO_PIECE_SET; + promotionPieceTypes[BLACK] = NO_PIECE_SET; } // Reset values that always need to be redefined @@ -214,29 +215,33 @@ struct Variant { if (!doubleStepRegion[WHITE] && !doubleStepRegion[BLACK]) doubleStep = false; - fastAttacks = std::all_of(pieceTypes.begin(), pieceTypes.end(), [this](PieceType pt) { - return ( pt < FAIRY_PIECES - || pt == COMMONER || pt == IMMOBILE_PIECE - || pt == ARCHBISHOP || pt == CHANCELLOR - || (pt == KING && kingType == KING)) - && !(mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt]); - }) - && !cambodianMoves - && !diagonalLines; - fastAttacks2 = std::all_of(pieceTypes.begin(), pieceTypes.end(), [this](PieceType pt) { - return ( pt < FAIRY_PIECES - || pt == COMMONER || pt == FERS || pt == WAZIR || pt == BREAKTHROUGH_PIECE - || pt == SHOGI_PAWN || pt == GOLD || pt == SILVER || pt == SHOGI_KNIGHT - || pt == DRAGON || pt == DRAGON_HORSE || pt == LANCE - || (pt == KING && kingType == KING)) - && !(mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt]); - }) - && !cambodianMoves - && !diagonalLines; + fastAttacks = !cambodianMoves && !diagonalLines; + for (PieceSet ps = pieceTypes; fastAttacks && ps;) + { + PieceType pt = pop_lsb(ps); + if (!( pt < FAIRY_PIECES + || pt == COMMONER || pt == IMMOBILE_PIECE + || pt == ARCHBISHOP || pt == CHANCELLOR + || (pt == KING && kingType == KING)) + || (mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt])) + fastAttacks = false; + } + fastAttacks2 = !cambodianMoves && !diagonalLines; + for (PieceSet ps = pieceTypes; fastAttacks2 && ps;) + { + PieceType pt = pop_lsb(ps); + if (!( pt < FAIRY_PIECES + || pt == COMMONER || pt == FERS || pt == WAZIR || pt == BREAKTHROUGH_PIECE + || pt == SHOGI_PAWN || pt == GOLD || pt == SILVER || pt == SHOGI_KNIGHT + || pt == DRAGON || pt == DRAGON_HORSE || pt == LANCE + || (pt == KING && kingType == KING)) + || (mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt])) + fastAttacks2 = false; + } // Initialize calculated NNUE properties - nnueKing = pieceTypes.find(KING) != pieceTypes.end() ? KING - : extinctionPieceCount == 0 && extinctionPieceTypes.find(COMMONER) != extinctionPieceTypes.end() ? COMMONER + nnueKing = pieceTypes & KING ? KING + : extinctionPieceCount == 0 && (extinctionPieceTypes & COMMONER) ? COMMONER : NO_PIECE_TYPE; if (nnueKing != NO_PIECE_TYPE) { @@ -246,14 +251,16 @@ struct Variant { || std::count(fenBoard.begin(), fenBoard.end(), pieceToChar[make_piece(BLACK, nnueKing)]) != 1) nnueKing = NO_PIECE_TYPE; } + // We can not use popcount here yet, as the lookup tables are initialized after the variants int nnueSquares = (maxRank + 1) * (maxFile + 1); - nnueUsePockets = (pieceDrops && (capturesToHand || (!mustDrop && pieceTypes.size() != 1))) || seirawanGating; + nnueUsePockets = (pieceDrops && (capturesToHand || (!mustDrop && std::bitset<64>(pieceTypes).count() != 1))) || seirawanGating; int nnuePockets = nnueUsePockets ? 2 * int(maxFile + 1) : 0; - int nnueNonDropPieceIndices = (2 * pieceTypes.size() - (nnueKing != NO_PIECE_TYPE)) * nnueSquares; - int nnuePieceIndices = nnueNonDropPieceIndices + 2 * (pieceTypes.size() - (nnueKing != NO_PIECE_TYPE)) * nnuePockets; + int nnueNonDropPieceIndices = (2 * std::bitset<64>(pieceTypes).count() - (nnueKing != NO_PIECE_TYPE)) * nnueSquares; + int nnuePieceIndices = nnueNonDropPieceIndices + 2 * (std::bitset<64>(pieceTypes).count() - (nnueKing != NO_PIECE_TYPE)) * nnuePockets; int i = 0; - for (PieceType pt : pieceTypes) + for (PieceSet ps = pieceTypes; ps;) { + PieceType pt = pop_lsb(ps); for (Color c : { WHITE, BLACK}) { pieceSquareIndex[c][make_piece(c, pt)] = 2 * i * nnueSquares; @@ -300,10 +307,7 @@ struct Variant { // For endgame evaluation to be applicable, no special win rules must apply. // Furthermore, rules significantly changing game mechanics also invalidate it. - endgameEval = std::none_of(pieceTypes.begin(), pieceTypes.end(), [this](PieceType pt) { - return mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt]; - }) - && extinctionValue == VALUE_NONE + endgameEval = extinctionValue == VALUE_NONE && checkmateValue == -VALUE_MATE && stalemateValue == VALUE_DRAW && !materialCounting @@ -316,7 +320,13 @@ struct Variant { && !capturesToHand && !twoBoards && kingType == KING; - + for (PieceSet ps = pieceTypes; endgameEval && ps;) + { + PieceType pt = pop_lsb(ps); + if (mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt]) + endgameEval = false; + } + shogiStylePromotions = false; for (PieceType current: promotedPieceType) if (current != NO_PIECE_TYPE) -- 1.7.0.4