moveList = generate_moves<Checks>(pos, moveList, Us, pt, target);
// generate drops
if (pos.piece_drops() && Type != CAPTURES && pos.count_in_hand(Us, ALL_PIECES))
- for (PieceType pt = PAWN; pt < KING; ++pt)
- moveList = generate_drops<Us, Checks>(pos, moveList, pt, target & ~pos.pieces(~Us));
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ moveList = generate_drops<Us, Checks>(pos, moveList, pt, target & ~pos.pieces(~Us) & pos.drop_region(Us));
if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count<KING>(Us))
{
}
else if (token == '/')
+ {
sq += 2 * SOUTH + (FILE_MAX - max_file()) * EAST;
+ if (!is_ok(sq))
+ break;
+ }
else if ((idx = piece_to_char().find(token)) != string::npos)
{
{
ss << '[';
for (Color c = WHITE; c <= BLACK; ++c)
- for (PieceType pt = PieceType(KING - 1); pt >= PAWN; --pt)
+ for (PieceType pt = KING; pt >= PAWN; --pt)
ss << std::string(pieceCountInHand[c][pt], piece_to_char()[make_piece(c, pt)]);
ss << ']';
}
}
}
+ // illegal non-drop moves
+ if (must_drop() && type_of(m) != DROP && count_in_hand(us, ALL_PIECES))
+ {
+ if (checkers())
+ {
+ for (const auto& mevasion : MoveList<EVASIONS>(*this))
+ if (type_of(mevasion) == DROP && legal(mevasion))
+ return false;
+ }
+ else
+ {
+ for (const auto& mquiet : MoveList<QUIETS>(*this))
+ if (type_of(mquiet) == DROP && legal(mquiet))
+ return false;
+ }
+ }
+
+ // illegal drop move
+ if (drop_opposite_colored_bishop() && type_of(m) == DROP)
+ {
+ if (type_of(moved_piece(m)) != BISHOP)
+ {
+ Bitboard remaining = drop_region(us) & ~pieces() & ~SquareBB[to];
+ // Are enough squares available to drop bishops on opposite colors?
+ if ( (!( DarkSquares & pieces(us, BISHOP)) && ( DarkSquares & remaining))
+ + (!(~DarkSquares & pieces(us, BISHOP)) && (~DarkSquares & remaining)) < count_in_hand(us, BISHOP))
+ return false;
+ }
+ else
+ // Drop resulting in same-colored bishops
+ if ((DarkSquares & to ? DarkSquares : ~DarkSquares) & pieces(us, BISHOP))
+ return false;
+ }
+
// no legal moves from target square
if (immobility_illegal() && (type_of(m) == DROP || type_of(m) == NORMAL) && !(moves_bb(us, type_of(moved_piece(m)), to, 0) & board_bb()))
return false;
- // illegal drops
- if (piece_drops() && type_of(m) == DROP)
- return pieceCountInHand[us][type_of(moved_piece(m))] && empty(to_sq(m));
-
// game end
if (is_variant_end())
return false;
st->materialKey ^= Zobrist::psq[pc][pieceCount[pc]-1];
if (type_of(pc) != PAWN)
st->nonPawnMaterial[us] += PieceValue[MG][pc];
+ // Set castling rights for dropped king or rook
+ if (castling_dropped_piece() && relative_rank(us, to, max_rank()) == RANK_1)
+ {
+ if (type_of(pc) == KING && file_of(to) == FILE_E)
+ {
+ Bitboard castling_rooks = pieces(us, ROOK)
+ & rank_bb(relative_rank(us, RANK_1, max_rank()))
+ & (file_bb(FILE_A) | file_bb(max_file()));
+ while (castling_rooks)
+ set_castling_right(us, pop_lsb(&castling_rooks));
+ }
+ else if (type_of(pc) == ROOK)
+ {
+ if ( (file_of(to) == FILE_A || file_of(to) == max_file())
+ && piece_on(make_square(FILE_E, relative_rank(us, RANK_1, max_rank()))) == make_piece(us, KING))
+ set_castling_right(us, to);
+ }
+ }
}
else if (type_of(m) != CASTLING)
move_piece(pc, from, to);
bool double_step_enabled() const;
bool first_rank_double_steps() const;
bool castling_enabled() const;
+ bool castling_dropped_piece() const;
File castling_kingside_file() const;
File castling_queenside_file() const;
bool checking_permitted() const;
bool must_capture() const;
+ bool must_drop() const;
bool piece_drops() const;
bool drop_loop() const;
bool captures_to_hand() const;
bool first_rank_drops() const;
bool drop_on_top() const;
+ Bitboard drop_region(Color c) const;
+ bool drop_opposite_colored_bishop() const;
bool immobility_illegal() const;
// winning conditions
Value stalemate_value(int ply = 0) const;
return var->castling;
}
+inline bool Position::castling_dropped_piece() const {
+ assert(var != nullptr);
+ return var->castlingDroppedPiece;
+}
+
inline File Position::castling_kingside_file() const {
assert(var != nullptr);
return var->castlingKingsideFile;
return var->mustCapture;
}
+inline bool Position::must_drop() const {
+ assert(var != nullptr);
+ return var->mustDrop;
+}
+
inline bool Position::piece_drops() const {
assert(var != nullptr);
return var->pieceDrops;
return var->dropOnTop;
}
+inline Bitboard Position::drop_region(Color c) const {
+ assert(var != nullptr);
+ return c == WHITE ? var->whiteDropRegion : var->blackDropRegion;
+}
+
+inline bool Position::drop_opposite_colored_bishop() const {
+ assert(var != nullptr);
+ return var->dropOppositeColoredBishop;
+}
+
inline bool Position::immobility_illegal() const {
assert(var != nullptr);
return var->immobilityIllegal;
v->capturesToHand = false;
return v;
}
+ Variant* placement_variant() {
+ Variant* v = chess_variant();
+ v->startFen = "8/pppppppp/8/8/8/8/PPPPPPPP/8[KQRRBBNNkqrrbbnn] w - - 0 1";
+ v->mustDrop = true;
+ v->pieceDrops = true;
+ v->capturesToHand = false;
+ v->whiteDropRegion = Rank1BB;
+ v->blackDropRegion = Rank8BB;
+ v->dropOppositeColoredBishop = true;
+ v->castlingDroppedPiece = true;
+ return v;
+ }
Variant* euroshogi_variant() {
Variant* v = fairy_variant_base();
v->reset_pieces();
add("loop", loop_variant());
add("chessgi", chessgi_variant());
add("pocketknight", pocketknight_variant());
+ add("placement", placement_variant());
add("euroshogi", euroshogi_variant());
add("judkinshogi", judkinsshogi_variant());
add("minishogi", minishogi_variant());
bool doubleStep = true;
bool firstRankDoubleSteps = false;
bool castling = true;
+ bool castlingDroppedPiece = false;
File castlingKingsideFile = FILE_G;
File castlingQueensideFile = FILE_C;
bool checking = true;
bool mustCapture = false;
+ bool mustDrop = false;
bool pieceDrops = false;
bool dropLoop = false;
bool capturesToHand = false;
bool firstRankDrops = false;
bool dropOnTop = false;
+ Bitboard whiteDropRegion = AllSquares;
+ Bitboard blackDropRegion = AllSquares;
+ bool dropOppositeColoredBishop = false;
bool immobilityIllegal = false;
// game end
Value stalemateValue = VALUE_DRAW;
expect perft.exp euroshogi startpos 5 9451149 > /dev/null
expect perft.exp minishogi startpos 5 533203 > /dev/null
expect perft.exp horde startpos 6 5396554 > /dev/null
+expect perft.exp placement startpos 4 1597696 > /dev/null
rm perft.exp