Support giveaway, antichess, extinction, and kinglet chess
authorianfab <ianfab@users.noreply.github.com>
Sat, 14 Jul 2018 17:33:36 +0000 (19:33 +0200)
committerianfab <ianfab@users.noreply.github.com>
Sat, 14 Jul 2018 17:59:28 +0000 (19:59 +0200)
Includes implementation of
- positions without kings
- castling with non-king piece
- winning condition "extinction"
- piece type commoner

bench: 4948195

src/bitboard.cpp
src/evaluate.cpp
src/movegen.cpp
src/position.cpp
src/position.h
src/psqt.cpp
src/types.h
src/variant.cpp
src/variant.h

index f43eb82..52f42fb 100644 (file)
@@ -167,6 +167,7 @@ void Bitboards::init() {
       { 15, 17 }, // shogi knight
       { -1, 1, 15, 17 }, // euroshogi knight
       { -8, -1, 1, 7, 8, 9 }, // gold
+      { -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner
       { -9, -8, -7, -1, 1, 7, 8, 9 } // king
   };
   int stepsQuiet[][13] = {
@@ -190,6 +191,7 @@ void Bitboards::init() {
       { 15, 17 }, // shogi knight
       { -1, 1, 15, 17 }, // euroshogi knight
       { -8, -1, 1, 7, 8, 9 }, // gold
+      { -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner
       { -9, -8, -7, -1, 1, 7, 8, 9 } // king
   };
   Direction sliderCapture[][9] = {
@@ -213,6 +215,7 @@ void Bitboards::init() {
     {}, // shogi knight
     {}, // euroshogi knight
     {}, // gold
+    {}, // commoner
     {} // king
   };
   Direction sliderQuiet[][9] = {
@@ -236,6 +239,7 @@ void Bitboards::init() {
     {}, // shogi knight
     {}, // euroshogi knight
     {}, // gold
+    {}, // commoner
     {} // king
   };
   int sliderDistCapture[] = {
@@ -259,6 +263,7 @@ void Bitboards::init() {
     0, // shogi knight
     0, // euroshogi knight
     0, // gold
+    0, // commoner
     0  // king
   };
   int sliderDistQuiet[] = {
@@ -282,6 +287,7 @@ void Bitboards::init() {
     0, // shogi knight
     0, // euroshogi knight
     0, // gold
+    0, // commoner
     0  // king
   };
 
index 5abb88a..43f30bc 100644 (file)
@@ -264,13 +264,13 @@ namespace {
     mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them));
 
     // Initialise attackedBy bitboards for kings and pawns
-    attackedBy[Us][KING] = pos.attacks_from<KING>(Us, pos.square<KING>(Us));
+    attackedBy[Us][KING] = pos.count<KING>(Us) ? pos.attacks_from<KING>(Us, pos.square<KING>(Us)) : 0;
     attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
     attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
     attackedBy2[Us]            = attackedBy[Us][KING] & attackedBy[Us][PAWN];
 
     // Init our king safety tables only if we are going to use them
-    if (pos.non_pawn_material(Them) >= RookValueMg + KnightValueMg)
+    if (pos.count<KING>(Us) && pos.non_pawn_material(Them) >= RookValueMg + KnightValueMg)
     {
         kingRing[Us] = attackedBy[Us][KING];
         if (relative_rank(Us, pos.square<KING>(Us)) == RANK_1)
@@ -336,7 +336,8 @@ namespace {
             mobility[Us] += make_score(300, 300) * (mob - 2) / (10 + mob);
 
         // Penalty if the piece is far from the king
-        score -= KingProtector[Pt - 2] * distance(s, pos.square<KING>(Us));
+        if (pos.count<KING>(Us))
+            score -= KingProtector[Pt - 2] * distance(s, pos.square<KING>(Us));
 
         if (Pt == BISHOP || Pt == KNIGHT)
         {
@@ -393,7 +394,7 @@ namespace {
                 score += RookOnFile[bool(pe->semiopen_file(Them, file_of(s)))];
 
             // Penalty when trapped by the king, even more if the king cannot castle
-            else if (mob <= 3)
+            else if (mob <= 3 && pos.count<KING>(Us))
             {
                 File kf = file_of(pos.square<KING>(Us));
                 if ((kf < FILE_E) == (file_of(s) < kf))
@@ -424,6 +425,9 @@ namespace {
     constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
                                            : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
 
+    if (!pos.count<KING>(Us))
+        return SCORE_ZERO;
+
     const Square ksq = pos.square<KING>(Us);
     Bitboard weak, b, b1, b2, safe, unsafeChecks;
 
@@ -638,7 +642,7 @@ namespace {
     constexpr Direction Up   = (Us == WHITE ? NORTH : SOUTH);
 
     auto king_proximity = [&](Color c, Square s) {
-      return std::min(distance(pos.square<KING>(c), s), 5);
+      return pos.count<KING>(c) ? std::min(distance(pos.square<KING>(c), s), 5) : 5;
     };
 
     Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
@@ -817,8 +821,9 @@ namespace {
   template<Tracing T>
   Score Evaluation<T>::initiative(Value eg) const {
 
-    int outflanking =  distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
-                     - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
+    int outflanking = !pos.count<KING>(WHITE) || !pos.count<KING>(BLACK) ? 0
+                     :  distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
+                      - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
 
     bool pawnsOnBothFlanks =   (pos.pieces(PAWN) & QueenSide)
                             && (pos.pieces(PAWN) & KingSide);
index 5f0cb89..4425bd7 100644 (file)
@@ -35,7 +35,7 @@ namespace {
 
     // After castling, the rook and king final positions are the same in Chess960
     // as they would be in standard chess.
-    Square kfrom = pos.square<KING>(us);
+    Square kfrom = pos.count<KING>(us) ? pos.square<KING>(us) : make_square(FILE_E, us == WHITE ? RANK_1 : RANK_8);
     Square rfrom = pos.castling_rook_square(Cr);
     Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1);
     Bitboard enemies = pos.pieces(~us);
@@ -45,15 +45,18 @@ namespace {
     const Direction step = Chess960 ? kto > kfrom ? WEST : EAST
                                     : KingSide    ? WEST : EAST;
 
-    for (Square s = kto; s != kfrom; s += step)
-        if (pos.attackers_to(s) & enemies)
-            return moveList;
+    if (type_of(pos.piece_on(kfrom)) == KING)
+    {
+        for (Square s = kto; s != kfrom; s += step)
+            if (pos.attackers_to(s) & enemies)
+                return moveList;
 
-    // Because we generate only legal castling moves we need to verify that
-    // when moving the castling rook we do not discover some hidden checker.
-    // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
-    if (Chess960 && (pos.attackers_to(kto, pos.pieces() ^ rfrom) & pos.pieces(~us)))
-        return moveList;
+        // Because we generate only legal castling moves we need to verify that
+        // when moving the castling rook we do not discover some hidden checker.
+        // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
+        if (Chess960 && (pos.attackers_to(kto, pos.pieces() ^ rfrom) & pos.pieces(~us)))
+            return moveList;
+    }
 
     Move m = make<CASTLING>(kfrom, rfrom);
 
@@ -134,7 +137,7 @@ namespace {
             b2 &= target;
         }
 
-        if (Type == QUIET_CHECKS)
+        if (Type == QUIET_CHECKS && pos.count<KING>(Them))
         {
             Square ksq = pos.square<KING>(Them);
 
@@ -274,7 +277,7 @@ namespace {
         for (PieceType pt = PAWN; pt < KING; ++pt)
             moveList = generate_drops<Us, Checks>(pos, moveList, pt, target & ~pos.pieces(~Us));
 
-    if (Type != QUIET_CHECKS && Type != EVASIONS)
+    if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count<KING>(Us))
     {
         Square ksq = pos.square<KING>(Us);
         Bitboard b = pos.attacks_from<KING>(Us, ksq) & target;
index 2de52df..618c82a 100644 (file)
@@ -374,7 +374,7 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
 
 void Position::set_castling_right(Color c, Square rfrom) {
 
-  Square kfrom = square<KING>(c);
+  Square kfrom = count<KING>(c) ? square<KING>(c) : make_square(FILE_E, c == WHITE ? RANK_1 : RANK_8);
   CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE;
   CastlingRight cr = (c | cs);
 
@@ -400,13 +400,13 @@ void Position::set_castling_right(Color c, Square rfrom) {
 
 void Position::set_check_info(StateInfo* si) const {
 
-  si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), si->pinners[BLACK]);
-  si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si->pinners[WHITE]);
+  si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), count<KING>(WHITE) ? square<KING>(WHITE) : SQ_NONE, si->pinners[BLACK]);
+  si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), count<KING>(BLACK) ? square<KING>(BLACK) : SQ_NONE, si->pinners[WHITE]);
 
-  Square ksq = square<KING>(~sideToMove);
+  Square ksq = count<KING>(~sideToMove) ? square<KING>(~sideToMove) : SQ_NONE;
 
   for (PieceType pt = PAWN; pt < KING; ++pt)
-      si->checkSquares[pt] = attacks_from(~sideToMove, pt, ksq);
+      si->checkSquares[pt] = ksq != SQ_NONE ? attacks_from(~sideToMove, pt, ksq) : 0;
   si->checkSquares[KING]   = 0;
 }
 
@@ -422,7 +422,7 @@ void Position::set_state(StateInfo* si) const {
   si->pawnKey = Zobrist::noPawns;
   si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO;
   si->psq = SCORE_ZERO;
-  si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
+  si->checkersBB = count<KING>(sideToMove) ? attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove) : 0;
 
   set_check_info(si);
 
@@ -585,6 +585,9 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners
   Bitboard blockers = 0;
   pinners = 0;
 
+  if (s == SQ_NONE)
+      return blockers;
+
   // Snipers are sliders that attack 's' when a piece is removed
   Bitboard snipers =   sliders
                     &  attackers_to(s, 0)
@@ -629,10 +632,10 @@ bool Position::legal(Move m) const {
   Color us = sideToMove;
   Square from = from_sq(m);
   Square to = to_sq(m);
-  Square ksq = square<KING>(us);
+  Square ksq = count<KING>(us) ? square<KING>(us) : SQ_NONE;
 
   assert(color_of(moved_piece(m)) == us);
-  assert(piece_on(square<KING>(us)) == make_piece(us, KING));
+  assert(!count<KING>(us) || piece_on(square<KING>(us)) == make_piece(us, KING));
 
   // illegal moves to squares outside of board
   if (rank_of(to) > max_rank() || file_of(to) > max_file())
@@ -680,7 +683,7 @@ bool Position::legal(Move m) const {
       assert(piece_on(capsq) == make_piece(~us, PAWN));
       assert(piece_on(to) == NO_PIECE);
 
-      return !(attackers_to(ksq, occupied) & pieces(~us) & occupied);
+      return !count<KING>(us) || !(attackers_to(ksq, occupied) & pieces(~us) & occupied);
   }
 
   // If the moving piece is a king, check whether the destination
@@ -690,7 +693,7 @@ bool Position::legal(Move m) const {
       return type_of(m) == CASTLING || !(attackers_to(to) & pieces(~us));
 
   // A non-king move is legal if the king is not under attack after the move.
-  return !(  attackers_to(ksq, (type_of(m) != DROP ? pieces() ^ from : pieces()) | to)
+  return !count<KING>(us) || !(  attackers_to(ksq, (type_of(m) != DROP ? pieces() ^ from : pieces()) | to)
            & pieces(~us) & ~SquareBB[to]);
 }
 
@@ -780,6 +783,10 @@ bool Position::gives_check(Move m) const {
   Square from = from_sq(m);
   Square to = to_sq(m);
 
+  // No check possible without king
+  if (!count<KING>(~sideToMove))
+      return false;
+
   // Is there a direct check?
   if (st->checkSquares[type_of(moved_piece(m))] & to)
       return true;
@@ -869,7 +876,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
 
   if (type_of(m) == CASTLING)
   {
-      assert(pc == make_piece(us, KING));
+      assert(type_of(pc) != NO_PIECE_TYPE);
       assert(captured == make_piece(us, ROOK));
 
       Square rfrom, rto;
@@ -1129,10 +1136,11 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
   to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
 
   // Remove both pieces first since squares could overlap in Chess960
-  remove_piece(make_piece(us, KING), Do ? from : to);
+  Piece castling_piece = piece_on(Do ? from : to);
+  remove_piece(castling_piece, Do ? from : to);
   remove_piece(make_piece(us, ROOK), Do ? rfrom : rto);
   board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
-  put_piece(make_piece(us, KING), Do ? to : from);
+  put_piece(castling_piece, Do ? to : from);
   put_piece(make_piece(us, ROOK), Do ? rto : rfrom);
 }
 
@@ -1447,8 +1455,8 @@ bool Position::pos_is_ok() const {
   constexpr bool Fast = true; // Quick (default) or full check?
 
   if (   (sideToMove != WHITE && sideToMove != BLACK)
-      || piece_on(square<KING>(WHITE)) != make_piece(WHITE, KING)
-      || piece_on(square<KING>(BLACK)) != make_piece(BLACK, KING)
+      || (count<KING>(WHITE) && piece_on(square<KING>(WHITE)) != make_piece(WHITE, KING))
+      || (count<KING>(BLACK) && piece_on(square<KING>(BLACK)) != make_piece(BLACK, KING))
       || (   ep_square() != SQ_NONE
           && relative_rank(sideToMove, ep_square()) != RANK_6))
       assert(0 && "pos_is_ok: Default");
@@ -1456,9 +1464,8 @@ bool Position::pos_is_ok() const {
   if (Fast)
       return true;
 
-  if (   pieceCount[make_piece(WHITE, KING)] != 1
-      || pieceCount[make_piece(BLACK, KING)] != 1
-      || attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
+  if (   pieceCount[make_piece(~sideToMove, KING)]
+      && (attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove)))
       assert(0 && "pos_is_ok: Kings");
 
   if (   (pieces(PAWN) & Rank8BB)
index 8331e6c..926c871 100644 (file)
@@ -106,7 +106,9 @@ public:
   Value stalemate_value(int ply = 0) const;
   Value checkmate_value(int ply = 0) const;
   Value bare_king_value(int ply = 0) const;
+  Value extinction_value(int ply = 0) const;
   bool bare_king_move() const;
+  const std::set<PieceType>& extinction_piece_types() const;
   Bitboard capture_the_flag(Color c) const;
   bool flag_move() const;
   CheckCount max_check_count() const;
@@ -127,6 +129,7 @@ public:
   Piece piece_on(Square s) const;
   Square ep_square() const;
   bool empty(Square s) const;
+  int count(Color c, PieceType pt) const;
   template<PieceType Pt> int count(Color c) const;
   template<PieceType Pt> int count() const;
   template<PieceType Pt> const Square* squares(Color c) const;
@@ -340,11 +343,24 @@ inline Value Position::bare_king_value(int ply) const {
         : v;
 }
 
+inline Value Position::extinction_value(int ply) const {
+  assert(var != nullptr);
+  Value v = var->extinctionValue;
+  return  v ==  VALUE_MATE ? mate_in(ply)
+        : v == -VALUE_MATE ? mated_in(ply)
+        : v;
+}
+
 inline bool Position::bare_king_move() const {
   assert(var != nullptr);
   return var->bareKingMove;
 }
 
+inline const std::set<PieceType>& Position::extinction_piece_types() const {
+  assert(var != nullptr);
+  return var->extinctionPieceTypes;
+}
+
 inline Bitboard Position::capture_the_flag(Color c) const {
   assert(var != nullptr);
   return c == WHITE ? var->whiteFlag : var->blackFlag;
@@ -385,13 +401,23 @@ inline bool Position::is_variant_end(Value& result, int ply) const {
       result = -bare_king_value(ply);
       return true;
   }
+  // 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;
+          }
+  }
   // capture the flag
-  if (!flag_move() && (capture_the_flag(~sideToMove) & square<KING>(~sideToMove)))
+  if (count<KING>(~sideToMove) && !flag_move() && (capture_the_flag(~sideToMove) & square<KING>(~sideToMove)))
   {
       result = mated_in(ply);
       return true;
   }
-  if (flag_move() && (capture_the_flag(sideToMove) & square<KING>(sideToMove)))
+  if (count<KING>( sideToMove) &&  flag_move() && (capture_the_flag( sideToMove) & square<KING>( sideToMove)))
   {
       result = mate_in(ply);
       return true;
@@ -447,6 +473,10 @@ inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
   return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]);
 }
 
+inline int Position::count(Color c, PieceType pt) const {
+  return pieceCount[make_piece(c, pt)];
+}
+
 template<PieceType Pt> inline int Position::count(Color c) const {
   return pieceCount[make_piece(c, Pt)];
 }
index a6a9cf7..ae83b84 100644 (file)
@@ -26,11 +26,13 @@ Value PieceValue[PHASE_NB][PIECE_NB] = {
   { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg,
     FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg, ChancellorValueMg,
     AmazonValueMg, KnibisValueMg, BiskniValueMg,
-    ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg },
+    ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg,
+    CommonerValueMg },
   { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
     FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg, ChancellorValueEg,
     AmazonValueEg, KnibisValueMg, BiskniValueMg,
-    ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg }
+    ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg,
+    CommonerValueEg }
 };
 
 namespace PSQT {
index 94ff7a4..93868ea 100644 (file)
@@ -209,6 +209,7 @@ enum Value : int {
   ShogiKnightValueMg     = 300,   ShogiKnightValueEg     = 300,
   EuroShogiKnightValueMg = 400,   EuroShogiKnightValueEg = 400,
   GoldValueMg            = 600,   GoldValueEg            = 600,
+  CommonerValueMg        = 600,   CommonerValueEg        = 600,
 
   MidgameLimit  = 15258, EndgameLimit  = 3915
 };
@@ -218,7 +219,7 @@ const int PIECE_TYPE_BITS = 5; // PIECE_TYPE_NB = pow(2, PIECE_TYPE_BITS)
 enum PieceType {
   NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK,
   QUEEN, FERS, MET = FERS, ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS, CHANCELLOR,
-  AMAZON, KNIBIS, BISKNI, SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, KING,
+  AMAZON, KNIBIS, BISKNI, SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, COMMONER, KING,
   ALL_PIECES = 0,
 
   PIECE_TYPE_NB = 1 << PIECE_TYPE_BITS
index cc57253..fb9e908 100644 (file)
@@ -128,6 +128,51 @@ void VariantMap::init() {
         v->mustCapture = true;
         return v;
     } ();
+    const Variant* giveaway = [&]{
+        Variant* v = new Variant();
+        v->remove_piece(KING);
+        v->add_piece(COMMONER, 'k');
+        v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
+        v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT};
+        v->stalemateValue = VALUE_MATE;
+        v->extinctionValue = VALUE_MATE;
+        v->extinctionPieceTypes = {ALL_PIECES};
+        v->mustCapture = true;
+        return v;
+    } ();
+    const Variant* antichess = [&]{
+        Variant* v = new Variant();
+        v->remove_piece(KING);
+        v->add_piece(COMMONER, 'k');
+        v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1";
+        v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT};
+        v->stalemateValue = VALUE_MATE;
+        v->extinctionValue = VALUE_MATE;
+        v->extinctionPieceTypes = {ALL_PIECES};
+        v->castling = false;
+        v->mustCapture = true;
+        return v;
+    } ();
+    const Variant* extinction = [&]{
+        Variant* v = new Variant();
+        v->remove_piece(KING);
+        v->add_piece(COMMONER, 'k');
+        v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
+        v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT};
+        v->extinctionValue = -VALUE_MATE;
+        v->extinctionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT, PAWN};
+        return v;
+    } ();
+    const Variant* kinglet = [&]{
+        Variant* v = new Variant();
+        v->remove_piece(KING);
+        v->add_piece(COMMONER, 'k');
+        v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
+        v->promotionPieceTypes = {COMMONER};
+        v->extinctionValue = -VALUE_MATE;
+        v->extinctionPieceTypes = {PAWN};
+        return v;
+    } ();
     const Variant* threecheck = [&]{
         Variant* v = new Variant();
         v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+3 0 1";
@@ -263,6 +308,10 @@ void VariantMap::init() {
     add("kingofthehill", kingofthehill);
     add("racingkings", racingkings);
     add("losers", losers);
+    add("giveaway", giveaway);
+    add("antichess", antichess);
+    add("extinction", extinction);
+    add("kinglet", kinglet);
     add("3check", threecheck);
     add("5check", fivecheck);
     add("crazyhouse", crazyhouse);
index 8644161..a79ffa7 100644 (file)
@@ -54,7 +54,9 @@ struct Variant {
   Value stalemateValue = VALUE_DRAW;
   Value checkmateValue = -VALUE_MATE;
   Value bareKingValue = VALUE_NONE;
+  Value extinctionValue = VALUE_NONE;
   bool bareKingMove = false;
+  std::set<PieceType> extinctionPieceTypes = {};
   Bitboard whiteFlag = 0;
   Bitboard blackFlag = 0;
   bool flagMove = false;