Simplifies the code and improves performance.
No functional change.
// 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
// 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 += "[-]";
}
// 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
// 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;
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
// 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;
// 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;
std::function <Bitboard (Color, PieceType)> 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:
// 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]);
if (!(attackedBy[Us][KING] & ~(attackedBy[Them][ALL_PIECES] | pos.pieces(Us))))
kingDanger += 2000;
}
+ }
}
if (pos.check_counting())
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);
// 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]);
}
// 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
dist = std::min(dist, popcount(pos.pieces(PAWN) & file_bb(f)));
score += make_score(70, 70) * pos.count<PAWN>(Them) / (1 + dist * dist) / (pos.pieces(Us, QUEEN) ? 2 : 4);
}
+ }
}
// Connect-n
// 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<WHITE>(pt) - pieces<BLACK>(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<WHITE>(pt) - hand<BLACK>(pt);
+ }
score += (mobility[WHITE] - mobility[BLACK]) * (1 + pos.captures_to_hand() + pos.must_capture() + pos.check_counting());
// 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<FERS>(us) || pos.count<PAWN>(us))
&& !(pos.count<ALL_PIECES>(us) - pos.count<FERS>(us) - pos.count<PAWN>(us) - pos.count<KING>(us));
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<PAWN>() * PawnValueMg) * countAll / (pos.files() * pos.ranks());
// 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<T>(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<T>(from, to, pt_gating, to);
+ }
return moveList;
}
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<PROMOTION>(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<PIECE_PROMOTION>(pos, moveList, pos.side_to_move(), to - D, to);
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;
// 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<PROMOTION>(pos, moveList, pos.side_to_move(), from, pop_lsb(promotions), ptP);
+ }
// En passant captures
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
target &= pos.board_bb();
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
- for (PieceType pt : pos.piece_types())
- if (pt != PAWN && pt != KING)
- moveList = generate_moves<Us, Type>(pos, moveList, pt, target);
+ for (PieceSet ps = pos.piece_types() & ~(piece_set(PAWN) | KING); ps;)
+ moveList = generate_moves<Us, Type>(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<Us, Type>(pos, moveList, pt, target & ~pos.pieces(~Us));
+ for (PieceSet ps = pos.piece_types(); ps;)
+ moveList = generate_drops<Us, Type>(pos, moveList, pop_lsb(ps), target & ~pos.pieces(~Us));
// Castling with non-king piece
if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(Us & ANY_CASTLING))
// 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));
+ }
}
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;
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);
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;
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;
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;
// 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)
{
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);
}
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)
{
}
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;
else
b |= attacks_bb(~c, move_pt, s, occupied) & pieces(c, pt);
}
+ }
// Janggi palace moves
if (diagonal_lines() & s)
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
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)
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)]);
}
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;
// 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<ALL_PIECES>(~sideToMove) == extinction_piece_count() + 1)))
return extinction_value() < VALUE_ZERO;
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()
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)
{
bool two_boards() const;
Bitboard board_bb() const;
Bitboard board_bb(Color c, PieceType pt) const;
- const std::set<PieceType>& 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<PieceType, std::greater<PieceType> >& 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;
Value checkmate_value(int ply = 0) const;
Value extinction_value(int ply = 0) const;
bool extinction_claim() const;
- const std::set<PieceType>& 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;
return var->mobilityRegion[c][pt] ? var->mobilityRegion[c][pt] & board_bb() : board_bb();
}
-inline const std::set<PieceType>& Position::piece_types() const {
+inline PieceSet Position::piece_types() const {
assert(var != nullptr);
return var->pieceTypes;
}
return var->promotionPawnType[c];
}
-inline const std::set<PieceType, std::greater<PieceType> >& Position::promotion_piece_types(Color c) const {
+inline PieceSet Position::promotion_piece_types(Color c) const {
assert(var != nullptr);
return var->promotionPieceTypes[c];
}
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;
return var->extinctionClaim;
}
-inline const std::set<PieceType>& Position::extinction_piece_types() const {
+inline PieceSet Position::extinction_piece_types() const {
assert(var != nullptr);
return var->extinctionPieceTypes;
}
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 {
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);
}
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)
{
// 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.
: 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));
&& !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)
{
PIECE_NB = 2 * PIECE_TYPE_NB
};
-enum PieceSet : uint64_t {};
+enum PieceSet : uint64_t {
+ NO_PIECE_SET = 0
+};
enum RiderType : int {
NO_RIDER = 0,
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);
// 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
<< 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"
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;
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;
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
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;
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
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
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;
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
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
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
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;
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;
// 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
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
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;
}
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)
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;
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;
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;
}
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
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
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;
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
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
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;
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;
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;
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;
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
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
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
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
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
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
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;
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;
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;
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;
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;
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;
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;
#ifndef VARIANT_H_INCLUDED
#define VARIANT_H_INCLUDED
+#include <bitset>
#include <set>
#include <map>
#include <vector>
bool twoBoards = false;
int pieceValue[PHASE_NB][PIECE_TYPE_NB] = {};
std::string customPiece[CUSTOM_PIECES_NB] = {};
- std::set<PieceType> 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, ' ');
Bitboard promotionRegion[COLOR_NB] = {Rank8BB, Rank1BB};
PieceType promotionPawnType[COLOR_NB] = {PAWN, PAWN};
PieceSet promotionPawnTypes[COLOR_NB] = {piece_set(PAWN), piece_set(PAWN)};
- std::set<PieceType, std::greater<PieceType> > 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] = {};
bool extinctionClaim = false;
bool extinctionPseudoRoyal = false;
bool dupleCheck = false;
- std::set<PieceType> extinctionPieceTypes = {};
+ PieceSet extinctionPieceTypes = NO_PIECE_SET;
int extinctionPieceCount = 0;
int extinctionOpponentPieceCount = 0;
PieceType flagPiece = NO_PIECE_TYPE;
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;
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
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)
{
|| 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;
// 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
&& !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)