]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Fully qualify memset and memcpy
[stockfish] / src / position.cpp
index 37b5c049cadd2152b6fdccaee44a87d0f57df315..1273a62fb3d0a0e975e2d06cdbf590359d9c473d 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-2012 Marco Costalba, Joona Kiiski, Tord Romstad
+  Copyright (C) 2008-2013 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
@@ -19,6 +19,7 @@
 
 #include <cassert>
 #include <cstring>
+#include <iomanip>
 #include <iostream>
 #include <sstream>
 #include <algorithm>
@@ -40,73 +41,27 @@ static const string PieceToChar(" PNBRQK  pnbrqk");
 
 CACHE_LINE_ALIGNMENT
 
-Score pieceSquareTable[PIECE_NB][SQUARE_NB];
+Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
 Value PieceValue[PHASE_NB][PIECE_NB] = {
 { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
 { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } };
 
 namespace Zobrist {
 
-Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
-Key enpassant[FILE_NB];
-Key castle[CASTLE_RIGHT_NB];
-Key side;
-Key exclusion;
-
-/// init() initializes at startup the various arrays used to compute hash keys
-/// and the piece square tables. The latter is a two-step operation: First, the
-/// white halves of the tables are copied from PSQT[] tables. Second, the black
-/// halves of the tables are initialized by flipping and changing the sign of
-/// the white scores.
-
-void init() {
-
-  RKISS rk;
-
-  for (Color c = WHITE; c <= BLACK; c++)
-      for (PieceType pt = PAWN; pt <= KING; pt++)
-          for (Square s = SQ_A1; s <= SQ_H8; s++)
-              psq[c][pt][s] = rk.rand<Key>();
-
-  for (File f = FILE_A; f <= FILE_H; f++)
-      enpassant[f] = rk.rand<Key>();
-
-  for (int cr = CASTLES_NONE; cr <= ALL_CASTLES; cr++)
-  {
-      Bitboard b = cr;
-      while (b)
-      {
-          Key k = castle[1ULL << pop_lsb(&b)];
-          castle[cr] ^= k ? k : rk.rand<Key>();
-      }
-  }
-
-  side = rk.rand<Key>();
-  exclusion  = rk.rand<Key>();
-
-  for (PieceType pt = PAWN; pt <= KING; pt++)
-  {
-      PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
-      PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];
-
-      Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);
-
-      for (Square s = SQ_A1; s <= SQ_H8; s++)
-      {
-          pieceSquareTable[make_piece(WHITE, pt)][ s] =  (v + PSQT[pt][s]);
-          pieceSquareTable[make_piece(BLACK, pt)][~s] = -(v + PSQT[pt][s]);
-      }
-  }
+  Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+  Key enpassant[FILE_NB];
+  Key castle[CASTLE_RIGHT_NB];
+  Key side;
+  Key exclusion;
 }
 
-} // namespace Zobrist
-
+Key Position::exclusion_key() const { return st->key ^ Zobrist::exclusion;}
 
 namespace {
 
-/// next_attacker() is an helper function used by see() to locate the least
-/// valuable attacker for the side to move, remove the attacker we just found
-/// from the 'occupied' bitboard and scan for new X-ray attacks behind it.
+// next_attacker() is an helper function used by see() to locate the least
+// valuable attacker for the side to move, remove the attacker we just found
+// from the 'occupied' bitboard and scan for new X-ray attacks behind it.
 
 template<int Pt> FORCE_INLINE
 PieceType next_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers,
@@ -155,13 +110,60 @@ CheckInfo::CheckInfo(const Position& pos) {
 }
 
 
+/// Position::init() initializes at startup the various arrays used to compute
+/// hash keys and the piece square tables. The latter is a two-step operation:
+/// First, the white halves of the tables are copied from PSQT[] tables. Second,
+/// the black halves of the tables are initialized by flipping and changing the
+/// sign of the white scores.
+
+void Position::init() {
+
+  RKISS rk;
+
+  for (Color c = WHITE; c <= BLACK; c++)
+      for (PieceType pt = PAWN; pt <= KING; pt++)
+          for (Square s = SQ_A1; s <= SQ_H8; s++)
+              Zobrist::psq[c][pt][s] = rk.rand<Key>();
+
+  for (File f = FILE_A; f <= FILE_H; f++)
+      Zobrist::enpassant[f] = rk.rand<Key>();
+
+  for (int cr = CASTLES_NONE; cr <= ALL_CASTLES; cr++)
+  {
+      Bitboard b = cr;
+      while (b)
+      {
+          Key k = Zobrist::castle[1ULL << pop_lsb(&b)];
+          Zobrist::castle[cr] ^= k ? k : rk.rand<Key>();
+      }
+  }
+
+  Zobrist::side = rk.rand<Key>();
+  Zobrist::exclusion  = rk.rand<Key>();
+
+  for (PieceType pt = PAWN; pt <= KING; pt++)
+  {
+      PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
+      PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];
+
+      Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);
+
+      for (Square s = SQ_A1; s <= SQ_H8; s++)
+      {
+         psq[WHITE][pt][ s] =  (v + PSQT[pt][s]);
+         psq[BLACK][pt][~s] = -(v + PSQT[pt][s]);
+      }
+  }
+}
+
+
 /// Position::operator=() creates a copy of 'pos'. We want the new born Position
 /// object do not depend on any external data so we detach state pointer from
 /// the source one.
 
 Position& Position::operator=(const Position& pos) {
 
-  memcpy(this, &pos, sizeof(Position));
+  std::memcpy(this, &pos, sizeof(Position));
   startState = *st;
   st = &startState;
   nodes = 0;
@@ -278,16 +280,16 @@ void Position::set(const string& fenStr, bool isChess960, Thread* th) {
   }
 
   // 5-6. Halfmove clock and fullmove number
-  ss >> std::skipws >> st->rule50 >> startPosPly;
+  ss >> std::skipws >> st->rule50 >> gamePly;
 
   // Convert from fullmove starting from 1 to ply starting from 0,
   // handle also common incorrect FEN with fullmove = 0.
-  startPosPly = std::max(2 * (startPosPly - 1), 0) + int(sideToMove == BLACK);
+  gamePly = std::max(2 * (gamePly - 1), 0) + int(sideToMove == BLACK);
 
   st->key = compute_key();
   st->pawnKey = compute_pawn_key();
   st->materialKey = compute_material_key();
-  st->psqScore = compute_psq_score();
+  st->psq = compute_psq_score();
   st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
   st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
   st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove);
@@ -331,33 +333,26 @@ void Position::set_castle_right(Color c, Square rfrom) {
 const string Position::fen() const {
 
   std::ostringstream ss;
-  Square sq;
-  int emptyCnt;
 
   for (Rank rank = RANK_8; rank >= RANK_1; rank--)
   {
-      emptyCnt = 0;
-
       for (File file = FILE_A; file <= FILE_H; file++)
       {
-          sq = file | rank;
+          Square sq = file | rank;
 
           if (is_empty(sq))
-              emptyCnt++;
-          else
           {
-              if (emptyCnt > 0)
-              {
-                  ss << emptyCnt;
-                  emptyCnt = 0;
-              }
-              ss << PieceToChar[piece_on(sq)];
+              int emptyCnt = 1;
+
+              for ( ; file < FILE_H && is_empty(sq++); file++)
+                  emptyCnt++;
+
+              ss << emptyCnt;
           }
+          else
+              ss << PieceToChar[piece_on(sq)];
       }
 
-      if (emptyCnt > 0)
-          ss << emptyCnt;
-
       if (rank > RANK_1)
           ss << '/';
   }
@@ -365,22 +360,22 @@ const string Position::fen() const {
   ss << (sideToMove == WHITE ? " w " : " b ");
 
   if (can_castle(WHITE_OO))
-      ss << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE, KING_SIDE))))) : 'K');
+      ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE,  KING_SIDE)), false) : 'K');
 
   if (can_castle(WHITE_OOO))
-      ss << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE, QUEEN_SIDE))))) : 'Q');
+      ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE, QUEEN_SIDE)), false) : 'Q');
 
   if (can_castle(BLACK_OO))
-      ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, KING_SIDE))) : 'k');
+      ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK,  KING_SIDE)),  true) : 'k');
 
   if (can_castle(BLACK_OOO))
-      ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, QUEEN_SIDE))) : 'q');
+      ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, QUEEN_SIDE)),  true) : 'q');
 
   if (st->castleRights == CASTLES_NONE)
       ss << '-';
 
   ss << (ep_square() == SQ_NONE ? " - " : " " + square_to_string(ep_square()) + " ")
-      << st->rule50 << " " << 1 + (startPosPly - int(sideToMove == BLACK)) / 2;
+      << st->rule50 << " " << 1 + (gamePly - int(sideToMove == BLACK)) / 2;
 
   return ss.str();
 }
@@ -400,48 +395,49 @@ const string Position::pretty(Move move) const {
   std::ostringstream ss;
 
   if (move)
-      ss << "\nMove is: " << (sideToMove == BLACK ? ".." : "")
+      ss << "\nMove: " << (sideToMove == BLACK ? ".." : "")
          << move_to_san(*const_cast<Position*>(this), move);
 
   for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
       if (piece_on(sq) != NO_PIECE)
           brd[513 - 68*rank_of(sq) + 4*file_of(sq)] = PieceToChar[piece_on(sq)];
 
-  ss << brd << "\nFen is: " << fen() << "\nKey is: " << st->key;
+  ss << brd << "\nFen: " << fen() << "\nKey: " << std::hex << std::uppercase
+     << std::setfill('0') << std::setw(16) << st->key << "\nCheckers: ";
+
+  for (Bitboard b = checkers(); b; )
+      ss << square_to_string(pop_lsb(&b)) << " ";
+
+  ss << "\nLegal moves: ";
+  for (MoveList<LEGAL> it(*this); *it; ++it)
+      ss << move_to_san(*const_cast<Position*>(this), *it) << " ";
+
   return ss.str();
 }
 
 
-/// Position:hidden_checkers<>() returns a bitboard of all pinned (against the
-/// king) pieces for the given color. Or, when template parameter FindPinned is
-/// false, the function return the pieces of the given color candidate for a
-/// discovery check against the enemy king.
-template<bool FindPinned>
-Bitboard Position::hidden_checkers() const {
+/// Position:hidden_checkers() returns a bitboard of all pinned / discovery check
+/// pieces, according to the call parameters. Pinned pieces protect our king,
+/// discovery check pieces attack the enemy king.
+
+Bitboard Position::hidden_checkers(Square ksq, Color c) const {
 
-  // Pinned pieces protect our king, dicovery checks attack the enemy king
-  Bitboard b, result = 0;
-  Bitboard pinners = pieces(FindPinned ? ~sideToMove : sideToMove);
-  Square ksq = king_square(FindPinned ? sideToMove : ~sideToMove);
+  Bitboard b, pinners, result = 0;
 
-  // Pinners are sliders, that give check when candidate pinned is removed
-  pinners &=  (pieces(ROOK, QUEEN) & PseudoAttacks[ROOK][ksq])
-            | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq]);
+  // Pinners are sliders that give check when pinned piece is removed
+  pinners = (  (pieces(  ROOK, QUEEN) & PseudoAttacks[ROOK  ][ksq])
+             | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq])) & pieces(c);
 
   while (pinners)
   {
       b = between_bb(ksq, pop_lsb(&pinners)) & pieces();
 
-      if (b && !more_than_one(b) && (b & pieces(sideToMove)))
-          result |= b;
+      if (!more_than_one(b))
+          result |= b & pieces(sideToMove);
   }
   return result;
 }
 
-// Explicit template instantiations
-template Bitboard Position::hidden_checkers<true>() const;
-template Bitboard Position::hidden_checkers<false>() const;
-
 
 /// Position::attackers_to() computes a bitboard of all pieces which attack a
 /// given square. Slider attacks use occ bitboard as occupancy.
@@ -521,20 +517,6 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 }
 
 
-/// Position::move_is_legal() takes a random move and tests whether the move
-/// is legal. This version is not very fast and should be used only in non
-/// time-critical paths.
-
-bool Position::move_is_legal(const Move m) const {
-
-  for (MoveList<LEGAL> ml(*this); !ml.end(); ++ml)
-      if (ml.move() == m)
-          return true;
-
-  return false;
-}
-
-
 /// Position::is_pseudo_legal() takes a random move and tests whether the move
 /// is pseudo legal. It is used to validate moves from TT that can be corrupted
 /// due to SMP concurrent access or hash position key aliasing.
@@ -542,14 +524,13 @@ bool Position::move_is_legal(const Move m) const {
 bool Position::is_pseudo_legal(const Move m) const {
 
   Color us = sideToMove;
-  Color them = ~sideToMove;
   Square from = from_sq(m);
   Square to = to_sq(m);
   Piece pc = piece_moved(m);
 
   // Use a slower but simpler function for uncommon cases
   if (type_of(m) != NORMAL)
-      return move_is_legal(m);
+      return MoveList<LEGAL>(*this).contains(m);
 
   // Is not a promotion, so promotion piece must be empty
   if (promotion_type(m) - 2 != NO_PIECE_TYPE)
@@ -587,7 +568,7 @@ bool Position::is_pseudo_legal(const Move m) const {
       case DELTA_SE:
       // Capture. The destination square must be occupied by an enemy
       // piece (en passant captures was handled earlier).
-      if (piece_on(to) == NO_PIECE || color_of(piece_on(to)) != them)
+      if (piece_on(to) == NO_PIECE || color_of(piece_on(to)) != ~us)
           return false;
 
       // From and to files must be one file apart, avoids a7h5
@@ -632,18 +613,16 @@ bool Position::is_pseudo_legal(const Move m) const {
   // Evasions generator already takes care to avoid some kind of illegal moves
   // and pl_move_is_legal() relies on this. So we have to take care that the
   // same kind of moves are filtered out here.
-  if (in_check())
+  if (checkers())
   {
       if (type_of(pc) != KING)
       {
-          Bitboard b = checkers();
-          Square checksq = pop_lsb(&b);
-
-          if (b) // double check ? In this case a king move is required
+          // Double check? In this case a king move is required
+          if (more_than_one(checkers()))
               return false;
 
           // Our move must be a blocking evasion or a capture of the checking piece
-          if (!((between_bb(checksq, king_square(us)) | checkers()) & to))
+          if (!((between_bb(lsb(checkers()), king_square(us)) | checkers()) & to))
               return false;
       }
       // In case of king moves under check we have to remove king so to catch
@@ -743,7 +722,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   // Copy some fields of old state to our new StateInfo object except the ones
   // which are going to be recalculated from scratch anyway, then switch our state
   // pointer to point to the new, ready to be updated, state.
-  memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t));
+  std::memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t));
 
   newSt.previous = st;
   st = &newSt;
@@ -751,30 +730,40 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   // Update side to move
   k ^= Zobrist::side;
 
-  // Increment the 50 moves rule draw counter. Resetting it to zero in the
-  // case of a capture or a pawn move is taken care of later.
+  // Increment ply counters.In particular rule50 will be later reset it to zero
+  // in case of a capture or a pawn move.
+  gamePly++;
   st->rule50++;
   st->pliesFromNull++;
 
-  if (type_of(m) == CASTLE)
-  {
-      st->key = k;
-      do_castle_move<true>(m);
-      return;
-  }
-
   Color us = sideToMove;
   Color them = ~us;
   Square from = from_sq(m);
   Square to = to_sq(m);
-  Piece piece = piece_on(from);
-  PieceType pt = type_of(piece);
+  Piece pc = piece_on(from);
+  PieceType pt = type_of(pc);
   PieceType capture = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));
 
-  assert(color_of(piece) == us);
-  assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == them);
+  assert(color_of(pc) == us);
+  assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == them || type_of(m) == CASTLE);
   assert(capture != KING);
 
+  if (type_of(m) == CASTLE)
+  {
+      assert(pc == make_piece(us, KING));
+
+      bool kingSide = to > from;
+      Square rfrom = to; // Castle is encoded as "king captures friendly rook"
+      Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
+      to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
+      capture = NO_PIECE_TYPE;
+
+      do_castle(from, to, rfrom, rto);
+
+      st->psq += psq[us][ROOK][rto] - psq[us][ROOK][rfrom];
+      k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];
+  }
+
   if (capture)
   {
       Square capsq = to;
@@ -809,7 +798,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
       // Update piece list, move the last piece at index[capsq] position and
       // shrink the list.
       //
-      // WARNING: This is a not revresible operation. When we will reinsert the
+      // WARNING: This is a not reversible operation. When we will reinsert the
       // captured piece in undo_move() we will put it at the end of the list and
       // not in its original place, it means index[] and pieceList[] are not
       // guaranteed to be invariant to a do_move() + undo_move() sequence.
@@ -818,12 +807,13 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
       pieceList[them][capture][index[lastSquare]] = lastSquare;
       pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE;
 
-      // Update hash keys
+      // Update material hash key and prefetch access to materialTable
       k ^= Zobrist::psq[them][capture][capsq];
       st->materialKey ^= Zobrist::psq[them][capture][pieceCount[them][capture]];
+      prefetch((char*)thisThread->materialTable[st->materialKey]);
 
       // Update incremental scores
-      st->psqScore -= pieceSquareTable[make_piece(them, capture)][capsq];
+      st->psq -= psq[them][capture][capsq];
 
       // Reset rule 50 counter
       st->rule50 = 0;
@@ -847,22 +837,25 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
       st->castleRights &= ~cr;
   }
 
-  // Prefetch TT access as soon as we know key is updated
+  // Prefetch TT access as soon as we know the new hash key
   prefetch((char*)TT.first_entry(k));
 
-  // Move the piece
-  Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
-  byTypeBB[ALL_PIECES] ^= from_to_bb;
-  byTypeBB[pt] ^= from_to_bb;
-  byColorBB[us] ^= from_to_bb;
-
-  board[to] = board[from];
-  board[from] = NO_PIECE;
-
-  // Update piece lists, index[from] is not updated and becomes stale. This
-  // works as long as index[] is accessed just by known occupied squares.
-  index[to] = index[from];
-  pieceList[us][pt][index[to]] = to;
+  // Move the piece. The tricky Chess960 castle is handled earlier
+  if (type_of(m) != CASTLE)
+  {
+      Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
+      byTypeBB[ALL_PIECES] ^= from_to_bb;
+      byTypeBB[pt] ^= from_to_bb;
+      byColorBB[us] ^= from_to_bb;
+
+      board[from] = NO_PIECE;
+      board[to] = pc;
+
+      // Update piece lists, index[from] is not updated and becomes stale. This
+      // works as long as index[] is accessed just by known occupied squares.
+      index[to] = index[from];
+      pieceList[us][pt][index[to]] = to;
+  }
 
   // If the moving piece is a pawn do some special extra work
   if (pt == PAWN)
@@ -903,26 +896,22 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
                             ^ Zobrist::psq[us][PAWN][pieceCount[us][PAWN]];
 
           // Update incremental score
-          st->psqScore +=  pieceSquareTable[make_piece(us, promotion)][to]
-                         - pieceSquareTable[make_piece(us, PAWN)][to];
+          st->psq += psq[us][promotion][to] - psq[us][PAWN][to];
 
           // Update material
           st->npMaterial[us] += PieceValue[MG][promotion];
       }
 
-      // Update pawn hash key
+      // Update pawn hash key and prefetch access to pawnsTable
       st->pawnKey ^= Zobrist::psq[us][PAWN][from] ^ Zobrist::psq[us][PAWN][to];
+      prefetch((char*)thisThread->pawnsTable[st->pawnKey]);
 
       // Reset rule 50 draw counter
       st->rule50 = 0;
   }
 
-  // Prefetch pawn and material hash tables
-  prefetch((char*)thisThread->pawnTable.entries[st->pawnKey]);
-  prefetch((char*)thisThread->materialTable.entries[st->materialKey]);
-
   // Update incremental scores
-  st->psqScore += psq_delta(piece, from, to);
+  st->psq += psq[us][pt][to] - psq[us][pt][from];
 
   // Set capture piece
   st->capturedType = capture;
@@ -970,22 +959,14 @@ void Position::undo_move(Move m) {
 
   sideToMove = ~sideToMove;
 
-  if (type_of(m) == CASTLE)
-  {
-      do_castle_move<false>(m);
-      return;
-  }
-
   Color us = sideToMove;
   Color them = ~us;
   Square from = from_sq(m);
   Square to = to_sq(m);
-  Piece piece = piece_on(to);
-  PieceType pt = type_of(piece);
+  PieceType pt = type_of(piece_on(to));
   PieceType capture = st->capturedType;
 
-  assert(is_empty(from));
-  assert(color_of(piece) == us);
+  assert(is_empty(from) || type_of(m) == CASTLE);
   assert(capture != KING);
 
   if (type_of(m) == PROMOTION)
@@ -1013,19 +994,32 @@ void Position::undo_move(Move m) {
       pt = PAWN;
   }
 
-  // Put the piece back at the source square
-  Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
-  byTypeBB[ALL_PIECES] ^= from_to_bb;
-  byTypeBB[pt] ^= from_to_bb;
-  byColorBB[us] ^= from_to_bb;
-
-  board[from] = board[to];
-  board[to] = NO_PIECE;
-
-  // Update piece lists, index[to] is not updated and becomes stale. This
-  // works as long as index[] is accessed just by known occupied squares.
-  index[from] = index[to];
-  pieceList[us][pt][index[from]] = from;
+  if (type_of(m) == CASTLE)
+  {
+      bool kingSide = to > from;
+      Square rfrom = to; // Castle is encoded as "king captures friendly rook"
+      Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
+      to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
+      capture = NO_PIECE_TYPE;
+      pt = KING;
+      do_castle(to, from, rto, rfrom);
+  }
+  else
+  {
+      // Put the piece back at the source square
+      Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
+      byTypeBB[ALL_PIECES] ^= from_to_bb;
+      byTypeBB[pt] ^= from_to_bb;
+      byColorBB[us] ^= from_to_bb;
+
+      board[to] = NO_PIECE;
+      board[from] = make_piece(us, pt);
+
+      // Update piece lists, index[to] is not updated and becomes stale. This
+      // works as long as index[] is accessed just by known occupied squares.
+      index[from] = index[to];
+      pieceList[us][pt][index[from]] = from;
+  }
 
   if (capture)
   {
@@ -1055,49 +1049,18 @@ void Position::undo_move(Move m) {
 
   // Finally point our state pointer back to the previous state
   st = st->previous;
+  gamePly--;
 
   assert(pos_is_ok());
 }
 
 
-/// Position::do_castle_move() is a private method used to do/undo a castling
-/// move. Note that castling moves are encoded as "king captures friendly rook"
-/// moves, for instance white short castling in a non-Chess960 game is encoded
-/// as e1h1.
-template<bool Do>
-void Position::do_castle_move(Move m) {
-
-  assert(is_ok(m));
-  assert(type_of(m) == CASTLE);
+/// Position::do_castle() is a helper used to do/undo a castling move. This
+/// is a bit tricky, especially in Chess960.
 
-  Square kto, kfrom, rfrom, rto, kAfter, rAfter;
+void Position::do_castle(Square kfrom, Square kto, Square rfrom, Square rto) {
 
   Color us = sideToMove;
-  Square kBefore = from_sq(m);
-  Square rBefore = to_sq(m);
-
-  // Find after-castle squares for king and rook
-  if (rBefore > kBefore) // O-O
-  {
-      kAfter = relative_square(us, SQ_G1);
-      rAfter = relative_square(us, SQ_F1);
-  }
-  else // O-O-O
-  {
-      kAfter = relative_square(us, SQ_C1);
-      rAfter = relative_square(us, SQ_D1);
-  }
-
-  kfrom = Do ? kBefore : kAfter;
-  rfrom = Do ? rBefore : rAfter;
-
-  kto = Do ? kAfter : kBefore;
-  rto = Do ? rAfter : rBefore;
-
-  assert(piece_on(kfrom) == make_piece(us, KING));
-  assert(piece_on(rfrom) == make_piece(us, ROOK));
-
-  // Move the pieces, with some care; in chess960 could be kto == rfrom
   Bitboard k_from_to_bb = SquareBB[kfrom] ^ SquareBB[kto];
   Bitboard r_from_to_bb = SquareBB[rfrom] ^ SquareBB[rto];
   byTypeBB[KING] ^= k_from_to_bb;
@@ -1105,105 +1068,63 @@ void Position::do_castle_move(Move m) {
   byTypeBB[ALL_PIECES] ^= k_from_to_bb ^ r_from_to_bb;
   byColorBB[us] ^= k_from_to_bb ^ r_from_to_bb;
 
-  // Update board
-  Piece king = make_piece(us, KING);
-  Piece rook = make_piece(us, ROOK);
+  // Could be from == to, so first set NO_PIECE then KING and ROOK
   board[kfrom] = board[rfrom] = NO_PIECE;
-  board[kto] = king;
-  board[rto] = rook;
-
-  // Update piece lists
-  pieceList[us][KING][index[kfrom]] = kto;
-  pieceList[us][ROOK][index[rfrom]] = rto;
-  int tmp = index[rfrom]; // In Chess960 could be kto == rfrom
-  index[kto] = index[kfrom];
-  index[rto] = tmp;
+  board[kto] = make_piece(us, KING);
+  board[rto] = make_piece(us, ROOK);
+
+  // Could be kfrom == rto, so use a 'tmp' variable
+  int tmp = index[kfrom];
+  index[rto] = index[rfrom];
+  index[kto] = tmp;
+  pieceList[us][KING][index[kto]] = kto;
+  pieceList[us][ROOK][index[rto]] = rto;
+}
 
-  if (Do)
-  {
-      // Reset capture field
-      st->capturedType = NO_PIECE_TYPE;
 
-      // Update incremental scores
-      st->psqScore += psq_delta(king, kfrom, kto);
-      st->psqScore += psq_delta(rook, rfrom, rto);
+/// Position::do(undo)_null_move() is used to do(undo) a "null move": It flips
+/// the side to move without executing any move on the board.
 
-      // Update hash key
-      st->key ^= Zobrist::psq[us][KING][kfrom] ^ Zobrist::psq[us][KING][kto];
-      st->key ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];
+void Position::do_null_move(StateInfo& newSt) {
 
-      // Clear en passant square
-      if (st->epSquare != SQ_NONE)
-      {
-          st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
-          st->epSquare = SQ_NONE;
-      }
+  assert(!checkers());
 
-      // Update castling rights
-      st->key ^= Zobrist::castle[st->castleRights & castleRightsMask[kfrom]];
-      st->castleRights &= ~castleRightsMask[kfrom];
+  std::memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy here
 
-      // Update checkers BB
-      st->checkersBB = attackers_to(king_square(~us)) & pieces(us);
+  newSt.previous = st;
+  st = &newSt;
 
-      sideToMove = ~sideToMove;
+  if (st->epSquare != SQ_NONE)
+  {
+      st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
+      st->epSquare = SQ_NONE;
   }
-  else
-      // Undo: point our state pointer back to the previous state
-      st = st->previous;
-
-  assert(pos_is_ok());
-}
-
 
-/// Position::do_null_move() is used to do/undo a "null move": It flips the side
-/// to move and updates the hash key without executing any move on the board.
-template<bool Do>
-void Position::do_null_move(StateInfo& backupSt) {
+  st->key ^= Zobrist::side;
+  prefetch((char*)TT.first_entry(st->key));
 
-  assert(!in_check());
-
-  // Back up the information necessary to undo the null move to the supplied
-  // StateInfo object. Note that differently from normal case here backupSt
-  // is actually used as a backup storage not as the new state. This reduces
-  // the number of fields to be copied.
-  StateInfo* src = Do ? st : &backupSt;
-  StateInfo* dst = Do ? &backupSt : st;
-
-  dst->key      = src->key;
-  dst->epSquare = src->epSquare;
-  dst->psqScore = src->psqScore;
-  dst->rule50   = src->rule50;
-  dst->pliesFromNull = src->pliesFromNull;
+  st->rule50++;
+  st->pliesFromNull = 0;
 
   sideToMove = ~sideToMove;
 
-  if (Do)
-  {
-      if (st->epSquare != SQ_NONE)
-          st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
+  assert(pos_is_ok());
+}
 
-      st->key ^= Zobrist::side;
-      prefetch((char*)TT.first_entry(st->key));
+void Position::undo_null_move() {
 
-      st->epSquare = SQ_NONE;
-      st->rule50++;
-      st->pliesFromNull = 0;
-  }
+  assert(!checkers());
 
-  assert(pos_is_ok());
+  st = st->previous;
+  sideToMove = ~sideToMove;
 }
 
-// Explicit template instantiations
-template void Position::do_null_move<false>(StateInfo& backupSt);
-template void Position::do_null_move<true>(StateInfo& backupSt);
-
 
 /// 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
-/// move, and one which takes a 'from' and a 'to' square. The function does
-/// not yet understand promotions captures.
+/// material gain or loss resulting from a move. Parameter 'asymmThreshold' takes
+/// tempi into account. If the side who initiated the capturing sequence does the
+/// last capture, he loses a tempo and if the result is below 'asymmThreshold'
+/// the capturing sequence is considered bad.
 
 int Position::see_sign(Move m) const {
 
@@ -1218,7 +1139,7 @@ int Position::see_sign(Move m) const {
   return see(m);
 }
 
-int Position::see(Move m) const {
+int Position::see(Move m, int asymmThreshold) const {
 
   Square from, to;
   Bitboard occupied, attackers, stmAttackers;
@@ -1295,6 +1216,15 @@ int Position::see(Move m) const {
 
   } while (stmAttackers);
 
+  // If we are doing asymmetric SEE evaluation and the same side does the first
+  // and the last capture, he loses a tempo and gain must be at least worth
+  // 'asymmThreshold', otherwise we replace the score with a very low value,
+  // before negamaxing.
+  if (asymmThreshold)
+      for (int i = 0; i < slIndex; i += 2)
+          if (swapList[i] < asymmThreshold)
+              swapList[i] = - QueenValueMg * 16;
+
   // 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.
   while (--slIndex)
@@ -1309,7 +1239,7 @@ int Position::see(Move m) const {
 
 void Position::clear() {
 
-  memset(this, 0, sizeof(Position));
+  std::memset(this, 0, sizeof(Position));
   startState.epSquare = SQ_NONE;
   st = &startState;
 
@@ -1394,7 +1324,7 @@ Key Position::compute_material_key() const {
 
   for (Color c = WHITE; c <= BLACK; c++)
       for (PieceType pt = PAWN; pt <= QUEEN; pt++)
-          for (int cnt = 0; cnt < piece_count(c, pt); cnt++)
+          for (int cnt = 0; cnt < pieceCount[c][pt]; cnt++)
               k ^= Zobrist::psq[c][pt][cnt];
 
   return k;
@@ -1412,7 +1342,8 @@ Score Position::compute_psq_score() const {
   for (Bitboard b = pieces(); b; )
   {
       Square s = pop_lsb(&b);
-      score += pieceSquareTable[piece_on(s)][s];
+      Piece pc = piece_on(s);
+      score += psq[color_of(pc)][type_of(pc)][s];
   }
 
   return score;
@@ -1429,7 +1360,7 @@ Value Position::compute_non_pawn_material(Color c) const {
   Value value = VALUE_ZERO;
 
   for (PieceType pt = KNIGHT; pt <= QUEEN; pt++)
-      value += piece_count(c, pt) * PieceValue[MG][pt];
+      value += pieceCount[c][pt] * PieceValue[MG][pt];
 
   return value;
 }
@@ -1438,42 +1369,38 @@ 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.
-template<bool CheckRepetition, bool CheckThreeFold>
 bool Position::is_draw() const {
 
+  // Draw by material?
   if (   !pieces(PAWN)
       && (non_pawn_material(WHITE) + non_pawn_material(BLACK) <= BishopValueMg))
       return true;
 
-  if (st->rule50 > 99 && (!in_check() || MoveList<LEGAL>(*this).size()))
+  // Draw by the 50 moves rule?
+  if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
       return true;
 
-  if (CheckRepetition)
+  // Draw by repetition?
+  int i = 4, e = std::min(st->rule50, st->pliesFromNull);
+
+  if (i <= e)
   {
-      int i = 4, e = std::min(st->rule50, st->pliesFromNull), cnt;
+      StateInfo* stp = st->previous->previous;
 
-      if (i <= e)
-      {
-          StateInfo* stp = st->previous->previous;
+      do {
+          stp = stp->previous->previous;
 
-          for (cnt = 0; i <= e; i += 2)
-          {
-              stp = stp->previous->previous;
+          if (stp->key == st->key)
+              return true;
 
-              if (stp->key == st->key && (!CheckThreeFold || ++cnt >= 2))
-                  return true;
-          }
-      }
+          i += 2;
+
+      } while (i <= e);
   }
 
   return false;
 }
 
-// Explicit template instantiations
-template bool Position::is_draw<true,  true>() const;
-template bool Position::is_draw<true, false>() const;
-template bool Position::is_draw<false,false>() const;
-
 
 /// Position::flip() flips position with the white and black sides reversed. This
 /// is only useful for debugging especially for finding evaluation symmetry bugs.
@@ -1488,7 +1415,7 @@ void Position::flip() {
   thisThread = pos.this_thread();
   nodes = pos.nodes_searched();
   chess960 = pos.is_chess960();
-  startPosPly = pos.startpos_ply_counter();
+  gamePly = pos.game_ply();
 
   for (Square s = SQ_A1; s <= SQ_H8; s++)
       if (!pos.is_empty(s))
@@ -1511,7 +1438,7 @@ void Position::flip() {
   st->key = compute_key();
   st->pawnKey = compute_pawn_key();
   st->materialKey = compute_material_key();
-  st->psqScore = compute_psq_score();
+  st->psq = compute_psq_score();
   st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
   st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
 
@@ -1602,15 +1529,13 @@ bool Position::pos_is_ok(int* failedStep) const {
   if ((*step)++, debugMaterialKey && st->materialKey != compute_material_key())
       return false;
 
-  if ((*step)++, debugIncrementalEval && st->psqScore != compute_psq_score())
+  if ((*step)++, debugIncrementalEval && st->psq != compute_psq_score())
       return false;
 
   if ((*step)++, debugNonPawnMaterial)
-  {
       if (   st->npMaterial[WHITE] != compute_non_pawn_material(WHITE)
           || st->npMaterial[BLACK] != compute_non_pawn_material(BLACK))
           return false;
-  }
 
   if ((*step)++, debugPieceCounts)
       for (Color c = WHITE; c <= BLACK; c++)
@@ -1622,13 +1547,9 @@ bool Position::pos_is_ok(int* failedStep) const {
       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]) != make_piece(c, pt))
-                      return false;
-
-                  if (index[piece_list(c, pt)[i]] != i)
+                  if (   board[pieceList[c][pt][i]] != make_piece(c, pt)
+                      || index[pieceList[c][pt][i]] != i)
                       return false;
-              }
 
   if ((*step)++, debugCastleSquares)
       for (Color c = WHITE; c <= BLACK; c++)
@@ -1639,10 +1560,8 @@ bool Position::pos_is_ok(int* failedStep) const {
               if (!can_castle(cr))
                   continue;
 
-              if ((castleRightsMask[king_square(c)] & cr) != cr)
-                  return false;
-
-              if (   piece_on(castleRookSquare[c][s]) != make_piece(c, ROOK)
+              if (  (castleRightsMask[king_square(c)] & cr) != cr
+                  || piece_on(castleRookSquare[c][s]) != make_piece(c, ROOK)
                   || castleRightsMask[castleRookSquare[c][s]] != cr)
                   return false;
           }