]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Retire seeValues[] and move PieceValue[] out of Position
[stockfish] / src / position.cpp
index b254d60b2020bc9632d2f20e002699d8bb4b8e98..7166e8f1e8cf1aca22a216d46be5671556948ddb 100644 (file)
@@ -20,7 +20,6 @@
 #include <cassert>
 #include <cstring>
 #include <fstream>
-#include <map>
 #include <iostream>
 #include <sstream>
 
@@ -46,7 +45,7 @@ Key Position::zobExclusion;
 Score Position::PieceSquareTable[16][64];
 
 // Material values arrays, indexed by Piece
-const Value Position::PieceValueMidgame[17] = {
+const Value PieceValueMidgame[17] = {
   VALUE_ZERO,
   PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
   RookValueMidgame, QueenValueMidgame, VALUE_ZERO,
@@ -55,7 +54,7 @@ const Value Position::PieceValueMidgame[17] = {
   RookValueMidgame, QueenValueMidgame
 };
 
-const Value Position::PieceValueEndgame[17] = {
+const Value PieceValueEndgame[17] = {
   VALUE_ZERO,
   PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
   RookValueEndgame, QueenValueEndgame, VALUE_ZERO,
@@ -64,46 +63,14 @@ const Value Position::PieceValueEndgame[17] = {
   RookValueEndgame, QueenValueEndgame
 };
 
-// Material values array used by SEE, indexed by PieceType
-const Value Position::seeValues[] = {
-    VALUE_ZERO,
-    PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
-    RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10
-};
-
 
 namespace {
 
   // Bonus for having the side to move (modified by Joona Kiiski)
   const Score TempoValue = make_score(48, 22);
 
-  struct PieceLetters : public std::map<char, Piece> {
-
-    PieceLetters() {
-
-      operator[]('K') = WK; operator[]('k') = BK;
-      operator[]('Q') = WQ; operator[]('q') = BQ;
-      operator[]('R') = WR; operator[]('r') = BR;
-      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;
-    }
-
-    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;
-
-      assert(false);
-      return 0;
-    }
-  };
-
-  PieceLetters pieceLetters;
+  // To convert a Piece to and from a FEN char
+  const string PieceToChar(".PNBRQK  pnbrqk  ");
 }
 
 
@@ -113,16 +80,17 @@ CheckInfo::CheckInfo(const Position& pos) {
 
   Color us = pos.side_to_move();
   Color them = opposite_color(us);
+  Square ksq = pos.king_square(them);
 
-  ksq = pos.king_square(them);
   dcCandidates = pos.discovered_check_candidates(us);
+  pinned = pos.pinned_pieces(us);
 
-  checkSq[PAWN] = pos.attacks_from<PAWN>(ksq, them);
+  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;
+  checkSq[ROOK]   = pos.attacks_from<ROOK>(ksq);
+  checkSq[QUEEN]  = checkSq[BISHOP] | checkSq[ROOK];
+  checkSq[KING]   = EmptyBoardBB;
 }
 
 
@@ -192,17 +160,19 @@ void Position::from_fen(const string& fen, bool isChess960) {
 
   char token;
   int hmc, fmn;
-  std::istringstream ss(fen);
+  size_t p;
   Square sq = SQ_A8;
+  std::istringstream ss(fen);
 
   clear();
+  ss >> std::noskipws;
 
   // 1. Piece placement field
-  while (ss.get(token) && token != ' ')
+  while ((ss >> token) && !isspace(token))
   {
-      if (pieceLetters.find(token) != pieceLetters.end())
+      if ((p = PieceToChar.find(token)) != string::npos)
       {
-          put_piece(pieceLetters[token], sq);
+          put_piece(Piece(p), sq);
           sq++;
       }
       else if (isdigit(token))
@@ -214,25 +184,25 @@ void Position::from_fen(const string& fen, bool isChess960) {
   }
 
   // 2. Active color
-  if (!ss.get(token) || (token != 'w' && token != 'b'))
+  if (!(ss >> token) || (token != 'w' && token != 'b'))
       goto incorrect_fen;
 
   sideToMove = (token == 'w' ? WHITE : BLACK);
 
-  if (!ss.get(token) || token != ' ')
+  if (!(ss >> token) || !isspace(token))
       goto incorrect_fen;
 
   // 3. Castling availability
-  while (ss.get(token) && token != ' ')
+  while ((ss >> token) && !isspace(token))
       if (!set_castling_rights(token))
           goto incorrect_fen;
 
   // 4. En passant square
   char col, row;
-  if (   (ss.get(col) && (col >= 'a' && col <= 'h'))
-      && (ss.get(row) && (row == '3' || row == '6')))
+  if (   ((ss >> col) && (col >= 'a' && col <= 'h'))
+      && ((ss >> row) && (row == '3' || row == '6')))
   {
-      st->epSquare = make_square(file_from_char(col), rank_from_char(row));
+      st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1);
 
       // Ignore if no capture is possible
       Color them = opposite_color(sideToMove);
@@ -241,7 +211,7 @@ void Position::from_fen(const string& fen, bool isChess960) {
   }
 
   // 5. Halfmove clock
-  if (ss >> hmc)
+  if (ss >> std::skipws >> hmc)
       st->rule50 = hmc;
 
   // 6. Fullmove number
@@ -294,7 +264,7 @@ bool Position::set_castling_rights(char token) {
         for (Square sq = sqH; sq >= sqA; sq--)
             if (piece_on(sq) == rook)
             {
-                do_allow_oo(c);
+                set_castle_kingside(c);
                 initialKRFile = square_file(sq);
                 break;
             }
@@ -304,7 +274,7 @@ bool Position::set_castling_rights(char token) {
         for (Square sq = sqA; sq <= sqH; sq++)
             if (piece_on(sq) == rook)
             {
-                do_allow_ooo(c);
+                set_castle_queenside(c);
                 initialQRFile = square_file(sq);
                 break;
             }
@@ -314,12 +284,12 @@ bool Position::set_castling_rights(char token) {
         File rookFile = File(token - 'A') + FILE_A;
         if (rookFile < initialKFile)
         {
-            do_allow_ooo(c);
+            set_castle_queenside(c);
             initialQRFile = rookFile;
         }
         else
         {
-            do_allow_oo(c);
+            set_castle_kingside(c);
             initialKRFile = rookFile;
         }
     }
@@ -337,10 +307,12 @@ const string Position::to_fen() const {
 
   string fen;
   Square sq;
-  char emptyCnt = '0';
+  char emptyCnt;
 
   for (Rank rank = RANK_8; rank >= RANK_1; rank--, fen += '/')
   {
+      emptyCnt = '0';
+
       for (File file = FILE_A; file <= FILE_H; file++)
       {
           sq = make_square(file, rank);
@@ -352,16 +324,13 @@ const string Position::to_fen() const {
                   fen += emptyCnt;
                   emptyCnt = '0';
               }
-              fen += pieceLetters.from_piece(piece_on(sq));
+              fen += PieceToChar[piece_on(sq)];
           } else
               emptyCnt++;
       }
 
       if (emptyCnt != '0')
-      {
           fen += emptyCnt;
-          emptyCnt = '0';
-      }
   }
 
   fen += (sideToMove == WHITE ? " w " : " b ");
@@ -413,7 +382,7 @@ void Position::print(Move move) const {
               piece = PIECE_NONE_DARK_SQ;
 
           char c = (color_of_piece_on(sq) == BLACK ? '=' : ' ');
-          cout << c << pieceLetters.from_piece(piece) << c << '|';
+          cout << c << PieceToChar[piece] << c << '|';
       }
   }
   cout << dottedLine << "Fen is: " << to_fen() << "\nKey is: " << st->key << endl;
@@ -490,6 +459,16 @@ Bitboard Position::attackers_to(Square s) const {
         | (attacks_from<KING>(s)        & pieces(KING));
 }
 
+Bitboard Position::attackers_to(Square s, Bitboard occ) const {
+
+  return  (attacks_from<PAWN>(s, BLACK) & pieces(PAWN, WHITE))
+        | (attacks_from<PAWN>(s, WHITE) & pieces(PAWN, BLACK))
+        | (attacks_from<KNIGHT>(s)      & pieces(KNIGHT))
+        | (rook_attacks_bb(s, occ)      & pieces(ROOK, QUEEN))
+        | (bishop_attacks_bb(s, occ)    & pieces(BISHOP, QUEEN))
+        | (attacks_from<KING>(s)        & pieces(KING));
+}
+
 /// Position::attacks_from() computes a bitboard of all attacks
 /// of a given piece put in a given square.
 
@@ -570,14 +549,18 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
   assert(move_is_ok(m));
   assert(pinned == pinned_pieces(side_to_move()));
 
+  Color us = side_to_move();
+  Square from = move_from(m);
+
+  assert(color_of_piece_on(from) == us);
+  assert(piece_on(king_square(us)) == make_piece(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));
       Square ksq = king_square(us);
@@ -596,12 +579,6 @@ 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)) == make_piece(us, KING));
-
   // If the moving piece is a king, check whether the destination
   // square is attacked by the opponent. Castling moves are checked
   // for legality during move generation.
@@ -616,55 +593,32 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 }
 
 
-/// Position::pl_move_is_evasion() tests whether a pseudo-legal move is a legal evasion
-
-bool Position::pl_move_is_evasion(Move m, Bitboard pinned) const
-{
-  assert(in_check());
-
-  Color us = side_to_move();
-  Square from = move_from(m);
-  Square to = move_to(m);
+/// Position::move_is_pl_slow() takes a position and a move and tests whether
+/// the move is pseudo legal. This version is not very fast and should be used
+/// only in non time-critical paths.
 
-  // King moves and en-passant captures are verified in pl_move_is_legal()
-  if (type_of_piece_on(from) == KING || move_is_ep(m))
-      return pl_move_is_legal(m, pinned);
-
-  Bitboard target = checkers();
-  Square checksq = pop_1st_bit(&target);
-
-  if (target) // double check ?
-      return false;
-
-  // Our move must be a blocking evasion or a capture of the checking piece
-  target = squares_between(checksq, king_square(us)) | checkers();
-  return bit_is_set(target, to) && pl_move_is_legal(m, pinned);
-}
-
-/// Position::move_is_legal() takes a position and a (not necessarily pseudo-legal)
-/// 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 {
+bool Position::move_is_pl_slow(const Move m) const {
 
   MoveStack mlist[MAX_MOVES];
-  MoveStack *cur, *last = generate<MV_PSEUDO_LEGAL>(*this, mlist);
+  MoveStack *cur, *last;
+
+  last = in_check() ? generate<MV_EVASION>(*this, mlist)
+                    : generate<MV_NON_EVASION>(*this, mlist);
 
-   for (cur = mlist; cur != last; cur++)
+  for (cur = mlist; cur != last; cur++)
       if (cur->move == m)
-          return pl_move_is_legal(m, pinned_pieces(sideToMove));
+          return true;
 
   return false;
 }
 
 
-/// Fast version of Position::move_is_legal() that takes a position a move and
-/// a bitboard of pinned pieces as input, and tests whether the move is legal.
+/// Fast version of Position::move_is_pl() that takes a position a move and a
+/// bitboard of pinned pieces as input, and tests whether the move is pseudo legal.
 
-bool Position::move_is_legal(const Move m, Bitboard pinned) const {
+bool Position::move_is_pl(const Move m) const {
 
   assert(is_ok());
-  assert(pinned == pinned_pieces(sideToMove));
 
   Color us = sideToMove;
   Color them = opposite_color(sideToMove);
@@ -674,11 +628,15 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const {
 
   // Use a slower but simpler function for uncommon cases
   if (move_is_special(m))
-      return move_is_legal(m);
+      return move_is_pl_slow(m);
+
+  // Is not a promotion, so promotion piece must be empty
+  if (promotion_piece_type(m) - 2 != PIECE_TYPE_NONE)
+      return false;
 
   // If the from square is not occupied by a piece belonging to the side to
   // move, the move is obviously not legal.
-  if (color_of_piece(pc) != us)
+  if (pc == PIECE_NONE || color_of_piece(pc) != us)
       return false;
 
   // The destination square cannot be occupied by a friendly piece
@@ -708,16 +666,20 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const {
       case DELTA_SE:
       // Capture. The destination square must be occupied by an enemy
       // piece (en passant captures was handled earlier).
-          if (color_of_piece_on(to) != them)
-              return false;
-          break;
+      if (color_of_piece_on(to) != them)
+          return false;
+
+      // From and to files must be one file apart, avoids a7h5
+      if (abs(square_file(from) - square_file(to)) != 1)
+          return false;
+      break;
 
       case DELTA_N:
       case DELTA_S:
       // Pawn push. The destination square must be empty.
-          if (!square_is_empty(to))
-              return false;
-          break;
+      if (!square_is_empty(to))
+          return false;
+      break;
 
       case DELTA_NN:
       // Double white pawn push. The destination square must be on the fourth
@@ -727,17 +689,17 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const {
           || !square_is_empty(to)
           || !square_is_empty(from + DELTA_N))
           return false;
-          break;
+      break;
 
       case DELTA_SS:
       // Double black pawn push. The destination square must be on the fifth
       // rank, and both the destination square and the square between the
       // source and destination squares must be empty.
-          if (   square_rank(to) != RANK_5
-              || !square_is_empty(to)
-              || !square_is_empty(from + DELTA_S))
-              return false;
-          break;
+      if (   square_rank(to) != RANK_5
+          || !square_is_empty(to)
+          || !square_is_empty(from + DELTA_S))
+          return false;
+      break;
 
       default:
           return false;
@@ -746,25 +708,44 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const {
   else if (!bit_is_set(attacks_from(pc, from), to))
       return false;
 
-  // The move is pseudo-legal, check if it is also legal
-  return in_check() ? pl_move_is_evasion(m, pinned) : pl_move_is_legal(m, pinned);
-}
-
+  if (in_check())
+  {
+      // In case of king moves under check we have to remove king so to catch
+      // as invalid moves like b1a1 when opposite queen is on c1.
+      if (type_of_piece_on(from) == KING)
+      {
+          Bitboard b = occupied_squares();
+          clear_bit(&b, from);
+          if (attackers_to(move_to(m), b) & pieces_of_color(opposite_color(us)))
+              return false;
+      }
+      else
+      {
+          Bitboard target = checkers();
+          Square checksq = pop_1st_bit(&target);
 
-/// Position::move_gives_check() tests whether a pseudo-legal move is a check
+          if (target) // double check ? In this case a king move is required
+              return false;
 
-bool Position::move_gives_check(Move m) const {
+          // Our move must be a blocking evasion or a capture of the checking piece
+          target = squares_between(checksq, king_square(us)) | checkers();
+          if (!bit_is_set(target, move_to(m)))
+              return false;
+      }
+  }
 
-  return move_gives_check(m, CheckInfo(*this));
+  return true;
 }
 
+
+/// Position::move_gives_check() tests whether a pseudo-legal move is a check
+
 bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
 
   assert(is_ok());
   assert(move_is_ok(m));
   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) == make_piece(opposite_color(side_to_move()), KING));
 
   Square from = move_from(m);
   Square to = move_to(m);
@@ -779,7 +760,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
   {
       // For pawn and king moves we need to verify also direction
       if (  (pt != PAWN && pt != KING)
-          || !squares_aligned(from, to, ci.ksq))
+          || !squares_aligned(from, to, king_square(opposite_color(side_to_move()))))
           return true;
   }
 
@@ -789,22 +770,23 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
 
   Color us = side_to_move();
   Bitboard b = occupied_squares();
+  Square ksq = king_square(opposite_color(us));
 
   // Promotion with check ?
   if (move_is_promotion(m))
   {
       clear_bit(&b, from);
 
-      switch (move_promotion_piece(m))
+      switch (promotion_piece_type(m))
       {
       case KNIGHT:
-          return bit_is_set(attacks_from<KNIGHT>(to), ci.ksq);
+          return bit_is_set(attacks_from<KNIGHT>(to), ksq);
       case BISHOP:
-          return bit_is_set(bishop_attacks_bb(to, b), ci.ksq);
+          return bit_is_set(bishop_attacks_bb(to, b), ksq);
       case ROOK:
-          return bit_is_set(rook_attacks_bb(to, b), ci.ksq);
+          return bit_is_set(rook_attacks_bb(to, b), ksq);
       case QUEEN:
-          return bit_is_set(queen_attacks_bb(to, b), ci.ksq);
+          return bit_is_set(queen_attacks_bb(to, b), ksq);
       default:
           assert(false);
       }
@@ -820,8 +802,8 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
       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));
+      return  (rook_attacks_bb(ksq, b) & pieces(ROOK, QUEEN, us))
+            ||(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, us));
   }
 
   // Castling with check ?
@@ -843,7 +825,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
       clear_bit(&b, rfrom);
       set_bit(&b, rto);
       set_bit(&b, kto);
-      return bit_is_set(rook_attacks_bb(rto, b), ci.ksq);
+      return bit_is_set(rook_attacks_bb(rto, b), ksq);
   }
 
   return false;
@@ -956,13 +938,12 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
       st->epSquare = SQ_NONE;
   }
 
-  // Update castle rights, try to shortcut a common case
-  int cm = castleRightsMask[from] & castleRightsMask[to];
-  if (cm != ALL_CASTLES && ((cm & st->castleRights) != st->castleRights))
+  // Update castle rights if needed
+  if (    st->castleRights != CASTLES_NONE
+      && (castleRightsMask[from] & castleRightsMask[to]) != ALL_CASTLES)
   {
       key ^= zobCastle[st->castleRights];
-      st->castleRights &= castleRightsMask[from];
-      st->castleRights &= castleRightsMask[to];
+      st->castleRights &= castleRightsMask[from] & castleRightsMask[to];
       key ^= zobCastle[st->castleRights];
   }
 
@@ -1005,7 +986,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
 
       if (pm) // promotion ?
       {
-          PieceType promotion = move_promotion_piece(m);
+          PieceType promotion = promotion_piece_type(m);
 
           assert(promotion >= KNIGHT && promotion <= QUEEN);
 
@@ -1074,10 +1055,10 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
           if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from))
           {
               if (pt != ROOK)
-                  st->checkersBB |= (attacks_from<ROOK>(ci.ksq) & pieces(ROOK, QUEEN, us));
+                  st->checkersBB |= (attacks_from<ROOK>(king_square(them)) & pieces(ROOK, QUEEN, us));
 
               if (pt != BISHOP)
-                  st->checkersBB |= (attacks_from<BISHOP>(ci.ksq) & pieces(BISHOP, QUEEN, us));
+                  st->checkersBB |= (attacks_from<BISHOP>(king_square(them)) & pieces(BISHOP, QUEEN, us));
           }
       }
   }
@@ -1285,7 +1266,7 @@ void Position::undo_move(Move m) {
 
   if (pm) // promotion ?
   {
-      PieceType promotion = move_promotion_piece(m);
+      PieceType promotion = promotion_piece_type(m);
       pt = PAWN;
 
       assert(promotion >= KNIGHT && promotion <= QUEEN);
@@ -1497,7 +1478,7 @@ int Position::see_sign(Move m) const {
   // Early return if SEE cannot be negative because captured piece value
   // is not less then capturing one. Note that king moves always return
   // here because king midgame value is set to 0.
-  if (midgame_value_of_piece_on(to) >= midgame_value_of_piece_on(from))
+  if (piece_value_midgame(piece_on(to)) >= piece_value_midgame(piece_on(from)))
       return 1;
 
   return see(m);
@@ -1540,18 +1521,13 @@ int Position::see(Move m) const {
   // Find all attackers to the destination square, with the moving piece
   // removed, but possibly an X-ray attacker added behind it.
   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));
+  attackers = attackers_to(to, occupied);
 
   // If the opponent has no attackers we are finished
   stm = opposite_color(color_of_piece_on(from));
   stmAttackers = attackers & pieces_of_color(stm);
   if (!stmAttackers)
-      return seeValues[capturedType];
+      return PieceValueMidgame[capturedType];
 
   // The destination square is defended, which makes things rather more
   // difficult to compute. We proceed by building up a "swap list" containing
@@ -1559,7 +1535,7 @@ int Position::see(Move m) const {
   // destination square, where the sides alternately capture, and always
   // capture with the least valuable piece. After each capture, we look for
   // new X-ray attacks from behind the capturing piece.
-  swapList[0] = seeValues[capturedType];
+  swapList[0] = PieceValueMidgame[capturedType];
   capturedType = type_of_piece_on(from);
 
   do {
@@ -1580,7 +1556,7 @@ int Position::see(Move m) const {
 
       // Add the new entry to the swap list
       assert(slIndex < 32);
-      swapList[slIndex] = -swapList[slIndex - 1] + seeValues[capturedType];
+      swapList[slIndex] = -swapList[slIndex - 1] + PieceValueMidgame[capturedType];
       slIndex++;
 
       // Remember the value of the capturing piece, and change the side to
@@ -1765,7 +1741,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.
-
+template<bool SkipRepetition>
 bool Position::is_draw() const {
 
   // Draw by material?
@@ -1778,13 +1754,18 @@ bool Position::is_draw() const {
       return true;
 
   // Draw by repetition?
-  for (int i = 4, e = Min(Min(st->gamePly, st->rule50), st->pliesFromNull); i <= e; i += 2)
-      if (history[st->gamePly - i] == st->key)
-          return true;
+  if (!SkipRepetition)
+      for (int i = 4, e = Min(Min(st->gamePly, st->rule50), st->pliesFromNull); i <= e; i += 2)
+          if (history[st->gamePly - i] == st->key)
+              return true;
 
   return false;
 }
 
+// Explicit template instantiations
+template bool Position::is_draw<false>() const;
+template bool Position::is_draw<true>() const;
+
 
 /// Position::is_mate() returns true or false depending on whether the
 /// side to move is checkmated.
@@ -1796,35 +1777,30 @@ bool Position::is_mate() const {
 }
 
 
-/// Position::init_zobrist() is a static member function which initializes at
-/// startup the various arrays used to compute hash keys.
+/// Position::init() is a static member function which 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 the MgPST[][] and EgPST[][] arrays.
+/// Second, the black halves of the tables are initialized by mirroring
+/// and changing the sign of the corresponding white scores.
 
-void Position::init_zobrist() {
+void Position::init() {
 
-  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] = rk.rand<Key>();
+  for (Color c = WHITE; c <= BLACK; c++)
+      for (PieceType pt = PAWN; pt <= KING; pt++)
+          for (Square s = SQ_A1; s <= SQ_H8; s++)
+              zobrist[c][pt][s] = rk.rand<Key>();
 
-  for (i = 0; i < 64; i++)
-      zobEp[i] = rk.rand<Key>();
+  for (Square s = SQ_A1; s <= SQ_H8; s++)
+      zobEp[s] = rk.rand<Key>();
 
-  for (i = 0; i < 16; i++)
+  for (int i = 0; i < 16; i++)
       zobCastle[i] = rk.rand<Key>();
 
   zobSideToMove = rk.rand<Key>();
   zobExclusion  = rk.rand<Key>();
-}
-
-
-/// Position::init_piece_square_tables() initializes the piece square tables.
-/// This is a two-step operation: First, the white halves of the tables are
-/// copied from the MgPST[][] and EgPST[][] arrays. Second, the black halves
-/// of the tables are initialized by mirroring and changing the sign of the
-/// corresponding white scores.
-
-void Position::init_piece_square_tables() {
 
   for (Square s = SQ_A1; s <= SQ_H8; s++)
       for (Piece p = WP; p <= WK; p++)
@@ -1858,10 +1834,10 @@ void Position::flip() {
   sideToMove = opposite_color(pos.side_to_move());
 
   // Castling rights
-  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);
+  if (pos.can_castle_kingside(WHITE))  set_castle_kingside(BLACK);
+  if (pos.can_castle_queenside(WHITE)) set_castle_queenside(BLACK);
+  if (pos.can_castle_kingside(BLACK))  set_castle_kingside(WHITE);
+  if (pos.can_castle_queenside(BLACK)) set_castle_queenside(WHITE);
 
   initialKFile  = pos.initialKFile;
   initialKRFile = pos.initialKRFile;
@@ -1921,7 +1897,7 @@ bool Position::is_ok(int* failedStep) const {
   if (failedStep) *failedStep = 1;
 
   // Side to move OK?
-  if (!color_is_ok(side_to_move()))
+  if (side_to_move() != WHITE && side_to_move() != BLACK)
       return false;
 
   // Are the king squares in the position correct?
@@ -1935,10 +1911,10 @@ bool Position::is_ok(int* failedStep) const {
 
   // Castle files OK?
   if (failedStep) (*failedStep)++;
-  if (!file_is_ok(initialKRFile))
+  if (!square_is_ok(make_square(initialKRFile, RANK_1)))
       return false;
 
-  if (!file_is_ok(initialQRFile))
+  if (!square_is_ok(make_square(initialQRFile, RANK_1)))
       return false;
 
   // Do both sides have exactly one king?