]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Implement MaxGain table
[stockfish] / src / position.cpp
index fb17f209e3e4d24adeb9a45542f77f0b4fa8a3ba..2508db669dfb2241ed0e4c322fbfb6fbd8d0cfe0 100644 (file)
@@ -76,15 +76,52 @@ CheckInfo::CheckInfo(const Position& pos) {
   checkSq[KING] = EmptyBoardBB;
 }
 
+
+/// Position c'tors. Here we always create a slower but safer copy of
+/// the original position or the FEN string, we want the new born Position
+/// object do not depend on any external data. Instead if we know what we
+/// are doing and we need speed we can create a position with default
+/// c'tor Position() and then use just fast_copy().
+
+Position::Position() {}
+
 Position::Position(const Position& pos) {
-  copy(pos);
+
+  fast_copy(pos);
+  detach(); // Always detach() in copy c'tor to avoid surprises
 }
 
 Position::Position(const string& fen) {
+
   from_fen(fen);
 }
 
 
+/// Position::fast_copy() creates a partial copy of the given position,
+/// only data that changes with a do_move() / undo_move() cycle is copied,
+/// in particular for stateInfo are copied only the pointers, so that the
+/// actual data remains stored in the parent Position. This is not a problem
+/// if the parent Position is known not to be destroyed while we are still alive,
+/// as is the common case, see detach() otherwise.
+
+void Position::fast_copy(const Position& pos) {
+
+  memcpy(this, &pos, sizeof(Position));
+}
+
+
+/// Position::detach() copies the content of the current state and castling
+/// masks inside the position itself. This is needed when the st pointee could
+/// become stale, as example because the caller is about to going out of scope.
+
+void Position::detach() {
+
+  startState = *st;
+  st = &startState;
+  st->previous = NULL; // as a safe guard
+}
+
+
 /// Position::from_fen() initializes the position object with the given FEN
 /// string. This function is not very robust - make sure that input FENs are
 /// correct (this is assumed to be the responsibility of the GUI).
@@ -143,61 +180,61 @@ void Position::from_fen(const string& fen) {
   }
 
   i++;
-  while(strchr("KQkqabcdefghABCDEFGH-", fen[i])) {
-    if (fen[i] == '-')
-    {
-      i++;
-      break;
-    }
-    else if(fen[i] == 'K') allow_oo(WHITE);
-    else if(fen[i] == 'Q') allow_ooo(WHITE);
-    else if(fen[i] == 'k') allow_oo(BLACK);
-    else if(fen[i] == 'q') allow_ooo(BLACK);
-    else if(fen[i] >= 'A' && fen[i] <= 'H') {
-      File rookFile, kingFile = FILE_NONE;
-      for(Square square = SQ_B1; square <= SQ_G1; square++)
-        if(piece_on(square) == WK)
-          kingFile = square_file(square);
-      if(kingFile == FILE_NONE) {
-        std::cout << "Error in FEN at character " << i << std::endl;
-        return;
-      }
-      initialKFile = kingFile;
-      rookFile = File(fen[i] - 'A') + FILE_A;
-      if(rookFile < initialKFile) {
-        allow_ooo(WHITE);
-        initialQRFile = rookFile;
-      }
-      else {
-        allow_oo(WHITE);
-        initialKRFile = rookFile;
+  while (strchr("KQkqabcdefghABCDEFGH-", fen[i])) {
+      if (fen[i] == '-')
+      {
+          i++;
+          break;
       }
-    }
-    else if(fen[i] >= 'a' && fen[i] <= 'h') {
-      File rookFile, kingFile = FILE_NONE;
-      for(Square square = SQ_B8; square <= SQ_G8; square++)
-        if(piece_on(square) == BK)
-          kingFile = square_file(square);
-      if(kingFile == FILE_NONE) {
-        std::cout << "Error in FEN at character " << i << std::endl;
-        return;
+      else if (fen[i] == 'K') allow_oo(WHITE);
+      else if (fen[i] == 'Q') allow_ooo(WHITE);
+      else if (fen[i] == 'k') allow_oo(BLACK);
+      else if (fen[i] == 'q') allow_ooo(BLACK);
+      else if (fen[i] >= 'A' && fen[i] <= 'H') {
+          File rookFile, kingFile = FILE_NONE;
+          for (Square square = SQ_B1; square <= SQ_G1; square++)
+              if (piece_on(square) == WK)
+                  kingFile = square_file(square);
+          if (kingFile == FILE_NONE) {
+              std::cout << "Error in FEN at character " << i << std::endl;
+              return;
+          }
+          initialKFile = kingFile;
+          rookFile = File(fen[i] - 'A') + FILE_A;
+          if (rookFile < initialKFile) {
+              allow_ooo(WHITE);
+              initialQRFile = rookFile;
+          }
+          else {
+              allow_oo(WHITE);
+              initialKRFile = rookFile;
+          }
       }
-      initialKFile = kingFile;
-      rookFile = File(fen[i] - 'a') + FILE_A;
-      if(rookFile < initialKFile) {
-        allow_ooo(BLACK);
-        initialQRFile = rookFile;
+      else if (fen[i] >= 'a' && fen[i] <= 'h') {
+          File rookFile, kingFile = FILE_NONE;
+          for (Square square = SQ_B8; square <= SQ_G8; square++)
+              if (piece_on(square) == BK)
+                  kingFile = square_file(square);
+          if (kingFile == FILE_NONE) {
+              std::cout << "Error in FEN at character " << i << std::endl;
+              return;
+          }
+          initialKFile = kingFile;
+          rookFile = File(fen[i] - 'a') + FILE_A;
+          if (rookFile < initialKFile) {
+              allow_ooo(BLACK);
+              initialQRFile = rookFile;
+          }
+          else {
+              allow_oo(BLACK);
+              initialKRFile = rookFile;
+          }
       }
       else {
-        allow_oo(BLACK);
-        initialKRFile = rookFile;
+          std::cout << "Error in FEN at character " << i << std::endl;
+          return;
       }
-    }
-    else {
-      std::cout << "Error in FEN at character " << i << std::endl;
-      return;
-    }
-    i++;
+      i++;
   }
 
   // Skip blanks
@@ -271,10 +308,24 @@ const string Position::to_fen() const {
   fen += (sideToMove == WHITE ? "w " : "b ");
   if (st->castleRights != NO_CASTLES)
   {
-    if (can_castle_kingside(WHITE))  fen += 'K';
-    if (can_castle_queenside(WHITE)) fen += 'Q';
-    if (can_castle_kingside(BLACK))  fen += 'k';
-    if (can_castle_queenside(BLACK)) fen += 'q';
+     if (initialKFile == FILE_E && initialQRFile == FILE_A && initialKRFile == FILE_H)
+     {
+        if (can_castle_kingside(WHITE))  fen += 'K';
+        if (can_castle_queenside(WHITE)) fen += 'Q';
+        if (can_castle_kingside(BLACK))  fen += 'k';
+        if (can_castle_queenside(BLACK)) fen += 'q';
+     }
+     else
+     {
+        if (can_castle_kingside(WHITE))
+           fen += char(toupper(file_to_char(initialKRFile)));
+        if (can_castle_queenside(WHITE))
+           fen += char(toupper(file_to_char(initialQRFile)));
+        if (can_castle_kingside(BLACK))
+           fen += file_to_char(initialKRFile);
+        if (can_castle_queenside(BLACK))
+           fen += file_to_char(initialQRFile);
+     }
   } else
       fen += '-';
 
@@ -305,8 +356,9 @@ void Position::print(Move m) const {
   std::cout << std::endl;
   if (m != MOVE_NONE)
   {
+      Position p(*this);
       string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : "");
-      std::cout << "Move is: " << col << move_to_san(*this, m) << std::endl;
+      std::cout << "Move is: " << col << move_to_san(p, m) << std::endl;
   }
   for (Rank rank = RANK_8; rank >= RANK_1; rank--)
   {
@@ -331,15 +383,6 @@ void Position::print(Move m) const {
 }
 
 
-/// Position::copy() creates a copy of the input position.
-
-void Position::copy(const Position& pos) {
-
-  memcpy(this, &pos, sizeof(Position));
-  saveState(); // detach and copy state info
-}
-
-
 /// Position:hidden_checkers<>() returns a bitboard of all pinned (against the
 /// king) pieces for the given color and for the given pinner type. Or, when
 /// template parameter FindPinned is false, the pieces of the given color
@@ -1258,6 +1301,11 @@ void Position::undo_null_move() {
 }
 
 
+///
+PieceType Position::captured_piece() const {
+  return st->capture;
+}
+
 /// Position::see() is a static exchange evaluator: It tries to estimate the
 /// material gain or loss resulting from a move. There are three versions of
 /// this function: One which takes a destination square as input, one takes a
@@ -1429,19 +1477,6 @@ int Position::see(Square from, Square to) const {
 }
 
 
-/// Position::saveState() copies the content of the current state
-/// inside startState and makes st point to it. This is needed
-/// when the st pointee could become stale, as example because
-/// the caller is about to going out of scope.
-
-void Position::saveState() {
-
-  startState = *st;
-  st = &startState;
-  st->previous = NULL; // as a safe guard
-}
-
-
 /// Position::clear() erases the position object to a pristine state, with an
 /// empty board, white to move, and no castling rights.
 
@@ -1560,7 +1595,7 @@ Key Position::compute_pawn_key() const {
   for (Color c = WHITE; c <= BLACK; c++)
   {
       b = pieces(PAWN, c);
-      while(b)
+      while (b)
       {
           s = pop_1st_bit(&b);
           result ^= zobrist[c][PAWN][s];
@@ -1604,7 +1639,7 @@ Score Position::compute_value() const {
       for (PieceType pt = PAWN; pt <= KING; pt++)
       {
           b = pieces(pt, c);
-          while(b)
+          while (b)
           {
               s = pop_1st_bit(&b);
               assert(piece_on(s) == piece_of_color_and_type(c, pt));
@@ -1850,6 +1885,7 @@ bool Position::is_ok(int* failedStep) const {
   static const bool debugNonPawnMaterial = false;
   static const bool debugPieceCounts = false;
   static const bool debugPieceList = false;
+  static const bool debugCastleSquares = false;
 
   if (failedStep) *failedStep = 1;
 
@@ -1975,9 +2011,9 @@ bool Position::is_ok(int* failedStep) const {
   if (failedStep) (*failedStep)++;
   if (debugPieceList)
   {
-      for(Color c = WHITE; c <= BLACK; c++)
-          for(PieceType pt = PAWN; pt <= KING; pt++)
-              for(int i = 0; i < pieceCount[c][pt]; i++)
+      for (Color c = WHITE; c <= BLACK; c++)
+          for (PieceType pt = PAWN; pt <= KING; pt++)
+              for (int i = 0; i < pieceCount[c][pt]; i++)
               {
                   if (piece_on(piece_list(c, pt, i)) != piece_of_color_and_type(c, pt))
                       return false;
@@ -1986,6 +2022,25 @@ bool Position::is_ok(int* failedStep) const {
                       return false;
               }
   }
+
+  if (failedStep) (*failedStep)++;
+  if (debugCastleSquares) {
+      for (Color c = WHITE; c <= BLACK; c++) {
+          if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != piece_of_color_and_type(c, ROOK))
+              return false;
+          if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != piece_of_color_and_type(c, ROOK))
+              return false;
+      }
+      if (castleRightsMask[initial_kr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OO))
+          return false;
+      if (castleRightsMask[initial_qr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OOO))
+          return false;
+      if (castleRightsMask[initial_kr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OO))
+          return false;
+      if (castleRightsMask[initial_qr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OOO))
+          return false;
+  }
+
   if (failedStep) *failedStep = 0;
   return true;
 }