]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Change zobMaterial[] index 0 definition
[stockfish] / src / position.cpp
index b6c0a522e204edb3889e02d26036932d1e7da3d7..1364c7ed7d2cb9c7b3453fd02d578d9d528947e0 100644 (file)
@@ -1,7 +1,7 @@
 /*
   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
-  Copyright (C) 2008-2009 Marco Costalba
+  Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
 
   Stockfish is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -44,33 +44,69 @@ using std::string;
 //// Variables
 ////
 
-int Position::castleRightsMask[64];
-
 Key Position::zobrist[2][8][64];
 Key Position::zobEp[64];
 Key Position::zobCastle[16];
 Key Position::zobMaterial[2][8][16];
 Key Position::zobSideToMove;
+Key Position::zobExclusion;
 
 Score Position::PieceSquareTable[16][64];
 
 static bool RequestPending = false;
 
-////
-//// Functions
-////
 
 /// Constructors
 
+CheckInfo::CheckInfo(const Position& pos) {
+
+  Color us = pos.side_to_move();
+  Color them = opposite_color(us);
+
+  ksq = pos.king_square(them);
+  dcCandidates = pos.discovered_check_candidates(us);
+
+  checkSq[PAWN] = pos.attacks_from<PAWN>(ksq, them);
+  checkSq[KNIGHT] = pos.attacks_from<KNIGHT>(ksq);
+  checkSq[BISHOP] = pos.attacks_from<BISHOP>(ksq);
+  checkSq[ROOK] = pos.attacks_from<ROOK>(ksq);
+  checkSq[QUEEN] = checkSq[BISHOP] | checkSq[ROOK];
+  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);
+
+  memcpy(this, &pos, sizeof(Position));
+  detach(); // Always detach() in copy c'tor to avoid surprises
 }
 
 Position::Position(const string& fen) {
+
   from_fen(fen);
 }
 
 
+/// 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).
@@ -129,72 +165,77 @@ 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
   while (fen[i] == ' ')
       i++;
 
-  // En passant square
+  // En passant square -- ignore if no capture is possible
   if (    i <= fen.length() - 2
       && (fen[i] >= 'a' && fen[i] <= 'h')
       && (fen[i+1] == '3' || fen[i+1] == '6'))
-      st->epSquare = square_from_string(fen.substr(i, 2));
+  {
+      Square fenEpSquare = square_from_string(fen.substr(i, 2));
+      Color them = opposite_color(sideToMove);
+      if (attacks_from<PAWN>(fenEpSquare, them) & this->pieces(PAWN, sideToMove))
+          st->epSquare = square_from_string(fen.substr(i, 2));
+  }
 
   // Various initialisation
   for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
@@ -252,10 +293,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 += '-';
 
@@ -286,8 +341,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--)
   {
@@ -312,34 +368,24 @@ 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
 /// candidate for a discovery check against the enemy king.
-/// Note that checkersBB bitboard must be already updated.
+/// Bitboard checkersBB must be already updated when looking for pinners.
 
 template<bool FindPinned>
 Bitboard Position::hidden_checkers(Color c) const {
 
-  Bitboard pinners, result = EmptyBoardBB;
+  Bitboard result = EmptyBoardBB;
+  Bitboard pinners = pieces_of_color(FindPinned ? opposite_color(c) : c);
 
   // Pinned pieces protect our king, dicovery checks attack
   // the enemy king.
   Square ksq = king_square(FindPinned ? c : opposite_color(c));
 
-  // Pinners are sliders, not checkers, that give check when
-  // candidate pinned is removed.
-  pinners =  (pieces(ROOK, QUEEN, FindPinned ? opposite_color(c) : c) & RookPseudoAttacks[ksq])
-           | (pieces(BISHOP, QUEEN, FindPinned ? opposite_color(c) : c) & BishopPseudoAttacks[ksq]);
+  // Pinners are sliders, not checkers, that give check when candidate pinned is removed
+  pinners &= (pieces(ROOK, QUEEN) & RookPseudoAttacks[ksq]) | (pieces(BISHOP, QUEEN) & BishopPseudoAttacks[ksq]);
 
   if (FindPinned && pinners)
       pinners &= ~st->checkersBB;
@@ -360,7 +406,8 @@ Bitboard Position::hidden_checkers(Color c) const {
 
 
 /// Position:pinned_pieces() returns a bitboard of all pinned (against the
-/// king) pieces for the given color.
+/// king) pieces for the given color. Note that checkersBB bitboard must
+/// be already updated.
 
 Bitboard Position::pinned_pieces(Color c) const {
 
@@ -370,7 +417,8 @@ Bitboard Position::pinned_pieces(Color c) const {
 
 /// Position:discovered_check_candidates() returns a bitboard containing all
 /// pieces for the given side which are candidates for giving a discovered
-/// check.
+/// check. Contrary to pinned_pieces() here there is no need of checkersBB
+/// to be already updated.
 
 Bitboard Position::discovered_check_candidates(Color c) const {
 
@@ -539,162 +587,98 @@ bool Position::pl_move_is_evasion(Move m, Bitboard pinned) const
 
 bool Position::move_is_check(Move m) const {
 
-  Bitboard dc = discovered_check_candidates(side_to_move());
-  return move_is_check(m, dc);
+  return move_is_check(m, CheckInfo(*this));
 }
 
-bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
+bool Position::move_is_check(Move m, const CheckInfo& ci) const {
 
   assert(is_ok());
   assert(move_is_ok(m));
-  assert(dcCandidates == discovered_check_candidates(side_to_move()));
+  assert(ci.dcCandidates == discovered_check_candidates(side_to_move()));
+  assert(color_of_piece_on(move_from(m)) == side_to_move());
+  assert(piece_on(ci.ksq) == piece_of_color_and_type(opposite_color(side_to_move()), KING));
 
-  Color us = side_to_move();
-  Color them = opposite_color(us);
   Square from = move_from(m);
   Square to = move_to(m);
-  Square ksq = king_square(them);
+  PieceType pt = type_of_piece_on(from);
 
-  assert(color_of_piece_on(from) == us);
-  assert(piece_on(ksq) == piece_of_color_and_type(them, KING));
+  // Direct check ?
+  if (bit_is_set(ci.checkSq[pt], to))
+      return true;
 
-  // Proceed according to the type of the moving piece
-  switch (type_of_piece_on(from))
+  // Discovery check ?
+  if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from))
   {
-  case PAWN:
-
-      if (bit_is_set(attacks_from<PAWN>(ksq, them), to)) // Normal check?
-          return true;
-
-      if (   dcCandidates // Discovered check?
-          && bit_is_set(dcCandidates, from)
-          && (direction_between_squares(from, ksq) != direction_between_squares(to, ksq)))
+      // 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)))
           return true;
+  }
 
-      if (move_is_promotion(m)) // Promotion with check?
-      {
-          Bitboard b = occupied_squares();
-          clear_bit(&b, from);
-
-          switch (move_promotion_piece(m))
-          {
-          case KNIGHT:
-              return bit_is_set(attacks_from<KNIGHT>(to), ksq);
-          case BISHOP:
-              return bit_is_set(bishop_attacks_bb(to, b), ksq);
-          case ROOK:
-              return bit_is_set(rook_attacks_bb(to, b), ksq);
-          case QUEEN:
-              return bit_is_set(queen_attacks_bb(to, b), ksq);
-          default:
-              assert(false);
-          }
-      }
-      // En passant capture with check?  We have already handled the case
-      // of direct checks and ordinary discovered check, the only case we
-      // need to handle is the unusual case of a discovered check through the
-      // captured pawn.
-      else if (move_is_ep(m))
-      {
-          Square capsq = make_square(square_file(to), square_rank(from));
-          Bitboard b = occupied_squares();
-          clear_bit(&b, from);
-          clear_bit(&b, capsq);
-          set_bit(&b, to);
-          return  (rook_attacks_bb(ksq, b) & pieces(ROOK, QUEEN, us))
-                ||(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, us));
-      }
+  // Can we skip the ugly special cases ?
+  if (!move_is_special(m))
       return false;
 
-  // Test discovered check and normal check according to piece type
-  case KNIGHT:
-    return   (dcCandidates && bit_is_set(dcCandidates, from))
-          || bit_is_set(attacks_from<KNIGHT>(ksq), to);
-
-  case BISHOP:
-    return   (dcCandidates && bit_is_set(dcCandidates, from))
-          || (direction_is_diagonal(ksq, to) && bit_is_set(attacks_from<BISHOP>(ksq), to));
-
-  case ROOK:
-    return   (dcCandidates && bit_is_set(dcCandidates, from))
-          || (direction_is_straight(ksq, to) && bit_is_set(attacks_from<ROOK>(ksq), to));
-
-  case QUEEN:
-      // Discovered checks are impossible!
-      assert(!bit_is_set(dcCandidates, from));
-      return (   (direction_is_straight(ksq, to) && bit_is_set(attacks_from<ROOK>(ksq), to))
-              || (direction_is_diagonal(ksq, to) && bit_is_set(attacks_from<BISHOP>(ksq), to)));
-
-  case KING:
-      // Discovered check?
-      if (   bit_is_set(dcCandidates, from)
-          && (direction_between_squares(from, ksq) != direction_between_squares(to, ksq)))
-          return true;
+  Color us = side_to_move();
+  Bitboard b = occupied_squares();
 
-      // Castling with check?
-      if (move_is_castle(m))
-      {
-          Square kfrom, kto, rfrom, rto;
-          Bitboard b = occupied_squares();
-          kfrom = from;
-          rfrom = to;
+  // Promotion with check ?
+  if (move_is_promotion(m))
+  {
+      clear_bit(&b, from);
 
-          if (rfrom > kfrom)
-          {
-              kto = relative_square(us, SQ_G1);
-              rto = relative_square(us, SQ_F1);
-          } else {
-              kto = relative_square(us, SQ_C1);
-              rto = relative_square(us, SQ_D1);
-          }
-          clear_bit(&b, kfrom);
-          clear_bit(&b, rfrom);
-          set_bit(&b, rto);
-          set_bit(&b, kto);
-          return bit_is_set(rook_attacks_bb(rto, b), ksq);
+      switch (move_promotion_piece(m))
+      {
+      case KNIGHT:
+          return bit_is_set(attacks_from<KNIGHT>(to), ci.ksq);
+      case BISHOP:
+          return bit_is_set(bishop_attacks_bb(to, b), ci.ksq);
+      case ROOK:
+          return bit_is_set(rook_attacks_bb(to, b), ci.ksq);
+      case QUEEN:
+          return bit_is_set(queen_attacks_bb(to, b), ci.ksq);
+      default:
+          assert(false);
       }
-      return false;
-
-  default: // NO_PIECE_TYPE
-      break;
   }
-  assert(false);
-  return false;
-}
-
-
-/// Position::update_checkers() udpates chekers info given the move. It is called
-/// in do_move() and is faster then find_checkers().
-
-template<PieceType Piece>
-inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square from,
-                                      Square to, Bitboard dcCandidates) {
-
-  const bool Bishop = (Piece == QUEEN || Piece == BISHOP);
-  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(attacks_from<Piece>(ksq), to)) // slow, try to early skip
-      set_bit(pCheckersBB, to);
 
-  else if (   Piece != KING
-           && !Slider
-           && bit_is_set(Piece == PAWN ? attacks_from<PAWN>(ksq, opposite_color(sideToMove))
-                                       : attacks_from<Piece>(ksq), to))
-      set_bit(pCheckersBB, to);
+  // En passant capture with check?  We have already handled the case
+  // of direct checks and ordinary discovered check, the only case we
+  // need to handle is the unusual case of a discovered check through the
+  // captured pawn.
+  if (move_is_ep(m))
+  {
+      Square capsq = make_square(square_file(to), square_rank(from));
+      clear_bit(&b, from);
+      clear_bit(&b, capsq);
+      set_bit(&b, to);
+      return  (rook_attacks_bb(ci.ksq, b) & pieces(ROOK, QUEEN, us))
+            ||(bishop_attacks_bb(ci.ksq, b) & pieces(BISHOP, QUEEN, us));
+  }
 
-  // Discovery checks
-  if (Piece != QUEEN && bit_is_set(dcCandidates, from))
+  // Castling with check ?
+  if (move_is_castle(m))
   {
-      if (Piece != ROOK)
-          (*pCheckersBB) |= (attacks_from<ROOK>(ksq) & pieces(ROOK, QUEEN, side_to_move()));
+      Square kfrom, kto, rfrom, rto;
+      kfrom = from;
+      rfrom = to;
 
-      if (Piece != BISHOP)
-          (*pCheckersBB) |= (attacks_from<BISHOP>(ksq) & pieces(BISHOP, QUEEN, side_to_move()));
+      if (rfrom > kfrom)
+      {
+          kto = relative_square(us, SQ_G1);
+          rto = relative_square(us, SQ_F1);
+      } else {
+          kto = relative_square(us, SQ_C1);
+          rto = relative_square(us, SQ_D1);
+      }
+      clear_bit(&b, kfrom);
+      clear_bit(&b, rfrom);
+      set_bit(&b, rto);
+      set_bit(&b, kto);
+      return bit_is_set(rook_attacks_bb(rto, b), ci.ksq);
   }
+
+  return false;
 }
 
 
@@ -704,24 +688,25 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square
 
 void Position::do_move(Move m, StateInfo& newSt) {
 
-  do_move(m, newSt, discovered_check_candidates(side_to_move()));
+  CheckInfo ci(*this);
+  do_move(m, newSt, ci, move_is_check(m, ci));
 }
 
-void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
+void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) {
 
   assert(is_ok());
   assert(move_is_ok(m));
 
-  Bitboard key = st->key;
+  Key key = st->key;
 
   // Copy some fields of old state to our new StateInfo object except the
   // ones which are recalculated from scratch anyway, then switch our state
   // pointer to point to the new, ready to be updated, state.
   struct ReducedStateInfo {
-    Key key, pawnKey, materialKey;
+    Key pawnKey, materialKey;
     int castleRights, rule50, pliesFromNull;
     Square epSquare;
-    Value value;
+    Score value;
     Value npMaterial[2];
   };
 
@@ -758,16 +743,15 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
 
   Piece piece = piece_on(from);
   PieceType pt = type_of_piece(piece);
+  PieceType capture = ep ? PAWN : type_of_piece_on(to);
 
   assert(color_of_piece_on(from) == us);
   assert(color_of_piece_on(to) == them || square_is_empty(to));
   assert(!(ep || pm) || piece == piece_of_color_and_type(us, PAWN));
   assert(!pm || relative_rank(us, to) == RANK_8);
 
-  st->capture = ep ? PAWN : type_of_piece_on(to);
-
-  if (st->capture)
-      do_capture_move(key, st->capture, them, to, ep);
+  if (capture)
+      do_capture_move(key, capture, them, to, ep);
 
   // Update hash key
   key ^= zobrist[us][pt][from] ^ zobrist[us][pt][to];
@@ -817,7 +801,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
       st->pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to];
 
       // Set en passant square, only if moved pawn can be captured
-      if (abs(int(to) - int(from)) == 16)
+      if ((to ^ from) == 16)
       {
           if (attacks_from<PAWN>(from + (us == WHITE ? DELTA_N : DELTA_S), us) & pieces(PAWN, them))
           {
@@ -830,6 +814,9 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
   // Update incremental scores
   st->value += pst_delta(piece, from, to);
 
+  // Set capture piece
+  st->capture = capture;
+
   if (pm) // promotion ?
   {
       PieceType promotion = move_promotion_piece(m);
@@ -841,13 +828,13 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
       set_bit(&(byTypeBB[promotion]), to);
       board[to] = piece_of_color_and_type(us, promotion);
 
+      // Update piece counts      
+      pieceCount[us][promotion]++;
+      pieceCount[us][PAWN]--;
+
       // Update material key
       st->materialKey ^= zobMaterial[us][PAWN][pieceCount[us][PAWN]];
-      st->materialKey ^= zobMaterial[us][promotion][pieceCount[us][promotion]+1];
-
-      // Update piece counts
-      pieceCount[us][PAWN]--;
-      pieceCount[us][promotion]++;
+      st->materialKey ^= zobMaterial[us][promotion][pieceCount[us][promotion]-1];
 
       // Update piece lists, move the last pawn at index[to] position
       // and shrink the list. Add a new promotion piece to the list.
@@ -874,27 +861,33 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
   st->key = key;
 
   // Update checkers bitboard, piece must be already moved
-  if (ep | pm)
-      st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us);
-  else
+  st->checkersBB = EmptyBoardBB;
+
+  if (moveIsCheck)
   {
-      st->checkersBB = EmptyBoardBB;
-      Square ksq = king_square(them);
-      switch (pt)
+      if (ep | pm)
+          st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us);
+      else
       {
-      case PAWN:   update_checkers<PAWN>(&(st->checkersBB), ksq, from, to, dcCandidates);   break;
-      case KNIGHT: update_checkers<KNIGHT>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
-      case BISHOP: update_checkers<BISHOP>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
-      case ROOK:   update_checkers<ROOK>(&(st->checkersBB), ksq, from, to, dcCandidates);   break;
-      case QUEEN:  update_checkers<QUEEN>(&(st->checkersBB), ksq, from, to, dcCandidates);  break;
-      case KING:   update_checkers<KING>(&(st->checkersBB), ksq, from, to, dcCandidates);   break;
-      default: assert(false); break;
+          // Direct checks
+          if (bit_is_set(ci.checkSq[pt], to))
+              st->checkersBB = SetMaskBB[to];
+
+          // Discovery checks
+          if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from))
+          {
+              if (pt != ROOK)
+                  st->checkersBB |= (attacks_from<ROOK>(ci.ksq) & pieces(ROOK, QUEEN, us));
+
+              if (pt != BISHOP)
+                  st->checkersBB |= (attacks_from<BISHOP>(ci.ksq) & pieces(BISHOP, QUEEN, us));
+          }
       }
   }
 
   // Finish
   sideToMove = opposite_color(sideToMove);
-  st->value += (sideToMove == WHITE) ?  TempoValue : -TempoValue;
+  st->value += (sideToMove == WHITE ?  TempoValue : -TempoValue);
 
   assert(is_ok());
 }
@@ -903,7 +896,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
 /// Position::do_capture_move() is a private method used to update captured
 /// piece info. It is called from the main Position::do_move function.
 
-void Position::do_capture_move(Bitboard& key, PieceType capture, Color them, Square to, bool ep) {
+void Position::do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep) {
 
     assert(capture != KING);
 
@@ -939,12 +932,12 @@ void Position::do_capture_move(Bitboard& key, PieceType capture, Color them, Squ
     else
         st->npMaterial[them] -= piece_value_midgame(capture);
 
-    // Update material hash key
-    st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
-
     // Update piece count
     pieceCount[them][capture]--;
 
+    // Update material hash key
+    st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
+
     // Update piece list, move the last piece at index[capsq] position
     //
     // WARNING: This is a not perfectly revresible operation. When we
@@ -1011,7 +1004,7 @@ void Position::do_castle_move(Move m) {
   set_bit(&(byColorBB[us]), rto);
   set_bit(&(byTypeBB[ROOK]), rto);
   set_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares
-  
+
   // Update board array
   Piece king = piece_of_color_and_type(us, KING);
   Piece rook = piece_of_color_and_type(us, ROOK);
@@ -1054,7 +1047,7 @@ void Position::do_castle_move(Move m) {
 
   // Finish
   sideToMove = opposite_color(sideToMove);
-  st->value += (sideToMove == WHITE) ?  TempoValue : -TempoValue;
+  st->value += (sideToMove == WHITE ?  TempoValue : -TempoValue);
 
   assert(is_ok());
 }
@@ -1196,7 +1189,7 @@ void Position::undo_castle_move(Move m) {
 
   assert(piece_on(kto) == piece_of_color_and_type(us, KING));
   assert(piece_on(rto) == piece_of_color_and_type(us, ROOK));
-  
+
   // Remove pieces from destination squares:
   clear_bit(&(byColorBB[us]), kto);
   clear_bit(&(byTypeBB[KING]), kto);
@@ -1204,7 +1197,7 @@ void Position::undo_castle_move(Move m) {
   clear_bit(&(byColorBB[us]), rto);
   clear_bit(&(byTypeBB[ROOK]), rto);
   clear_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares
+
   // Put pieces on source squares:
   set_bit(&(byColorBB[us]), kfrom);
   set_bit(&(byTypeBB[KING]), kfrom);
@@ -1464,19 +1457,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.
 
@@ -1595,7 +1575,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];
@@ -1618,7 +1598,7 @@ Key Position::compute_material_key() const {
       for (PieceType pt = PAWN; pt <= QUEEN; pt++)
       {
           int count = piece_count(c, pt);
-          for (int i = 0; i <= count; i++)
+          for (int i = 0; i < count; i++)
               result ^= zobMaterial[c][pt][i];
       }
   return result;
@@ -1631,7 +1611,7 @@ 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(0, 0);
+  Score result = make_score(0, 0);
   Bitboard b;
   Square s;
 
@@ -1639,7 +1619,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));
@@ -1647,7 +1627,7 @@ Score Position::compute_value() const {
           }
       }
 
-  result += (side_to_move() == WHITE)? TempoValue / 2 : -TempoValue / 2;
+  result += (side_to_move() == WHITE ? TempoValue / 2 : -TempoValue / 2);
   return result;
 }
 
@@ -1678,6 +1658,7 @@ Value Position::compute_non_pawn_material(Color c) const {
 /// Position::is_draw() tests whether the position is drawn by material,
 /// repetition, or the 50 moves rule. It does not detect stalemates, this
 /// must be done by the search.
+// FIXME: Currently we are not handling 50 move rule correctly when in check
 
 bool Position::is_draw() const {
 
@@ -1691,7 +1672,7 @@ bool Position::is_draw() const {
       return true;
 
   // Draw by repetition?
-  for (int i = 2; i < Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2)
+  for (int i = 4; i <= Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2)
       if (history[gamePly - i] == st->key)
           return true;
 
@@ -1774,11 +1755,13 @@ void Position::init_zobrist() {
 
   for (int i = 0; i < 2; i++)
       for (int j = 0; j < 8; j++)
-          for (int k = 0; k < 16; k++)
-              zobMaterial[i][j][k] = (k > 0)? Key(genrand_int64()) : Key(0LL);
+          for (int k = 0; k < 8; k++)
+              zobMaterial[i][j][k] = Key(genrand_int64());
 
-  for (int i = 0; i < 16; i++)
+  for (int i = 0; i < 8; i++)
       zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = Key(0ULL);
+
+  zobExclusion = genrand_int64();
 }
 
 
@@ -1796,7 +1779,7 @@ void Position::init_piece_square_tables() {
       for (Piece p = WP; p <= WK; p++)
       {
           i = (r == 0)? 0 : (genrand_int32() % (r*2) - r);
-          PieceSquareTable[p][s] = Score(MgPST[p][s] + i, EgPST[p][s] + i);
+          PieceSquareTable[p][s] = make_score(MgPST[p][s] + i, EgPST[p][s] + i);
       }
 
   for (Square s = SQ_A1; s <= SQ_H8; s++)
@@ -1883,6 +1866,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;
 
@@ -2008,9 +1992,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;
@@ -2019,6 +2003,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;
 }