}
-/// promotion_zone_bb() returns a bitboard representing the squares on all the ranks
+/// zone_bb() returns a bitboard representing the squares on all the ranks
/// in front of and on the given relative rank, from the point of view of the given color.
-/// For instance, promotion_zone_bb(BLACK, RANK_7) will return the 16 squares on ranks 1 and 2.
+/// For instance, zone_bb(BLACK, RANK_7) will return the 16 squares on ranks 1 and 2.
-inline Bitboard promotion_zone_bb(Color c, Rank r, Rank maxRank) {
+inline Bitboard zone_bb(Color c, Rank r, Rank maxRank) {
return forward_ranks_bb(c, relative_rank(c, r, maxRank)) | rank_bb(relative_rank(c, r, maxRank));
}
// Piece promotion bonus
if (pos.promoted_piece_type(Pt) != NO_PIECE_TYPE)
{
- Bitboard zone = promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank());
+ Bitboard zone = zone_bb(Us, pos.promotion_rank(), pos.max_rank());
if (zone & (b | s))
score += make_score(PieceValue[MG][pos.promoted_piece_type(Pt)] - PieceValue[MG][Pt],
PieceValue[EG][pos.promoted_piece_type(Pt)] - PieceValue[EG][Pt]) / (zone & s && b ? 6 : 12);
const Square ksq = pos.count<KING>(Them) ? pos.square<KING>(Them) : SQ_NONE;
Bitboard TRank8BB = pos.mandatory_pawn_promotion() ? rank_bb(relative_rank(Us, pos.promotion_rank(), pos.max_rank()))
- : promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank());
+ : zone_bb(Us, pos.promotion_rank(), pos.max_rank());
Bitboard TRank7BB = shift<Down>(TRank8BB);
// Define squares a pawn can pass during a double step
- Bitboard TRank3BB = rank_bb(relative_rank(Us, Rank(pos.double_step_rank() + 1), pos.max_rank()));
- if (pos.first_rank_double_steps())
- TRank3BB |= rank_bb(relative_rank(Us, RANK_2, pos.max_rank()));
+ Bitboard TRank3BB = forward_ranks_bb(Us, relative_rank(Us, pos.double_step_rank_min(), pos.max_rank()))
+ & ~shift<Up>(forward_ranks_bb(Us, relative_rank(Us, pos.double_step_rank_max(), pos.max_rank())));
Bitboard emptySquares;
if (pos.ep_square() != SQ_NONE)
{
- assert(rank_of(pos.ep_square()) == relative_rank(Them, Rank(pos.double_step_rank() + 1), pos.max_rank()));
+ assert(relative_rank(Them, rank_of(pos.ep_square()), pos.max_rank()) <= Rank(pos.double_step_rank_max() + 1));
// An en passant capture can be an evasion only if the checking piece
// is the double pushed pawn and so is in the target. Otherwise this
// Restrict target squares considering promotion zone
if (b2 | b3)
{
- Bitboard promotion_zone = promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank());
+ Bitboard promotion_zone = zone_bb(Us, pos.promotion_rank(), pos.max_rank());
if (pos.mandatory_piece_promotion())
b1 &= (promotion_zone & from ? Bitboard(0) : ~promotion_zone) | (pos.piece_promotion_on_capture() ? ~pos.pieces() : Bitboard(0));
// Exclude quiet promotions/demotions
parse_attribute("endgameEval", v->endgameEval);
parse_attribute("doubleStep", v->doubleStep);
parse_attribute("doubleStepRank", v->doubleStepRank);
- parse_attribute("firstRankDoubleSteps", v->firstRankDoubleSteps);
+ parse_attribute("doubleStepRankMin", v->doubleStepRankMin);
+ parse_attribute("enPassantRegion", v->enPassantRegion);
parse_attribute("castling", v->castling);
parse_attribute("castlingDroppedPiece", v->castlingDroppedPiece);
parse_attribute("castlingKingsideFile", v->castlingKingsideFile);
// 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)
- && (promotion_zone_bb(us, promotion_rank(), max_rank()) & (SquareBB[from] | to))
+ && (zone_bb(us, promotion_rank(), max_rank()) & (SquareBB[from] | to))
&& (!piece_promotion_on_capture() || capture(m)))
return false;
if ( !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture
&& !((from + pawn_push(us) == to) && empty(to)) // Not a single push
&& !( (from + 2 * pawn_push(us) == to) // Not a double push
- && (rank_of(from) == relative_rank(us, double_step_rank(), max_rank())
- || (first_rank_double_steps() && rank_of(from) == relative_rank(us, RANK_1, max_rank())))
+ && ( relative_rank(us, from, max_rank()) <= double_step_rank_max()
+ && relative_rank(us, from, max_rank()) >= double_step_rank_min())
&& empty(to)
&& empty(to - pawn_push(us))
&& double_step_enabled()))
assert(pc == make_piece(us, PAWN));
assert(to == st->epSquare);
- assert(relative_rank(~us, to, max_rank()) == Rank(double_step_rank() + 1));
+ assert((var->enPassantRegion & to)
+ && relative_rank(~us, to, max_rank()) <= Rank(double_step_rank_max() + 1)
+ && relative_rank(~us, to, max_rank()) > double_step_rank_min());
assert(piece_on(to) == NO_PIECE);
assert(piece_on(capsq) == make_piece(them, PAWN));
}
{
// Set en-passant square if the moved pawn can be captured
if ( std::abs(int(to) - int(from)) == 2 * NORTH
- && relative_rank(us, rank_of(from), max_rank()) == double_step_rank()
+ && (var->enPassantRegion & (to - pawn_push(us)))
&& (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)))
{
st->epSquare = to - pawn_push(us);
assert(type_of(pc) == PAWN);
assert(to == st->previous->epSquare);
- assert(relative_rank(~us, to, max_rank()) == Rank(double_step_rank() + 1));
+ assert(relative_rank(~us, to, max_rank()) <= Rank(double_step_rank_max() + 1));
assert(piece_on(capsq) == NO_PIECE);
assert(st->capturedPiece == make_piece(~us, PAWN));
}
|| (count<KING>(WHITE) && piece_on(square<KING>(WHITE)) != make_piece(WHITE, KING))
|| (count<KING>(BLACK) && piece_on(square<KING>(BLACK)) != make_piece(BLACK, KING))
|| ( ep_square() != SQ_NONE
- && relative_rank(~sideToMove, ep_square(), max_rank()) != Rank(double_step_rank() + 1)))
+ && relative_rank(~sideToMove, ep_square(), max_rank()) > Rank(double_step_rank_max() + 1)))
assert(0 && "pos_is_ok: Default");
if (Fast)
bool piece_demotion() const;
bool endgame_eval() const;
bool double_step_enabled() const;
- Rank double_step_rank() const;
- bool first_rank_double_steps() const;
+ Rank double_step_rank_max() const;
+ Rank double_step_rank_min() const;
bool castling_enabled() const;
bool castling_dropped_piece() const;
File castling_kingside_file() const;
return var->doubleStep;
}
-inline Rank Position::double_step_rank() const {
+inline Rank Position::double_step_rank_max() const {
assert(var != nullptr);
return var->doubleStepRank;
}
-inline bool Position::first_rank_double_steps() const {
+inline Rank Position::double_step_rank_min() const {
assert(var != nullptr);
- return var->firstRankDoubleSteps;
+ return var->doubleStepRankMin;
}
inline bool Position::castling_enabled() const {
if (pt == PAWN)
{
if (!var->promotionZonePawnDrops)
- b &= ~promotion_zone_bb(c, promotion_rank(), max_rank());
+ b &= ~zone_bb(c, promotion_rank(), max_rank());
if (!first_rank_pawn_drops())
b &= ~rank_bb(relative_rank(c, RANK_1, max_rank()));
}
inline Bitboard Position::promoted_soldiers(Color c) const {
assert(var != nullptr);
- return pieces(c, SOLDIER) & promotion_zone_bb(c, var->soldierPromotionRank, max_rank());
+ return pieces(c, SOLDIER) & zone_bb(c, var->soldierPromotionRank, max_rank());
}
inline bool Position::makpong() const {
}
inline bool Position::advanced_pawn_push(Move m) const {
- return type_of(moved_piece(m)) == PAWN
- && relative_rank(sideToMove, to_sq(m), max_rank()) > (max_rank() + 1) / 2;
+ return ( type_of(moved_piece(m)) == PAWN
+ && relative_rank(sideToMove, to_sq(m), max_rank()) > (max_rank() + 1) / 2)
+ || type_of(m) == ENPASSANT;
}
inline int Position::pawns_on_same_color_squares(Color c, Square s) const {
v->extinctionPieceCount = 2;
return v;
}
+ // Horde chess
+ // https://en.wikipedia.org/wiki/Dunsany%27s_chess#Horde_chess
Variant* horde_variant() {
Variant* v = fairy_variant_base();
v->startFen = "rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPP w kq - 0 1";
- v->firstRankDoubleSteps = true;
+ v->doubleStepRankMin = RANK_1;
+ v->enPassantRegion = Rank3BB | Rank6BB; // exclude en passant on second rank
v->extinctionValue = -VALUE_MATE;
v->extinctionPieceTypes = {ALL_PIECES};
return v;
v->add_piece(BREAKTHROUGH_PIECE, 'p');
v->startFen = "pppppppp/pppppppp/8/8/8/8/PPPPPPPP/PPPPPPPP w 0 1";
v->promotionPieceTypes = {};
- v->firstRankDoubleSteps = false;
v->doubleStep = false;
v->castling = false;
v->stalemateValue = -VALUE_MATE;
v->mandatoryPawnPromotion = false;
v->immobilityIllegal = true;
v->doubleStepRank = RANK_3;
+ v->doubleStepRankMin = RANK_3;
v->castling = false;
return v;
}
v->castlingQueensideFile = FILE_D;
v->castlingRank = RANK_2;
v->doubleStepRank = RANK_3;
+ v->doubleStepRankMin = RANK_3;
return v;
}
Variant* clobber10_variant() {
bool endgameEval = false;
bool doubleStep = true;
Rank doubleStepRank = RANK_2;
- bool firstRankDoubleSteps = false;
+ Rank doubleStepRankMin = RANK_2;
+ Bitboard enPassantRegion = AllSquares;
bool castling = true;
bool castlingDroppedPiece = false;
File castlingKingsideFile = FILE_G;
# endgameEval: enable special endgame evaluation (for very chess-like variants only) [bool] (default: false)
# doubleStep: enable pawn double step [bool] (default: true)
# doubleStepRank: relative rank from where pawn double steps are allowed [Rank] (default: 2)
-# firstRankDoubleSteps: enable pawn double steps from first rank [bool] (default: false)
+# doubleStepRankMin: earlist relative rank from where pawn double steps are allowed [Rank] (default: 2)
+# enPassantRegion: define region (target squares) where en passant is allowed after double steps [Bitboard]
# castling: enable castling [bool] (default: true)
# castlingDroppedPiece: enable castling with dropped rooks/kings [bool] (default: false)
# castlingKingsideFile: destination file of king after kingside castling [File] (default: g)
[weak:chess]
startFen = nnnnknnn/pppppppp/2p2p2/1pppppp1/8/8/PPPPPPPP/RNBQKBNR w KQ - 0 1
+[semitorpedo:chess]
+doubleStepRank = 3
+
# This variant is similar to Capablanca Chess, but with two archbishops and no chancellor piece.
[gemini:janus]
startFen = rnbaqkabnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNBAQKABNR w KQkq - 0 1
expect perft.exp euroshogi startpos 5 9451149 > /dev/null
expect perft.exp minishogi startpos 5 533203 > /dev/null
expect perft.exp kyotoshogi startpos 5 225903 > /dev/null
- expect perft.exp horde startpos 6 5396554 > /dev/null
+ expect perft.exp horde startpos 5 265223 > /dev/null
+ expect perft.exp horde "fen 4k3/7r/8/P7/2p1n2P/3p2P1/1P3P2/PPP1PPP1 w - - 0 1" 4 128809 > /dev/null
expect perft.exp placement startpos 4 1597696 > /dev/null
expect perft.exp sittuyin startpos 3 580096 > /dev/null
expect perft.exp sittuyin "fen 8/8/6R1/s3r3/P5R1/1KP3p1/1F2kr2/8[] b - - 0 72" 4 652686 > /dev/null