Support 3check/5check/nCheck ; initial development for crazyhouse
authorianfab <ianfab@users.noreply.github.com>
Sun, 24 Jun 2018 19:18:39 +0000 (21:18 +0200)
committerianfab <ianfab@users.noreply.github.com>
Sun, 24 Jun 2018 19:18:39 +0000 (21:18 +0200)
src/position.cpp
src/position.h
src/psqt.cpp
src/types.h
src/variant.cpp
src/variant.h

index 286a989..841b8b9 100644 (file)
@@ -37,7 +37,7 @@
 using std::string;
 
 namespace PSQT {
-  extern Score psq[PIECE_NB][SQUARE_NB];
+  extern Score psq[PIECE_NB][SQUARE_NB + 1];
 }
 
 namespace Zobrist {
@@ -46,6 +46,8 @@ namespace Zobrist {
   Key enpassant[FILE_NB];
   Key castling[CASTLING_RIGHT_NB];
   Key side, noPawns;
+  Key inHand[PIECE_NB][17];
+  Key checks[COLOR_NB][CHECKS_NB];
 }
 
 namespace {
@@ -167,6 +169,15 @@ void Position::init() {
   Zobrist::side = rng.rand<Key>();
   Zobrist::noPawns = rng.rand<Key>();
 
+  for (Color c = WHITE; c <= BLACK; ++c)
+      for (int n = 0; n < CHECKS_NB; ++n)
+          Zobrist::checks[c][n] = rng.rand<Key>();
+
+  for (Color c = WHITE; c <= BLACK; ++c)
+      for (PieceType pt = KNIGHT; pt <= KING; ++pt)
+          for (int n = 0; n < 17; ++n)
+              Zobrist::inHand[make_piece(c, pt)][n] = rng.rand<Key>();
+
   // Prepare the cuckoo tables
   int count = 0;
   for (Color c = WHITE; c <= BLACK; ++c)
@@ -313,6 +324,18 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
   }
   }
 
+  // Check counter for nCheck
+  ss >> std::skipws >> token;
+
+  if (max_check_count() && ss.peek() == '+')
+  {
+      st->checksGiven[WHITE] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0));
+      ss >> token >> token;
+      st->checksGiven[BLACK] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0));
+  }
+  else
+      ss.putback(token);
+
   // 5-6. Halfmove clock and fullmove number
   ss >> std::skipws >> st->rule50 >> gamePly;
 
@@ -394,6 +417,16 @@ void Position::set_state(StateInfo* si) const {
       si->key ^= Zobrist::psq[pc][s];
       si->psq += PSQT::psq[pc][s];
   }
+  // pieces in hand
+  if (piece_drops())
+  {
+      for (Color c = WHITE; c <= BLACK; ++c)
+          for (PieceType pt = PAWN; pt <= KING; ++pt)
+          {
+              Piece pc = make_piece(c, pt);
+              si->psq += PSQT::psq[pc][SQ_NONE] * pieceCountInHand[color_of(pc)][type_of(pc)];
+          }
+  }
 
   if (si->epSquare != SQ_NONE)
       si->key ^= Zobrist::enpassant[file_of(si->epSquare)];
@@ -418,7 +451,18 @@ void Position::set_state(StateInfo* si) const {
 
           for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
               si->materialKey ^= Zobrist::psq[pc][cnt];
+
+          if (piece_drops())
+          {
+              if (type_of(pc) != PAWN && type_of(pc) != KING)
+                  si->nonPawnMaterial[color_of(pc)] += pieceCountInHand[color_of(pc)][type_of(pc)] * PieceValue[MG][pc];
+              si->key ^= Zobrist::inHand[pc][pieceCountInHand[color_of(pc)][type_of(pc)]];
+          }
       }
+
+  if (max_check_count())
+      for (Color c = WHITE; c <= BLACK; ++c)
+          si->key ^= Zobrist::checks[c][si->checksGiven[c]];
 }
 
 
@@ -469,6 +513,16 @@ const string Position::fen() const {
           ss << '/';
   }
 
+  // pieces in hand
+  if (piece_drops())
+  {
+      ss << '[';
+      for (Color c = WHITE; c <= BLACK; ++c)
+          for (PieceType pt = PieceType(KING - 1); pt >= PAWN; --pt)
+              ss << std::string(pieceCountInHand[c][pt], piece_to_char()[make_piece(c, pt)]);
+      ss << ']';
+  }
+
   ss << (sideToMove == WHITE ? " w " : " b ");
 
   if (can_castle(WHITE_OO))
@@ -486,6 +540,10 @@ const string Position::fen() const {
   if (!can_castle(WHITE) && !can_castle(BLACK))
       ss << '-';
 
+  // check count
+  if (max_check_count())
+      ss << " " << (max_check_count() - st->checksGiven[WHITE]) << "+" << (max_check_count() - st->checksGiven[BLACK]);
+
   ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(ep_square()) + " ")
      << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
 
@@ -771,6 +829,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
   assert(type_of(captured) != KING);
 
+  if (max_check_count() && givesCheck)
+      k ^= Zobrist::checks[us][st->checksGiven[us]] ^ Zobrist::checks[us][++(st->checksGiven[us])];
+
   if (type_of(m) == CASTLING)
   {
       assert(pc == make_piece(us, KING));
index d978a97..1b8cbfe 100644 (file)
@@ -44,6 +44,7 @@ struct StateInfo {
   int    castlingRights;
   int    rule50;
   int    pliesFromNull;
+  CheckCount checksGiven[COLOR_NB];
   Score  psq;
   Square epSquare;
 
@@ -92,6 +93,7 @@ public:
   bool castling_enabled() const;
   bool checking_permitted() const;
   bool must_capture() const;
+  bool piece_drops() const;
   // winning conditions
   Value stalemate_value(int ply = 0) const;
   Value checkmate_value(int ply = 0) const;
@@ -99,6 +101,7 @@ public:
   bool bare_king_move() const;
   Bitboard capture_the_flag(Color c) const;
   bool flag_move() const;
+  CheckCount max_check_count() const;
   bool is_variant_end() const;
   bool is_variant_end(Value& result, int ply = 0) const;
 
@@ -203,6 +206,8 @@ 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];
@@ -257,6 +262,11 @@ inline bool Position::must_capture() const {
   return var->mustCapture;
 }
 
+inline bool Position::piece_drops() const {
+  assert(var != nullptr);
+  return var->pieceDrops;
+}
+
 inline Value Position::stalemate_value(int ply) const {
   assert(var != nullptr);
   Value v = var->stalemateValue;
@@ -296,6 +306,11 @@ inline bool Position::flag_move() const {
   return var->flagMove;
 }
 
+inline CheckCount Position::max_check_count() const {
+  assert(var != nullptr);
+  return var->maxCheckCount;
+}
+
 inline bool Position::is_variant_end() const {
   Value result;
   return is_variant_end(result);
@@ -328,6 +343,12 @@ inline bool Position::is_variant_end(Value& result, int ply) const {
       result = mate_in(ply);
       return true;
   }
+  // nCheck
+  if (max_check_count() && st->checksGiven[~sideToMove] == max_check_count())
+  {
+      result = mated_in(ply);
+      return true;
+  }
   return false;
 }
 
index 86593c1..c921636 100644 (file)
@@ -102,7 +102,7 @@ constexpr Score Bonus[PIECE_TYPE_NB][RANK_NB][int(FILE_NB) / 2] = {
 
 #undef S
 
-Score psq[PIECE_NB][SQUARE_NB];
+Score psq[PIECE_NB][SQUARE_NB + 1];
 
 // init() initializes piece-square tables: the white halves of the tables are
 // copied from Bonus[] adding the piece value, then the black halves of the
@@ -124,6 +124,9 @@ void init() {
           psq[ pc][ s] = score + Bonus[pc][rank_of(s)][f];
           psq[~pc][~s] = -psq[pc][s];
       }
+      // pieces in pocket
+      psq[ pc][SQ_NONE] = score;
+      psq[~pc][SQ_NONE] = -psq[pc][SQ_NONE];
   }
 }
 
index 0003e17..dd9914b 100644 (file)
@@ -154,6 +154,10 @@ template<Color C, CastlingSide S> struct MakeCastling {
                      : S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
 };
 
+enum CheckCount : int {
+  CHECKS_0 = 0, CHECKS_NB = 11
+};
+
 enum Phase {
   PHASE_ENDGAME,
   PHASE_MIDGAME = 128,
@@ -316,6 +320,7 @@ inline T& operator*=(T& d, int i) { return d = T(int(d) * i); }    \
 inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
 
 ENABLE_FULL_OPERATORS_ON(Value)
+ENABLE_FULL_OPERATORS_ON(CheckCount)
 ENABLE_FULL_OPERATORS_ON(Depth)
 ENABLE_FULL_OPERATORS_ON(Direction)
 
index ca6aa68..f04201f 100644 (file)
@@ -139,6 +139,24 @@ void VariantMap::init() {
         v->mustCapture = true;
         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";
+        v->maxCheckCount = CheckCount(3);
+        return v;
+    } ();
+    const Variant* fivecheck = [&]{
+        Variant* v = new Variant();
+        v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 5+5 0 1";
+        v->maxCheckCount = CheckCount(5);
+        return v;
+    } ();
+    const Variant* crazyhouse = [&]{
+        Variant* v = new Variant();
+        v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[] w KQkq - 0 1";
+        v->pieceDrops = 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));
@@ -149,6 +167,9 @@ void VariantMap::init() {
     insert(std::pair<std::string, const Variant*>(std::string("kingofthehill"), kingofthehill));
     insert(std::pair<std::string, const Variant*>(std::string("racingkings"), racingkings));
     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));
 }
 
 void VariantMap::clear_all() {
index 0ed3cb5..160398d 100644 (file)
@@ -41,6 +41,7 @@ struct Variant {
   bool castling = true;
   bool checking = true;
   bool mustCapture = false;
+  bool pieceDrops = false;
   // game end
   Value stalemateValue = VALUE_DRAW;
   Value checkmateValue = -VALUE_MATE;
@@ -49,6 +50,7 @@ struct Variant {
   Bitboard whiteFlag = 0;
   Bitboard blackFlag = 0;
   bool flagMove = false;
+  CheckCount maxCheckCount = CheckCount(0);
 
   void set_piece(PieceType pt, char c) {
       pieceToChar[make_piece(WHITE, pt)] = toupper(c);