No functional change.
return !ss.fail();
}
+ template <> bool set(const std::string& value, CastlingRights& target) {
+ char c;
+ CastlingRights castlingRight;
+ std::stringstream ss(value);
+ target = NO_CASTLING;
+ bool valid = true;
+ while (ss >> c && c != '-')
+ {
+ castlingRight = c == 'K' ? WHITE_OO
+ : c == 'Q' ? WHITE_OOO
+ : c == 'k' ? BLACK_OO
+ : c == 'q' ? BLACK_OOO
+ : NO_CASTLING;
+ if (castlingRight)
+ target = CastlingRights(target | castlingRight);
+ else
+ valid = false;
+ }
+ return valid;
+ }
+
template <typename T> void set(PieceType pt, T& target) {
target.insert(pt);
}
: std::is_same<T, ChasingRule>() ? "ChasingRule"
: std::is_same<T, EnclosingRule>() ? "EnclosingRule"
: std::is_same<T, Bitboard>() ? "Bitboard"
+ : std::is_same<T, CastlingRights>() ? "CastlingRights"
: typeid(T).name();
std::cerr << key << " - Invalid value " << it->second << " for type " << typeName << std::endl;
}
}
// Castle chess
- if (var->castlingWinConditions) {
- if (type_of(st->move) == CASTLING)
+ if (var->castlingWins)
+ {
+ if (st->pliesFromNull > 0 && type_of(st->move) == CASTLING)
{
- //check for victory first, because castling also removes castling rights.
- CastlingRights justCastled = static_cast<CastlingRights>((sideToMove == BLACK ? WHITE_OOO : BLACK_OOO)
- >> ((from_sq(st->move) < to_sq(st->move)) ? 1 : 0));
- if (var->castlingWinConditions & justCastled)
+ // check for victory first, because castling also removes castling rights.
+ CastlingRights justCastled = ~sideToMove & ((from_sq(st->move) < to_sq(st->move)) ? KING_SIDE : QUEEN_SIDE);
+ if (var->castlingWins & justCastled)
{
result = mated_in(ply);
return true;
}
}
- if ((var->castlingWinConditions & BLACK_CASTLING) && (!(var->castlingWinConditions & BLACK_CASTLING & st->castlingRights)))
- {
- //black permanently losing castling rights. either through moving a castling piece,
- //or having their rook captured. Either way, black lost.
- result = sideToMove == WHITE ? mate_in(ply) : mated_in(ply);
- return true;
- }
- if ((var->castlingWinConditions & WHITE_CASTLING) && (!(var->castlingWinConditions & WHITE_CASTLING & st->castlingRights)))
- {
- //white permanently losing castling rights. either through moving a castling piece,
- //or having their rook captured. Either way, white lost.
- result = sideToMove == BLACK ? mate_in(ply) : mated_in(ply);
- return true;
- }
+ // We check the opponent side first, because a rook capturing a rook could remove both sides castling rights,
+ // which should likely be seen as losing, analogous to extinction rules.
+ for (Color c : { ~sideToMove, sideToMove })
+ if ((c & var->castlingWins) && !(c & var->castlingWins & st->castlingRights))
+ {
+ // player permanently losing castling rights. either through moving a castling piece,
+ // or having their rook captured.
+ result = c == sideToMove ? mated_in(ply) : mate_in(ply);
+ return true;
+ }
}
// nCheck
connect_directions.push_back(SOUTH_EAST);
}
- for (char c : castlingWins) {
- switch (c) {
- case 'K': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | WHITE_OO); break;
- case 'Q': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | WHITE_OOO); break;
- case 'k': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | BLACK_OO); break;
- case 'q': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | BLACK_OOO); break;
- }
- }
-
return this;
}
bool connectDiagonal = true;
MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
CountingRule countingRule = NO_COUNTING;
- std::string castlingWins = "";
+ CastlingRights castlingWins = NO_CASTLING;
// Derived properties
bool fastAttacks = true;
bool endgameEval = false;
bool shogiStylePromotions = false;
std::vector<Direction> connect_directions;
- CastlingRights castlingWinConditions = NO_CASTLING;
void add_piece(PieceType pt, char c, std::string betza = "", char c2 = ' ') {
// Avoid ambiguous definition by removing existing piece with same letter
# [int]: any natural number [0, 1, ...]
# [PieceType]: a piece type [letters defined for pieces, e.g., p]
# [PieceSet]: multiple piece types [letters defined for pieces, e.g., nbrq]
+# [CastlingRights]: set of castling rights [letters for castling rights as in FEN, e.g., KQkq]
# [Bitboard]: list of squares [e.g., d4 e4 d5 e5]. * can be used as wildcard for files (e.g., *1 is the first rank)
# [Value]: game result for the side to move [win, loss, draw]
# [MaterialCounting]: material counting rules for adjudication [janggi, unweighted, whitedrawodds, blackdrawodds, none]
# connectDiagonal: connectN looks at Diagonal rows [bool] (default: true)
# materialCounting: enable material counting rules [MaterialCounting] (default: none)
# countingRule: enable counting rules [CountingRule] (default: none)
-# castlingWins: Specified castling moves are win conditions. Losing these rights is losing. (ie. KQkq) [string] (default: "")
+# castlingWins: Specified castling moves are win conditions. Losing these rights is losing. [CastlingRights] (default: -)
################################################
### Example for minishogi configuration that would be equivalent to the built-in variant: