]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Fix a (bestValue == -VALUE_INFINITE) assert
[stockfish] / src / position.cpp
index 6abef5b47bcb42c764901fdc0cb7a871d7e80039..fc9ac124da2cd9a0109b68337f490b49b7dd9654 100644 (file)
@@ -36,7 +36,6 @@
 #include "position.h"
 #include "psqtab.h"
 #include "rkiss.h"
-#include "san.h"
 #include "tt.h"
 #include "ucioption.h"
 
@@ -101,20 +100,23 @@ namespace {
       operator[]('B') = WB; operator[]('b') = BB;
       operator[]('N') = WN; operator[]('n') = BN;
       operator[]('P') = WP; operator[]('p') = BP;
-      operator[](' ') = PIECE_NONE; operator[]('.') = PIECE_NONE_DARK_SQ;
+      operator[](' ') = PIECE_NONE;
+      operator[]('.') = PIECE_NONE_DARK_SQ;
     }
 
     char from_piece(Piece p) const {
 
-        std::map<char, Piece>::const_iterator it;
-        for (it = begin(); it != end(); ++it)
-            if (it->second == p)
-                return it->first;
+      std::map<char, Piece>::const_iterator it;
+      for (it = begin(); it != end(); ++it)
+          if (it->second == p)
+              return it->first;
 
-        assert(false);
-        return 0;
+      assert(false);
+      return 0;
     }
-  } pieceLetters;
+  };
+
+  PieceLetters pieceLetters;
 }
 
 
@@ -149,9 +151,9 @@ Position::Position(const Position& pos, int th) {
   nodes = 0;
 }
 
-Position::Position(const string& fen, int th) {
+Position::Position(const string& fen, bool isChess960, int th) {
 
-  from_fen(fen);
+  from_fen(fen, isChess960);
   threadID = th;
 }
 
@@ -172,14 +174,14 @@ void Position::detach() {
 /// string. This function is not very robust - make sure that input FENs are
 /// correct (this is assumed to be the responsibility of the GUI).
 
-void Position::from_fen(const string& fen) {
+void Position::from_fen(const string& fen, bool c960) {
 /*
    A FEN string defines a particular position using only the ASCII character set.
 
    A FEN string contains six fields. The separator between fields is a space. The fields are:
 
    1) Piece placement (from white's perspective). Each rank is described, starting with rank 8 and ending
-      with rank 1; within each rank, the contents of each square are described from file a through file h.
+      with rank 1; within each rank, the contents of each square are described from file A through file H.
       Following the Standard Algebraic Notation (SAN), each piece is identified by a single letter taken
       from the standard English names. White pieces are designated using upper-case letters ("PNBRQK")
       while Black take lowercase ("pnbrqk"). Blank squares are noted using digits 1 through 8 (the number
@@ -202,32 +204,26 @@ void Position::from_fen(const string& fen) {
 */
 
   char token;
+  int hmc, fmn;
   std::istringstream ss(fen);
-  Rank rank = RANK_8;
-  File file = FILE_A;
+  Square sq = SQ_A8;
 
   clear();
 
   // 1. Piece placement field
   while (ss.get(token) && token != ' ')
   {
-      if (isdigit(token))
+      if (pieceLetters.find(token) != pieceLetters.end())
       {
-          file += File(token - '0'); // Skip the given number of files
-          continue;
+          put_piece(pieceLetters[token], sq);
+          sq++;
       }
+      else if (isdigit(token))
+          sq += Square(token - '0'); // Skip the given number of files
       else if (token == '/')
-      {
-          file = FILE_A;
-          rank--;
-          continue;
-      }
-
-      if (pieceLetters.find(token) == pieceLetters.end())
+          sq -= SQ_A3; // Jump back of 2 rows
+      else
           goto incorrect_fen;
-
-      put_piece(pieceLetters[token], make_square(file, rank));
-      file++;
   }
 
   // 2. Active color
@@ -241,27 +237,29 @@ void Position::from_fen(const string& fen) {
 
   // 3. Castling availability
   while (ss.get(token) && token != ' ')
-  {
-      if (token == '-')
-          continue;
-
       if (!set_castling_rights(token))
           goto incorrect_fen;
-  }
 
-  // 4. En passant square -- ignore if no capture is possible
+  // 4. En passant square
   char col, row;
   if (   (ss.get(col) && (col >= 'a' && col <= 'h'))
       && (ss.get(row) && (row == '3' || row == '6')))
   {
-      Square fenEpSquare = make_square(file_from_char(col), rank_from_char(row));
-      Color them = opposite_color(sideToMove);
+      st->epSquare = make_square(file_from_char(col), rank_from_char(row));
 
-      if (attacks_from<PAWN>(fenEpSquare, them) & pieces(PAWN, sideToMove))
-          st->epSquare = fenEpSquare;
+      // Ignore if no capture is possible
+      Color them = opposite_color(sideToMove);
+      if (!(attacks_from<PAWN>(st->epSquare, them) & pieces(PAWN, sideToMove)))
+          st->epSquare = SQ_NONE;
   }
 
-  // 5-6. Halfmove clock and fullmove number are not parsed
+  // 5. Halfmove clock
+  if (ss >> hmc)
+      st->rule50 = hmc;
+
+  // 6. Fullmove number
+  if (ss >> fmn)
+      startPosPlyCounter = (fmn - 1) * 2 + int(sideToMove == BLACK);
 
   // Various initialisations
   castleRightsMask[make_square(initialKFile,  RANK_1)] ^= WHITE_OO | WHITE_OOO;
@@ -271,10 +269,7 @@ void Position::from_fen(const string& fen) {
   castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO;
   castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO;
 
-  isChess960 =   initialKFile  != FILE_E
-              || initialQRFile != FILE_A
-              || initialKRFile != FILE_H;
-
+  isChess960 = c960;
   find_checkers();
 
   st->key = compute_key();
@@ -312,7 +307,7 @@ bool Position::set_castling_rights(char token) {
         for (Square sq = sqH; sq >= sqA; sq--)
             if (piece_on(sq) == rook)
             {
-                allow_oo(c);
+                do_allow_oo(c);
                 initialKRFile = square_file(sq);
                 break;
             }
@@ -322,7 +317,7 @@ bool Position::set_castling_rights(char token) {
         for (Square sq = sqA; sq <= sqH; sq++)
             if (piece_on(sq) == rook)
             {
-                allow_ooo(c);
+                do_allow_ooo(c);
                 initialQRFile = square_file(sq);
                 break;
             }
@@ -332,16 +327,17 @@ bool Position::set_castling_rights(char token) {
         File rookFile = File(token - 'A') + FILE_A;
         if (rookFile < initialKFile)
         {
-            allow_ooo(c);
+            do_allow_ooo(c);
             initialQRFile = rookFile;
         }
         else
         {
-            allow_oo(c);
+            do_allow_oo(c);
             initialKRFile = rookFile;
         }
     }
-    else return false;
+    else
+        return token == '-';
 
   return true;
 }
@@ -521,16 +517,24 @@ Bitboard Position::attacks_from(Piece p, Square s) const {
 
   switch (p)
   {
-  case WP:          return attacks_from<PAWN>(s, WHITE);
-  case BP:          return attacks_from<PAWN>(s, BLACK);
-  case WN: case BN: return attacks_from<KNIGHT>(s);
   case WB: case BB: return attacks_from<BISHOP>(s);
   case WR: case BR: return attacks_from<ROOK>(s);
   case WQ: case BQ: return attacks_from<QUEEN>(s);
-  case WK: case BK: return attacks_from<KING>(s);
-  default: break;
+  default: return NonSlidingAttacksBB[p][s];
+  }
+}
+
+Bitboard Position::attacks_from(Piece p, Square s, Bitboard occ) {
+
+  assert(square_is_ok(s));
+
+  switch (p)
+  {
+  case WB: case BB: return bishop_attacks_bb(s, occ);
+  case WR: case BR: return rook_attacks_bb(s, occ);
+  case WQ: case BQ: return bishop_attacks_bb(s, occ) | rook_attacks_bb(s, occ);
+  default: return NonSlidingAttacksBB[p][s];
   }
-  return false;
 }
 
 
@@ -588,22 +592,18 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
   if (move_is_castle(m))
       return true;
 
-  Color us = side_to_move();
-  Square from = move_from(m);
-
-  assert(color_of_piece_on(from) == us);
-  assert(piece_on(king_square(us)) == piece_of_color_and_type(us, KING));
-
   // En passant captures are a tricky special case. Because they are
   // rather uncommon, we do it simply by testing whether the king is attacked
   // after the move is made
   if (move_is_ep(m))
   {
+      Color us = side_to_move();
       Color them = opposite_color(us);
+      Square from = move_from(m);
       Square to = move_to(m);
       Square capsq = make_square(square_file(to), square_rank(from));
-      Bitboard b = occupied_squares();
       Square ksq = king_square(us);
+      Bitboard b = occupied_squares();
 
       assert(to == ep_square());
       assert(piece_on(from) == piece_of_color_and_type(us, PAWN));
@@ -618,6 +618,12 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
             && !(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, them));
   }
 
+  Color us = side_to_move();
+  Square from = move_from(m);
+
+  assert(color_of_piece_on(from) == us);
+  assert(piece_on(king_square(us)) == piece_of_color_and_type(us, KING));
+
   // If the moving piece is a king, check whether the destination
   // square is attacked by the opponent.
   if (type_of_piece_on(from) == KING)
@@ -625,9 +631,9 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 
   // A non-king move is legal if and only if it is not pinned or it
   // is moving along the ray towards or away from the king.
-  return   !pinned
-          || !bit_is_set(pinned, from)
-          || (direction_between_squares(from, king_square(us)) == direction_between_squares(move_to(m), king_square(us))));
+  return   !pinned
+        || !bit_is_set(pinned, from)
+        ||  squares_aligned(from, move_to(m), king_square(us));
 }
 
 
@@ -685,7 +691,7 @@ bool Position::move_is_check(Move m, const CheckInfo& ci) const {
   {
       // For pawn and king moves we need to verify also direction
       if (  (pt != PAWN && pt != KING)
-          ||(direction_between_squares(from, ci.ksq) != direction_between_squares(to, ci.ksq)))
+          || !squares_aligned(from, to, ci.ksq))
           return true;
   }
 
@@ -756,6 +762,29 @@ bool Position::move_is_check(Move m, const CheckInfo& ci) const {
 }
 
 
+/// Position::do_setup_move() makes a permanent move on the board.
+/// It should be used when setting up a position on board.
+/// You can't undo the move.
+
+void Position::do_setup_move(Move m) {
+
+  StateInfo newSt;
+
+  do_move(m, newSt);
+
+  // Reset "game ply" in case we made a non-reversible move.
+  // "game ply" is used for repetition detection.
+  if (st->rule50 == 0)
+      st->gamePly = 0;
+
+  // Update the number of plies played from the starting position
+  startPosPlyCounter++;
+
+  // Our StateInfo newSt is about going out of scope so copy
+  // its content inside pos before it disappears.
+  detach();
+}
+
 /// Position::do_move() makes a move, and saves all information necessary
 /// to a StateInfo object. The move is assumed to be legal.
 /// Pseudo-legal moves should be filtered out before this function is called.
@@ -770,6 +799,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
 
   assert(is_ok());
   assert(move_is_ok(m));
+  assert(&newSt != st);
 
   nodes++;
   Key key = st->key;
@@ -785,8 +815,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
     Value npMaterial[2];
   };
 
-  if (&newSt != st)
-      memcpy(&newSt, st, sizeof(ReducedStateInfo));
+  memcpy(&newSt, st, sizeof(ReducedStateInfo));
 
   newSt.previous = st;
   st = &newSt;
@@ -1391,7 +1420,7 @@ int Position::see_sign(Move m) const {
 
 int Position::see(Square from, Square to) const {
 
-  Bitboard occ, attackers, stmAttackers, b;
+  Bitboard occupied, attackers, stmAttackers, b;
   int swapList[32], slIndex = 1;
   PieceType capturedType, pt;
   Color stm;
@@ -1405,30 +1434,30 @@ int Position::see(Square from, Square to) const {
   if (capturedType == KING)
       return seeValues[capturedType];
 
-  occ = occupied_squares();
+  occupied = occupied_squares();
 
   // Handle en passant moves
   if (st->epSquare == to && type_of_piece_on(from) == PAWN)
   {
-      Square capQq = (side_to_move() == WHITE) ? (to - DELTA_N) : (to - DELTA_S);
+      Square capQq = (side_to_move() == WHITE ? to - DELTA_N : to - DELTA_S);
 
       assert(capturedType == PIECE_TYPE_NONE);
       assert(type_of_piece_on(capQq) == PAWN);
 
       // Remove the captured pawn
-      clear_bit(&occ, capQq);
+      clear_bit(&occupied, capQq);
       capturedType = PAWN;
   }
 
   // Find all attackers to the destination square, with the moving piece
   // removed, but possibly an X-ray attacker added behind it.
-  clear_bit(&occ, from);
-  attackers =  (rook_attacks_bb(to, occ)      & pieces(ROOK, QUEEN))
-             | (bishop_attacks_bb(to, occ)    & pieces(BISHOP, QUEEN))
-             | (attacks_from<KNIGHT>(to)      & pieces(KNIGHT))
-             | (attacks_from<KING>(to)        & pieces(KING))
-             | (attacks_from<PAWN>(to, WHITE) & pieces(PAWN, BLACK))
-             | (attacks_from<PAWN>(to, BLACK) & pieces(PAWN, WHITE));
+  clear_bit(&occupied, from);
+  attackers =  (rook_attacks_bb(to, occupied)  & pieces(ROOK, QUEEN))
+             | (bishop_attacks_bb(to, occupied)& pieces(BISHOP, QUEEN))
+             | (attacks_from<KNIGHT>(to)       & pieces(KNIGHT))
+             | (attacks_from<KING>(to)         & pieces(KING))
+             | (attacks_from<PAWN>(to, WHITE)  & pieces(PAWN, BLACK))
+             | (attacks_from<PAWN>(to, BLACK)  & pieces(PAWN, WHITE));
 
   // If the opponent has no attackers we are finished
   stm = opposite_color(color_of_piece_on(from));
@@ -1452,28 +1481,28 @@ int Position::see(Square from, Square to) const {
       for (pt = PAWN; !(stmAttackers & pieces(pt)); pt++)
           assert(pt < KING);
 
-      // Remove the attacker we just found from the 'attackers' bitboard,
+      // Remove the attacker we just found from the 'occupied' bitboard,
       // and scan for new X-ray attacks behind the attacker.
       b = stmAttackers & pieces(pt);
-      occ ^= (b & (~b + 1));
-      attackers |=  (rook_attacks_bb(to, occ)   & pieces(ROOK, QUEEN))
-                  | (bishop_attacks_bb(to, occ) & pieces(BISHOP, QUEEN));
+      occupied ^= (b & (~b + 1));
+      attackers |=  (rook_attacks_bb(to, occupied)   & pieces(ROOK, QUEEN))
+                  | (bishop_attacks_bb(to, occupied) & pieces(BISHOP, QUEEN));
 
-      attackers &= occ; // Cut out pieces we've already done
+      attackers &= occupied; // Cut out pieces we've already done
 
       // Add the new entry to the swap list
       assert(slIndex < 32);
       swapList[slIndex] = -swapList[slIndex - 1] + seeValues[capturedType];
       slIndex++;
 
-      // Remember the value of the capturing piece, and change the side to move
-      // before beginning the next iteration
+      // Remember the value of the capturing piece, and change the side to
+      // move before beginning the next iteration.
       capturedType = pt;
       stm = opposite_color(stm);
       stmAttackers = attackers & pieces_of_color(stm);
 
-      // Stop after a king capture
-      if (pt == KING && stmAttackers)
+      // Stop before processing a king capture
+      if (capturedType == KING && stmAttackers)
       {
           assert(slIndex < 32);
           swapList[slIndex++] = QueenValueMidgame*10;
@@ -1482,7 +1511,7 @@ int Position::see(Square from, Square to) const {
   } while (stmAttackers);
 
   // Having built the swap list, we negamax through it to find the best
-  // achievable score from the point of view of the side to move
+  // achievable score from the point of view of the side to move.
   while (--slIndex)
       swapList[slIndex-1] = Min(-swapList[slIndex], swapList[slIndex-1]);
 
@@ -1523,24 +1552,8 @@ void Position::clear() {
 }
 
 
-/// Position::reset_game_ply() simply sets gamePly to 0. It is used from the
-/// UCI interface code, whenever a non-reversible move is made in a
-/// 'position fen <fen> moves m1 m2 ...' command.  This makes it possible
-/// for the program to handle games of arbitrary length, as long as the GUI
-/// handles draws by the 50 move rule correctly.
-
-void Position::reset_game_ply() {
-
-  st->gamePly = 0;
-}
-
-void Position::inc_startpos_ply_counter() {
-
-  startPosPlyCounter++;
-}
-
 /// Position::put_piece() puts a piece on the given square of the board,
-/// updating the board array, bitboards, and piece counts.
+/// updating the board array, pieces list, bitboards, and piece counts.
 
 void Position::put_piece(Piece p, Square s) {
 
@@ -1548,32 +1561,12 @@ void Position::put_piece(Piece p, Square s) {
   PieceType pt = type_of_piece(p);
 
   board[s] = p;
-  index[s] = pieceCount[c][pt];
+  index[s] = pieceCount[c][pt]++;
   pieceList[c][pt][index[s]] = s;
 
   set_bit(&(byTypeBB[pt]), s);
   set_bit(&(byColorBB[c]), s);
-  set_bit(&byTypeBB[0], s); // HACK: byTypeBB[0] contains all occupied squares.
-
-  pieceCount[c][pt]++;
-}
-
-
-/// Position::allow_oo() gives the given side the right to castle kingside.
-/// Used when setting castling rights during parsing of FEN strings.
-
-void Position::allow_oo(Color c) {
-
-  st->castleRights |= (1 + int(c));
-}
-
-
-/// Position::allow_ooo() gives the given side the right to castle queenside.
-/// Used when setting castling rights during parsing of FEN strings.
-
-void Position::allow_ooo(Color c) {
-
-  st->castleRights |= (4 + 4*int(c));
+  set_bit(&(byTypeBB[0]), s); // HACK: byTypeBB[0] contains all occupied squares.
 }
 
 
@@ -1584,7 +1577,7 @@ void Position::allow_ooo(Color c) {
 
 Key Position::compute_key() const {
 
-  Key result = 0;
+  Key result = zobCastle[st->castleRights];
 
   for (Square s = SQ_A1; s <= SQ_H8; s++)
       if (square_is_occupied(s))
@@ -1593,7 +1586,6 @@ Key Position::compute_key() const {
   if (ep_square() != SQ_NONE)
       result ^= zobEp[ep_square()];
 
-  result ^= zobCastle[st->castleRights];
   if (side_to_move() == BLACK)
       result ^= zobSideToMove;
 
@@ -1609,18 +1601,14 @@ Key Position::compute_key() const {
 
 Key Position::compute_pawn_key() const {
 
-  Key result = 0;
   Bitboard b;
-  Square s;
+  Key result = 0;
 
   for (Color c = WHITE; c <= BLACK; c++)
   {
       b = pieces(PAWN, c);
       while (b)
-      {
-          s = pop_1st_bit(&b);
-          result ^= zobrist[c][PAWN][s];
-      }
+          result ^= zobrist[c][PAWN][pop_1st_bit(&b)];
   }
   return result;
 }
@@ -1634,11 +1622,13 @@ Key Position::compute_pawn_key() const {
 
 Key Position::compute_material_key() const {
 
+  int count;
   Key result = 0;
+
   for (Color c = WHITE; c <= BLACK; c++)
       for (PieceType pt = PAWN; pt <= QUEEN; pt++)
       {
-          int count = piece_count(c, pt);
+          count = piece_count(c, pt);
           for (int i = 0; i < count; i++)
               result ^= zobrist[c][pt][i];
       }
@@ -1652,20 +1642,15 @@ Key Position::compute_material_key() const {
 /// updated by do_move and undo_move when the program is running in debug mode.
 Score Position::compute_value() const {
 
-  Score result = SCORE_ZERO;
   Bitboard b;
-  Square s;
+  Score result = SCORE_ZERO;
 
   for (Color c = WHITE; c <= BLACK; c++)
       for (PieceType pt = PAWN; pt <= KING; pt++)
       {
           b = pieces(pt, c);
           while (b)
-          {
-              s = pop_1st_bit(&b);
-              assert(piece_on(s) == piece_of_color_and_type(c, pt));
-              result += pst(c, pt, s);
-          }
+              result += pst(c, pt, pop_1st_bit(&b));
       }
 
   result += (side_to_move() == WHITE ? TempoValue / 2 : -TempoValue / 2);
@@ -1674,7 +1659,7 @@ Score Position::compute_value() const {
 
 
 /// Position::compute_non_pawn_material() computes the total non-pawn middle
-/// game material score for the given side. Material scores are updated
+/// game material value for the given side. Material values are updated
 /// incrementally during the search, this function is only used while
 /// initializing a new Position object.
 
@@ -1683,16 +1668,8 @@ Value Position::compute_non_pawn_material(Color c) const {
   Value result = VALUE_ZERO;
 
   for (PieceType pt = KNIGHT; pt <= QUEEN; pt++)
-  {
-      Bitboard b = pieces(pt, c);
-      while (b)
-      {
-          assert(piece_on(first_1(b)) == piece_of_color_and_type(c, pt));
+      result += piece_count(c, pt) * PieceValueMidgame[pt];
 
-          pop_1st_bit(&b);
-          result += PieceValueMidgame[pt];
-      }
-  }
   return result;
 }
 
@@ -1709,7 +1686,7 @@ bool Position::is_draw() const {
       return true;
 
   // Draw by the 50 moves rule?
-  if (st->rule50 > 99 && (st->rule50 > 100 || !is_mate()))
+  if (st->rule50 > 99 && !is_mate())
       return true;
 
   // Draw by repetition?
@@ -1727,7 +1704,7 @@ bool Position::is_draw() const {
 bool Position::is_mate() const {
 
   MoveStack moves[MOVES_MAX];
-  return is_check() && (generate_moves(*this, moves) == moves);
+  return is_check() && generate<MV_LEGAL>(*this, moves) == moves;
 }
 
 
@@ -1747,9 +1724,9 @@ bool Position::has_mate_threat() {
   // First pass the move to our opponent doing a null move
   do_null_move(st1);
 
-  // Then generate pseudo-legal moves that give check
-  last = generate_non_capture_checks(*this, mlist);
-  last = generate_captures(*this, last);
+  // Then generate pseudo-legal moves that could give check
+  last = generate<MV_NON_CAPTURE_CHECK>(*this, mlist);
+  last = generate<MV_CAPTURE>(*this, last);
 
   // Loop through the moves, and see if one of them gives mate
   Bitboard pinned = pinned_pieces(sideToMove);
@@ -1779,20 +1756,20 @@ bool Position::has_mate_threat() {
 
 void Position::init_zobrist() {
 
-  RKISS RKiss;
   int i,j, k;
+  RKISS rk;
 
   for (i = 0; i < 2; i++) for (j = 0; j < 8; j++) for (k = 0; k < 64; k++)
-      zobrist[i][j][k] = RKiss.rand<Key>();
+      zobrist[i][j][k] = rk.rand<Key>();
 
   for (i = 0; i < 64; i++)
-      zobEp[i] = RKiss.rand<Key>();
+      zobEp[i] = rk.rand<Key>();
 
   for (i = 0; i < 16; i++)
-      zobCastle[i] = RKiss.rand<Key>();
+      zobCastle[i] = rk.rand<Key>();
 
-  zobSideToMove = RKiss.rand<Key>();
-  zobExclusion  = RKiss.rand<Key>();
+  zobSideToMove = rk.rand<Key>();
+  zobExclusion  = rk.rand<Key>();
 }
 
 
@@ -1828,16 +1805,16 @@ void Position::flipped_copy(const Position& pos) {
   // Board
   for (Square s = SQ_A1; s <= SQ_H8; s++)
       if (!pos.square_is_empty(s))
-          put_piece(Piece(int(pos.piece_on(s)) ^ 8), flip_square(s));
+          put_piece(Piece(pos.piece_on(s) ^ 8), flip_square(s));
 
   // Side to move
   sideToMove = opposite_color(pos.side_to_move());
 
   // Castling rights
-  if (pos.can_castle_kingside(WHITE))  allow_oo(BLACK);
-  if (pos.can_castle_queenside(WHITE)) allow_ooo(BLACK);
-  if (pos.can_castle_kingside(BLACK))  allow_oo(WHITE);
-  if (pos.can_castle_queenside(BLACK)) allow_ooo(WHITE);
+  if (pos.can_castle_kingside(WHITE))  do_allow_oo(BLACK);
+  if (pos.can_castle_queenside(WHITE)) do_allow_ooo(BLACK);
+  if (pos.can_castle_kingside(BLACK))  do_allow_oo(WHITE);
+  if (pos.can_castle_queenside(BLACK)) do_allow_ooo(WHITE);
 
   initialKFile  = pos.initialKFile;
   initialKRFile = pos.initialKRFile;
@@ -1879,18 +1856,20 @@ void Position::flipped_copy(const Position& pos) {
 bool Position::is_ok(int* failedStep) const {
 
   // What features of the position should be verified?
-  static const bool debugBitboards = false;
-  static const bool debugKingCount = false;
-  static const bool debugKingCapture = false;
-  static const bool debugCheckerCount = false;
-  static const bool debugKey = false;
-  static const bool debugMaterialKey = false;
-  static const bool debugPawnKey = false;
-  static const bool debugIncrementalEval = false;
-  static const bool debugNonPawnMaterial = false;
-  static const bool debugPieceCounts = false;
-  static const bool debugPieceList = false;
-  static const bool debugCastleSquares = false;
+  const bool debugAll = false;
+
+  const bool debugBitboards       = debugAll || false;
+  const bool debugKingCount       = debugAll || false;
+  const bool debugKingCapture     = debugAll || false;
+  const bool debugCheckerCount    = debugAll || false;
+  const bool debugKey             = debugAll || false;
+  const bool debugMaterialKey     = debugAll || false;
+  const bool debugPawnKey         = debugAll || false;
+  const bool debugIncrementalEval = debugAll || false;
+  const bool debugNonPawnMaterial = debugAll || false;
+  const bool debugPieceCounts     = debugAll || false;
+  const bool debugPieceList       = debugAll || false;
+  const bool debugCastleSquares   = debugAll || false;
 
   if (failedStep) *failedStep = 1;