// Castling with non-king piece
if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(Us & ANY_CASTLING))
{
- Square from = make_square(FILE_E, pos.castling_rank(Us));
+ Square from = pos.castling_king_square(Us);
for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
if (!pos.castling_impeded(cr) && pos.can_castle(cr))
moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, from, pos.castling_rook_square(cr));
parse_attribute("castlingKingsideFile", v->castlingKingsideFile);
parse_attribute("castlingQueensideFile", v->castlingQueensideFile);
parse_attribute("castlingRank", v->castlingRank);
+ parse_attribute("castlingKingFile", v->castlingKingFile);
+ parse_attribute("castlingKingPiece", v->castlingKingPiece, v->pieceToChar);
parse_attribute("castlingRookPiece", v->castlingRookPiece, v->pieceToChar);
parse_attribute("kingType", v->kingType, v->pieceToChar);
parse_attribute("checking", v->checking);
// 3-4. Skip parsing castling and en passant flags if not present
st->epSquare = SQ_NONE;
+ st->castlingKingSquare[WHITE] = st->castlingKingSquare[BLACK] = SQ_NONE;
if (!isdigit(ss.peek()) && !sfen)
{
// 3. Castling availability. Compatible with 3 standards: Normal FEN standard,
else
continue;
+ // Determine castling "king" position
+ if (castling_enabled() && st->castlingKingSquare[c] == SQ_NONE)
+ {
+ Bitboard castlingKings = pieces(c, castling_king_piece()) & rank_bb(castling_rank(c));
+ // Ambiguity resolution for 960 variants with more than one "king"
+ // e.g., EAH means that an e-file king can castle with a- and h-file rooks
+ st->castlingKingSquare[c] = isChess960 && piece_on(rsq) == make_piece(c, castling_king_piece()) ? rsq
+ : castlingKings && (!more_than_one(castlingKings) || isChess960) ? lsb(castlingKings)
+ : make_square(castling_king_file(), castling_rank(c));
+ }
+
// Set gates (and skip castling rights)
if (gating())
{
st->gatesBB[c] |= rsq;
if (token == 'K' || token == 'Q')
- st->gatesBB[c] |= count<KING>(c) ? square<KING>(c) : make_square(FILE_E, castling_rank(c));
+ st->gatesBB[c] |= st->castlingKingSquare[c];
// Do not set castling rights for gates unless there are no pieces in hand,
// which means that the file is referring to a chess960 castling right.
else if (!seirawan_gating() || count_in_hand(c, ALL_PIECES) || captures_to_hand())
continue;
}
- if (castling_enabled())
+ if (castling_enabled() && piece_on(rsq) == rook)
set_castling_right(c, rsq);
}
// Set castling rights for 960 gating variants
if (gating() && castling_enabled())
for (Color c : {WHITE, BLACK})
- if ((gates(c) & pieces(KING)) && !castling_rights(c) && (!seirawan_gating() || count_in_hand(c, ALL_PIECES) || captures_to_hand()))
+ if ((gates(c) & pieces(castling_king_piece())) && !castling_rights(c) && (!seirawan_gating() || count_in_hand(c, ALL_PIECES) || captures_to_hand()))
{
Bitboard castling_rooks = gates(c) & pieces(castling_rook_piece());
while (castling_rooks)
void Position::set_castling_right(Color c, Square rfrom) {
- Square kfrom = count<KING>(c) ? square<KING>(c) : make_square(FILE_E, castling_rank(c));
+ assert(st->castlingKingSquare[c] != SQ_NONE);
+ Square kfrom = st->castlingKingSquare[c];
CastlingRights cr = c & (kfrom < rfrom ? KING_SIDE: QUEEN_SIDE);
st->castlingRights |= cr;
ss << (sideToMove == WHITE ? " w " : " b ");
+ // Disambiguation for chess960 "king" square
+ if (chess960 && can_castle(WHITE_CASTLING) && popcount(pieces(WHITE, castling_king_piece()) & rank_bb(castling_rank(WHITE))) > 1)
+ ss << char('A' + castling_king_square(WHITE));
+
if (can_castle(WHITE_OO))
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OO ))) : 'K');
if (gates(WHITE) & file_bb(f))
ss << char('A' + f);
+ // Disambiguation for chess960 "king" square
+ if (chess960 && can_castle(BLACK_CASTLING) && popcount(pieces(BLACK, castling_king_piece()) & rank_bb(castling_rank(BLACK))) > 1)
+ ss << char('a' + castling_king_square(BLACK));
+
if (can_castle(BLACK_OO))
ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK_OO ))) : 'k');
// Set castling rights for dropped king or rook
if (castling_dropped_piece() && rank_of(to) == castling_rank(us))
{
- if (type_of(pc) == KING && file_of(to) == FILE_E)
+ if (type_of(pc) == castling_king_piece() && file_of(to) == castling_king_file())
{
Bitboard castling_rooks = pieces(us, castling_rook_piece())
& rank_bb(castling_rank(us))
else if (type_of(pc) == castling_rook_piece())
{
if ( (file_of(to) == FILE_A || file_of(to) == max_file())
- && piece_on(make_square(FILE_E, castling_rank(us))) == make_piece(us, KING))
+ && piece_on(make_square(castling_king_file(), castling_rank(us))) == make_piece(us, castling_king_piece()))
set_castling_right(us, to);
}
}
int countingLimit;
CheckCount checksRemaining[COLOR_NB];
Square epSquare;
+ Square castlingKingSquare[COLOR_NB];
Bitboard gatesBB[COLOR_NB];
// Not copied when making a move (will be recomputed anyhow)
File castling_kingside_file() const;
File castling_queenside_file() const;
Rank castling_rank(Color c) const;
+ File castling_king_file() const;
+ PieceType castling_king_piece() const;
PieceType castling_rook_piece() const;
PieceType king_type() const;
bool checking_permitted() const;
Piece piece_on(Square s) const;
Piece unpromoted_piece_on(Square s) const;
Square ep_square() const;
+ Square castling_king_square(Color c) const;
Bitboard gates(Color c) const;
bool empty(Square s) const;
int count(Color c, PieceType pt) const;
template<PieceType Pt> int count(Color c) const;
template<PieceType Pt> int count() const;
template<PieceType Pt> Square square(Color c) const;
+ Square square(Color c, PieceType pt) const;
bool is_on_semiopen_file(Color c, Square s) const;
// Castling
return relative_rank(c, var->castlingRank, max_rank());
}
+inline File Position::castling_king_file() const {
+ assert(var != nullptr);
+ return var->castlingKingFile;
+}
+
+inline PieceType Position::castling_king_piece() const {
+ assert(var != nullptr);
+ return var->castlingKingPiece;
+}
+
inline PieceType Position::castling_rook_piece() const {
assert(var != nullptr);
return var->castlingRookPiece;
return lsb(pieces(c, Pt));
}
+inline Square Position::square(Color c, PieceType pt) const {
+ assert(count(c, pt) == 1);
+ return lsb(pieces(c, pt));
+}
+
inline Square Position::ep_square() const {
return st->epSquare;
}
+inline Square Position::castling_king_square(Color c) const {
+ return st->castlingKingSquare[c];
+}
+
inline Bitboard Position::gates(Color c) const {
assert(var != nullptr);
return st->gatesBB[c];
v->remove_piece(KNIGHT);
v->startFen = "rmbqkbmr/pppppppp/8/8/8/8/PPPPPPPP/RMBQKBMR w KQkq - 0 1";
v->kingType = KNIGHT;
+ v->castlingKingPiece = KNIGHT;
v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP};
return v;
}
v->variantTemplate = "giveaway";
v->remove_piece(KING);
v->add_piece(COMMONER, 'k');
+ v->castlingKingPiece = COMMONER;
v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT};
v->stalemateValue = VALUE_MATE;
v->extinctionValue = VALUE_MATE;
Variant* v = fairy_variant_base();
v->remove_piece(KING);
v->add_piece(COMMONER, 'k');
+ v->castlingKingPiece = COMMONER;
v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT};
v->extinctionValue = -VALUE_MATE;
v->extinctionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT, PAWN};
Variant* v = fairy_variant_base();
v->remove_piece(KING);
v->add_piece(COMMONER, 'k');
+ v->castlingKingPiece = COMMONER;
v->startFen = "knbqkbnk/pppppppp/8/8/8/8/PPPPPPPP/KNBQKBNK w - - 0 1";
v->extinctionValue = -VALUE_MATE;
v->extinctionPieceTypes = {COMMONER};
v->variantTemplate = "atomic";
v->remove_piece(KING);
v->add_piece(COMMONER, 'k');
+ v->castlingKingPiece = COMMONER;
v->extinctionValue = -VALUE_MATE;
v->extinctionPieceTypes = {COMMONER};
v->blastOnCapture = true;
Variant* v = bughouse_variant();
v->remove_piece(KING);
v->add_piece(COMMONER, 'k');
+ v->castlingKingPiece = COMMONER;
v->mustDrop = true;
v->mustDropType = COMMONER;
v->extinctionValue = -VALUE_MATE;
File castlingKingsideFile = FILE_G;
File castlingQueensideFile = FILE_C;
Rank castlingRank = RANK_1;
+ File castlingKingFile = FILE_E;
+ PieceType castlingKingPiece = KING;
PieceType castlingRookPiece = ROOK;
PieceType kingType = KING;
bool checking = true;
# castlingKingsideFile: destination file of king after kingside castling [File] (default: g)
# castlingQueensideFile: destination file of king after queenside castling [File] (default: c)
# castlingRank: relative rank of castling [Rank] (default: 1)
-# castlingRookPiece: piece type that participates in castling [PieceType] (default: r)
+# castlingKingFile: starting file of the castlingKingPiece if there can be more than one of that type [File] (default: e)
+# castlingKingPiece: first piece type that participates in castling [PieceType] (default: k)
+# castlingRookPiece: second piece type that participates in castling [PieceType] (default: r)
# kingType: piece type defining moves of king/royal piece (default: k)
# checking: allow checks [bool] (default: true)
# dropChecks: allow checks by piece drops [bool] (default: true)