- [Shogi](https://en.wikipedia.org/wiki/Shogi)
**Chess variants**
-- [Capablanca](https://en.wikipedia.org/wiki/Capablanca_Chess), [Janus](https://en.wikipedia.org/wiki/Janus_Chess), [Modern](https://en.wikipedia.org/wiki/Modern_Chess_(chess_variant)), [Chancellor](https://en.wikipedia.org/wiki/Chancellor_Chess), [Embassy](https://en.wikipedia.org/wiki/Embassy_Chess), [Gothic](https://www.chessvariants.com/large.dir/gothicchess.html), [Capablanca random chess](https://en.wikipedia.org/wiki/Capablanca_Random_Chess), [Shako](https://www.chessvariants.com/large.dir/shako.html)
+- [Capablanca](https://en.wikipedia.org/wiki/Capablanca_Chess), [Janus](https://en.wikipedia.org/wiki/Janus_Chess), [Modern](https://en.wikipedia.org/wiki/Modern_Chess_(chess_variant)), [Chancellor](https://en.wikipedia.org/wiki/Chancellor_Chess), [Embassy](https://en.wikipedia.org/wiki/Embassy_Chess), [Gothic](https://www.chessvariants.com/large.dir/gothicchess.html), [Capablanca random chess](https://en.wikipedia.org/wiki/Capablanca_Random_Chess)
+- [Grand](https://en.wikipedia.org/wiki/Grand_Chess), [Shako](https://www.chessvariants.com/large.dir/shako.html)
- [Chess960](https://en.wikipedia.org/wiki/Chess960), [Placement/Pre-Chess](https://www.chessvariants.com/link/placement-chess)
- [Crazyhouse](https://en.wikipedia.org/wiki/Crazyhouse), [Loop](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Chessgi](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Pocket Knight](http://www.chessvariants.com/other.dir/pocket.html)
- [Seirawan](https://en.wikipedia.org/wiki/Seirawan_chess)
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
for (PieceType pt : pos.promotion_piece_types())
- *moveList++ = make<PROMOTION>(to - D, to, pt);
+ if (!pos.promotion_limit(pt) || pos.promotion_limit(pt) > pos.count(c, pt))
+ *moveList++ = make<PROMOTION>(to - D, to, pt);
return moveList;
}
Bitboard emptySquares;
- Bitboard TRank8BB = rank_bb(Us == WHITE ? pos.promotion_rank() : Rank(pos.max_rank() - pos.promotion_rank()));
+ 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());
Bitboard TRank7BB = shift<Down>(TRank8BB);
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
- Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
+ Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & (pos.mandatory_pawn_promotion() ? ~TRank7BB : AllSquares);
Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
Type == CAPTURES ? target : pos.pieces(Them));
{
// We have already handled promotion moves, so destination
// cannot be on the 8th/1st rank.
- if (rank_of(to) == relative_rank(us, promotion_rank(), max_rank()))
+ if (mandatory_pawn_promotion() && (promotion_zone_bb(us, promotion_rank(), max_rank()) & to))
return false;
if ( !(attacks_from<PAWN>(us, from) & pieces(~us) & to) // Not a capture
{
Piece promotion = make_piece(us, promotion_type(m));
- assert(relative_rank(us, to, max_rank()) == promotion_rank() || sittuyin_promotion());
+ assert(relative_rank(us, to, max_rank()) >= promotion_rank() || sittuyin_promotion());
assert(type_of(promotion) >= KNIGHT && type_of(promotion) < KING);
remove_piece(pc, to);
if (type_of(m) == PROMOTION)
{
- assert(relative_rank(us, to, max_rank()) == promotion_rank() || sittuyin_promotion());
+ assert(relative_rank(us, to, max_rank()) >= promotion_rank() || sittuyin_promotion());
assert(type_of(pc) == promotion_type(m));
assert(type_of(pc) >= KNIGHT && type_of(pc) < KING);
Rank promotion_rank() const;
const std::set<PieceType, std::greater<PieceType> >& promotion_piece_types() const;
bool sittuyin_promotion() const;
+ int promotion_limit(PieceType pt) const;
PieceType promoted_piece_type(PieceType pt) const;
bool piece_promotion_on_capture() const;
+ bool mandatory_pawn_promotion() const;
bool mandatory_piece_promotion() const;
bool piece_demotion() const;
bool endgame_eval() const;
return var->sittuyinPromotion;
}
+inline int Position::promotion_limit(PieceType pt) const {
+ assert(var != nullptr);
+ return var->promotionLimit[pt];
+}
+
inline PieceType Position::promoted_piece_type(PieceType pt) const {
assert(var != nullptr);
return var->promotedPieceType[pt];
return var->piecePromotionOnCapture;
}
+inline bool Position::mandatory_pawn_promotion() const {
+ assert(var != nullptr);
+ return var->mandatoryPawnPromotion;
+}
+
inline bool Position::mandatory_piece_promotion() const {
assert(var != nullptr);
return var->mandatoryPiecePromotion;
v->stalemateValue = -VALUE_MATE;
return v;
}
+ Variant* grand_variant() {
+ Variant* v = fairy_variant_base();
+ v->maxRank = RANK_10;
+ v->maxFile = FILE_J;
+ v->add_piece(ARCHBISHOP, 'a');
+ v->add_piece(CHANCELLOR, 'c');
+ v->startFen = "r8r/1nbqkcabn1/pppppppppp/10/10/10/10/PPPPPPPPPP/1NBQKCABN1/R8R w - - 0 1";
+ v->promotionPieceTypes = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT};
+ v->promotionRank = RANK_8;
+ v->promotionLimit[ARCHBISHOP] = 1;
+ v->promotionLimit[CHANCELLOR] = 1;
+ v->promotionLimit[QUEEN] = 1;
+ v->promotionLimit[ROOK] = 2;
+ v->promotionLimit[BISHOP] = 2;
+ v->promotionLimit[KNIGHT] = 2;
+ v->mandatoryPawnPromotion = false;
+ v->immobilityIllegal = true;
+ v->doubleStepRank = RANK_3;
+ v->castling = false;
+ return v;
+ }
Variant* shako_variant() {
Variant* v = fairy_variant_base();
v->maxRank = RANK_10;
add("embassy", embassy_variant());
add("jesonmor", jesonmor_variant());
add("courier", courier_variant());
+ add("grand", grand_variant());
add("shako", shako_variant());
add("clobber10", clobber10_variant());
#endif
Rank promotionRank = RANK_8;
std::set<PieceType, std::greater<PieceType> > promotionPieceTypes = { QUEEN, ROOK, BISHOP, KNIGHT };
bool sittuyinPromotion = false;
+ uint8_t promotionLimit[PIECE_TYPE_NB] = {}; // 0 means unlimited
PieceType promotedPieceType[PIECE_TYPE_NB] = {};
bool piecePromotionOnCapture = false;
+ bool mandatoryPawnPromotion = true;
bool mandatoryPiecePromotion = false;
bool pieceDemotion = false;
bool endgameEval = false;
expect perft.exp modern startpos 4 433729 > /dev/null
expect perft.exp chancellor startpos 4 436656 > /dev/null
expect perft.exp courier startpos 4 500337 > /dev/null
+ expect perft.exp grand startpos 3 259514 > /dev/null
fi
rm perft.exp