{
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<KING>(Us))
score += make_score(5000, pos.non_pawn_material(Us)) / pos.count<ALL_PIECES>(Us);
}
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);
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);
}
// 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())
{
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<ALL_PIECES>(~sideToMove) == 1)))
+ && count<ALL_PIECES>(~sideToMove) == extinction_piece_count() + 1)))
return extinction_value() < VALUE_ZERO;
int swap = PieceValue[MG][piece_on(to)] - threshold;
// 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()
Value extinction_value(int ply = 0) const;
bool bare_king_move() const;
const std::set<PieceType>& 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;
// 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;
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;
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]++;
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() {
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());
bool dropChecks = true;
bool mustCapture = false;
bool mustDrop = false;
+ PieceType mustDropType = ALL_PIECES;
bool pieceDrops = false;
bool dropLoop = false;
bool capturesToHand = false;
Value extinctionValue = VALUE_NONE;
bool bareKingMove = false;
std::set<PieceType> extinctionPieceTypes = {};
+ int extinctionPieceCount = 0;
+ int extinctionOpponentPieceCount = 0;
PieceType flagPiece = NO_PIECE_TYPE;
Bitboard whiteFlag = 0;
Bitboard blackFlag = 0;
# 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)
# extinctionValue: result when one of extinctionPieceTypes is extinct [Value] (default: <none>)
# 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: <none>)
+# 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: <none>)
# whiteFlag: white's target region for capture the flag win rule [Bitboard] (default: <none>)
# blackFlag: black's target region for capture the flag win rule [Bitboard] (default: <none>)