]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Fix Shredder-FEN regression in from_fen()
[stockfish] / src / position.cpp
index 42fdd62da8bfc3c121c61916164449682a2ed630..bc94fe82acb02b064c4d7b1203efed8d4d36ace8 100644 (file)
@@ -48,8 +48,8 @@ Score Position::PieceSquareTable[16][64];
 const Value PieceValueMidgame[17] = {
   VALUE_ZERO,
   PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
-  RookValueMidgame, QueenValueMidgame, VALUE_ZERO,
-  VALUE_ZERO, VALUE_ZERO,
+  RookValueMidgame, QueenValueMidgame,
+  VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
   PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
   RookValueMidgame, QueenValueMidgame
 };
@@ -57,8 +57,8 @@ const Value PieceValueMidgame[17] = {
 const Value PieceValueEndgame[17] = {
   VALUE_ZERO,
   PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
-  RookValueEndgame, QueenValueEndgame, VALUE_ZERO,
-  VALUE_ZERO, VALUE_ZERO,
+  RookValueEndgame, QueenValueEndgame,
+  VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
   PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
   RookValueEndgame, QueenValueEndgame
 };
@@ -121,7 +121,7 @@ void Position::detach() {
 
   startState = *st;
   st = &startState;
-  st->previous = NULL; // as a safe guard
+  st->previous = NULL; // As a safe guard
 }
 
 
@@ -158,74 +158,56 @@ void Position::from_fen(const string& fen, bool isChess960) {
    6) Fullmove number: The number of the full move. It starts at 1, and is incremented after Black's move.
 */
 
-  char token;
-  int hmc, fmn;
+  char col, row, token;
   size_t p;
   Square sq = SQ_A8;
   std::istringstream ss(fen);
 
   clear();
-  ss >> std::noskipws;
+  ss >> token >> std::noskipws;
 
-  // 1. Piece placement field
-  while ((ss >> token) && !isspace(token))
+  // 1. Piece placement
+  while (!isspace(token))
   {
-      if ((p = PieceToChar.find(token)) != string::npos)
+      if (token == '/')
+          sq -= Square(16); // Jump back of 2 rows
+
+      else if (isdigit(token))
+          sq += Square(token - '0'); // Skip the given number of files
+
+      else if ((p = PieceToChar.find(token)) != string::npos)
       {
           put_piece(Piece(p), sq);
           sq++;
       }
-      else if (isdigit(token))
-          sq += Square(token - '0'); // Skip the given number of files
-      else if (token == '/')
-          sq -= SQ_A3; // Jump back of 2 rows
-      else
-          goto incorrect_fen;
+
+      ss >> token;
   }
 
   // 2. Active color
-  if (!(ss >> token) || (token != 'w' && token != 'b'))
-      goto incorrect_fen;
-
+  ss >> token;
   sideToMove = (token == 'w' ? WHITE : BLACK);
-
-  if (!(ss >> token) || !isspace(token))
-      goto incorrect_fen;
+  ss >> token;
 
   // 3. Castling availability
   while ((ss >> token) && !isspace(token))
-      if (!set_castling_rights(token))
-          goto incorrect_fen;
+      set_castling_rights(token);
 
-  // 4. En passant square
-  char col, row;
+  // 4. En passant square. Ignore if no pawn capture is possible
   if (   ((ss >> col) && (col >= 'a' && col <= 'h'))
       && ((ss >> row) && (row == '3' || row == '6')))
   {
-      st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1);
-
-      // Ignore if no capture is possible
+      st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
       Color them = opposite_color(sideToMove);
+
       if (!(attacks_from<PAWN>(st->epSquare, them) & pieces(PAWN, sideToMove)))
           st->epSquare = SQ_NONE;
   }
 
-  // 5. Halfmove clock
-  if (ss >> std::skipws >> hmc)
-      st->rule50 = hmc;
-
-  // 6. Fullmove number
-  if (ss >> fmn)
-      startPosPlyCounter = (fmn - 1) * 2 + int(sideToMove == BLACK);
+  // 5-6. Halfmove clock and fullmove number
+  ss >> std::skipws >> st->rule50 >> fullMoves;
 
   // Various initialisations
-  castleRightsMask[make_square(initialKFile,  RANK_1)] ^= WHITE_OO | WHITE_OOO;
-  castleRightsMask[make_square(initialKFile,  RANK_8)] ^= BLACK_OO | BLACK_OOO;
-  castleRightsMask[make_square(initialKRFile, RANK_1)] ^= WHITE_OO;
-  castleRightsMask[make_square(initialKRFile, RANK_8)] ^= BLACK_OO;
-  castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO;
-  castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO;
-
   chess960 = isChess960;
   find_checkers();
 
@@ -235,10 +217,18 @@ void Position::from_fen(const string& fen, bool isChess960) {
   st->value = compute_value();
   st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
   st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
-  return;
+}
+
+
+/// Position::set_castle() is an helper function used to set
+/// correct castling related flags.
+
+void Position::set_castle(int f, Square ksq, Square rsq) {
 
-incorrect_fen:
-  cout << "Error in FEN string: " << fen << endl;
+  st->castleRights |= f;
+  castleRightsMask[ksq] ^= f;
+  castleRightsMask[rsq] ^= f;
+  castleRookSquare[f] = rsq;
 }
 
 
@@ -249,54 +239,31 @@ incorrect_fen:
 /// associated with the castling right, the traditional castling tag will be replaced
 /// by the file letter of the involved rook as for the Shredder-FEN.
 
-bool Position::set_castling_rights(char token) {
+void Position::set_castling_rights(char token) {
 
-    Color c = token >= 'a' ? BLACK : WHITE;
-    Square sqA = (c == WHITE ? SQ_A1 : SQ_A8);
-    Square sqH = (c == WHITE ? SQ_H1 : SQ_H8);
-    Piece rook = (c == WHITE ? WR : BR);
+    Color c = islower(token) ? BLACK : WHITE;
 
-    initialKFile = square_file(king_square(c));
-    token = char(toupper(token));
+    Square sqA = relative_square(c, SQ_A1);
+    Square sqH = relative_square(c, SQ_H1);
+
+    Square rsq, ksq = king_square(c);
+    token = toupper(token);
 
     if (token == 'K')
-    {
-        for (Square sq = sqH; sq >= sqA; sq--)
-            if (piece_on(sq) == rook)
-            {
-                set_castle_kingside(c);
-                initialKRFile = square_file(sq);
-                break;
-            }
-    }
+        for (rsq = sqH; piece_on(rsq) != make_piece(c, ROOK); rsq--) {}
+
     else if (token == 'Q')
-    {
-        for (Square sq = sqA; sq <= sqH; sq++)
-            if (piece_on(sq) == rook)
-            {
-                set_castle_queenside(c);
-                initialQRFile = square_file(sq);
-                break;
-            }
-    }
+        for (rsq = sqA; piece_on(rsq) != make_piece(c, ROOK); rsq++) {}
+
     else if (token >= 'A' && token <= 'H')
-    {
-        File rookFile = File(token - 'A') + FILE_A;
-        if (rookFile < initialKFile)
-        {
-            set_castle_queenside(c);
-            initialQRFile = rookFile;
-        }
-        else
-        {
-            set_castle_kingside(c);
-            initialKRFile = rookFile;
-        }
-    }
-    else
-        return token == '-';
+        rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
 
-  return true;
+    else return;
+
+    if (square_file(rsq) < square_file(ksq))
+        set_castle(WHITE_OOO << c, ksq, rsq);
+    else
+        set_castle(WHITE_OO << c, ksq, rsq);
 }
 
 
@@ -337,17 +304,17 @@ const string Position::to_fen() const {
 
   if (st->castleRights != CASTLES_NONE)
   {
-      if (can_castle_kingside(WHITE))
-          fen += chess960 ? char(toupper(file_to_char(initialKRFile))) : 'K';
+      if (can_castle(WHITE_OO))
+          fen += chess960 ? char(toupper(file_to_char(square_file(castle_rook_square(WHITE_OO))))) : 'K';
 
-      if (can_castle_queenside(WHITE))
-          fen += chess960 ? char(toupper(file_to_char(initialQRFile))) : 'Q';
+      if (can_castle(WHITE_OOO))
+          fen += chess960 ? char(toupper(file_to_char(square_file(castle_rook_square(WHITE_OOO))))) : 'Q';
 
-      if (can_castle_kingside(BLACK))
-          fen += chess960 ? file_to_char(initialKRFile) : 'k';
+      if (can_castle(BLACK_OO))
+          fen += chess960 ? file_to_char(square_file(castle_rook_square(BLACK_OO))) : 'k';
 
-      if (can_castle_queenside(BLACK))
-          fen += chess960 ? file_to_char(initialQRFile) : 'q';
+      if (can_castle(BLACK_OOO))
+          fen += chess960 ? file_to_char(square_file(castle_rook_square(BLACK_OOO))) : 'q';
   } else
       fen += '-';
 
@@ -593,8 +560,8 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 }
 
 
-/// 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
+/// Position::move_is_pl_slow() takes 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_slow(const Move m) const {
@@ -613,8 +580,8 @@ bool Position::move_is_pl_slow(const Move m) const {
 }
 
 
-/// 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.
+/// Fast version of Position::move_is_pl() that takes 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 {
 
@@ -839,6 +806,10 @@ void Position::do_setup_move(Move m) {
 
   StateInfo newSt;
 
+  // Update the number of full moves after black's move
+  if (sideToMove == BLACK)
+      fullMoves++;
+
   do_move(m, newSt);
 
   // Reset "game ply" in case we made a non-reversible move.
@@ -846,9 +817,6 @@ void Position::do_setup_move(Move m) {
   if (st->rule50 == 0)
       st->gamePly = 0;
 
-  // Update the number of plies played from the starting position
-  startPosPlyCounter++;
-
   // Our StateInfo newSt is about going out of scope so copy
   // its content before it disappears.
   detach();
@@ -1591,7 +1559,7 @@ void Position::clear() {
   st = &startState;
   memset(st, 0, sizeof(StateInfo));
   st->epSquare = SQ_NONE;
-  startPosPlyCounter = 0;
+  fullMoves = 1;
   nodes = 0;
 
   memset(byColorBB,  0, sizeof(Bitboard) * 2);
@@ -1610,9 +1578,6 @@ void Position::clear() {
       castleRightsMask[sq] = ALL_CASTLES;
 
   sideToMove = WHITE;
-  initialKFile = FILE_E;
-  initialKRFile = FILE_H;
-  initialQRFile = FILE_A;
 }
 
 
@@ -1686,16 +1651,13 @@ Key Position::compute_pawn_key() const {
 
 Key Position::compute_material_key() const {
 
-  int count;
   Key result = 0;
 
   for (Color c = WHITE; c <= BLACK; c++)
       for (PieceType pt = PAWN; pt <= QUEEN; pt++)
-      {
-          count = piece_count(c, pt);
-          for (int i = 0; i < count; i++)
+          for (int i = 0, cnt = piece_count(c, pt); i < cnt; i++)
               result ^= zobrist[c][pt][i];
-      }
+
   return result;
 }
 
@@ -1834,21 +1796,14 @@ void Position::flip() {
   sideToMove = opposite_color(pos.side_to_move());
 
   // Castling rights
-  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;
-  initialQRFile = pos.initialQRFile;
-
-  castleRightsMask[make_square(initialKFile,  RANK_1)] ^= (WHITE_OO | WHITE_OOO);
-  castleRightsMask[make_square(initialKFile,  RANK_8)] ^= (BLACK_OO | BLACK_OOO);
-  castleRightsMask[make_square(initialKRFile, RANK_1)] ^=  WHITE_OO;
-  castleRightsMask[make_square(initialKRFile, RANK_8)] ^=  BLACK_OO;
-  castleRightsMask[make_square(initialQRFile, RANK_1)] ^=  WHITE_OOO;
-  castleRightsMask[make_square(initialQRFile, RANK_8)] ^=  BLACK_OOO;
+  if (pos.can_castle(WHITE_OO))
+      set_castle(BLACK_OO,  king_square(BLACK), flip_square(pos.castle_rook_square(WHITE_OO)));
+  if (pos.can_castle(WHITE_OOO))
+      set_castle(BLACK_OOO, king_square(BLACK), flip_square(pos.castle_rook_square(WHITE_OOO)));
+  if (pos.can_castle(BLACK_OO))
+      set_castle(WHITE_OO,  king_square(WHITE), flip_square(pos.castle_rook_square(BLACK_OO)));
+  if (pos.can_castle(BLACK_OOO))
+      set_castle(WHITE_OOO, king_square(WHITE), flip_square(pos.castle_rook_square(BLACK_OOO)));
 
   // En passant square
   if (pos.st->epSquare != SQ_NONE)
@@ -1909,14 +1864,6 @@ bool Position::is_ok(int* failedStep) const {
   if (piece_on(king_square(BLACK)) != BK)
       return false;
 
-  // Castle files OK?
-  if (failedStep) (*failedStep)++;
-  if (!square_is_ok(make_square(initialKRFile, RANK_1)))
-      return false;
-
-  if (!square_is_ok(make_square(initialQRFile, RANK_1)))
-      return false;
-
   // Do both sides have exactly one king?
   if (failedStep) (*failedStep)++;
   if (debugKingCount)
@@ -2030,29 +1977,17 @@ bool Position::is_ok(int* failedStep) const {
 
   if (failedStep) (*failedStep)++;
   if (debugCastleSquares)
-  {
-      for (Color c = WHITE; c <= BLACK; c++)
+      for (CastleRight f = WHITE_OO; f <= BLACK_OOO; f = CastleRight(f << 1))
       {
-          if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != make_piece(c, ROOK))
-              return false;
+          if (!can_castle(f))
+              continue;
 
-          if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != make_piece(c, ROOK))
-              return false;
-      }
-      // If we cannot castle castleRightsMask[] could be not valid, for instance when
-      // king initial file is FILE_A as queen rook.
-      if (can_castle(WHITE) || can_castle(BLACK))
-      {
-          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))
+          Piece rook = (f & (WHITE_OO | WHITE_OOO) ? WR : BR);
+
+          if (   castleRightsMask[castleRookSquare[f]] != (ALL_CASTLES ^ f)
+              || piece_on(castleRookSquare[f]) != rook)
               return false;
       }
-  }
 
   if (failedStep) *failedStep = 0;
   return true;