moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(&b));
// Passing move by king
- if (pos.king_pass())
+ if (pos.pass())
*moveList++ = make<SPECIAL>(ksq, ksq);
if (Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO)))
moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, ksq, pos.castling_rook_square(OOO));
}
}
+ // Workaround for passing: Execute a non-move with any piece
+ else if (pos.pass() && !pos.count<KING>(Us) && pos.pieces(Us))
+ *moveList++ = make<SPECIAL>(lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));
// Castling with non-king piece
if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO)))
Bitboard sliders = pos.checkers();
// Passing move by king in bikjang
- if (pos.bikjang() && pos.king_pass())
+ if (pos.bikjang() && pos.pass())
*moveList++ = make<SPECIAL>(ksq, ksq);
// Consider all evasion moves for special pieces
parse_attribute("firstRankPawnDrops", v->firstRankPawnDrops);
parse_attribute("promotionZonePawnDrops", v->promotionZonePawnDrops);
parse_attribute("dropOnTop", v->dropOnTop);
+ parse_attribute("enclosingDrop", v->enclosingDrop);
+ parse_attribute("enclosingDropStart", v->enclosingDropStart);
parse_attribute("whiteDropRegion", v->whiteDropRegion);
parse_attribute("blackDropRegion", v->blackDropRegion);
parse_attribute("sittuyinRookDrop", v->sittuyinRookDrop);
parse_attribute("seirawanGating", v->seirawanGating);
parse_attribute("cambodianMoves", v->cambodianMoves);
parse_attribute("diagonalLines", v->diagonalLines);
- parse_attribute("kingPass", v->kingPass);
- parse_attribute("kingPassOnStalemate", v->kingPassOnStalemate);
+ parse_attribute("pass", v->pass);
+ parse_attribute("passOnStalemate", v->passOnStalemate);
parse_attribute("makpongRule", v->makpongRule);
parse_attribute("flyingGeneral", v->flyingGeneral);
parse_attribute("soldierPromotionRank", v->soldierPromotionRank);
+ parse_attribute("flipEnclosedPieces", v->flipEnclosedPieces);
// game end
parse_attribute("nMoveRule", v->nMoveRule);
parse_attribute("nFoldRule", v->nFoldRule);
parse_attribute("nFoldValueAbsolute", v->nFoldValueAbsolute);
parse_attribute("perpetualCheckIllegal", v->perpetualCheckIllegal);
parse_attribute("stalemateValue", v->stalemateValue);
+ parse_attribute("stalematePieceCount", v->stalematePieceCount);
parse_attribute("checkmateValue", v->checkmateValue);
parse_attribute("shogiPawnDropMateIllegal", v->shogiPawnDropMateIllegal);
parse_attribute("shatarMateRule", v->shatarMateRule);
return false;
// Illegal king passing move
- if (king_pass_on_stalemate() && is_pass(m) && !checkers())
+ if (pass_on_stalemate() && is_pass(m) && !checkers())
{
for (const auto& move : MoveList<NON_EVASIONS>(*this))
if (!is_pass(move) && legal(move))
Piece captured = type_of(m) == ENPASSANT ? make_piece(them, PAWN) : piece_on(to);
if (to == from)
{
- assert((type_of(m) == PROMOTION && sittuyin_promotion()) || (is_pass(m) && king_pass()));
+ assert((type_of(m) == PROMOTION && sittuyin_promotion()) || (is_pass(m) && pass()));
captured = NO_PIECE;
}
st->capturedpromoted = is_promoted(to);
set_castling_right(us, to);
}
}
+ // Flip enclosed pieces
+ if (flip_enclosed_pieces())
+ {
+ st->flippedPieces = 0;
+ // Find end of rows to be flipped
+ Bitboard b = attacks_bb(us, QUEEN, to, board_bb() & ~pieces(~us)) & ~PseudoAttacks[us][KING][to] & pieces(us);
+ while(b)
+ st->flippedPieces |= between_bb(to, pop_lsb(&b));
+ // Flip pieces
+ Bitboard to_flip = st->flippedPieces;
+ while(to_flip)
+ {
+ Square s = pop_lsb(&to_flip);
+ Piece flipped = piece_on(s);
+ Piece resulting = ~flipped;
+
+ // remove opponent's piece
+ remove_piece(s);
+ k ^= Zobrist::psq[flipped][s];
+ st->materialKey ^= Zobrist::psq[flipped][pieceCount[flipped]];
+ st->nonPawnMaterial[them] -= PieceValue[MG][flipped];
+
+ // add our piece
+ put_piece(resulting, s);
+ k ^= Zobrist::psq[resulting][s];
+ st->materialKey ^= Zobrist::psq[resulting][pieceCount[resulting]-1];
+ st->nonPawnMaterial[us] += PieceValue[MG][resulting];
+ }
+ }
}
else if (type_of(m) != CASTLING)
move_piece(from, to);
assert(type_of(m) == DROP || empty(from) || type_of(m) == CASTLING || is_gating(m)
|| (type_of(m) == PROMOTION && sittuyin_promotion())
- || (is_pass(m) && king_pass()));
+ || (is_pass(m) && pass()));
assert(type_of(st->capturedPiece) != KING);
// Remove gated piece
else
{
if (type_of(m) == DROP)
+ {
+ if (flip_enclosed_pieces())
+ {
+ // Flip pieces
+ Bitboard to_flip = st->flippedPieces;
+ while(to_flip)
+ {
+ Square s = pop_lsb(&to_flip);
+ Piece resulting = ~piece_on(s);
+ remove_piece(s);
+ put_piece(resulting, s);
+ }
+ }
undrop_piece(make_piece(us, in_hand_piece_type(m)), to); // Remove the dropped piece
+ }
else
move_piece(to, from); // Put the piece back at the source square
Bitboard blockersForKing[COLOR_NB];
Bitboard pinners[COLOR_NB];
Bitboard checkSquares[PIECE_TYPE_NB];
+ Bitboard flippedPieces;
bool capturedpromoted;
bool shak;
bool bikjang;
bool captures_to_hand() const;
bool first_rank_pawn_drops() const;
bool drop_on_top() const;
+ bool enclosing_drop() const;
Bitboard drop_region(Color c) const;
Bitboard drop_region(Color c, PieceType pt) const;
bool sittuyin_rook_drop() const;
bool seirawan_gating() const;
bool cambodian_moves() const;
Bitboard diagonal_lines() const;
- bool king_pass() const;
- bool king_pass_on_stalemate() const;
+ bool pass() const;
+ bool pass_on_stalemate() const;
Bitboard promoted_soldiers(Color c) const;
bool makpong() const;
+ bool flip_enclosed_pieces() const;
// winning conditions
int n_move_rule() const;
int n_fold_rule() const;
return var->dropOnTop;
}
+inline bool Position::enclosing_drop() const {
+ assert(var != nullptr);
+ return var->enclosingDrop;
+}
+
inline Bitboard Position::drop_region(Color c) const {
assert(var != nullptr);
return c == WHITE ? var->whiteDropRegion : var->blackDropRegion;
if (pt == ROOK && sittuyin_rook_drop())
b &= rank_bb(relative_rank(c, RANK_1, max_rank()));
+ // Filter out squares where the drop does not enclose at least one opponent's piece
+ if (enclosing_drop())
+ {
+ // Reversi start
+ if (var->enclosingDropStart & ~pieces())
+ b &= var->enclosingDropStart;
+ else
+ {
+ Bitboard theirs = pieces(~c);
+ b &= shift<NORTH >(theirs) | shift<SOUTH >(theirs)
+ | shift<NORTH_EAST>(theirs) | shift<SOUTH_WEST>(theirs)
+ | shift<EAST >(theirs) | shift<WEST >(theirs)
+ | shift<SOUTH_EAST>(theirs) | shift<NORTH_WEST>(theirs);
+ Bitboard b2 = b;
+ while (b2)
+ {
+ Square s = pop_lsb(&b2);
+ if (!(attacks_bb(c, QUEEN, s, board_bb() & ~pieces(~c)) & ~PseudoAttacks[c][KING][s] & pieces(c)))
+ b ^= s;
+ }
+ }
+ }
+
return b;
}
return var->diagonalLines;
}
-inline bool Position::king_pass() const {
+inline bool Position::pass() const {
assert(var != nullptr);
- return var->kingPass || var->kingPassOnStalemate;
+ return var->pass || var->passOnStalemate;
}
-inline bool Position::king_pass_on_stalemate() const {
+inline bool Position::pass_on_stalemate() const {
assert(var != nullptr);
- return var->kingPassOnStalemate;
+ return var->passOnStalemate;
}
inline Bitboard Position::promoted_soldiers(Color c) const {
return var->nFoldRule;
}
+inline bool Position::flip_enclosed_pieces() const {
+ assert(var != nullptr);
+ return var->flipEnclosedPieces;
+}
+
inline Value Position::stalemate_value(int ply) const {
assert(var != nullptr);
if (var->stalematePieceCount)
v->materialCounting = JANGGI_MATERIAL;
v->diagonalLines = make_bitboard(SQ_D1, SQ_F1, SQ_E2, SQ_D3, SQ_F3,
SQ_D8, SQ_F8, SQ_E9, SQ_D10, SQ_F10);
- v->kingPass = true;
+ v->pass = true;
v->nFoldValue = VALUE_DRAW;
v->perpetualCheckIllegal = true;
return v;
bool firstRankPawnDrops = false;
bool promotionZonePawnDrops = false;
bool dropOnTop = false;
+ bool enclosingDrop = false;
+ Bitboard enclosingDropStart = 0;
Bitboard whiteDropRegion = AllSquares;
Bitboard blackDropRegion = AllSquares;
bool sittuyinRookDrop = false;
bool seirawanGating = false;
bool cambodianMoves = false;
Bitboard diagonalLines = 0;
- bool kingPass = false;
- bool kingPassOnStalemate = false;
+ bool pass = false;
+ bool passOnStalemate = false;
bool makpongRule = false;
bool flyingGeneral = false;
Rank soldierPromotionRank = RANK_1;
+ bool flipEnclosedPieces = false;
// game end
int nMoveRule = 50;
int nFoldRule = 3;
# firstRankPawnDrops: allow pawn drops to first rank [bool] (default: false)
# promotionZonePawnDrops: allow pawn drops in promotion zone [bool] (default: false)
# dropOnTop: piece drops need to be on top of pieces on board (e.g., for connect4) [bool] (default: false)
+# enclosingDrop: require piece drop to enclose opponent's pieces (e.g., for othello) [bool] (default: false)
+# enclosingDropStart: drop region for starting phase disregarding enclosingDrop (e.g., for reversi) [Bitboard]
# whiteDropRegion: restrict region for piece drops of all white pieces [Bitboard]
# blackDropRegion: restrict region for piece drops of all black pieces [Bitboard]
# sittuyinRookDrop: restrict region of rook drops to first rank [bool] (default: false)
# seirawanGating: allow gating of pieces in hand like in S-Chess, requires "gating = true" [bool] (default: false)
# cambodianMoves: enable special moves of cambodian chess, requires "gating = true" [bool] (default: false)
# diagonalLines: enable special moves along diagonal for specific squares (Janggi) [Bitboard]
-# kingPass: allow passing by king [bool] (default: false)
-# kingPassOnStalemate: allow passing by king in case of stalemate [bool] (default: false)
+# pass: allow passing [bool] (default: false)
+# passOnStalemate: allow passing in case of stalemate [bool] (default: false)
# makpongRule: the king may not move away from check [bool] (default: false)
# flyingGeneral: disallow general face-off like in xiangqi [bool] (default: false)
# soldierPromotionRank: restrict soldier to shogi pawn movements until reaching n-th rank [bool] (default: 1)
+# flipEnclosedPieces: change color of pieces that are enclosed by a drop (e.g., for othello) [bool] (default: false)
# nMoveRule: move count for 50/n-move rule [int] (default: 50)
# nFoldRule: move count for 3/n-fold repetition rule [int] (default: 3)
# nFoldValue: result in case of 3/n-fold repetition [Value] (default: draw)
# nFoldValueAbsolute: result in case of 3/n-fold repetition is from white's point of view [bool] (default: false)
# perpetualCheckIllegal: prohibit perpetual checks [bool] (default: false)
# stalemateValue: result in case of stalemate [Value] (default: draw)
+# stalematePieceCount: count material in case of stalemate [bool] (default: false)
# checkmateValue: result in case of checkmate [Value] (default: loss)
# shogiPawnDropMateIllegal: prohibit checkmate via shogi pawn drops [bool] (default: false)
# shatarMateRule: enable shatar mating rules [bool] (default: false)
connectN = 4
nMoveRule = 0
+[reversi]
+immobile = p
+startFen = 8/8/8/8/8/8/8/8[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppp] w 0 1
+pieceDrops = true
+promotionPieceTypes = -
+doubleStep = false
+castling = false
+stalemateValue = loss
+stalematePieceCount = true
+materialCounting = unweighted
+enclosingDrop = true
+enclosingDropStart = d4 e4 d5 e5
+immobilityIllegal = false
+flipEnclosedPieces = true
+passOnStalemate = false
+
+[othello:reversi]
+startFen = 8/8/8/3pP3/3Pp3/8/8/8[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppp] w 0 1
+passOnStalemate = true
+
[grandhouse:grand]
startFen = r8r/1nbqkcabn1/pppppppppp/10/10/10/10/PPPPPPPPPP/1NBQKCABN1/R8R[] w - - 0 1
pieceDrops = true
std::getline(is >> std::ws, fen);
// Check if setboard actually indicates a passing move
// to avoid unnecessarily clearing the move history
- if (pos.king_pass())
+ if (pos.pass())
{
StateInfo st;
Position p;