Skip to content

Commit

Permalink
Merge remote-tracking branch 'fairy/master' into tools
Browse files Browse the repository at this point in the history
  • Loading branch information
ianfab committed Sep 10, 2023
2 parents a7e7722 + 5f98659 commit abfd218
Show file tree
Hide file tree
Showing 15 changed files with 315 additions and 84 deletions.
2 changes: 1 addition & 1 deletion src/apiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ inline const std::string move_to_san(Position& pos, Move m, Notation n) {
}

// Wall square
if (pos.wall_gating())
if (pos.walling())
san += "," + square(pos, gating_square(m), n);

// Check and checkmate
Expand Down
11 changes: 7 additions & 4 deletions src/evaluate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,13 @@ namespace Eval {
exit(EXIT_FAILURE);
}

if (useNNUE != UseNNUEMode::False)
sync_cout << "info string NNUE evaluation using " << eval_file << " enabled" << sync_endl;
else
sync_cout << "info string classical evaluation enabled" << sync_endl;
if (CurrentProtocol != XBOARD)
{
if (useNNUE != UseNNUEMode::False)
sync_cout << "info string NNUE evaluation using " << eval_file_loaded << " enabled" << sync_endl;
else
sync_cout << "info string classical evaluation enabled" << sync_endl;
}
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace {
ExtMove* make_move_and_gating(const Position& pos, ExtMove* moveList, Color us, Square from, Square to, PieceType pt = NO_PIECE_TYPE) {

// Wall placing moves
if (pos.wall_gating())
if (pos.walling())
{
Bitboard b = pos.board_bb() & ~((pos.pieces() ^ from) | to);
if (T == CASTLING)
Expand All @@ -41,11 +41,11 @@ namespace {
}
if (T == EN_PASSANT)
b ^= pos.capture_square(to);
if (pos.variant()->arrowGating)
if (pos.variant()->arrowWalling)
b &= moves_bb(us, type_of(pos.piece_on(from)), to, pos.pieces() ^ from);
if (pos.variant()->staticGating)
b &= pos.variant()->staticGatingRegion;
if (pos.variant()->pastGating)
if ((pos.variant()->staticWalling)||(pos.variant()->duckWalling))
b &= pos.variant()->wallingRegion[us];
if (pos.variant()->pastWalling)
b &= square_bb(from);

while (b)
Expand Down
50 changes: 39 additions & 11 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ namespace {
template <> bool set(const std::string& value, EnclosingRule& target) {
target = value == "reversi" ? REVERSI
: value == "ataxx" ? ATAXX
: value == "quadwrangle" ? QUADWRANGLE
: NO_ENCLOSING;
return value == "reversi" || value == "ataxx" || value == "none";
return value == "reversi" || value == "ataxx" || value == "quadwrangle" || value == "none";
}

template <> bool set(const std::string& value, Bitboard& target) {
Expand All @@ -123,6 +124,27 @@ namespace {
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);
}
Expand Down Expand Up @@ -157,6 +179,7 @@ template <bool Current, class T> bool VariantParser<DoCheck>::parse_attribute(co
: 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;
}
Expand Down Expand Up @@ -387,6 +410,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("castlingRookPieces", v->castlingRookPieces[BLACK], v->pieceToChar);
parse_attribute("castlingRookPiecesWhite", v->castlingRookPieces[WHITE], v->pieceToChar);
parse_attribute("castlingRookPiecesBlack", v->castlingRookPieces[BLACK], v->pieceToChar);
parse_attribute("oppositeCastling", v->oppositeCastling);
parse_attribute("checking", v->checking);
parse_attribute("dropChecks", v->dropChecks);
parse_attribute("mustCapture", v->mustCapture);
Expand All @@ -409,11 +433,14 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("dropNoDoubledCount", v->dropNoDoubledCount);
parse_attribute("immobilityIllegal", v->immobilityIllegal);
parse_attribute("gating", v->gating);
parse_attribute("arrowGating", v->arrowGating);
parse_attribute("duckGating", v->duckGating);
parse_attribute("staticGating", v->staticGating);
parse_attribute("pastGating", v->pastGating);
parse_attribute("staticGatingRegion", v->staticGatingRegion);
parse_attribute("arrowWalling", v->arrowWalling);
parse_attribute("duckWalling", v->duckWalling);
parse_attribute("wallingRegionWhite", v->wallingRegion[WHITE]);
parse_attribute("wallingRegionBlack", v->wallingRegion[BLACK]);
parse_attribute("wallingRegion", v->wallingRegion[WHITE]);
parse_attribute("wallingRegion", v->wallingRegion[BLACK]);
parse_attribute("staticWalling", v->staticWalling);
parse_attribute("pastWalling", v->pastWalling);
parse_attribute("seirawanGating", v->seirawanGating);
parse_attribute("cambodianMoves", v->cambodianMoves);
parse_attribute("diagonalLines", v->diagonalLines);
Expand Down Expand Up @@ -467,7 +494,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("connectDiagonal", v->connectDiagonal);
parse_attribute("materialCounting", v->materialCounting);
parse_attribute("countingRule", v->countingRule);

parse_attribute("castlingWins", v->castlingWins);

// Report invalid options
if (DoCheck)
{
Expand Down Expand Up @@ -524,8 +552,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
std::cerr << "Inconsistent settings: castlingQueensideFile > castlingKingsideFile." << std::endl;

// Check for limitations
if (v->pieceDrops && (v->arrowGating || v->duckGating || v->staticGating || v->pastGating))
std::cerr << "pieceDrops and arrowGating/duckGating are incompatible." << std::endl;
if (v->pieceDrops && (v->arrowWalling || v->duckWalling || v->staticWalling || v->pastWalling))
std::cerr << "pieceDrops and arrowWalling/duckWalling are incompatible." << std::endl;

// Options incompatible with royal kings
if (v->pieceTypes & KING)
Expand All @@ -534,8 +562,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
std::cerr << "Can not use kings with blastOnCapture." << std::endl;
if (v->flipEnclosedPieces)
std::cerr << "Can not use kings with flipEnclosedPieces." << std::endl;
if (v->duckGating)
std::cerr << "Can not use kings with duckGating." << std::endl;
if (v->duckWalling)
std::cerr << "Can not use kings with duckWalling." << std::endl;
// We can not fully check support for custom king movements at this point,
// since custom pieces are only initialized on loading of the variant.
// We will assume this is valid, but it might cause problems later if it's not.
Expand Down
4 changes: 2 additions & 2 deletions src/piece.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ namespace {
v[Direction(atom.first * FILE_NB + atom.second)] = distance;
if (directions.size() == 0 || has_dir("bb") || has_dir("vv") || has_dir("lb") || has_dir("lv") || has_dir("bh") || has_dir("lh") || has_dir("hr"))
v[Direction(-atom.first * FILE_NB - atom.second)] = distance;
if (directions.size() == 0 || has_dir("rr") || has_dir("ss") || has_dir("br") || has_dir("bs") || has_dir("bh") || has_dir("lh") || has_dir("hr"))
if (directions.size() == 0 || has_dir("rr") || has_dir("ss") || has_dir("br") || has_dir("bs") || has_dir("bh") || has_dir("rh") || has_dir("hr"))
v[Direction(-atom.second * FILE_NB + atom.first)] = distance;
if (directions.size() == 0 || has_dir("ll") || has_dir("ss") || has_dir("fl") || has_dir("fs") || has_dir("fh") || has_dir("rh") || has_dir("hr"))
if (directions.size() == 0 || has_dir("ll") || has_dir("ss") || has_dir("fl") || has_dir("fs") || has_dir("fh") || has_dir("lh") || has_dir("hr"))
v[Direction(atom.second * FILE_NB - atom.first)] = distance;
if (directions.size() == 0 || has_dir("rr") || has_dir("ss") || has_dir("fr") || has_dir("fs") || has_dir("fh") || has_dir("rh") || has_dir("hl"))
v[Direction(atom.second * FILE_NB + atom.first)] = distance;
Expand Down
85 changes: 63 additions & 22 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,

ss >> std::noskipws;

Square sq = SQ_A1 + max_rank() * NORTH;
Rank r = max_rank();
Square sq = SQ_A1 + r * NORTH;

// 1. Piece placement
while ((ss >> token) && !isspace(token))
Expand All @@ -288,11 +289,19 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,

else if (token == '/')
{
sq += 2 * SOUTH + (FILE_MAX - max_file()) * EAST;
sq = SQ_A1 + --r * NORTH;
if (!is_ok(sq))
break;
}

// Stop before pieces in hand
else if (token == '[')
break;

// Ignore pieces outside the board and wait for next / or [ to return to a valid state
else if (!is_ok(sq) || file_of(sq) > max_file() || rank_of(sq) > r)
continue;

// Wall square
else if (token == '*')
{
Expand All @@ -316,10 +325,6 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
put_piece(make_piece(color_of(Piece(idx)), promoted_piece_type(type_of(Piece(idx)))), sq, true, Piece(idx));
++sq;
}

// Stop before pieces in hand
else if (token == '[')
break;
}
// Pieces in hand
if (!isspace(token))
Expand Down Expand Up @@ -1104,9 +1109,9 @@ bool Position::legal(Move m) const {
{
Square kto = to;
Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces());
if (var->duckGating)
if (var->duckWalling)
occupied ^= st->wallSquares;
if (wall_gating() || is_gating(m))
if (walling() || is_gating(m))
occupied |= gating_square(m);
if (type_of(m) == CASTLING)
{
Expand Down Expand Up @@ -1301,15 +1306,15 @@ bool Position::pseudo_legal(const Move m) const {
: MoveList<NON_EVASIONS>(*this).contains(m);

// Illegal wall square placement
if (wall_gating() && !((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
if (walling() && !((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
return false;
if (var->arrowGating && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
if (var->arrowWalling && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
return false;
if (var->pastGating && (from != gating_square(m)))
if (var->pastWalling && (from != gating_square(m)))
return false;
if (var->staticGating && !(var->staticGatingRegion & gating_square(m)))
if ((var->staticWalling || var->duckWalling) && !(var->wallingRegion[us] & gating_square(m)))
return false;

// Handle the case where a mandatory piece promotion/demotion is not taken
if ( mandatory_piece_promotion()
&& (is_promoted(from) ? piece_demotion() : promoted_piece_type(type_of(pc)) != NO_PIECE_TYPE)
Expand Down Expand Up @@ -1664,6 +1669,13 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
{
k ^= Zobrist::castling[st->castlingRights];
st->castlingRights &= ~(castlingRightsMask[from] | castlingRightsMask[to]);

// Remove castling rights from opponent on the same side if oppositeCastling
if ((var->oppositeCastling) && (type_of(m) == CASTLING))
{
bool kingSide = to > from;
st->castlingRights &= ~(~us & (kingSide ? KING_SIDE : QUEEN_SIDE));
}
k ^= Zobrist::castling[st->castlingRights];
}

Expand All @@ -1680,8 +1692,11 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
}
else
{
assert(flip_enclosed_pieces() == ATAXX);
st->flippedPieces = PseudoAttacks[us][KING][to] & pieces(~us);
assert((flip_enclosed_pieces() == ATAXX) || (flip_enclosed_pieces() == QUADWRANGLE));
if ((flip_enclosed_pieces() == ATAXX) || (flip_enclosed_pieces() == QUADWRANGLE && (PseudoAttacks[us][KING][to] & pieces(us) || type_of(m) == NORMAL)))
{
st->flippedPieces = PseudoAttacks[us][KING][to] & pieces(~us);
}
}

// Flip pieces
Expand Down Expand Up @@ -1805,15 +1820,15 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
{
if ( (var->enPassantRegion & (to - pawn_push(us)))
&& ((pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN))
&& !(wall_gating() && gating_square(m) == to - pawn_push(us)))
&& !(walling() && gating_square(m) == to - pawn_push(us)))
{
st->epSquares |= to - pawn_push(us);
k ^= Zobrist::enpassant[file_of(to)];
}
if ( std::abs(int(to) - int(from)) == 3 * NORTH
&& (var->enPassantRegion & (to - 2 * pawn_push(us)))
&& ((pawn_attacks_bb(us, to - 2 * pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN))
&& !(wall_gating() && gating_square(m) == to - 2 * pawn_push(us)))
&& !(walling() && gating_square(m) == to - 2 * pawn_push(us)))
{
st->epSquares |= to - 2 * pawn_push(us);
k ^= Zobrist::enpassant[file_of(to)];
Expand Down Expand Up @@ -2018,10 +2033,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
}

// Add gated wall square
if (wall_gating())
if (walling())
{
// Reset wall squares for duck gating
if (var->duckGating)
// Reset wall squares for duck walling
if (var->duckWalling)
{
Bitboard b = st->previous->wallSquares;
byTypeBB[ALL_PIECES] ^= b;
Expand Down Expand Up @@ -2460,7 +2475,7 @@ bool Position::see_ge(Move m, Value threshold) const {
stmAttackers &= ~blockers_for_king(stm);

// Ignore distant sliders
if (var->duckGating)
if (var->duckWalling)
stmAttackers &= attacks_bb<KING>(to) | ~(pieces(BISHOP, ROOK) | pieces(QUEEN));

if (!stmAttackers)
Expand Down Expand Up @@ -2727,6 +2742,32 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
return true;
}
}

// Castle chess
if (var->castlingWins)
{
if (st->pliesFromNull > 0 && type_of(st->move) == CASTLING)
{
// 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;
}
}
// 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
if (check_counting() && checks_remaining(~sideToMove) == 0)
{
Expand Down Expand Up @@ -2927,7 +2968,7 @@ bool Position::has_game_cycle(int ply) const {

int end = captures_to_hand() ? st->pliesFromNull : std::min(st->rule50, st->pliesFromNull);

if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal || var->duckGating)
if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal || var->duckWalling)
return false;

Key originalKey = st->key;
Expand Down
6 changes: 3 additions & 3 deletions src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class Position {
PieceType drop_no_doubled() const;
bool immobility_illegal() const;
bool gating() const;
bool wall_gating() const;
bool walling() const;
bool seirawan_gating() const;
bool cambodian_moves() const;
Bitboard diagonal_lines() const;
Expand Down Expand Up @@ -778,9 +778,9 @@ inline bool Position::gating() const {
return var->gating;
}

inline bool Position::wall_gating() const {
inline bool Position::walling() const {
assert(var != nullptr);
return var->arrowGating || var->duckGating || var->staticGating || var->pastGating;
return var->arrowWalling || var->duckWalling || var->staticWalling || var->pastWalling;
}

inline bool Position::seirawan_gating() const {
Expand Down
Loading

0 comments on commit abfd218

Please sign in to comment.