]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Micro-optimize castling handling in do_move()
[stockfish] / src / position.cpp
index 4c925f5bba16fc51b8f2417668d0159e47ee450e..8f70b5dfd3ab3af4c644072396622c75257ce381 100644 (file)
@@ -20,7 +20,6 @@
 #include <cassert>
 #include <cstring>
 #include <fstream>
-#include <map>
 #include <iostream>
 #include <sstream>
 
@@ -77,33 +76,8 @@ 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  ");
 }
 
 
@@ -192,17 +166,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,23 +190,23 @@ 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));
 
@@ -241,7 +217,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 +270,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 +280,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 +290,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 +313,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 +330,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 +388,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;
@@ -624,16 +599,19 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 }
 
 
-/// 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.
+/// 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.
 
-bool Position::move_is_pl_full(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;
 
-   for (cur = mlist; cur != last; cur++)
+  last = in_check() ? generate<MV_EVASION>(*this, mlist)
+                    : generate<MV_NON_EVASION>(*this, mlist);
+
+  for (cur = mlist; cur != last; cur++)
       if (cur->move == m)
           return true;
 
@@ -641,8 +619,8 @@ bool Position::move_is_pl_full(const Move m) const {
 }
 
 
-/// 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_pl(const Move m) const {
 
@@ -656,10 +634,10 @@ bool Position::move_is_pl(const Move m) const {
 
   // Use a slower but simpler function for uncommon cases
   if (move_is_special(m))
-      return move_is_pl_full(m);
+      return move_is_pl_slow(m);
 
   // Is not a promotion, so promotion piece must be empty
-  if (move_promotion_piece(m) - 2 != PIECE_TYPE_NONE)
+  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
@@ -810,7 +788,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
   {
       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);
@@ -971,13 +949,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];
   }
 
@@ -1020,7 +997,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);
 
@@ -1300,7 +1277,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);
@@ -1775,7 +1752,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?
@@ -1788,13 +1765,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.
@@ -1868,10 +1850,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;