From 052dce6a150c5dfc4a4775fc23319028904a86ab Mon Sep 17 00:00:00 2001 From: Sebastian Buchwald Date: Sat, 11 Mar 2023 22:08:35 +0100 Subject: [PATCH 01/10] Fix Makefile for clang 16 The clang 16 release will remove the -fexperimental-new-pass-manager flag (see https://github.com/llvm/llvm-project/commit/69b2b7282e92a1b576b7bd26f3b16716a5027e8e). Thus, the commit adapts the Makefile to use this flag only for older clang versions. closes https://github.com/official-stockfish/Stockfish/pull/4437 No functional change --- src/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 8572369b1..4fe40955b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -539,7 +539,10 @@ ifeq ($(optimize),yes) endif ifeq ($(comp),clang) - CXXFLAGS += -fexperimental-new-pass-manager + clangmajorversion = $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.) + ifeq ($(shell expr $(clangmajorversion) \< 16),1) + CXXFLAGS += -fexperimental-new-pass-manager + endif endif endif From 7d42030f631551af033ada63c6eaa2d9ab922ddb Mon Sep 17 00:00:00 2001 From: RainRat Date: Tue, 13 Feb 2024 04:49:27 -0800 Subject: [PATCH 02/10] add Three Musketeers. needs collinearN and connectPieceTypes. (#755) --- src/parser.cpp | 2 ++ src/position.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++------ src/position.h | 12 ++++++++++++ src/variant.cpp | 11 +++++++++++ src/variant.h | 2 ++ src/variants.ini | 18 ++++++++++++++++- 6 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 9d2b55b98..2a4db2d2b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -527,6 +527,7 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("flagPieceSafe", v->flagPieceSafe); parse_attribute("checkCounting", v->checkCounting); parse_attribute("connectN", v->connectN); + parse_attribute("connectPieceTypes", v->connectPieceTypes, v->pieceToChar); parse_attribute("connectHorizontal", v->connectHorizontal); parse_attribute("connectVertical", v->connectVertical); parse_attribute("connectDiagonal", v->connectDiagonal); @@ -535,6 +536,7 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("connectRegion1Black", v->connectRegion1[BLACK]); parse_attribute("connectRegion2Black", v->connectRegion2[BLACK]); parse_attribute("connectNxN", v->connectNxN); + parse_attribute("collinearN", v->collinearN); parse_attribute("connectValue", v->connectValue); parse_attribute("materialCounting", v->materialCounting); parse_attribute("adjudicateFullBoard", v->adjudicateFullBoard); diff --git a/src/position.cpp b/src/position.cpp index bf6e60f28..c449b6a94 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -2703,7 +2703,7 @@ bool Position::is_optional_game_end(Value& result, int ply, int countStarted) co /// Position::is_immediate_game_end() tests whether the position ends the game /// immediately by a variant rule, i.e., there are no more legal moves. -/// It does not not detect stalemates. +/// It does not detect stalemates. bool Position::is_immediate_game_end(Value& result, int ply) const { @@ -2789,6 +2789,15 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { result = mated_in(ply); return true; } + + //Calculate eligible pieces for connection once. + Bitboard connectPieces = 0; + for (PieceSet ps = connect_piece_types(); ps;){ + PieceType pt = pop_lsb(ps); + connectPieces |= pieces(pt); + }; + connectPieces &= pieces(~sideToMove); + // Connect-n if (connect_n() > 0) { @@ -2796,7 +2805,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { for (Direction d : var->connect_directions) { - b = pieces(~sideToMove); + b = connectPieces; for (int i = 1; i < connect_n() && b; i++) b &= shift(d, b); if (b) @@ -2807,15 +2816,15 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { } } - if ((var->connectRegion1[~sideToMove] & pieces(~sideToMove)) && (var->connectRegion2[~sideToMove] & pieces(~sideToMove))) + if ((var->connectRegion1[~sideToMove] & connectPieces) && (var->connectRegion2[~sideToMove] & connectPieces)) { Bitboard target = var->connectRegion2[~sideToMove]; - Bitboard current = var->connectRegion1[~sideToMove] & pieces(~sideToMove); + Bitboard current = var->connectRegion1[~sideToMove] & connectPieces; while (true) { Bitboard newBitboard = 0; for (Direction d : var->connect_directions) { - newBitboard |= shift(d, current | newBitboard) & pieces(~sideToMove); // the "| newBitboard" here probably saves a few loops + newBitboard |= shift(d, current | newBitboard) & connectPieces; // the "| newBitboard" here probably saves a few loops } if (newBitboard & target) { @@ -2835,7 +2844,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { if (connect_nxn()) { - Bitboard connectors = pieces(~sideToMove); + Bitboard connectors = connectPieces; for (int i = 1; i < connect_nxn() && connectors; i++) connectors &= shift(connectors) & shift(connectors) & shift(connectors); if (connectors) @@ -2845,6 +2854,36 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { } } + // Collinear-n + if (collinear_n() > 0) { + Bitboard allPieces = connectPieces; + for (Direction d : var->connect_directions) { + Bitboard b = allPieces; + while (b) { + Square s = pop_lsb(b); + + int total_count = 1; // Start with the current piece + + // Check in both directions + for (int sign : {-1, 1}) { + Bitboard shifted = shift(sign * d, square_bb(s)); + while (shifted) { + if (shifted & b) { + total_count++; + b &= ~shifted; // Remove this piece from further consideration + } + shifted = shift(sign * d, shifted); + } + } + + if (total_count >= collinear_n()) { + result = convert_mate_value(-var->connectValue, ply); + return true; + } + } + } + } + // Check for bikjang rule (Janggi), double passing, or board running full if ( (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || (st->pass && st->previous->pass))) || (var->adjudicateFullBoard && !(~pieces() & board_bb()))) diff --git a/src/position.h b/src/position.h index 4ee936657..adaeeb6ad 100644 --- a/src/position.h +++ b/src/position.h @@ -205,11 +205,13 @@ class Position { bool flag_reached(Color c) const; bool check_counting() const; int connect_n() const; + PieceSet connect_piece_types() const; bool connect_horizontal() const; bool connect_vertical() const; bool connect_diagonal() const; const std::vector& getConnectDirections() const; int connect_nxn() const; + int collinear_n() const; CheckCount checks_remaining(Color c) const; MaterialCounting material_counting() const; @@ -1035,6 +1037,11 @@ inline int Position::connect_n() const { return var->connectN; } +inline PieceSet Position::connect_piece_types() const { + assert(var != nullptr); + return var->connectPieceTypes; +} + inline bool Position::connect_horizontal() const { assert(var != nullptr); return var->connectHorizontal; @@ -1058,6 +1065,11 @@ inline int Position::connect_nxn() const { return var->connectNxN; } +inline int Position::collinear_n() const { + assert(var != nullptr); + return var->collinearN; +} + inline CheckCount Position::checks_remaining(Color c) const { return st->checksRemaining[c]; } diff --git a/src/variant.cpp b/src/variant.cpp index 386c21d5d..5b21b53dd 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -2064,6 +2064,17 @@ Variant* Variant::conclude() { connect_directions.push_back(SOUTH_EAST); } + // If not a connect variant, set connectPieceTypes to no pieces. + if ( !(connectRegion1[WHITE] || connectRegion1[BLACK] || connectN || connectNxN || collinearN) ) + { + connectPieceTypes = NO_PIECE_SET; + } + //Otherwise optimize to pieces actually in the game. + else + { + connectPieceTypes = connectPieceTypes & pieceTypes; + }; + return this; } diff --git a/src/variant.h b/src/variant.h index ec1991859..a34b37de3 100644 --- a/src/variant.h +++ b/src/variant.h @@ -149,12 +149,14 @@ struct Variant { bool flagPieceSafe = false; bool checkCounting = false; int connectN = 0; + PieceSet connectPieceTypes = ~NO_PIECE_SET; bool connectHorizontal = true; bool connectVertical = true; bool connectDiagonal = true; Bitboard connectRegion1[COLOR_NB] = {}; Bitboard connectRegion2[COLOR_NB] = {}; int connectNxN = 0; + int collinearN = 0; Value connectValue = VALUE_MATE; MaterialCounting materialCounting = NO_MATERIAL_COUNTING; bool adjudicateFullBoard = false; diff --git a/src/variants.ini b/src/variants.ini index abc2c7099..aaf40810f 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -280,6 +280,7 @@ # flagPieceSafe: the flag piece must be safe to win [bool] (default: false) # checkCounting: enable check count win rule (check count is communicated via FEN, see 3check) [bool] (default: false) # connectN: number of aligned pieces for win [int] (default: 0) +# connectPieceTypes: pieces evaluated for connection rule [PieceSet] (default: *) # connectVertical: connectN looks at Vertical rows [bool] (default: true) # connectHorizontal: connectN looks at Horizontal rows [bool] (default: true) # connectDiagonal: connectN looks at Diagonal rows [bool] (default: true) @@ -288,6 +289,7 @@ # connectRegion1Black: " # connectRegion2Black: " # connectNxN: connect a tight NxN square for win [int] (default: 0) +# collinearN: arrange N pieces collinearly (other squares can be between pieces) [int] (default: 0) # connectValue: result in case of connect [Value] (default: win) # materialCounting: enable material counting rules [MaterialCounting] (default: none) # adjudicateFullBoard: apply material counting immediately when board is full [bool] (default: false) @@ -1546,7 +1548,7 @@ nMoveRule = 0 #https://ludii.games/details.php?keyword=Djara-Badakh #https://ludii.games/details.php?keyword=Tuk%20Tak customPiece1 = p:mKmNmAmD -#moves anywhere on the board, KNAD is an list of all possible moves on a 3x3 +#moves anywhere on the board, KNAD is a list of all possible moves on a 3x3 startFen = 3/3/3[PPPppp] w - - 0 1 mustDrop = true nMoveRule = 0 @@ -1912,3 +1914,17 @@ enclosingDrop = anyside #http://gamescrafters.berkeley.edu/games.php?game=connect4 [cfour-misere:cfour] connectValue = loss + +#https://www.ludii.games/details.php?keyword=Three%20Musketeers +[three-musketeers] +pieceToCharTable = P......M..............p......m.............. +startFen = ppppM/ppppp/ppMpp/ppppp/Mpppp +maxRank = 5 +maxFile = 5 +collinearN = 3 +connectDiagonal = false +customPiece1 = m:cW +customPiece2 = p:mW +connectValue = loss +stalemateValue = win +connectPieceTypes = m From 0bfa4fcdfe9889bdf1b136f4739a3e21e25fb7d8 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 16 Feb 2024 19:42:26 +0100 Subject: [PATCH 03/10] Fix cannonshogi (#757) --- src/bitboard.cpp | 10 ++++++---- src/variants.ini | 4 ++-- test.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 3939296c3..4f0057597 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -111,7 +111,7 @@ namespace { const std::map GrasshopperDirectionsH { {EAST, 1}, {WEST, 1} }; const std::map GrasshopperDirectionsD { {NORTH_EAST, 1}, {SOUTH_EAST, 1}, {SOUTH_WEST, 1}, {NORTH_WEST, 1} }; - enum MovementType { RIDER, HOPPER, LAME_LEAPER, UNLIMITED_RIDER }; + enum MovementType { RIDER, HOPPER, LAME_LEAPER, HOPPER_RANGE }; template #ifdef PRECOMPUTED_MAGICS @@ -137,7 +137,9 @@ namespace { if (MT != HOPPER || hurdle) { attack |= s; - if (limit && MT != UNLIMITED_RIDER && ++count >= limit) + // For hoppers we consider limit == 1 as a grasshopper, + // but limit > 1 as a limited distance hopper + if (limit && !(MT == HOPPER_RANGE && limit == 1) && ++count >= limit) break; } @@ -300,7 +302,7 @@ void Bitboards::init_pieces() { leaper |= safe_destination(s, c == WHITE ? d : -d); } pseudo |= sliding_attack(pi->slider[initial][modality], s, 0, c); - pseudo |= sliding_attack(pi->hopper[initial][modality], s, 0, c); + pseudo |= sliding_attack(pi->hopper[initial][modality], s, 0, c); } } } @@ -420,7 +422,7 @@ namespace { // apply to the 64 or 32 bits word to get the index. Magic& m = magics[s]; // The mask for hoppers is unlimited distance, even if the hopper is limited distance (e.g., grasshopper) - m.mask = (MT == LAME_LEAPER ? lame_leaper_path(directions, s) : sliding_attack(directions, s, 0)) & ~edges; + m.mask = (MT == LAME_LEAPER ? lame_leaper_path(directions, s) : sliding_attack(directions, s, 0)) & ~edges; #ifdef LARGEBOARDS m.shift = 128 - popcount(m.mask); #else diff --git a/src/variants.ini b/src/variants.ini index aaf40810f..09be0e40a 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -1662,8 +1662,8 @@ cannon = u customPiece1 = a:pR customPiece2 = c:mBcpB customPiece3 = i:pB -customPiece4 = w:mRpRFAcpR -customPiece5 = f:mBpBWDcpB +customPiece4 = w:mRpRmFpB2 +customPiece5 = f:mBpBmWpR2 promotedPieceType = u:w a:w c:f i:f startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] w 0 1 diff --git a/test.py b/test.py index 9cf4c5393..7a5aa456b 100644 --- a/test.py +++ b/test.py @@ -100,6 +100,19 @@ customPiece3 = c:hlN customPiece4 = d:hrN startFen = 7/7/7/3A3/7/7/7 w - - 0 1 + +[cannonshogi:shogi] +dropNoDoubled = - +shogiPawnDropMateIllegal = false +soldier = p +cannon = u +customPiece1 = a:pR +customPiece2 = c:mBcpB +customPiece3 = i:pB +customPiece4 = w:mRpRmFpB2 +customPiece5 = f:mBpBmWpR2 +promotedPieceType = u:w a:w c:f i:f +startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] w 0 1 """ sf.load_variant_config(ini_text) @@ -317,6 +330,24 @@ def test_legal_moves(self): result = sf.legal_moves("shogun", SHOGUN, ["c2c4", "b8c6", "b2b4", "b7b5", "c4b5", "c6b8"]) self.assertIn("b5b6+", result) + # In Cannon Shogi the FGC and FSC can also move one square diagonally and, besides, + # move or capture two squares diagonally, by leaping an adjacent piece. + fen = "lnsg1gsnl/1rc1kuab1/p1+A1p1p1p/3P5/6i2/6P2/P1P1P3P/1B1U1ICR1/LNSGKGSNL[] w - - 1 3" + result = sf.legal_moves("cannonshogi", fen, []) + # mF + self.assertIn("c7b6", result) + self.assertIn("c7d8", result) + self.assertNotIn("c7d6", result) + self.assertNotIn("c7b8", result) + # pB2 + self.assertIn("c7a9", result) + self.assertIn("c7e5", result) + self.assertNotIn("c7a5", result) + self.assertNotIn("c7e9", result) + # verify distance limited to 2 + self.assertNotIn("c7f4", result) + self.assertNotIn("c7g3", result) + # Cambodian queen cannot capture with its leap # Cambodian king cannot leap to escape check result = sf.legal_moves("cambodian", CAMBODIAN, ["b1d2", "g8e7", "d2e4", "d6d5", "e4d6"]) From 203f8f8c1b6ed935e62f5e7d54fc655a951774b1 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 16 Feb 2024 20:10:00 +0100 Subject: [PATCH 04/10] Bump pyffish version --- setup.py | 2 +- src/pyffish.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index ab253c9ac..357001db8 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ sources=sources, extra_compile_args=args) -setup(name="pyffish", version="0.0.80", +setup(name="pyffish", version="0.0.81", description="Fairy-Stockfish Python wrapper", long_description=long_description, long_description_content_type="text/markdown", diff --git a/src/pyffish.cpp b/src/pyffish.cpp index d321a57cc..8439acd06 100644 --- a/src/pyffish.cpp +++ b/src/pyffish.cpp @@ -54,7 +54,7 @@ void buildPosition(Position& pos, StateListPtr& states, const char *variant, con } extern "C" PyObject* pyffish_version(PyObject* self) { - return Py_BuildValue("(iii)", 0, 0, 80); + return Py_BuildValue("(iii)", 0, 0, 81); } extern "C" PyObject* pyffish_info(PyObject* self) { From 2c22a948ed309c4c15f3534818a8d2935812f898 Mon Sep 17 00:00:00 2001 From: QueensGambit Date: Sat, 17 Feb 2024 10:51:15 +0100 Subject: [PATCH 05/10] Bump version --- tests/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/js/package.json b/tests/js/package.json index cc960f14a..aa744fd51 100644 --- a/tests/js/package.json +++ b/tests/js/package.json @@ -1,6 +1,6 @@ { "name": "ffish", - "version": "0.7.4", + "version": "0.7.5", "description": "A high performance WebAssembly chess variant library based on Fairy-Stockfish", "main": "ffish.js", "types": "ffish.d.ts", From 69cdd8257634612c52e4c032c50f3d5026b4710f Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 23 Feb 2024 15:25:11 +0100 Subject: [PATCH 06/10] Update reference bench bench: 6180480 From def2560cb130cd2b8eab4bbaf56fa91b14b4dd7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bajusz=20Tam=C3=A1s?= Date: Mon, 26 Feb 2024 15:53:51 +0100 Subject: [PATCH 07/10] Add missing soldier promotion to cannonshogi --- src/variants.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/variants.ini b/src/variants.ini index 09be0e40a..0b27fc2d0 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -1664,7 +1664,7 @@ customPiece2 = c:mBcpB customPiece3 = i:pB customPiece4 = w:mRpRmFpB2 customPiece5 = f:mBpBmWpR2 -promotedPieceType = u:w a:w c:f i:f +promotedPieceType = u:w a:w c:f i:f p:g startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] w 0 1 #https://www.chessvariants.com/difftaking.dir/deadsquare.html From fb8cf35d9dbd9278f00c772100abf5888e444c1a Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 1 Mar 2024 11:55:17 +0100 Subject: [PATCH 08/10] Validate max one king per side --- src/apiutil.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/apiutil.h b/src/apiutil.h index 4b364f63c..d39102fcd 100644 --- a/src/apiutil.h +++ b/src/apiutil.h @@ -821,6 +821,16 @@ inline Validation check_number_of_kings(const std::string& fenBoard, const std:: int nbWhiteKingsStart = piece_count(startFenBoard, WHITE, KING, v); int nbBlackKingsStart = piece_count(startFenBoard, BLACK, KING, v); + if (nbWhiteKings > 1) + { + std::cerr << "Invalid number of white kings. Maximum: 1. Given: " << nbWhiteKings << std::endl; + return NOK; + } + if (nbBlackKings > 1) + { + std::cerr << "Invalid number of black kings. Maximum: 1. Given: " << nbBlackKings << std::endl; + return NOK; + } if (nbWhiteKings != nbWhiteKingsStart) { std::cerr << "Invalid number of white kings. Expected: " << nbWhiteKingsStart << ". Given: " << nbWhiteKings << std::endl; From bbe0d954a18a258cff38c155e8b62925cd80f0de Mon Sep 17 00:00:00 2001 From: RainRat Date: Fri, 1 Mar 2024 05:01:13 -0800 Subject: [PATCH 09/10] add 'wall or move' rule (for Atlantis) (#728) --- src/movegen.cpp | 9 ++++++++- src/parser.cpp | 1 + src/position.cpp | 6 ++++-- src/variant.h | 1 + src/variants.ini | 5 ++--- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 43807bb0b..f5a16eb41 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -29,7 +29,8 @@ namespace { ExtMove* make_move_and_gating(const Position& pos, ExtMove* moveList, Color us, Square from, Square to, PieceType pt = NO_PIECE_TYPE) { // Wall placing moves - if (pos.walling()) + //if it's "wall or move", and they chose non-null move, skip even generating wall move + if (pos.walling() && !(pos.variant()->wallOrMove && (from!=to))) { Bitboard b = pos.board_bb() & ~((pos.pieces() ^ from) | to); if (T == CASTLING) @@ -443,6 +444,12 @@ namespace { // Workaround for passing: Execute a non-move with any piece if (pos.pass(Us) && !pos.count(Us) && pos.pieces(Us)) *moveList++ = make(lsb(pos.pieces(Us)), lsb(pos.pieces(Us))); + + //if "wall or move", generate walling action with null move + if (pos.variant()->wallOrMove) + { + moveList = make_move_and_gating(pos, moveList, Us, lsb(pos.pieces(Us)), lsb(pos.pieces(Us))); + } } // King moves diff --git a/src/parser.cpp b/src/parser.cpp index 2a4db2d2b..3ebf1b16f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -472,6 +472,7 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("wallingRegionBlack", v->wallingRegion[BLACK]); parse_attribute("wallingRegion", v->wallingRegion[WHITE]); parse_attribute("wallingRegion", v->wallingRegion[BLACK]); + parse_attribute("wallOrMove", v->wallOrMove); parse_attribute("seirawanGating", v->seirawanGating); parse_attribute("cambodianMoves", v->cambodianMoves); parse_attribute("diagonalLines", v->diagonalLines); diff --git a/src/position.cpp b/src/position.cpp index c449b6a94..023cdfa72 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1303,7 +1303,8 @@ bool Position::pseudo_legal(const Move m) const { return checkers() ? MoveList< EVASIONS>(*this).contains(m) : MoveList(*this).contains(m); - if (walling()) + //if walling, and walling is not optional, or they didn't move, do the checks. + if (walling() && (!var->wallOrMove || (from==to))) { Bitboard wallsquares = st->wallSquares; @@ -2045,7 +2046,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { } // Add gated wall square - if (walling()) + // if wallOrMove, only actually place the wall if they gave up their move + if (walling() && (!var->wallOrMove || (from==to))) { // Reset wall squares for duck walling if (walling_rule() == DUCK) diff --git a/src/variant.h b/src/variant.h index a34b37de3..aa2738356 100644 --- a/src/variant.h +++ b/src/variant.h @@ -108,6 +108,7 @@ struct Variant { bool gating = false; WallingRule wallingRule = NO_WALLING; Bitboard wallingRegion[COLOR_NB] = {AllSquares, AllSquares}; + bool wallOrMove = false; bool seirawanGating = false; bool cambodianMoves = false; Bitboard diagonalLines = 0; diff --git a/src/variants.ini b/src/variants.ini index 0b27fc2d0..fd5b50497 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -232,6 +232,7 @@ # wallingRule: rule on where wall can be placed [WallingRule] (default: none) # wallingRegionWhite: mask where wall squares (including duck) can be placed by white [Bitboard] (default: all squares) # wallingRegionBlack: mask where wall squares (including duck) can be placed by black [Bitboard] (default: all squares) +# wallOrMove: can wall or move, but not both [bool] (default: false) # seirawanGating: allow gating of pieces in hand like in S-Chess, requires "gating = true" [bool] (default: false) # cambodianMoves: enable special moves of cambodian chess, requires "gating = true" [bool] (default: false) # diagonalLines: enable special moves along diagonal for specific squares (Janggi) [Bitboard] @@ -1811,9 +1812,7 @@ connectDiagonal = false #https://www.chessvariants.com/boardrules.dir/atlantis.html [atlantis:chess] wallingRule = edge -#not ready yet. Other wall variants are "move and wall", this is "move or wall". -#need to figure out way to do this ie. write code for: -#wallOrMove = true +wallOrMove = true #https://www.chessvariants.com/rules/ajax-orthodox-chess [ajax-orthodox:chess] From 62577a4039e48c55a579edac78dbdbec5d3bf71e Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 1 Mar 2024 15:28:21 +0100 Subject: [PATCH 10/10] Handle invalid promoted piece (#416) --- src/position.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/position.cpp b/src/position.cpp index 023cdfa72..ade4798d1 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -314,7 +314,7 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, } // Promoted shogi pieces - else if (token == '+' && (idx = piece_to_char().find(ss.peek())) != string::npos) + else if (token == '+' && (idx = piece_to_char().find(ss.peek())) != string::npos && promoted_piece_type(type_of(Piece(idx)))) { ss >> token; put_piece(make_piece(color_of(Piece(idx)), promoted_piece_type(type_of(Piece(idx)))), sq, true, Piece(idx));