From: Fabian Fichter Date: Thu, 20 Feb 2020 20:56:43 +0000 (+0100) Subject: Support Koedem X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=26187ca22bcc988b48fbb80692be6b4740303ed4;p=fairystockfish.git Support Koedem http://schachclub-oetigheim.de/wp-content/uploads/2016/04/Koedem-rules.pdf Closes #78. --- diff --git a/src/evaluate.cpp b/src/evaluate.cpp index f5e88d1..b3382c5 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -911,7 +911,11 @@ namespace { { for (PieceType pt : pos.extinction_piece_types()) if (pt != ALL_PIECES) - score += make_score(1100, 1100) / pos.count(Us, pt) * (pos.extinction_value() / VALUE_MATE); + { + int denom = std::max(pos.count(Us, pt) - pos.extinction_piece_count(), 1); + if (pos.count(Them, pt) >= pos.extinction_opponent_piece_count() || pos.two_boards()) + score += make_score(1100, 1100) / denom * (pos.extinction_value() / VALUE_MATE); + } else if (pos.extinction_value() == VALUE_MATE && !pos.count(Us)) score += make_score(5000, pos.non_pawn_material(Us)) / pos.count(Us); } diff --git a/src/parser.cpp b/src/parser.cpp index 8798b17..50e192c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -224,6 +224,7 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("dropChecks", v->dropChecks); parse_attribute("mustCapture", v->mustCapture); parse_attribute("mustDrop", v->mustDrop); + parse_attribute("mustDropType", v->mustDropType, v->pieceToChar); parse_attribute("pieceDrops", v->pieceDrops); parse_attribute("dropLoop", v->dropLoop); parse_attribute("capturesToHand", v->capturesToHand); @@ -269,6 +270,8 @@ Variant* VariantParser::parse(Variant* v) { if (DoCheck && idx == std::string::npos) std::cerr << "extinctionPieceTypes - Invalid piece type: " << token << std::endl; } + parse_attribute("extinctionPieceCount", v->extinctionPieceCount); + parse_attribute("extinctionOpponentPieceCount", v->extinctionOpponentPieceCount); parse_attribute("flagPiece", v->flagPiece, v->pieceToChar); parse_attribute("whiteFlag", v->whiteFlag); parse_attribute("blackFlag", v->blackFlag); diff --git a/src/position.cpp b/src/position.cpp index 4c5f7d4..0596378 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -819,7 +819,7 @@ bool Position::legal(Move m) const { } // Illegal non-drop moves - if (must_drop() && type_of(m) != DROP && count_in_hand(us, ALL_PIECES)) + if (must_drop() && type_of(m) != DROP && count_in_hand(us, var->mustDropType)) { if (checkers()) { @@ -1615,9 +1615,9 @@ bool Position::see_ge(Move m, Value threshold) const { if ( extinction_value() != VALUE_NONE && piece_on(to) && ( ( extinction_piece_types().find(type_of(piece_on(to))) != extinction_piece_types().end() - && pieceCount[piece_on(to)] == 1) + && pieceCount[piece_on(to)] == extinction_piece_count() + 1) || ( extinction_piece_types().find(ALL_PIECES) != extinction_piece_types().end() - && count(~sideToMove) == 1))) + && count(~sideToMove) == extinction_piece_count() + 1))) return extinction_value() < VALUE_ZERO; int swap = PieceValue[MG][piece_on(to)] - threshold; @@ -1832,12 +1832,14 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { // extinction if (extinction_value() != VALUE_NONE) { - for (PieceType pt : extinction_piece_types()) - if (!count(WHITE, pt) || !count(BLACK, pt)) - { - result = !count(sideToMove, pt) ? extinction_value(ply) : -extinction_value(ply); - return true; - } + for (Color c : { WHITE, BLACK }) + for (PieceType pt : extinction_piece_types()) + if ( count_with_hand( c, pt) <= var->extinctionPieceCount + && count_with_hand(~c, pt) >= var->extinctionOpponentPieceCount) + { + result = c == sideToMove ? extinction_value(ply) : -extinction_value(ply); + return true; + } } // capture the flag if ( capture_the_flag_piece() diff --git a/src/position.h b/src/position.h index b6b8a24..6d9c59f 100644 --- a/src/position.h +++ b/src/position.h @@ -150,6 +150,8 @@ public: Value extinction_value(int ply = 0) const; bool bare_king_move() const; const std::set& extinction_piece_types() const; + int extinction_piece_count() const; + int extinction_opponent_piece_count() const; PieceType capture_the_flag_piece() const; Bitboard capture_the_flag(Color c) const; bool flag_move() const; @@ -160,6 +162,7 @@ public: // Variant-specific properties int count_in_hand(Color c, PieceType pt) const; + int count_with_hand(Color c, PieceType pt) const; // Position representation Bitboard pieces() const; @@ -647,6 +650,16 @@ inline const std::set& Position::extinction_piece_types() const { return var->extinctionPieceTypes; } +inline int Position::extinction_piece_count() const { + assert(var != nullptr); + return var->extinctionPieceCount; +} + +inline int Position::extinction_opponent_piece_count() const { + assert(var != nullptr); + return var->extinctionOpponentPieceCount; +} + inline PieceType Position::capture_the_flag_piece() const { assert(var != nullptr); return var->flagPiece; @@ -975,6 +988,10 @@ inline int Position::count_in_hand(Color c, PieceType pt) const { return pieceCountInHand[c][pt]; } +inline int Position::count_with_hand(Color c, PieceType pt) const { + return pieceCount[make_piece(c, pt)] + pieceCountInHand[c][pt]; +} + inline void Position::add_to_hand(Piece pc) { pieceCountInHand[color_of(pc)][type_of(pc)]++; pieceCountInHand[color_of(pc)][ALL_PIECES]++; diff --git a/src/variant.cpp b/src/variant.cpp index 70a41d4..9307ae5 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -287,6 +287,20 @@ namespace { v->variantTemplate = "bughouse"; v->twoBoards = true; v->capturesToHand = false; + v->stalemateValue = -VALUE_MATE; + return v; + } + // Koedem (Bughouse variant) + // http://schachclub-oetigheim.de/wp-content/uploads/2016/04/Koedem-rules.pdf + Variant* koedem_variant() { + Variant* v = bughouse_variant(); + v->remove_piece(KING); + v->add_piece(COMMONER, 'k'); + v->mustDrop = true; + v->mustDropType = COMMONER; + v->extinctionValue = -VALUE_MATE; + v->extinctionPieceTypes = {COMMONER}; + v->extinctionOpponentPieceCount = 2; // own all kings/commoners return v; } Variant* pocketknight_variant() { @@ -865,6 +879,7 @@ void VariantMap::init() { add("loop", loop_variant()); add("chessgi", chessgi_variant()); add("bughouse", bughouse_variant()); + add("koedem", koedem_variant()); add("pocketknight", pocketknight_variant()); add("placement", placement_variant()); add("sittuyin", sittuyin_variant()); diff --git a/src/variant.h b/src/variant.h index ec7712a..0ee06d3 100644 --- a/src/variant.h +++ b/src/variant.h @@ -69,6 +69,7 @@ struct Variant { bool dropChecks = true; bool mustCapture = false; bool mustDrop = false; + PieceType mustDropType = ALL_PIECES; bool pieceDrops = false; bool dropLoop = false; bool capturesToHand = false; @@ -103,6 +104,8 @@ struct Variant { Value extinctionValue = VALUE_NONE; bool bareKingMove = false; std::set extinctionPieceTypes = {}; + int extinctionPieceCount = 0; + int extinctionOpponentPieceCount = 0; PieceType flagPiece = NO_PIECE_TYPE; Bitboard whiteFlag = 0; Bitboard blackFlag = 0; diff --git a/src/variants.ini b/src/variants.ini index 89fe1ef..399f0ed 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -126,6 +126,7 @@ # dropChecks: allow checks by piece drops [bool] (default: true) # mustCapture: captures are mandatory (check evasion still takes precedence) [bool] (default: false) # mustDrop: drops are mandatory (e.g., for Sittuyin setup phase) [bool] (default: false) +# mustDropType: piece type for which piece drops are mandatory [PieceType] (default: *) # pieceDrops: enable piece drops [bool] (default: false) # dropLoop: captures promoted pieces are not demoted [bool] (default: false) # capturesToHand: captured pieces are go to opponent's hand [bool] (default: false) @@ -158,6 +159,8 @@ # extinctionValue: result when one of extinctionPieceTypes is extinct [Value] (default: ) # bareKingMove: allow additional move by opponent after lone/bare king position [bool] (default: false) # extinctionPieceTypes: list of piece types for extinction rules, e.g., pnbrq (* means all) (default: ) +# extinctionPieceCount: piece count at which the game is decided by extinction rule (default: 0) +# extinctionOpponentPieceCount: opponent piece count required to adjudicate by extinction rule (default: 0) # flagPiece: piece type for capture the flag win rule [PieceType] (default: ) # whiteFlag: white's target region for capture the flag win rule [Bitboard] (default: ) # blackFlag: black's target region for capture the flag win rule [Bitboard] (default: )