diff --git a/src/movegen.cpp b/src/movegen.cpp index b658619d3..43807bb0b 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -441,7 +441,7 @@ namespace { } // Workaround for passing: Execute a non-move with any piece - if (pos.pass() && !pos.count(Us) && pos.pieces(Us)) + if (pos.pass(Us) && !pos.count(Us) && pos.pieces(Us)) *moveList++ = make(lsb(pos.pieces(Us)), lsb(pos.pieces(Us))); } @@ -454,7 +454,7 @@ namespace { moveList = make_move_and_gating(pos, moveList, Us, ksq, pop_lsb(b)); // Passing move by king - if (pos.pass()) + if (pos.pass(Us)) *moveList++ = make(ksq, ksq); if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING)) diff --git a/src/parser.cpp b/src/parser.cpp index c925b2dee..7535e686e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -475,8 +475,14 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("seirawanGating", v->seirawanGating); parse_attribute("cambodianMoves", v->cambodianMoves); parse_attribute("diagonalLines", v->diagonalLines); - parse_attribute("pass", v->pass); - parse_attribute("passOnStalemate", v->passOnStalemate); + parse_attribute("pass", v->pass[WHITE]); + parse_attribute("pass", v->pass[BLACK]); + parse_attribute("passWhite", v->pass[WHITE]); + parse_attribute("passBlack", v->pass[BLACK]); + parse_attribute("passOnStalemate", v->passOnStalemate[WHITE]); + parse_attribute("passOnStalemate", v->passOnStalemate[BLACK]); + parse_attribute("passOnStalemateWhite", v->passOnStalemate[WHITE]); + parse_attribute("passOnStalemateBlack", v->passOnStalemate[BLACK]); parse_attribute("makpongRule", v->makpongRule); parse_attribute("flyingGeneral", v->flyingGeneral); parse_attribute("soldierPromotionRank", v->soldierPromotionRank); @@ -529,6 +535,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("connectValue", v->connectValue); parse_attribute("materialCounting", v->materialCounting); parse_attribute("countingRule", v->countingRule); parse_attribute("castlingWins", v->castlingWins); diff --git a/src/position.cpp b/src/position.cpp index 9b8ce391d..a7ada05c6 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1092,7 +1092,7 @@ bool Position::legal(Move m) const { return false; // Illegal king passing move - if (pass_on_stalemate() && is_pass(m) && !checkers()) + if (pass_on_stalemate(us) && is_pass(m) && !checkers()) { for (const auto& move : MoveList(*this)) if (!is_pass(move) && legal(move)) @@ -1557,7 +1557,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { Piece captured = piece_on(type_of(m) == EN_PASSANT ? capture_square(to) : to); if (to == from) { - assert((type_of(m) == PROMOTION && sittuyin_promotion()) || (is_pass(m) && pass())); + assert((type_of(m) == PROMOTION && sittuyin_promotion()) || (is_pass(m) && pass(us))); captured = NO_PIECE; } st->capturedpromoted = is_promoted(to); @@ -2126,7 +2126,7 @@ void Position::undo_move(Move m) { assert(type_of(m) == DROP || empty(from) || type_of(m) == CASTLING || is_gating(m) || (type_of(m) == PROMOTION && sittuyin_promotion()) - || (is_pass(m) && pass())); + || (is_pass(m) && pass(us))); assert(type_of(st->capturedPiece) != KING); // Reset wall squares @@ -2564,7 +2564,7 @@ bool Position::see_ge(Move m, Value threshold) const { return bool(res); } -/// Position::is_optinal_game_end() tests whether the position may end the game by +/// Position::is_optional_game_end() tests whether the position may end the game by /// 50-move rule, by repetition, or a variant rule that allows a player to claim a game result. bool Position::is_optional_game_end(Value& result, int ply, int countStarted) const { @@ -2801,7 +2801,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { b &= shift(d, b); if (b) { - result = mated_in(ply); + result = convert_mate_value(-var->connectValue, ply); return true; } } @@ -2820,7 +2820,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { if (newBitboard & target) { // A connection has been made - result = mated_in(ply); + result = convert_mate_value(-var->connectValue, ply); return true; } @@ -2840,7 +2840,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { connectors &= shift(connectors) & shift(connectors) & shift(connectors); if (connectors) { - result = mated_in(ply); + result = convert_mate_value(-var->connectValue, ply); return true; } } diff --git a/src/position.h b/src/position.h index 81c61dd49..4ee936657 100644 --- a/src/position.h +++ b/src/position.h @@ -182,8 +182,8 @@ class Position { bool seirawan_gating() const; bool cambodian_moves() const; Bitboard diagonal_lines() const; - bool pass() const; - bool pass_on_stalemate() const; + bool pass(Color c) const; + bool pass_on_stalemate(Color c) const; Bitboard promoted_soldiers(Color c) const; bool makpong() const; EnclosingRule flip_enclosed_pieces() const; @@ -812,14 +812,14 @@ inline Bitboard Position::diagonal_lines() const { return var->diagonalLines; } -inline bool Position::pass() const { +inline bool Position::pass(Color c) const { assert(var != nullptr); - return var->pass || var->passOnStalemate; + return var->pass[c] || var->passOnStalemate[c]; } -inline bool Position::pass_on_stalemate() const { +inline bool Position::pass_on_stalemate(Color c) const { assert(var != nullptr); - return var->passOnStalemate; + return var->passOnStalemate[c]; } inline Bitboard Position::promoted_soldiers(Color c) const { diff --git a/src/variant.cpp b/src/variant.cpp index 8a4246817..cd565baf2 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -1136,7 +1136,8 @@ namespace { v->immobilityIllegal = false; v->stalemateValue = -VALUE_MATE; v->stalematePieceCount = true; - v->passOnStalemate = true; + v->passOnStalemate[WHITE] = true; + v->passOnStalemate[BLACK] = true; v->enclosingDrop = ATAXX; v->flipEnclosedPieces = ATAXX; v->materialCounting = UNWEIGHTED_MATERIAL; @@ -1160,7 +1161,8 @@ namespace { v->immobilityIllegal = false; v->stalemateValue = -VALUE_MATE; v->stalematePieceCount = true; - v->passOnStalemate = false; + v->passOnStalemate[WHITE] = false; + v->passOnStalemate[BLACK] = false; v->enclosingDrop = REVERSI; v->enclosingDropStart = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5); v->flipEnclosedPieces = REVERSI; @@ -1172,7 +1174,8 @@ namespace { Variant* flipello_variant() { Variant* v = flipersi_variant()->init(); v->startFen = "8/8/8/3pP3/3Pp3/8/8/8[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppp] w 0 1"; - v->passOnStalemate = true; + v->passOnStalemate[WHITE] = true; + v->passOnStalemate[BLACK] = true; return v; } // Minixiangqi @@ -1742,7 +1745,8 @@ namespace { v->materialCounting = JANGGI_MATERIAL; v->diagonalLines = make_bitboard(SQ_D1, SQ_F1, SQ_E2, SQ_D3, SQ_F3, SQ_D8, SQ_F8, SQ_E9, SQ_D10, SQ_F10); - v->pass = true; + v->pass[WHITE] = true; + v->pass[BLACK] = true; v->nFoldValue = VALUE_DRAW; v->perpetualCheckIllegal = true; return v; diff --git a/src/variant.h b/src/variant.h index 49bc54404..b9174ad07 100644 --- a/src/variant.h +++ b/src/variant.h @@ -111,8 +111,8 @@ struct Variant { bool seirawanGating = false; bool cambodianMoves = false; Bitboard diagonalLines = 0; - bool pass = false; - bool passOnStalemate = false; + bool pass[COLOR_NB] = {false, false}; + bool passOnStalemate[COLOR_NB] = {false, false}; bool makpongRule = false; bool flyingGeneral = false; Rank soldierPromotionRank = RANK_1; @@ -155,6 +155,7 @@ struct Variant { Bitboard connectRegion1[COLOR_NB] = {}; Bitboard connectRegion2[COLOR_NB] = {}; int connectNxN = 0; + Value connectValue = VALUE_MATE; MaterialCounting materialCounting = NO_MATERIAL_COUNTING; CountingRule countingRule = NO_COUNTING; CastlingRights castlingWins = NO_CASTLING; diff --git a/src/variants.ini b/src/variants.ini index b7dd011f9..6b3ea7407 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -236,7 +236,11 @@ # cambodianMoves: enable special moves of cambodian chess, requires "gating = true" [bool] (default: false) # diagonalLines: enable special moves along diagonal for specific squares (Janggi) [Bitboard] # pass: allow passing [bool] (default: false) +# passWhite: allow passing for white [bool] (default: false) +# passBlack: allow passing for black [bool] (default: false) # passOnStalemate: allow passing in case of stalemate [bool] (default: false) +# passOnStalemateWhite: allow passing in case of stalemate for white [bool] (default: false) +# passOnStalemateBlack: allow passing in case of stalemate for black [bool] (default: false) # makpongRule: the king may not move away from check [bool] (default: false) # flyingGeneral: disallow general face-off like in xiangqi [bool] (default: false) # soldierPromotionRank: restrict soldier to shogi pawn movements until reaching n-th rank [Rank] (default: 1) @@ -284,6 +288,7 @@ # connectRegion1Black: " # connectRegion2Black: " # connectNxN: connect a tight NxN square for win [int] (default: 0) +# connectValue: result in case of connect [Value] (default: win) # materialCounting: enable material counting rules [MaterialCounting] (default: none) # countingRule: enable counting rules [CountingRule] (default: none) # castlingWins: Specified castling moves are win conditions. Losing these rights is losing. [CastlingRights] (default: -) @@ -1903,3 +1908,6 @@ maxRank = 7 startFen = 7/7/7/7/7/7/7[PPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppp] w - - 0 1 enclosingDrop = anyside +#http://gamescrafters.berkeley.edu/games.php?game=connect4 +[cfour-misere:cfour] +connectValue = loss diff --git a/src/xboard.cpp b/src/xboard.cpp index 482b5e47f..09228edb3 100644 --- a/src/xboard.cpp +++ b/src/xboard.cpp @@ -308,7 +308,7 @@ void StateMachine::process_command(std::string token, std::istringstream& is) { std::getline(is >> std::ws, fen); // Check if setboard actually indicates a passing move // to avoid unnecessarily clearing the move history - if (pos.pass()) + if (pos.pass(~pos.side_to_move())) { StateInfo st; Position p;