Support crazyhouse and loop chess
authorianfab <ianfab@users.noreply.github.com>
Mon, 25 Jun 2018 21:26:05 +0000 (23:26 +0200)
committerianfab <ianfab@users.noreply.github.com>
Mon, 25 Jun 2018 22:04:43 +0000 (00:04 +0200)
src/bitboard.h
src/movegen.cpp
src/movepick.h
src/position.cpp
src/position.h
src/types.h
src/uci.cpp
src/variant.cpp
src/variant.h

index 0691e54..40a4d8f 100644 (file)
@@ -123,6 +123,11 @@ inline Bitboard operator^(Bitboard b, Square s) {
   return b ^ SquareBB[s];
 }
 
+inline Bitboard operator-(Bitboard b, Square s) {
+  assert(s >= SQ_A1 && s <= SQ_H8);
+  return b & ~SquareBB[s];
+}
+
 inline Bitboard& operator|=(Bitboard& b, Square s) {
   assert(s >= SQ_A1 && s <= SQ_H8);
   return b |= SquareBB[s];
@@ -133,6 +138,11 @@ inline Bitboard& operator^=(Bitboard& b, Square s) {
   return b ^= SquareBB[s];
 }
 
+inline Bitboard& operator-=(Bitboard& b, Square s) {
+  assert(s >= SQ_A1 && s <= SQ_H8);
+  return b &= ~SquareBB[s];
+}
+
 constexpr bool more_than_one(Bitboard b) {
   return b & (b - 1);
 }
@@ -216,6 +226,15 @@ inline Bitboard forward_ranks_bb(Color c, Square s) {
 }
 
 
+/// promotion_zone_bb() returns a bitboard representing the squares on all the ranks
+/// in front of and on the given relative rank, from the point of view of the given color.
+/// For instance, promotion_zone_bb(BLACK, RANK_7) will return the 16 squares on ranks 1 and 2.
+
+inline Bitboard promotion_zone_bb(Color c, Rank r) {
+  return ForwardRanksBB[c][relative_rank(c, r)] | rank_bb(relative_rank(c, r));
+}
+
+
 /// forward_file_bb() returns a bitboard representing all the squares along the line
 /// in front of the given one, from the point of view of the given color:
 ///      ForwardFileBB[c][s] = forward_ranks_bb(c, s) & file_bb(s)
index 288c0cc..88f350d 100644 (file)
@@ -79,6 +79,20 @@ namespace {
     return moveList;
   }
 
+  template<Color Us, bool Checks>
+  ExtMove* generate_drops(const Position& pos, ExtMove* moveList, PieceType pt, Bitboard b) {
+    if (pos.count_in_hand(Us, pt))
+    {
+        if (pt == PAWN)
+            b &= ~(promotion_zone_bb(Us, pos.promotion_rank()) | rank_bb(relative_rank(Us, RANK_1)));
+        if (Checks)
+            b &= pos.check_squares(pt);
+        while (b)
+            *moveList++ = make_drop(pop_lsb(&b), pt);
+    }
+
+    return moveList;
+  }
 
   template<Color Us, GenType Type>
   ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
@@ -251,6 +265,10 @@ namespace {
     moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
     for (PieceType pt = PieceType(PAWN + 1); pt < KING; ++pt)
         moveList = generate_moves<Checks>(pos, moveList, Us, pt, target);
+    // generate drops
+    if (pos.piece_drops() && Type != CAPTURES && pos.count_in_hand(Us, ALL_PIECES))
+        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)
     {
index b6e5620..30a9c2b 100644 (file)
@@ -85,7 +85,7 @@ enum StatsParams { NOT_USED = 0 };
 /// unsuccessful during the current search, and is used for reduction and move
 /// ordering decisions. It uses 2 tables (one for each color) indexed by
 /// the move's from and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards
-typedef Stats<int16_t, 10368, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
+typedef Stats<int16_t, 10368, COLOR_NB, int(SQUARE_NB + 1) * int(SQUARE_NB)> ButterflyHistory;
 
 /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
 /// move, see chessprogramming.wikispaces.com/Countermove+Heuristic
index 841b8b9..1a0d010 100644 (file)
@@ -273,7 +273,22 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
           put_piece(Piece(idx), sq);
           ++sq;
       }
+      // Set flag for promoted pieces
+      else if (piece_drops() && !drop_loop() && token == '~')
+          promotedPieces |= SquareBB[sq - 1];
+      // Stop before pieces in hand
+      else if (token == '[')
+          break;
   }
+  // Pieces in hand
+  if (!isspace(token))
+      while ((ss >> token) && !isspace(token))
+      {
+          if (token == ']')
+              continue;
+          else if ((idx = piece_to_char().find(token)) != string::npos)
+              add_to_hand(color_of(Piece(idx)), type_of(Piece(idx)));
+      }
 
   // 2. Active color
   ss >> token;
@@ -506,7 +521,13 @@ const string Position::fen() const {
               ss << emptyCnt;
 
           if (f <= FILE_H)
+          {
               ss << piece_to_char()[piece_on(make_square(f, r))];
+
+              // Set promoted pieces
+              if (piece_drops() && is_promoted(make_square(f, r)))
+                  ss << "~";
+          }
       }
 
       if (r > RANK_1)
@@ -602,6 +623,7 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
 bool Position::legal(Move m) const {
 
   assert(is_ok(m));
+  assert(type_of(m) != DROP || piece_drops());
 
   Color us = sideToMove;
   Square from = from_sq(m);
@@ -632,6 +654,10 @@ bool Position::legal(Move m) const {
       }
   }
 
+  // illegal drops
+  if (piece_drops() && type_of(m) == DROP)
+      return pieceCountInHand[us][type_of(moved_piece(m))] && empty(to_sq(m));
+
   // game end
   if (is_variant_end())
       return false;
@@ -655,11 +681,12 @@ bool Position::legal(Move m) const {
   // If the moving piece is a king, check whether the destination
   // square is attacked by the opponent. Castling moves are checked
   // for legality during move generation.
-  if (type_of(piece_on(from)) == KING)
+  if (type_of(moved_piece(m)) == KING)
       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, (pieces() ^ from) | to) & pieces(~us) & ~SquareBB[to]);
+  return !(  attackers_to(ksq, (type_of(m) != DROP ? pieces() ^ from : pieces()) | to)
+           & pieces(~us) & ~SquareBB[to]);
 }
 
 
@@ -748,11 +775,12 @@ bool Position::gives_check(Move m) const {
   Square to = to_sq(m);
 
   // Is there a direct check?
-  if (st->checkSquares[type_of(piece_on(from))] & to)
+  if (st->checkSquares[type_of(moved_piece(m))] & to)
       return true;
 
   // Is there a discovered check?
-  if (   (st->blockersForKing[~sideToMove] & from)
+  if (   type_of(m) != DROP
+      && (st->blockersForKing[~sideToMove] & from)
       && (  !aligned(from, to, square<KING>(~sideToMove))
           || (attackers_to(square<KING>(~sideToMove), (pieces() ^ from) | to) & pieces(sideToMove))))
       return true;
@@ -760,6 +788,7 @@ bool Position::gives_check(Move m) const {
   switch (type_of(m))
   {
   case NORMAL:
+  case DROP:
       return false;
 
   case PROMOTION:
@@ -822,7 +851,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   Color them = ~us;
   Square from = from_sq(m);
   Square to = to_sq(m);
-  Piece pc = piece_on(from);
+  Piece pc = moved_piece(m);
   Piece captured = type_of(m) == ENPASSANT ? make_piece(them, PAWN) : piece_on(to);
 
   assert(color_of(pc) == us);
@@ -869,10 +898,24 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
           st->pawnKey ^= Zobrist::psq[captured][capsq];
       }
       else
+      {
           st->nonPawnMaterial[them] -= PieceValue[MG][captured];
+          if (piece_drops() && !is_promoted(to))
+              st->nonPawnMaterial[us] += PieceValue[MG][captured];
+      }
 
       // Update board and piece lists
       remove_piece(captured, capsq);
+      if (piece_drops())
+      {
+          st->capturedpromoted = is_promoted(to);
+          Piece pieceToHand = is_promoted(to) ? make_piece(~color_of(captured), PAWN) : ~captured;
+          add_to_hand(color_of(pieceToHand), type_of(pieceToHand));
+          st->psq += PSQT::psq[pieceToHand][SQ_NONE];
+          k ^=  Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)] - 1]
+              ^ Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)]];
+          promotedPieces -= to;
+      }
 
       // Update material hash key and prefetch access to materialTable
       k ^= Zobrist::psq[captured][capsq];
@@ -887,7 +930,12 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   }
 
   // Update hash key
-  k ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
+  if (type_of(m) == DROP)
+      k ^=  Zobrist::psq[pc][to]
+          ^ Zobrist::inHand[pc][pieceCountInHand[color_of(pc)][type_of(pc)] - 1]
+          ^ Zobrist::inHand[pc][pieceCountInHand[color_of(pc)][type_of(pc)]];
+  else
+      k ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
 
   // Reset en passant square
   if (st->epSquare != SQ_NONE)
@@ -897,7 +945,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   }
 
   // Update castling rights if needed
-  if (st->castlingRights && (castlingRightsMask[from] | castlingRightsMask[to]))
+  if (type_of(m) != DROP && st->castlingRights && (castlingRightsMask[from] | castlingRightsMask[to]))
   {
       int cr = castlingRightsMask[from] | castlingRightsMask[to];
       k ^= Zobrist::castling[st->castlingRights & cr];
@@ -905,7 +953,12 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   }
 
   // Move the piece. The tricky Chess960 castling is handled earlier
-  if (type_of(m) != CASTLING)
+  if (type_of(m) == DROP)
+  {
+      drop_piece(pc, to);
+      st->materialKey ^= Zobrist::psq[pc][pieceCount[pc]-1];
+  }
+  else if (type_of(m) != CASTLING)
       move_piece(pc, from, to);
 
   // If the moving piece is a pawn do some special extra work
@@ -928,6 +981,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
 
           remove_piece(pc, to);
           put_piece(promotion, to);
+          if (piece_drops() && !drop_loop())
+              promotedPieces = promotedPieces | to;
 
           // Update hash keys
           k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
@@ -943,7 +998,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
       }
 
       // Update pawn hash key and prefetch access to pawnsTable
-      st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
+      if (type_of(m) == DROP)
+          st->pawnKey ^= Zobrist::psq[pc][to];
+      else
+          st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
       prefetch2(thisThread->pawnsTable[st->pawnKey]);
 
       // Reset rule 50 draw counter
@@ -955,6 +1013,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
 
   // Set capture piece
   st->capturedPiece = captured;
+  if (piece_drops() && !captured)
+      st->capturedpromoted = false;
 
   // Update the key with the final value
   st->key = k;
@@ -962,6 +1022,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   // Calculate checkers bitboard (if move gives check)
   st->checkersBB = givesCheck ? attackers_to(square<KING>(them)) & pieces(us) : 0;
 
+  if (type_of(m) != DROP && is_promoted(from))
+      promotedPieces = (promotedPieces - from) | to;
+
   sideToMove = ~sideToMove;
 
   // Update king attacks used for fast check detection
@@ -985,7 +1048,7 @@ void Position::undo_move(Move m) {
   Square to = to_sq(m);
   Piece pc = piece_on(to);
 
-  assert(empty(from) || type_of(m) == CASTLING);
+  assert(type_of(m) == DROP || empty(from) || type_of(m) == CASTLING);
   assert(type_of(st->capturedPiece) != KING);
 
   if (type_of(m) == PROMOTION)
@@ -997,6 +1060,8 @@ void Position::undo_move(Move m) {
       remove_piece(pc, to);
       pc = make_piece(us, PAWN);
       put_piece(pc, to);
+      if (piece_drops() && !drop_loop())
+          promotedPieces -= to;
   }
 
   if (type_of(m) == CASTLING)
@@ -1006,7 +1071,12 @@ void Position::undo_move(Move m) {
   }
   else
   {
-      move_piece(pc, to, from); // Put the piece back at the source square
+      if (type_of(m) == DROP)
+          undrop_piece(pc, to); // Remove the dropped piece
+      else
+          move_piece(pc, to, from); // Put the piece back at the source square
+      if (piece_drops() && !drop_loop() && is_promoted(to))
+          promotedPieces = (promotedPieces - to) | from;
 
       if (st->capturedPiece)
       {
@@ -1024,6 +1094,13 @@ void Position::undo_move(Move m) {
           }
 
           put_piece(st->capturedPiece, capsq); // Restore the captured piece
+          if (piece_drops())
+          {
+              remove_from_hand(~color_of(st->capturedPiece),
+                               !drop_loop() && st->capturedpromoted ? PAWN : type_of(st->capturedPiece));
+              if (!drop_loop() && st->capturedpromoted)
+                  promotedPieces |= to;
+          }
       }
   }
 
@@ -1102,12 +1179,23 @@ Key Position::key_after(Move m) const {
 
   Square from = from_sq(m);
   Square to = to_sq(m);
-  Piece pc = piece_on(from);
+  Piece pc = moved_piece(m);
   Piece captured = piece_on(to);
   Key k = st->key ^ Zobrist::side;
 
   if (captured)
+  {
       k ^= Zobrist::psq[captured][to];
+      if (piece_drops())
+      {
+          Piece removeFromHand = !drop_loop() && is_promoted(to) ? make_piece(~color_of(captured), PAWN) : ~captured;
+          k ^= Zobrist::inHand[removeFromHand][pieceCountInHand[color_of(removeFromHand)][type_of(removeFromHand)] + 1]
+              ^ Zobrist::inHand[removeFromHand][pieceCountInHand[color_of(removeFromHand)][type_of(removeFromHand)]];
+      }
+  }
+  if (type_of(m) == DROP)
+      return k ^ Zobrist::psq[pc][to] ^ Zobrist::inHand[pc][pieceCountInHand[color_of(pc)][type_of(pc)]]
+            ^ Zobrist::inHand[pc][pieceCountInHand[color_of(pc)][type_of(pc)] - 1];
 
   return k ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
 }
@@ -1205,7 +1293,7 @@ bool Position::is_draw(int ply) const {
   if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
       return true;
 
-  int end = std::min(st->rule50, st->pliesFromNull);
+  int end = piece_drops() ? st->pliesFromNull : std::min(st->rule50, st->pliesFromNull);
 
   if (end < 4)
     return false;
@@ -1367,15 +1455,15 @@ bool Position::pos_is_ok() const {
       || attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
       assert(0 && "pos_is_ok: Kings");
 
-  if (   (pieces(PAWN) & (Rank1BB | Rank8BB))
-      || pieceCount[make_piece(WHITE, PAWN)] > 8
-      || pieceCount[make_piece(BLACK, PAWN)] > 8)
+  if (   (pieces(PAWN) & Rank8BB)
+      || pieceCount[make_piece(WHITE, PAWN)] > 16
+      || pieceCount[make_piece(BLACK, PAWN)] > 16)
       assert(0 && "pos_is_ok: Pawns");
 
   if (   (pieces(WHITE) & pieces(BLACK))
       || (pieces(WHITE) | pieces(BLACK)) != pieces()
-      || popcount(pieces(WHITE)) > 16
-      || popcount(pieces(BLACK)) > 16)
+      || popcount(pieces(WHITE)) > 32
+      || popcount(pieces(BLACK)) > 32)
       assert(0 && "pos_is_ok: Bitboards");
 
   for (PieceType p1 = PAWN; p1 <= KING; ++p1)
index 1b8cbfe..6fc2006 100644 (file)
@@ -56,6 +56,7 @@ struct StateInfo {
   Bitboard   blockersForKing[COLOR_NB];
   Bitboard   pinners[COLOR_NB];
   Bitboard   checkSquares[PIECE_TYPE_NB];
+  bool       capturedpromoted;
 };
 
 /// A list to keep track of the position states along the setup moves (from the
@@ -94,6 +95,7 @@ public:
   bool checking_permitted() const;
   bool must_capture() const;
   bool piece_drops() const;
+  bool drop_loop() const;
   // winning conditions
   Value stalemate_value(int ply = 0) const;
   Value checkmate_value(int ply = 0) const;
@@ -105,6 +107,9 @@ public:
   bool is_variant_end() const;
   bool is_variant_end(Value& result, int ply = 0) const;
 
+  // Variant-specific properties
+  int count_in_hand(Color c, PieceType pt) const;
+
   // Position representation
   Bitboard pieces() const;
   Bitboard pieces(PieceType pt) const;
@@ -206,8 +211,6 @@ private:
   Bitboard byColorBB[COLOR_NB];
   int pieceCount[PIECE_NB];
   Square pieceList[PIECE_NB][16];
-  int pieceCountInHand[COLOR_NB][PIECE_TYPE_NB];
-  Bitboard promotedPieces;
   int index[SQUARE_NB];
   int castlingRightsMask[SQUARE_NB];
   Square castlingRookSquare[CASTLING_RIGHT_NB];
@@ -216,8 +219,17 @@ private:
   Color sideToMove;
   Thread* thisThread;
   StateInfo* st;
+
+  // variant-specific
   const Variant* var;
   bool chess960;
+  int pieceCountInHand[COLOR_NB][PIECE_TYPE_NB];
+  Bitboard promotedPieces;
+  bool is_promoted(Square s) const;
+  void add_to_hand(Color c, PieceType pt);
+  void remove_from_hand(Color c, PieceType pt);
+  void drop_piece(Piece pc, Square s);
+  void undrop_piece(Piece pc, Square s);
 };
 
 extern std::ostream& operator<<(std::ostream& os, const Position& pos);
@@ -267,6 +279,11 @@ inline bool Position::piece_drops() const {
   return var->pieceDrops;
 }
 
+inline bool Position::drop_loop() const {
+  assert(var != nullptr);
+  return var->dropLoop;
+}
+
 inline Value Position::stalemate_value(int ply) const {
   assert(var != nullptr);
   Value v = var->stalemateValue;
@@ -365,6 +382,8 @@ inline Piece Position::piece_on(Square s) const {
 }
 
 inline Piece Position::moved_piece(Move m) const {
+  if (type_of(m) == DROP)
+      return make_piece(sideToMove, dropped_piece_type(m));
   return board[from_sq(m)];
 }
 
@@ -515,7 +534,7 @@ inline bool Position::is_chess960() const {
 
 inline bool Position::capture_or_promotion(Move m) const {
   assert(is_ok(m));
-  return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
+  return type_of(m) != NORMAL ? type_of(m) != DROP && type_of(m) != CASTLING : !empty(to_sq(m));
 }
 
 inline bool Position::capture(Move m) const {
@@ -578,4 +597,35 @@ inline void Position::do_move(Move m, StateInfo& newSt) {
   do_move(m, newSt, gives_check(m));
 }
 
+inline int Position::count_in_hand(Color c, PieceType pt) const {
+  return pieceCountInHand[c][pt];
+}
+
+inline void Position::add_to_hand(Color c, PieceType pt) {
+  pieceCountInHand[c][pt]++;
+  pieceCountInHand[c][ALL_PIECES]++;
+}
+
+inline void Position::remove_from_hand(Color c, PieceType pt) {
+  pieceCountInHand[c][pt]--;
+  pieceCountInHand[c][ALL_PIECES]--;
+}
+
+inline bool Position::is_promoted(Square s) const {
+  return promotedPieces & s;
+}
+
+inline void Position::drop_piece(Piece pc, Square s) {
+  assert(pieceCountInHand[color_of(pc)][type_of(pc)]);
+  put_piece(pc, s);
+  remove_from_hand(color_of(pc), type_of(pc));
+}
+
+inline void Position::undrop_piece(Piece pc, Square s) {
+  remove_piece(pc, s);
+  board[s] = NO_PIECE;
+  add_to_hand(color_of(pc), type_of(pc));
+  assert(pieceCountInHand[color_of(pc)][type_of(pc)]);
+}
+
 #endif // #ifndef POSITION_H_INCLUDED
index dd9914b..074da9c 100644 (file)
@@ -100,7 +100,7 @@ constexpr bool Is64Bit = false;
 typedef uint64_t Key;
 typedef uint64_t Bitboard;
 
-constexpr int MAX_MOVES = 256;
+constexpr int MAX_MOVES = 512;
 constexpr int MAX_PLY   = 128;
 
 /// A move needs 16 bits to be stored
@@ -128,6 +128,7 @@ enum MoveType {
   PROMOTION_STRAIGHT = PROMOTION,
   PROMOTION_LEFT     = 4 << 12,
   PROMOTION_RIGHT    = 5 << 12,
+  DROP               = 6 << 12,
 };
 
 enum Color {
@@ -464,6 +465,8 @@ constexpr Square to_sq(Move m) {
 }
 
 inline Square from_sq(Move m) {
+  if (type_of(m) == DROP)
+      return SQ_NONE;
   if (type_of(m) == PROMOTION)
   {
       Square to = to_sq(m);
@@ -500,6 +503,14 @@ inline Move make(Square from, Square to, PieceType pt = NO_PIECE_TYPE) {
   return Move(T + (from << 6) + to);
 }
 
+constexpr Move make_drop(Square to, PieceType pt) {
+  return Move(DROP + (pt << 6) + to);
+}
+
+constexpr PieceType dropped_piece_type(Move m) {
+  return PieceType((m >> 6) & 63);
+}
+
 inline bool is_ok(Move m) {
   return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
 }
index cff5242..1692705 100644 (file)
@@ -288,7 +288,8 @@ string UCI::move(const Position& pos, Move m) {
   if (type_of(m) == CASTLING && !pos.is_chess960())
       to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
 
-  string move = UCI::square(from) + UCI::square(to);
+  string move = (type_of(m) == DROP ? std::string{pos.piece_to_char()[type_of(pos.moved_piece(m))], '@'}
+                                    : UCI::square(from)) + UCI::square(to);
 
   if (type_of(m) == PROMOTION)
       move += pos.piece_to_char()[make_piece(BLACK, promotion_type(m))];
index f04201f..75988fb 100644 (file)
@@ -157,6 +157,13 @@ void VariantMap::init() {
         v->pieceDrops = true;
         return v;
     } ();
+    const Variant* loop = [&]{
+        Variant* v = new Variant();
+        v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[] w KQkq - 0 1";
+        v->pieceDrops = true;
+        v->dropLoop = true;
+        return v;
+    } ();
     insert(std::pair<std::string, const Variant*>(std::string("chess"), chess));
     insert(std::pair<std::string, const Variant*>(std::string("makruk"), makruk));
     insert(std::pair<std::string, const Variant*>(std::string("asean"), asean));
@@ -169,7 +176,8 @@ void VariantMap::init() {
     insert(std::pair<std::string, const Variant*>(std::string("losers"), losers));
     insert(std::pair<std::string, const Variant*>(std::string("3check"), threecheck));
     insert(std::pair<std::string, const Variant*>(std::string("5check"), fivecheck));
-    //insert(std::pair<std::string, const Variant*>(std::string("crazyhouse"), crazyhouse));
+    insert(std::pair<std::string, const Variant*>(std::string("crazyhouse"), crazyhouse));
+    insert(std::pair<std::string, const Variant*>(std::string("loop"), loop));
 }
 
 void VariantMap::clear_all() {
index 160398d..f628f73 100644 (file)
@@ -42,6 +42,7 @@ struct Variant {
   bool checking = true;
   bool mustCapture = false;
   bool pieceDrops = false;
+  bool dropLoop = false;
   // game end
   Value stalemateValue = VALUE_DRAW;
   Value checkmateValue = -VALUE_MATE;