]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Detach the state when copying a position
[stockfish] / src / position.cpp
index 83fc6aba3b6949a3c4b6fa7aca27d920813eadfa..480a92ec9cfcd1a7e3850aea8fbc94f61c570ece 100644 (file)
@@ -27,6 +27,7 @@
 #include <fstream>
 #include <iostream>
 
+#include "bitcount.h"
 #include "mersenne.h"
 #include "movegen.h"
 #include "movepick.h"
@@ -213,8 +214,8 @@ void Position::from_fen(const string& fen) {
   st->materialKey = compute_material_key();
   st->mgValue = compute_value<MidGame>();
   st->egValue = compute_value<EndGame>();
-  npMaterial[WHITE] = compute_non_pawn_material(WHITE);
-  npMaterial[BLACK] = compute_non_pawn_material(BLACK);
+  st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
+  st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
 }
 
 
@@ -314,9 +315,10 @@ void Position::print(Move m) const {
 
 /// Position::copy() creates a copy of the input position.
 
-void Position::copy(const Position &pos) {
+void Position::copy(const Positionpos) {
 
   memcpy(this, &pos, sizeof(Position));
+  saveState(); // detach and copy state info
 }
 
 
@@ -377,9 +379,7 @@ Bitboard Position::discovered_check_candidates(Color c) const {
 }
 
 /// Position::attacks_to() computes a bitboard containing all pieces which
-/// attacks a given square. There are two versions of this function: One
-/// which finds attackers of both colors, and one which only finds the
-/// attackers for one side.
+/// attacks a given square.
 
 Bitboard Position::attacks_to(Square s) const {
 
@@ -658,6 +658,7 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square
   const bool Rook   = (Piece == QUEEN || Piece == ROOK);
   const bool Slider = Bishop || Rook;
 
+  // Direct checks
   if (  (   (Bishop && bit_is_set(BishopPseudoAttacks[ksq], to))
          || (Rook   && bit_is_set(RookPseudoAttacks[ksq], to)))
       && bit_is_set(piece_attacks<Piece>(ksq), to)) // slow, try to early skip
@@ -668,6 +669,7 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square
            && bit_is_set(piece_attacks<Piece>(ksq), to))
       set_bit(pCheckersBB, to);
 
+  // Discovery checks
   if (Piece != QUEEN && bit_is_set(dcCandidates, from))
   {
       if (Piece != ROOK)
@@ -701,6 +703,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
     int castleRights, rule50;
     Square epSquare;
     Value mgValue, egValue;
+    Value npMaterial[2];
   };
 
   memcpy(&newSt, st, sizeof(ReducedStateInfo));
@@ -740,12 +743,11 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
       do_capture_move(st->capture, them, to);
 
     // Move the piece
-    clear_bit(&(byColorBB[us]), from);
-    clear_bit(&(byTypeBB[piece]), from);
-    clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
-    set_bit(&(byColorBB[us]), to);
-    set_bit(&(byTypeBB[piece]), to);
-    set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
+    Bitboard move_bb = make_move_bb(from, to);
+    do_move_bb(&(byColorBB[us]), move_bb);
+    do_move_bb(&(byTypeBB[piece]), move_bb);
+    do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
+
     board[to] = board[from];
     board[from] = EMPTY;
 
@@ -837,6 +839,7 @@ void Position::do_capture_move(PieceType capture, Color them, Square to) {
     // Remove captured piece
     clear_bit(&(byColorBB[them]), to);
     clear_bit(&(byTypeBB[capture]), to);
+    clear_bit(&(byTypeBB[0]), to);
 
     // Update hash key
     st->key ^= zobrist[them][capture][to];
@@ -851,7 +854,7 @@ void Position::do_capture_move(PieceType capture, Color them, Square to) {
 
     // Update material
     if (capture != PAWN)
-        npMaterial[them] -= piece_value_midgame(capture);
+        st->npMaterial[them] -= piece_value_midgame(capture);
 
     // Update material hash key
     st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
@@ -990,7 +993,7 @@ void Position::do_promotion_move(Move m) {
   st->capture = type_of_piece_on(to);
 
   if (st->capture)
-    do_capture_move(st->capture, them, to);
+      do_capture_move(st->capture, them, to);
 
   // Remove pawn
   clear_bit(&(byColorBB[us]), from);
@@ -1033,7 +1036,7 @@ void Position::do_promotion_move(Move m) {
   st->egValue += pst<EndGame>(us, promotion, to);
 
   // Update material
-  npMaterial[us] += piece_value_midgame(promotion);
+  st->npMaterial[us] += piece_value_midgame(promotion);
 
   // Clear the en passant square
   if (st->epSquare != SQ_NONE)
@@ -1079,21 +1082,17 @@ void Position::do_ep_move(Move m) {
   assert(piece_on(from) == piece_of_color_and_type(us, PAWN));
   assert(piece_on(capsq) == piece_of_color_and_type(them, PAWN));
 
-  // Remove captured piece
+  // Remove captured pawn
   clear_bit(&(byColorBB[them]), capsq);
   clear_bit(&(byTypeBB[PAWN]), capsq);
   clear_bit(&(byTypeBB[0]), capsq); // HACK: byTypeBB[0] == occupied squares
   board[capsq] = EMPTY;
 
-  // Remove moving piece from source square
-  clear_bit(&(byColorBB[us]), from);
-  clear_bit(&(byTypeBB[PAWN]), from);
-  clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
-
-  // Put moving piece on destination square
-  set_bit(&(byColorBB[us]), to);
-  set_bit(&(byTypeBB[PAWN]), to);
-  set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
+  // Move capturing pawn
+  Bitboard move_bb = make_move_bb(from, to);
+  do_move_bb(&(byColorBB[us]), move_bb);
+  do_move_bb(&(byTypeBB[PAWN]), move_bb);
+  do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
   board[to] = board[from];
   board[from] = EMPTY;
 
@@ -1169,17 +1168,13 @@ void Position::undo_move(Move m) {
       assert(color_of_piece_on(to) == us);
 
       // Put the piece back at the source square
+      Bitboard move_bb = make_move_bb(to, from);
       piece = type_of_piece_on(to);
-      set_bit(&(byColorBB[us]), from);
-      set_bit(&(byTypeBB[piece]), from);
-      set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
+      do_move_bb(&(byColorBB[us]), move_bb);
+      do_move_bb(&(byTypeBB[piece]), move_bb);
+      do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
       board[from] = piece_of_color_and_type(us, piece);
 
-      // Clear the destination square
-      clear_bit(&(byColorBB[us]), to);
-      clear_bit(&(byTypeBB[piece]), to);
-      clear_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
-
       // If the moving piece was a king, update the king square
       if (piece == KING)
           kingSquare[us] = from;
@@ -1192,16 +1187,12 @@ void Position::undo_move(Move m) {
       {
           assert(st->capture != KING);
 
-          // Replace the captured piece
+          // Restore the captured piece
           set_bit(&(byColorBB[them]), to);
           set_bit(&(byTypeBB[st->capture]), to);
           set_bit(&(byTypeBB[0]), to);
           board[to] = piece_of_color_and_type(them, st->capture);
 
-          // Update material
-          if (st->capture != PAWN)
-              npMaterial[them] += piece_value_midgame(st->capture);
-
           // Update piece list
           pieceList[them][st->capture][pieceCount[them][st->capture]] = to;
           index[to] = pieceCount[them][st->capture];
@@ -1323,9 +1314,6 @@ void Position::undo_promotion_move(Move m) {
   set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
   board[from] = piece_of_color_and_type(us, PAWN);
 
-  // Update material
-  npMaterial[us] -= piece_value_midgame(promotion);
-
   // Update piece list
   pieceList[us][PAWN][pieceCount[us][PAWN]] = from;
   index[from] = pieceCount[us][PAWN];
@@ -1347,11 +1335,6 @@ void Position::undo_promotion_move(Move m) {
       set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
       board[to] = piece_of_color_and_type(them, st->capture);
 
-      // Update material. Because the move is a promotion move, we know
-      // that the captured piece cannot be a pawn.
-      assert(st->capture != PAWN);
-      npMaterial[them] += piece_value_midgame(st->capture);
-
       // Update piece list
       pieceList[them][st->capture][pieceCount[them][st->capture]] = to;
       index[to] = pieceCount[them][st->capture];
@@ -1386,31 +1369,27 @@ void Position::undo_ep_move(Move m) {
   assert(piece_on(from) == EMPTY);
   assert(piece_on(capsq) == EMPTY);
 
-  // Replace captured piece
+  // Restore captured pawn
   set_bit(&(byColorBB[them]), capsq);
   set_bit(&(byTypeBB[PAWN]), capsq);
   set_bit(&(byTypeBB[0]), capsq);
   board[capsq] = piece_of_color_and_type(them, PAWN);
 
-  // Remove moving piece from destination square
-  clear_bit(&(byColorBB[us]), to);
-  clear_bit(&(byTypeBB[PAWN]), to);
-  clear_bit(&(byTypeBB[0]), to);
+  // Move capturing pawn back to source square
+  Bitboard move_bb = make_move_bb(to, from);
+  do_move_bb(&(byColorBB[us]), move_bb);
+  do_move_bb(&(byTypeBB[PAWN]), move_bb);
+  do_move_bb(&(byTypeBB[0]), move_bb);
   board[to] = EMPTY;
-
-  // Replace moving piece at source square
-  set_bit(&(byColorBB[us]), from);
-  set_bit(&(byTypeBB[PAWN]), from);
-  set_bit(&(byTypeBB[0]), from);
   board[from] = piece_of_color_and_type(us, PAWN);
 
-  // Update piece list:
+  // Update piece list
   pieceList[us][PAWN][index[to]] = from;
   index[from] = index[to];
   pieceList[them][PAWN][pieceCount[them][PAWN]] = capsq;
   index[capsq] = pieceCount[them][PAWN];
 
-  // Update piece count:
+  // Update piece count
   pieceCount[them][PAWN]++;
 }
 
@@ -1424,11 +1403,13 @@ void Position::do_null_move(StateInfo& backupSt) {
   assert(!is_check());
 
   // Back up the information necessary to undo the null move to the supplied
-  // StateInfo object. In the case of a null move, the only thing we need to
-  // remember is the en passant square.
+  // StateInfo object.
   // Note that differently from normal case here backupSt is actually used as
   // a backup storage not as a new state to be used.
   backupSt.epSquare = st->epSquare;
+  backupSt.key = st->key;
+  backupSt.mgValue = st->mgValue;
+  backupSt.egValue = st->egValue;
   backupSt.previous = st->previous;
   st->previous = &backupSt;
 
@@ -1462,19 +1443,15 @@ void Position::undo_null_move() {
 
   // Restore information from the our backup StateInfo object
   st->epSquare = st->previous->epSquare;
+  st->key = st->previous->key;
+  st->mgValue = st->previous->mgValue;
+  st->egValue = st->previous->egValue;
   st->previous = st->previous->previous;
 
-  if (st->epSquare != SQ_NONE)
-      st->key ^= zobEp[st->epSquare];
-
   // Update the necessary information
   sideToMove = opposite_color(sideToMove);
   st->rule50--;
   gamePly--;
-  st->key ^= zobSideToMove;
-
-  st->mgValue += (sideToMove == WHITE)? TempoValueMidgame : -TempoValueMidgame;
-  st->egValue += (sideToMove == WHITE)? TempoValueEndgame : -TempoValueEndgame;
 
   assert(is_ok());
 }
@@ -1631,15 +1608,16 @@ int Position::see(Square from, Square to) const {
 }
 
 
-/// Position::setStartState() copies the content of the argument
+/// 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::setStartState(const StateInfo& s) {
+void Position::saveState() {
 
-  startState = s;
+  startState = *st;
   st = &startState;
+  st->previous = NULL; // as a safe guard
 }
 
 
@@ -1990,7 +1968,7 @@ void Position::init_piece_square_tables() {
 /// the white and black sides reversed. This is only useful for debugging,
 /// especially for finding evaluation symmetry bugs.
 
-void Position::flipped_copy(const Position &pos) {
+void Position::flipped_copy(const Positionpos) {
 
   assert(pos.is_ok());
 
@@ -2041,8 +2019,8 @@ void Position::flipped_copy(const Position &pos) {
   st->egValue = compute_value<EndGame>();
 
   // Material
-  npMaterial[WHITE] = compute_non_pawn_material(WHITE);
-  npMaterial[BLACK] = compute_non_pawn_material(BLACK);
+  st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
+  st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
 
   assert(is_ok());
 }
@@ -2178,10 +2156,10 @@ bool Position::is_ok(int* failedStep) const {
   if (failedStep) (*failedStep)++;
   if (debugNonPawnMaterial)
   {
-      if (npMaterial[WHITE] != compute_non_pawn_material(WHITE))
+      if (st->npMaterial[WHITE] != compute_non_pawn_material(WHITE))
           return false;
 
-      if (npMaterial[BLACK] != compute_non_pawn_material(BLACK))
+      if (st->npMaterial[BLACK] != compute_non_pawn_material(BLACK))
           return false;
   }