From: Fabian Fichter Date: Fri, 16 Aug 2019 16:15:59 +0000 (+0200) Subject: Support grand chess X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=8e78372a8f2bb694cbd501277e4b94b16e97d537;p=fairystockfish.git Support grand chess https://en.wikipedia.org/wiki/Grand_Chess --- diff --git a/Readme.md b/Readme.md index 00b4725..5733f03 100644 --- a/Readme.md +++ b/Readme.md @@ -15,7 +15,8 @@ Besides chess, the currently supported games are: - [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) diff --git a/src/movegen.cpp b/src/movegen.cpp index 3263266..7542044 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -48,7 +48,8 @@ namespace { if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) for (PieceType pt : pos.promotion_piece_types()) - *moveList++ = make(to - D, to, pt); + if (!pos.promotion_limit(pt) || pos.promotion_limit(pt) > pos.count(c, pt)) + *moveList++ = make(to - D, to, pt); return moveList; } @@ -95,10 +96,11 @@ namespace { 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(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)); diff --git a/src/position.cpp b/src/position.cpp index 1eede29..5a3e197 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -914,7 +914,7 @@ bool Position::pseudo_legal(const Move m) const { { // 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(us, from) & pieces(~us) & to) // Not a capture @@ -1210,7 +1210,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { { 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); @@ -1387,7 +1387,7 @@ void Position::undo_move(Move m) { 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); diff --git a/src/position.h b/src/position.h index cef06f7..c4c6ce8 100644 --- a/src/position.h +++ b/src/position.h @@ -101,8 +101,10 @@ public: Rank promotion_rank() const; const std::set >& 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; @@ -338,6 +340,11 @@ inline bool Position::sittuyin_promotion() 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]; @@ -348,6 +355,11 @@ inline bool Position::piece_promotion_on_capture() const { 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; diff --git a/src/variant.cpp b/src/variant.cpp index 4550639..30421c4 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -605,6 +605,27 @@ VariantMap variants; // Global object 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; @@ -688,6 +709,7 @@ void VariantMap::init() { 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 diff --git a/src/variant.h b/src/variant.h index 5e72c34..e5abcdd 100644 --- a/src/variant.h +++ b/src/variant.h @@ -44,8 +44,10 @@ struct Variant { Rank promotionRank = RANK_8; std::set > 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; diff --git a/tests/perft.sh b/tests/perft.sh index 8815c84..f77fe3c 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -67,6 +67,7 @@ if [[ $1 == "largeboard" ]]; then 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