Assume input FEN string is correct in from_fen()
authorMarco Costalba <mcostalba@gmail.com>
Mon, 27 Jun 2011 09:07:57 +0000 (10:07 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Mon, 27 Jun 2011 11:08:12 +0000 (12:08 +0100)
And also tolerate a 0 value for full move number.

Revert BUG_41 patch, now we set initial King file only
if a castling is possible, so we don't need the fix
anymore in case of correct FEN.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/position.cpp
src/position.h
src/search.cpp
src/timeman.cpp
src/timeman.h

index 42fdd62..0dbbbdd 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
 }
 
 
@@ -159,64 +159,56 @@ void Position::from_fen(const string& fen, bool isChess960) {
 */
 
   char token;
-  int hmc, fmn;
   size_t p;
+  string ep;
   Square sq = SQ_A8;
   std::istringstream ss(fen);
 
   clear();
-  ss >> std::noskipws;
+  ss >> std::skipws >> 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 >> std::skipws >> token;
   sideToMove = (token == 'w' ? WHITE : BLACK);
 
-  if (!(ss >> token) || !isspace(token))
-      goto incorrect_fen;
-
   // 3. Castling availability
-  while ((ss >> token) && !isspace(token))
-      if (!set_castling_rights(token))
-          goto incorrect_fen;
-
-  // 4. En passant square
-  char col, row;
-  if (   ((ss >> col) && (col >= 'a' && col <= 'h'))
-      && ((ss >> row) && (row == '3' || row == '6')))
+  ss >> token >> std::noskipws;
+  while (token != '-' && !isspace(token))
+  {
+      set_castling_rights(token);
+      ss >> token;
+  }
+
+  // 4. En passant square. Ignore if no pawn capture is possible
+  ss >> std::skipws >> ep;
+  if (ep.size() == 2)
   {
-      st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1);
+      st->epSquare = make_square(File(ep[0] - 'a'), Rank(ep[1] - '1'));
 
-      // Ignore if no capture is possible
-      Color them = opposite_color(sideToMove);
-      if (!(attacks_from<PAWN>(st->epSquare, them) & pieces(PAWN, sideToMove)))
+      if (!(attackers_to(st->epSquare) & 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 >> st->rule50 >> fullMoves;
 
   // Various initialisations
   castleRightsMask[make_square(initialKFile,  RANK_1)] ^= WHITE_OO | WHITE_OOO;
@@ -235,10 +227,6 @@ 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;
-
-incorrect_fen:
-  cout << "Error in FEN string: " << fen << endl;
 }
 
 
@@ -249,39 +237,39 @@ 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 = islower(token) ? BLACK : WHITE;
 
-    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);
+    Square sqA = relative_square(c, SQ_A1);
+    Square sqH = relative_square(c, SQ_H1);
 
     initialKFile = square_file(king_square(c));
-    token = char(toupper(token));
 
-    if (token == 'K')
+    if (toupper(token) == 'K')
     {
         for (Square sq = sqH; sq >= sqA; sq--)
-            if (piece_on(sq) == rook)
+            if (piece_on(sq) == make_piece(c, ROOK))
             {
                 set_castle_kingside(c);
                 initialKRFile = square_file(sq);
                 break;
             }
     }
-    else if (token == 'Q')
+    else if (toupper(token) == 'Q')
     {
         for (Square sq = sqA; sq <= sqH; sq++)
-            if (piece_on(sq) == rook)
+            if (piece_on(sq) == make_piece(c, ROOK))
             {
                 set_castle_queenside(c);
                 initialQRFile = square_file(sq);
                 break;
             }
     }
-    else if (token >= 'A' && token <= 'H')
+    else if (toupper(token) >= 'A' && toupper(token) <= 'H')
     {
-        File rookFile = File(token - 'A') + FILE_A;
+        File rookFile = File(toupper(token) - 'A');
+
         if (rookFile < initialKFile)
         {
             set_castle_queenside(c);
@@ -293,10 +281,6 @@ bool Position::set_castling_rights(char token) {
             initialKRFile = rookFile;
         }
     }
-    else
-        return token == '-';
-
-  return true;
 }
 
 
@@ -593,8 +577,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 +597,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 +823,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 +834,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 +1576,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);
@@ -2039,19 +2024,14 @@ bool Position::is_ok(int* failedStep) const {
           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))
-              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;
index bff5a8d..d822260 100644 (file)
@@ -226,7 +226,7 @@ public:
   template<bool SkipRepetition> bool is_draw() const;
 
   // Number of plies from starting position
-  int startpos_ply_counter() const;
+  int full_moves() const;
 
   // Other properties of the position
   bool opposite_colored_bishops() const;
@@ -253,7 +253,7 @@ private:
   void put_piece(Piece p, Square s);
   void set_castle_kingside(Color c);
   void set_castle_queenside(Color c);
-  bool set_castling_rights(char token);
+  void set_castling_rights(char token);
   bool move_is_pl_slow(const Move m) const;
 
   // Helper functions for doing and undoing moves
@@ -295,7 +295,7 @@ private:
   StateInfo startState;
   File initialKFile, initialKRFile, initialQRFile;
   bool chess960;
-  int startPosPlyCounter;
+  int fullMoves;
   int threadID;
   int64_t nodes;
   StateInfo* st;
@@ -489,8 +489,8 @@ inline bool Position::move_is_passed_pawn_push(Move m) const {
         && pawn_is_passed(c, move_to(m));
 }
 
-inline int Position::startpos_ply_counter() const {
-  return startPosPlyCounter;
+inline int Position::full_moves() const {
+  return fullMoves;
 }
 
 inline bool Position::opposite_colored_bishops() const {
index d99d5e1..daf40de 100644 (file)
@@ -403,7 +403,7 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
   NodesSincePoll = 0;
   current_search_time(get_system_time());
   Limits = limits;
-  TimeMgr.init(Limits, pos.startpos_ply_counter());
+  TimeMgr.init(Limits, pos.full_moves());
 
   // Set output steram in normal or chess960 mode
   cout << set960(pos.is_chess960());
index f07f27e..70d3592 100644 (file)
@@ -72,7 +72,7 @@ namespace {
   enum TimeType { OptimumTime, MaxTime };
 
   template<TimeType>
-  int remaining(int myTime, int movesToGo, int currentPly);
+  int remaining(int myTime, int movesToGo, int fullMoveNumber);
 }
 
 
@@ -83,7 +83,7 @@ void TimeManager::pv_instability(int curChanges, int prevChanges) {
 }
 
 
-void TimeManager::init(const SearchLimits& limits, int currentPly)
+void TimeManager::init(const SearchLimits& limits, int fullMoveNumber)
 {
   /* We support four different kind of time controls:
 
@@ -124,8 +124,8 @@ void TimeManager::init(const SearchLimits& limits, int currentPly)
 
       hypMyTime = Max(hypMyTime, 0);
 
-      t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly);
-      t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly);
+      t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, fullMoveNumber);
+      t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, fullMoveNumber);
 
       optimumSearchTime = Min(optimumSearchTime, t1);
       maximumSearchTime = Min(maximumSearchTime, t2);
@@ -142,11 +142,12 @@ void TimeManager::init(const SearchLimits& limits, int currentPly)
 namespace {
 
   template<TimeType T>
-  int remaining(int myTime, int movesToGo, int currentPly)
+  int remaining(int myTime, int movesToGo, int fullMoveNumber)
   {
     const float TMaxRatio   = (T == OptimumTime ? 1 : MaxRatio);
     const float TStealRatio = (T == OptimumTime ? 0 : StealRatio);
 
+    int currentPly = 2 * fullMoveNumber;
     int thisMoveImportance = move_importance(currentPly);
     int otherMovesImportance = 0;
 
index bf489b7..29a92e6 100644 (file)
@@ -25,7 +25,7 @@ struct SearchLimits;
 class TimeManager {
 public:
 
-  void init(const SearchLimits& limits, int currentPly);
+  void init(const SearchLimits& limits, int fullMoveNumber);
   void pv_instability(int curChanges, int prevChanges);
   int available_time() const { return optimumSearchTime + unstablePVExtraTime; }
   int maximum_time() const { return maximumSearchTime; }