From e147648fe7b85f914666ac87bcb24c617a300713 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Sat, 1 May 2021 15:02:01 +0200 Subject: [PATCH] Support Tori shogi --- README.md | 5 ++- src/parser.cpp | 1 + src/position.h | 2 +- src/ucioption.cpp | 2 +- src/variant.cpp | 76 ++++++++++++++++++++++++++++++++++++---------------- src/variant.h | 10 ++++++- src/variants.ini | 1 + tests/perft.sh | 1 + 8 files changed, 69 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index b4c8df4..2b1d5b7 100644 --- a/README.md +++ b/README.md @@ -49,15 +49,16 @@ The games currently supported besides chess are listed below. Fairy-Stockfish ca - [Extinction](https://en.wikipedia.org/wiki/Extinction_chess), [Kinglet](https://en.wikipedia.org/wiki/V._R._Parton#Kinglet_chess), Three Kings, [Coregal](https://www.chessvariants.com/winning.dir/coregal.html) - [King of the Hill](https://en.wikipedia.org/wiki/King_of_the_Hill_(chess)), [Racing Kings](https://en.wikipedia.org/wiki/V._R._Parton#Racing_Kings) - [Three-check](https://en.wikipedia.org/wiki/Three-check_chess), Five-check -- [Los Alamos](https://en.wikipedia.org/wiki/Los_Alamos_chess) +- [Los Alamos](https://en.wikipedia.org/wiki/Los_Alamos_chess), [Gardner's Minichess](https://en.wikipedia.org/wiki/Minichess#5%C3%975_chess) - [Atomic](https://en.wikipedia.org/wiki/Atomic_chess) - [Horde](https://en.wikipedia.org/wiki/Dunsany%27s_Chess#Horde_Chess), [Maharajah and the Sepoys](https://en.wikipedia.org/wiki/Maharajah_and_the_Sepoys) -- [Knightmate](https://www.chessvariants.com/diffobjective.dir/knightmate.html) +- [Knightmate](https://www.chessvariants.com/diffobjective.dir/knightmate.html), [Nightrider](https://en.wikipedia.org/wiki/Nightrider_(chess)) ### Shogi variants - [Minishogi](https://en.wikipedia.org/wiki/Minishogi), [EuroShogi](https://en.wikipedia.org/wiki/EuroShogi), [Judkins shogi](https://en.wikipedia.org/wiki/Judkins_shogi) - [Kyoto shogi](https://en.wikipedia.org/wiki/Kyoto_shogi), [Microshogi](https://en.wikipedia.org/wiki/Micro_shogi) - [Dobutsu shogi](https://en.wikipedia.org/wiki/Dōbutsu_shōgi), [Goro goro shogi](https://en.wikipedia.org/wiki/D%C5%8Dbutsu_sh%C5%8Dgi#Variation) +- [Tori shogi](https://en.wikipedia.org/wiki/Tori_shogi) - [Yari shogi](https://en.wikipedia.org/wiki/Yari_shogi) - [Okisaki shogi](https://en.wikipedia.org/wiki/Okisaki_shogi) diff --git a/src/parser.cpp b/src/parser.cpp index e925db3..5f8de07 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -312,6 +312,7 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("dropOppositeColoredBishop", v->dropOppositeColoredBishop); parse_attribute("dropPromoted", v->dropPromoted); parse_attribute("dropNoDoubled", v->dropNoDoubled, v->pieceToChar); + parse_attribute("dropNoDoubledCount", v->dropNoDoubledCount); parse_attribute("immobilityIllegal", v->immobilityIllegal); parse_attribute("gating", v->gating); parse_attribute("arrowGating", v->arrowGating); diff --git a/src/position.h b/src/position.h index f79b80f..a6307e8 100644 --- a/src/position.h +++ b/src/position.h @@ -610,7 +610,7 @@ inline Bitboard Position::drop_region(Color c, PieceType pt) const { // Doubled shogi pawns if (pt == drop_no_doubled()) for (File f = FILE_A; f <= max_file(); ++f) - if (file_bb(f) & pieces(c, pt)) + if (popcount(file_bb(f) & pieces(c, pt)) >= var->dropNoDoubledCount) b &= ~file_bb(f); // Sittuyin rook drops if (pt == ROOK && sittuyin_rook_drop()) diff --git a/src/ucioption.cpp b/src/ucioption.cpp index c30654b..f515237 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -128,7 +128,7 @@ void on_variant_change(const Option &o) { if (pt == PAWN && !v->firstRankPawnDrops) suffix += "j"; else if (pt == v->dropNoDoubled) - suffix += "f"; + suffix += std::string(v->dropNoDoubledCount, 'f'); else if (pt == BISHOP && v->dropOppositeColoredBishop) suffix += "s"; suffix += "@" + std::to_string(pt == PAWN && !v->promotionZonePawnDrops ? v->promotionRank : v->maxRank + 1); diff --git a/src/variant.cpp b/src/variant.cpp index 8287d61..06e48ce 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -198,8 +198,7 @@ namespace { Variant* nightrider_variant() { Variant* v = chess_variant_base(); v->remove_piece(KNIGHT); - v->customPiece[0] = "NN"; - v->add_piece(CUSTOM_PIECES, 'n'); + v->add_piece(CUSTOM_PIECES, 'n', "NN"); v->promotionPieceTypes = {QUEEN, ROOK, BISHOP, CUSTOM_PIECES}; return v; } @@ -662,6 +661,45 @@ namespace { v->promotedPieceType[SHOGI_KNIGHT] = GOLD; return v; } + // Tori shogi + // https://en.wikipedia.org/wiki/Tori_shogi + Variant* torishogi_variant() { + Variant* v = variant_base(); + v->variantTemplate = "shogi"; + v->pieceToCharTable = "S.....FLR.C+.....+.PKs.....flr.c+.....+.pk"; + v->maxRank = RANK_7; + v->maxFile = FILE_G; + v->reset_pieces(); + v->add_piece(SHOGI_PAWN, 's'); + v->add_piece(KING, 'k'); + v->add_piece(CUSTOM_PIECES, 'f', "FsfW"); // falcon + v->add_piece(CUSTOM_PIECES + 1, 'c', "FvW"); // crane + v->add_piece(CUSTOM_PIECES + 2, 'l', "fRrbBlbF"); // left quail + v->add_piece(CUSTOM_PIECES + 3, 'r', "fRlbBrbF"); // right quail + v->add_piece(CUSTOM_PIECES + 4, 'p', "bFfD"); // pheasant + v->add_piece(CUSTOM_PIECES + 5, 'g', "fAbD"); // goose + v->add_piece(CUSTOM_PIECES + 6, 'e', "KbRfBbF2"); // eagle + v->startFen = "rpckcpl/3f3/sssssss/2s1S2/SSSSSSS/3F3/LPCKCPR [-] w 0 1"; + v->pieceDrops = true; + v->capturesToHand = true; + v->promotionRank = RANK_6; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->promotedPieceType[SHOGI_PAWN] = CUSTOM_PIECES + 5; // swallow promotes to goose + v->promotedPieceType[CUSTOM_PIECES] = CUSTOM_PIECES + 6; // falcon promotes to eagle + v->mandatoryPiecePromotion = true; + v->dropNoDoubled = SHOGI_PAWN; + v->dropNoDoubledCount = 2; + v->immobilityIllegal = true; + v->shogiPawnDropMateIllegal = true; + v->stalemateValue = -VALUE_MATE; + v->nFoldValue = VALUE_MATE; + v->nFoldRule = 3; + v->nMoveRule = 0; + v->perpetualCheckIllegal = true; + return v; + } // EuroShogi // https://en.wikipedia.org/wiki/EuroShogi Variant* euroshogi_variant() { @@ -669,8 +707,7 @@ namespace { v->pieceToCharTable = "PNBR.....G.++++Kpnbr.....g.++++k"; v->maxRank = RANK_8; v->maxFile = FILE_H; - v->customPiece[0] = "fNsW"; - v->add_piece(CUSTOM_PIECES, 'n'); + v->add_piece(CUSTOM_PIECES, 'n', std::string("fNsW")); v->startFen = "1nbgkgn1/1r4b1/pppppppp/8/8/PPPPPPPP/1B4R1/1NGKGBN1[-] w 0 1"; v->promotionRank = RANK_6; v->promotedPieceType[CUSTOM_PIECES] = GOLD; @@ -797,8 +834,7 @@ namespace { v->maxRank = RANK_7; v->maxFile = FILE_G; v->reset_pieces(); - v->customPiece[0] = "mDmNmA"; - v->add_piece(CUSTOM_PIECES, 'p'); + v->add_piece(CUSTOM_PIECES, 'p', "mDmNmA"); v->startFen = "P5p/7/7/7/7/7/p5P[PPPPPPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppppppp] w 0 1"; v->promotionPieceTypes = {}; v->pieceDrops = true; @@ -867,16 +903,11 @@ namespace { v->add_piece(KING, 'k'); v->add_piece(SHOGI_PAWN, 'p'); v->add_piece(ROOK, 'l'); - v->customPiece[0] = "fRffN"; // Yari knight - v->add_piece(CUSTOM_PIECES, 'n'); - v->customPiece[1] = "fFfR"; // Yari bishop - v->add_piece(CUSTOM_PIECES + 1, 'b'); - v->customPiece[2] = "frlR"; // Yari rook - v->add_piece(CUSTOM_PIECES + 2, 'r'); - v->customPiece[3] = "WfFbR"; // Yari gold - v->add_piece(CUSTOM_PIECES + 3, 'g'); - v->customPiece[4] = "fKbR"; // Yari silver - v->add_piece(CUSTOM_PIECES + 4, 's'); + v->add_piece(CUSTOM_PIECES, 'n', "fRffN"); // Yari knight + v->add_piece(CUSTOM_PIECES + 1, 'b', "fFfR"); // Yari bishop + v->add_piece(CUSTOM_PIECES + 2, 'r', "frlR"); // Yari rook + v->add_piece(CUSTOM_PIECES + 3, 'g', "WfFbR"); // Yari gold + v->add_piece(CUSTOM_PIECES + 4, 's', "fKbR"); // Yari silver v->startFen = "rnnkbbr/7/ppppppp/7/7/7/PPPPPPP/7/RBBKNNR[-] w 0 1"; v->promotionRank = RANK_7; v->promotedPieceType[SHOGI_PAWN] = CUSTOM_PIECES + 4; @@ -903,8 +934,7 @@ namespace { Variant* v = minishogi_variant_base(); v->maxRank = RANK_10; v->maxFile = FILE_J; - v->customPiece[0] = "vR"; // Vertical slider - v->add_piece(CUSTOM_PIECES, 'l'); + v->add_piece(CUSTOM_PIECES, 'l', "vR"); // Vertical slider v->add_piece(KNIGHT, 'n'); v->add_piece(QUEEN, 'q'); v->startFen = "lnsgkqgsnl/1r6b1/pppppppppp/10/10/10/10/PPPPPPPPPP/1B6R1/LNSGQKGSNL[-] w 0 1"; @@ -1106,10 +1136,8 @@ namespace { v->startFen = "2cwamwc2/1rnbqkbnr1/pppppppppp/10/10/10/10/PPPPPPPPPP/1RNBQKBNR1/2CWAMWC2 w - - 0 1"; v->add_piece(ARCHBISHOP, 'a'); v->add_piece(CHANCELLOR, 'm'); - v->customPiece[0] = "DAW"; // Champion - v->customPiece[1] = "CF"; // Wizard - v->add_piece(CUSTOM_PIECES, 'c'); - v->add_piece(CUSTOM_PIECES + 1, 'w'); + v->add_piece(CUSTOM_PIECES, 'c', "DAW"); // Champion + v->add_piece(CUSTOM_PIECES + 1, 'w', "CF"); // Wizard v->promotionPieceTypes = {ARCHBISHOP, CHANCELLOR, QUEEN}; v->promotionRank = RANK_10; v->doubleStepRank = RANK_3; @@ -1157,8 +1185,7 @@ namespace { v->maxRank = RANK_10; v->maxFile = FILE_J; v->reset_pieces(); - v->customPiece[0] = "mQ"; - v->add_piece(CUSTOM_PIECES, 'q'); + v->add_piece(CUSTOM_PIECES, 'q', "mQ"); v->add_piece(IMMOBILE_PIECE, 'p'); v->startFen = "3q2q3/10/10/q8q/10/10/Q8Q/10/10/3Q2Q3[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppppppppppppp] w - - 0 1"; v->stalemateValue = -VALUE_MATE; @@ -1320,6 +1347,7 @@ void VariantMap::init() { add("dobutsu", dobutsu_variant()->conclude()); add("gorogoro", gorogoroshogi_variant()->conclude()); add("judkins", judkinsshogi_variant()->conclude()); + add("tori", torishogi_variant()->conclude()); add("euroshogi", euroshogi_variant()->conclude()); add("losalamos", losalamos_variant()->conclude()); add("gardner", gardner_variant()->conclude()); diff --git a/src/variant.h b/src/variant.h index dd03214..61cbdf7 100644 --- a/src/variant.h +++ b/src/variant.h @@ -89,6 +89,7 @@ struct Variant { bool dropOppositeColoredBishop = false; bool dropPromoted = false; PieceType dropNoDoubled = NO_PIECE_TYPE; + int dropNoDoubledCount = 1; bool immobilityIllegal = false; bool gating = false; bool arrowGating = false; @@ -138,12 +139,19 @@ struct Variant { PieceType nnueKing = KING; bool endgameEval = false; - void add_piece(PieceType pt, char c, char c2 = ' ') { + void add_piece(PieceType pt, char c, std::string betza = "", char c2 = ' ') { pieceToChar[make_piece(WHITE, pt)] = toupper(c); pieceToChar[make_piece(BLACK, pt)] = tolower(c); pieceToCharSynonyms[make_piece(WHITE, pt)] = toupper(c2); pieceToCharSynonyms[make_piece(BLACK, pt)] = tolower(c2); pieceTypes.insert(pt); + // Add betza notation for custom piece + if (pt >= CUSTOM_PIECES && pt <= CUSTOM_PIECES_END) + customPiece[pt - CUSTOM_PIECES] = betza; + } + + void add_piece(PieceType pt, char c, char c2) { + add_piece(pt, c, "", c2); } void remove_piece(PieceType pt) { diff --git a/src/variants.ini b/src/variants.ini index 6ea5280..7827066 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -181,6 +181,7 @@ # dropOppositeColoredBishop: dropped bishops have to be on opposite-colored squares [bool] (default: false) # dropPromoted: pieces may be dropped in promoted state [bool] (default: false) # dropNoDoubled: specified piece type can not be dropped to the same file (e.g. shogi pawn) [PieceType] (default: -) +# dropNoDoubledCount: specifies the count of already existing pieces for dropNoDoubled [PieceType] (default: 1) # immobilityIllegal: pieces may not move to squares where they can never move from [bool] (default: false) # gating: maintain squares on backrank with extra rights in castling field of FEN [bool] (default: false) # arrowGating: allow gating in Game of the Amazons style [bool] (default: false) diff --git a/tests/perft.sh b/tests/perft.sh index fab2ab8..788c8a1 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -104,6 +104,7 @@ if [[ $1 == "" || $1 == "variant" ]]; then expect perft.exp euroshogi startpos 4 380499 > /dev/null expect perft.exp minishogi startpos 5 533203 > /dev/null expect perft.exp kyotoshogi startpos 5 225903 > /dev/null + expect perft.exp tori startpos 4 103857 > /dev/null # non-chess expect perft.exp ataxx startpos 4 155888 > /dev/null expect perft.exp ataxx "fen 7/7/7/7/ppppppp/ppppppp/PPPPPPP[PPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppp] w 0 1" 5 452980 > /dev/null -- 1.7.0.4