]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Big trailing whitespace cleanup part 1
[stockfish] / src / position.cpp
index 67ee145c11efecb3500a26843db96ff1acf9c354..5e1ebfeb486880de58081900499f67cd2b4f55b3 100644 (file)
@@ -31,6 +31,7 @@
 #include "movepick.h"
 #include "position.h"
 #include "psqtab.h"
+#include "san.h"
 #include "ucioption.h"
 
 
@@ -38,6 +39,8 @@
 //// Variables
 ////
 
+extern SearchStack EmptySearchStack;
+
 int Position::castleRightsMask[64];
 
 Key Position::zobrist[2][8][64];
@@ -49,6 +52,7 @@ Key Position::zobSideToMove;
 Value Position::MgPieceSquareTable[16][64];
 Value Position::EgPieceSquareTable[16][64];
 
+static bool RequestPending = false;
 
 ////
 //// Functions
@@ -242,7 +246,7 @@ const std::string Position::to_fen() const {
 
       fen += (rank > RANK_1 ? '/' : ' ');
   }
-  fen += (sideToMove == WHITE ? 'w' : 'b') + ' ';
+  fen += (sideToMove == WHITE ? "w " : "b ");
   if (castleRights != NO_CASTLES)
   {
     if (can_castle_kingside(WHITE))  fen += 'K';
@@ -263,29 +267,45 @@ const std::string Position::to_fen() const {
 
 
 /// Position::print() prints an ASCII representation of the position to
-/// the standard output.
-
-void Position::print() const {
-  char pieceStrings[][8] =
-    {"| ? ", "| P ", "| N ", "| B ", "| R ", "| Q ", "| K ", "| ? ",
-     "| ? ", "|=P=", "|=N=", "|=B=", "|=R=", "|=Q=", "|=K="
-    };
-
-  for(Rank rank = RANK_8; rank >= RANK_1; rank--) {
-    std::cout << "+---+---+---+---+---+---+---+---+\n";
-    for(File file = FILE_A; file <= FILE_H; file++) {
-      Square sq = make_square(file, rank);
-      Piece piece = piece_on(sq);
-      if(piece == EMPTY)
-        std::cout << ((square_color(sq) == WHITE)? "|   " : "| . ");
-      else
-        std::cout << pieceStrings[piece];
-    }
-    std::cout << "|\n";
+/// the standard output. If a move is given then also the san is print.
+
+void Position::print(Move m) const {
+
+  static const std::string pieceLetters = " PNBRQK  PNBRQK .";
+
+  // Check for reentrancy, as example when called from inside
+  // MovePicker that is used also here in move_to_san()
+  if (RequestPending)
+      return;
+
+  RequestPending = true;
+
+  std::cout << std::endl;
+  if (m != MOVE_NONE)
+  {
+      std::string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : "");
+      std::cout << "Move is: " << col << move_to_san(*this, m) << std::endl;
+  }
+  for (Rank rank = RANK_8; rank >= RANK_1; rank--)
+  {
+      std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
+      for (File file = FILE_A; file <= FILE_H; file++)
+      {
+          Square sq = make_square(file, rank);
+          Piece piece = piece_on(sq);
+          if (piece == EMPTY && square_color(sq) == WHITE)
+              piece = NO_PIECE;
+
+          char col = (color_of_piece_on(sq) == BLACK ? '=' : ' ');
+          std::cout << '|' << col << pieceLetters[piece] << col;
+      }
+      std::cout << '|' << std::endl;
   }
-  std::cout << "+---+---+---+---+---+---+---+---+\n";
-  std::cout << to_fen() << std::endl;
-  std::cout << key << std::endl;
+  std::cout << "+---+---+---+---+---+---+---+---+" << std::endl
+            << "Fen is: " << to_fen() << std::endl
+            << "Key is: " << key << std::endl;
+
+  RequestPending = false;
 }
 
 
@@ -410,6 +430,7 @@ bool Position::piece_attacks_square(Square f, Square t) const {
   case WR: case BR: return piece_attacks_square<ROOK>(f, t);
   case WQ: case BQ: return piece_attacks_square<QUEEN>(f, t);
   case WK: case BK: return piece_attacks_square<KING>(f, t);
+  default: break;
   }
   return false;
 }
@@ -437,7 +458,7 @@ bool Position::move_attacks_square(Move m, Square s) const {
   case WR: case BR: return piece_attacks_square<ROOK>(t, s);
   case WQ: case BQ: return piece_attacks_square<QUEEN>(t, s);
   case WK: case BK: return piece_attacks_square<KING>(t, s);
-  default: assert(false);
+  default: break;
   }
   return false;
 }
@@ -446,12 +467,13 @@ bool Position::move_attacks_square(Move m, Square s) const {
 /// Position::find_checkers() computes the checkersBB bitboard, which
 /// contains a nonzero bit for each checking piece (0, 1 or 2).  It
 /// currently works by calling Position::attacks_to, which is probably
-/// inefficient.  Consider rewriting this function to use the last move
+/// inefficient. Consider rewriting this function to use the last move
 /// played, like in non-bitboard versions of Glaurung.
 
 void Position::find_checkers() {
 
-  checkersBB = attacks_to(king_square(side_to_move()),opposite_color(side_to_move()));
+  Color us = side_to_move();
+  checkersBB = attacks_to(king_square(us), opposite_color(us));
 }
 
 
@@ -468,9 +490,6 @@ bool Position::pl_move_is_legal(Move m)  const {
 
 bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 
-  Color us, them;
-  Square ksq, from;
-
   assert(is_ok());
   assert(move_is_ok(m));
   assert(pinned == pinned_pieces(side_to_move()));
@@ -484,10 +503,10 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
   if (move_is_castle(m))
       return true;
 
-  us = side_to_move();
-  them = opposite_color(us);
-  from = move_from(m);
-  ksq = king_square(us);
+  Color us = side_to_move();
+  Color them = opposite_color(us);
+  Square from = move_from(m);
+  Square ksq = king_square(us);
 
   assert(color_of_piece_on(from) == us);
   assert(piece_on(ksq) == king_of_color(us));
@@ -521,11 +540,8 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 
   // A non-king move is legal if and only if it is not pinned or it
   // is moving along the ray towards or away from the king.
-  if (   !bit_is_set(pinned, from)
-      || (direction_between_squares(from, ksq) == direction_between_squares(move_to(m), ksq)))
-      return true;
-
-  return false;
+  return (   !bit_is_set(pinned, from)
+          || (direction_between_squares(from, ksq) == direction_between_squares(move_to(m), ksq)));
 }
 
 
@@ -543,18 +559,15 @@ bool Position::move_is_check(Move m) const {
 
 bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
 
-  Color us, them;
-  Square ksq, from, to;
-
   assert(is_ok());
   assert(move_is_ok(m));
   assert(dcCandidates == discovered_check_candidates(side_to_move()));
 
-  us = side_to_move();
-  them = opposite_color(us);
-  from = move_from(m);
-  to = move_to(m);
-  ksq = king_square(them);
+  Color us = side_to_move();
+  Color them = opposite_color(us);
+  Square from = move_from(m);
+  Square to = move_to(m);
+  Square ksq = king_square(them);
 
   assert(color_of_piece_on(from) == us);
   assert(piece_on(ksq) == king_of_color(them));
@@ -653,8 +666,8 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
       }
       return false;
 
-  default:
-      assert(false);
+  default: // NO_PIECE_TYPE
+      break;
   }
   assert(false);
   return false;
@@ -662,12 +675,16 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
 
 
 /// Position::move_is_capture() tests whether a move from the current
-/// position is a capture.
+/// position is a capture. Move must not be MOVE_NONE.
 
 bool Position::move_is_capture(Move m) const {
 
-  return   color_of_piece_on(move_to(m)) == opposite_color(side_to_move())
-        || move_is_ep(m);
+  assert(m != MOVE_NONE);
+
+  return (   !square_is_empty(move_to(m))
+          && (color_of_piece_on(move_to(m)) == opposite_color(side_to_move()))
+         )
+         || move_is_ep(m);
 }
 
 
@@ -681,16 +698,16 @@ bool Position::move_is_capture(Move m) const {
 void Position::backup(UndoInfo& u) const {
 
   u.castleRights = castleRights;
-  u.epSquare = epSquare;
-  u.checkersBB = checkersBB;
-  u.key = key;
-  u.pawnKey = pawnKey;
-  u.materialKey = materialKey;
-  u.rule50 = rule50;
-  u.lastMove = lastMove;
-  u.capture = NO_PIECE_TYPE;
-  u.mgValue = mgValue;
-  u.egValue = egValue;
+  u.epSquare     = epSquare;
+  u.checkersBB   = checkersBB;
+  u.key          = key;
+  u.pawnKey      = pawnKey;
+  u.materialKey  = materialKey;
+  u.rule50       = rule50;
+  u.lastMove     = lastMove;
+  u.mgValue      = mgValue;
+  u.egValue      = egValue;
+  u.capture      = NO_PIECE_TYPE;
 }
 
 
@@ -700,25 +717,24 @@ void Position::backup(UndoInfo& u) const {
 void Position::restore(const UndoInfo& u) {
 
   castleRights = u.castleRights;
-  epSquare = u.epSquare;
-  checkersBB = u.checkersBB;
-  key = u.key;
-  pawnKey = u.pawnKey;
-  materialKey = u.materialKey;
-  rule50 = u.rule50;
-  lastMove = u.lastMove;
+  epSquare     = u.epSquare;
+  checkersBB   = u.checkersBB;
+  key          = u.key;
+  pawnKey      = u.pawnKey;
+  materialKey  = u.materialKey;
+  rule50       = u.rule50;
+  lastMove     = u.lastMove;
+  mgValue     = u.mgValue;
+  egValue     = u.egValue;
   // u.capture is restored in undo_move()
-  mgValue = u.mgValue;
-  egValue = u.egValue;
 }
 
-
 /// Position::do_move() makes a move, and backs up all information necessary
-/// to undo the move to an UndoInfo object.  The move is assumed to be legal.
+/// to undo the move to an UndoInfo object. The move is assumed to be legal.
 /// Pseudo-legal moves should be filtered out before this function is called.
 /// There are two versions of this function, one which takes only the move and
 /// the UndoInfo as input, and one which takes a third parameter, a bitboard of
-/// discovered check candidates.  The second version is faster, because knowing
+/// discovered check candidates. The second version is faster, because knowing
 /// the discovered check candidates makes it easier to update the checkersBB
 /// member variable in the position object.
 
@@ -765,42 +781,8 @@ void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) {
 
     if (capture)
     {
-        assert(capture != KING);
-
-        // Remove captured piece
-        clear_bit(&(byColorBB[them]), to);
-        clear_bit(&(byTypeBB[capture]), to);
-
-        // Update hash key
-        key ^= zobrist[them][capture][to];
-
-        // If the captured piece was a pawn, update pawn hash key
-        if (capture == PAWN)
-            pawnKey ^= zobrist[them][PAWN][to];
-
-        // Update incremental scores
-        mgValue -= mg_pst(them, capture, to);
-        egValue -= eg_pst(them, capture, to);
-
-        // Update material
-        if (capture != PAWN)
-            npMaterial[them] -= piece_value_midgame(capture);
-
-        // Update material hash key
-        materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
-
-        // Update piece count
-        pieceCount[them][capture]--;
-
-        // Update piece list
-        pieceList[them][capture][index[to]] = pieceList[them][capture][pieceCount[them][capture]];
-        index[pieceList[them][capture][index[to]]] = index[to];
-
-        // Remember the captured piece, in order to be able to undo the move correctly
-        u.capture = capture;
-
-        // Reset rule 50 counter
-        rule50 = 0;
+      u.capture = capture;
+      do_capture_move(m, capture, them, to);
     }
 
     // Move the piece
@@ -931,8 +913,51 @@ void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) {
 }
 
 
+/// Position::do_capture_move() is a private method used to update captured
+/// piece info. It is called from the main Position::do_move function.
+
+void Position::do_capture_move(Move m, PieceType capture, Color them, Square to) {
+
+    assert(capture != KING);
+
+    // Remove captured piece
+    clear_bit(&(byColorBB[them]), to);
+    clear_bit(&(byTypeBB[capture]), to);
+
+    // Update hash key
+    key ^= zobrist[them][capture][to];
+
+    // If the captured piece was a pawn, update pawn hash key
+    if (capture == PAWN)
+        pawnKey ^= zobrist[them][PAWN][to];
+
+    // Update incremental scores
+    mgValue -= mg_pst(them, capture, to);
+    egValue -= eg_pst(them, capture, to);
+
+    assert(!move_promotion(m) || capture != PAWN);
+
+    // Update material
+    if (capture != PAWN)
+        npMaterial[them] -= piece_value_midgame(capture);
+
+    // Update material hash key
+    materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
+
+    // Update piece count
+    pieceCount[them][capture]--;
+
+    // Update piece list
+    pieceList[them][capture][index[to]] = pieceList[them][capture][pieceCount[them][capture]];
+    index[pieceList[them][capture][index[to]]] = index[to];
+
+    // Reset rule 50 counter
+    rule50 = 0;
+}
+
+
 /// Position::do_castle_move() is a private method used to make a castling
-/// move.  It is called from the main Position::do_move function.  Note that
+/// move. It is called from the main Position::do_move function. 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.
 
@@ -1056,36 +1081,8 @@ void Position::do_promotion_move(Move m, UndoInfo &u) {
 
   if (capture)
   {
-    assert(capture != KING);
-
-    // Remove captured piece
-    clear_bit(&(byColorBB[them]), to);
-    clear_bit(&(byTypeBB[capture]), to);
-
-    // Update hash key
-    key ^= zobrist[them][capture][to];
-
-    // Update incremental scores
-    mgValue -= mg_pst(them, capture, to);
-    egValue -= eg_pst(them, capture, to);
-
-    // Update material. Because our move is a promotion, we know that the
-    // captured piece is not a pawn.
-    assert(capture != PAWN);
-    npMaterial[them] -= piece_value_midgame(capture);
-
-    // Update material hash key
-    materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
-
-    // Update piece count
-    pieceCount[them][capture]--;
-
-    // Update piece list
-    pieceList[them][capture][index[to]] = pieceList[them][capture][pieceCount[them][capture]];
-    index[pieceList[them][capture][index[to]]] = index[to];
-
-    // Remember the captured piece, in order to be able to undo the move correctly
     u.capture = capture;
+    do_capture_move(m, capture, them, to);
   }
 
   // Remove pawn
@@ -1585,10 +1582,16 @@ void Position::undo_null_move(const UndoInfo &u) {
 
 
 /// Position::see() is a static exchange evaluator:  It tries to estimate the
-/// material gain or loss resulting from a move.  There are two versions of
-/// this function: One which takes a move as input, and one which takes a
-/// 'from' and a 'to' square.  The function does not yet understand promotions
-/// or en passant captures.
+/// 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 or en passant captures.
+
+int Position::see(Square to) const {
+
+  assert(square_is_ok(to));
+  return see(SQ_NONE, to);
+}
 
 int Position::see(Move m) const {
 
@@ -1598,18 +1601,22 @@ int Position::see(Move m) const {
 
 int Position::see(Square from, Square to) const {
 
-  // Approximate material values, with pawn = 1
+  // Material values
   static const int seeValues[18] = {
-    0, 1, 3, 3, 5, 10, 100, 0, 0, 1, 3, 3, 5, 10, 100, 0, 0, 0
+    0, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
+       RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10, 0,
+    0, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
+       RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10, 0,
+    0, 0
   };
 
   Bitboard attackers, occ, b;
 
-  assert(square_is_ok(from));
+  assert(square_is_ok(from) || from == SQ_NONE);
   assert(square_is_ok(to));
 
   // Initialize colors
-  Color us = color_of_piece_on(from);
+  Color us = (from != SQ_NONE ? color_of_piece_on(from) : opposite_color(color_of_piece_on(to)));
   Color them = opposite_color(us);
 
   // Initialize pieces
@@ -1619,27 +1626,54 @@ int Position::see(Square from, Square to) const {
   // Find all attackers to the destination square, with the moving piece
   // removed, but possibly an X-ray attacker added behind it.
   occ = occupied_squares();
-  clear_bit(&occ, from);
-  attackers =  (rook_attacks_bb(to, occ)   & rooks_and_queens())
-             | (bishop_attacks_bb(to, occ) & bishops_and_queens())
-             | (piece_attacks<KNIGHT>(to)  & knights())
-             | (piece_attacks<KING>(to)    & kings())
-             | (pawn_attacks(WHITE, to)    & pawns(BLACK))
-             | (pawn_attacks(BLACK, to)    & pawns(WHITE));
-
-  // If the opponent has no attackers, we are finished
+
+  // Handle enpassant moves
+  if (ep_square() == to && type_of_piece_on(from) == PAWN)
+  {
+      assert(capture == EMPTY);
+
+      Square capQq = (side_to_move() == WHITE)? (to - DELTA_N) : (to - DELTA_S);
+      capture = piece_on(capQq);
+
+      assert(type_of_piece_on(capQq) == PAWN);
+
+      // Remove the captured pawn
+      clear_bit(&occ, capQq);
+  }
+
+  while (true)
+  {
+      clear_bit(&occ, from);
+      attackers =  (rook_attacks_bb(to, occ)   & rooks_and_queens())
+                 | (bishop_attacks_bb(to, occ) & bishops_and_queens())
+                 | (piece_attacks<KNIGHT>(to)  & knights())
+                 | (piece_attacks<KING>(to)    & kings())
+                 | (pawn_attacks(WHITE, to)    & pawns(BLACK))
+                 | (pawn_attacks(BLACK, to)    & pawns(WHITE));
+
+      if (from != SQ_NONE)
+          break;
+
+      // If we don't have any attacker we are finished
+      if ((attackers & pieces_of_color(us)) == EmptyBoardBB)
+          return 0;
+
+      // Locate the least valuable attacker to the destination square
+      // and use it to initialize from square.
+      PieceType pt;
+      for (pt = PAWN; !(attackers & pieces_of_color_and_type(us, pt)); pt++)
+          assert(pt < KING);
+
+      from = first_1(attackers & pieces_of_color_and_type(us, pt));
+      piece = piece_on(from);
+  }
+
+  // If the opponent has no attackers we are finished
   if ((attackers & pieces_of_color(them)) == EmptyBoardBB)
       return seeValues[capture];
 
   attackers &= occ; // Remove the moving piece
 
-  // If we don't have any attacker but the moving piece (common case)
-  // then we loose our piece and gain the opponent attacked one.
-  // Note that this is not perfect! It does not detect x-rays of
-  // an our piece behind an opposite one. But is a very rare case.
-  if ((attackers & pieces_of_color(us)) == EmptyBoardBB)
-      return seeValues[capture] - seeValues[piece];
-
   // The destination square is defended, which makes things rather more
   // difficult to compute. We proceed by building up a "swap list" containing
   // the material gain or loss at each stop in a sequence of captures to the
@@ -1937,8 +1971,7 @@ bool Position::is_mate() {
 
   if (is_check())
   {
-      MovePicker mp = MovePicker(*this, false, MOVE_NONE, MOVE_NONE,
-                                 MOVE_NONE, MOVE_NONE, Depth(0));
+      MovePicker mp = MovePicker(*this, false, MOVE_NONE, EmptySearchStack, Depth(0));
       return mp.get_next_move() == MOVE_NONE;
   }
   return false;