]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Stockfish 1.3.1
[stockfish] / src / position.cpp
index f558d73c67992138f1d96ec12521f8ed26027539..5f19403035313eddc8e7694c4f9ce52f9bdc60d6 100644 (file)
@@ -190,7 +190,7 @@ void Position::from_fen(const std::string& fen) {
       i++;
 
   // En passant square
-  if (    i < fen.length() - 2
+  if (    i <= fen.length() - 2
       && (fen[i] >= 'a' && fen[i] <= 'h')
       && (fen[i+1] == '3' || fen[i+1] == '6'))
       st->epSquare = square_from_string(fen.substr(i, 2));
@@ -479,7 +479,6 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
       return true;
 
   Color us = side_to_move();
-  Color them = opposite_color(us);
   Square from = move_from(m);
   Square ksq = king_square(us);
 
@@ -491,6 +490,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
   // after the move is made
   if (move_is_ep(m))
   {
+      Color them = opposite_color(us);
       Square to = move_to(m);
       Square capsq = make_square(square_file(to), square_rank(from));
       Bitboard b = occupied_squares();
@@ -511,11 +511,12 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
   // If the moving piece is a king, check whether the destination
   // square is attacked by the opponent.
   if (from == ksq)
-      return !(square_is_attacked(move_to(m), them));
+      return !(square_is_attacked(move_to(m), opposite_color(us)));
 
   // 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.
-  return (   !bit_is_set(pinned, from)
+  return (   !pinned
+          || !bit_is_set(pinned, from)
           || (direction_between_squares(from, ksq) == direction_between_squares(move_to(m), ksq)));
 }
 
@@ -551,7 +552,8 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
       if (bit_is_set(pawn_attacks(them, ksq), to)) // Normal check?
           return true;
 
-      if (    bit_is_set(dcCandidates, from)      // Discovered check?
+      if (   dcCandidates // Discovered check?
+          && bit_is_set(dcCandidates, from)
           && (direction_between_squares(from, ksq) != direction_between_squares(to, ksq)))
           return true;
 
@@ -590,22 +592,24 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
       }
       return false;
 
+  // Test discovered check and normal check according to piece type
   case KNIGHT:
-    return   bit_is_set(dcCandidates, from)              // Discovered check?
-          || bit_is_set(piece_attacks<KNIGHT>(ksq), to); // Normal check?
+    return   (dcCandidates && bit_is_set(dcCandidates, from))
+          || bit_is_set(piece_attacks<KNIGHT>(ksq), to);
 
   case BISHOP:
-    return   bit_is_set(dcCandidates, from)              // Discovered check?
-          || bit_is_set(piece_attacks<BISHOP>(ksq), to); // Normal check?
+    return   (dcCandidates && bit_is_set(dcCandidates, from))
+          || (direction_is_diagonal(ksq, to) && bit_is_set(piece_attacks<BISHOP>(ksq), to));
 
   case ROOK:
-    return   bit_is_set(dcCandidates, from)              // Discovered check?
-          || bit_is_set(piece_attacks<ROOK>(ksq), to);   // Normal check?
+    return   (dcCandidates && bit_is_set(dcCandidates, from))
+          || (direction_is_straight(ksq, to) && bit_is_set(piece_attacks<ROOK>(ksq), to));
 
   case QUEEN:
       // Discovered checks are impossible!
       assert(!bit_is_set(dcCandidates, from));
-      return bit_is_set(piece_attacks<QUEEN>(ksq), to);  // Normal check?
+      return (   (direction_is_straight(ksq, to) && bit_is_set(piece_attacks<ROOK>(ksq), to))
+              || (direction_is_diagonal(ksq, to) && bit_is_set(piece_attacks<BISHOP>(ksq), to)));
 
   case KING:
       // Discovered check?
@@ -645,20 +649,6 @@ 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. Move must not be MOVE_NONE.
-
-bool Position::move_is_capture(Move m) const {
-
-  assert(m != MOVE_NONE);
-
-  return (   !square_is_empty(move_to(m))
-          && (color_of_piece_on(move_to(m)) != color_of_piece_on(move_from(m)))
-         )
-         || move_is_ep(m);
-}
-
-
 /// Position::update_checkers() udpates chekers info given the move. It is called
 /// in do_move() and is faster then find_checkers().
 
@@ -749,7 +739,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
     st->capture = type_of_piece_on(to);
 
     if (st->capture)
-      do_capture_move(m, st->capture, them, to);
+      do_capture_move(st->capture, them, to);
 
     // Move the piece
     clear_bit(&(byColorBB[us]), from);
@@ -842,7 +832,7 @@ void Position::do_move(Move m, StateInfo& newSt, 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) {
+void Position::do_capture_move(PieceType capture, Color them, Square to) {
 
     assert(capture != KING);
 
@@ -861,8 +851,6 @@ void Position::do_capture_move(Move m, PieceType capture, Color them, Square to)
     st->mgValue -= pst<MidGame>(them, capture, to);
     st->egValue -= pst<EndGame>(them, capture, to);
 
-    assert(!move_promotion(m) || capture != PAWN);
-
     // Update material
     if (capture != PAWN)
         npMaterial[them] -= piece_value_midgame(capture);
@@ -1004,7 +992,7 @@ void Position::do_promotion_move(Move m) {
   st->capture = type_of_piece_on(to);
 
   if (st->capture)
-    do_capture_move(m, st->capture, them, to);
+    do_capture_move(st->capture, them, to);
 
   // Remove pawn
   clear_bit(&(byColorBB[us]), from);
@@ -1612,7 +1600,7 @@ int Position::see(Square from, Square to) const {
       // Remove the attacker we just found from the 'attackers' bitboard,
       // and scan for new X-ray attacks behind the attacker.
       b = attackers & pieces_of_color_and_type(c, pt);
-      occ ^= (b & -b);
+      occ ^= (b & (~b + 1));
       attackers |=  (rook_attacks_bb(to, occ) & rooks_and_queens())
                   | (bishop_attacks_bb(to, occ) & bishops_and_queens());
 
@@ -1848,15 +1836,14 @@ Value Position::compute_value() const {
 Value Position::compute_non_pawn_material(Color c) const {
 
   Value result = Value(0);
-  Square s;
 
   for (PieceType pt = KNIGHT; pt <= QUEEN; pt++)
   {
       Bitboard b = pieces_of_color_and_type(c, pt);
-      while(b)
+      while (b)
       {
-          s = pop_1st_bit(&b);
-          assert(piece_on(s) == piece_of_color_and_type(c, pt));
+          assert(piece_on(first_1(b)) == piece_of_color_and_type(c, pt));
+          pop_1st_bit(&b);
           result += piece_value_midgame(pt);
       }
   }
@@ -1864,21 +1851,6 @@ Value Position::compute_non_pawn_material(Color c) const {
 }
 
 
-/// Position::is_mate() returns true or false depending on whether the
-/// side to move is checkmated. Note that this function is currently very
-/// slow, and shouldn't be used frequently inside the search.
-
-bool Position::is_mate() const {
-
-  if (is_check())
-  {
-      MovePicker mp = MovePicker(*this, false, MOVE_NONE, EmptySearchStack, Depth(0));
-      return mp.get_next_move() == MOVE_NONE;
-  }
-  return false;
-}
-
-
 /// 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.
@@ -1903,21 +1875,25 @@ bool Position::is_draw() const {
 }
 
 
+/// Position::is_mate() returns true or false depending on whether the
+/// side to move is checkmated.
+
+bool Position::is_mate() const {
+
+  MoveStack moves[256];
+
+  return is_check() && !generate_evasions(*this, moves, pinned_pieces(sideToMove));
+}
+
+
 /// Position::has_mate_threat() tests whether a given color has a mate in one
-/// from the current position. This function is quite slow, but it doesn't
-/// matter, because it is currently only called from PV nodes, which are rare.
+/// from the current position.
 
 bool Position::has_mate_threat(Color c) {
 
   StateInfo st1, st2;
   Color stm = side_to_move();
 
-  // The following lines are useless and silly, but prevents gcc from
-  // emitting a stupid warning stating that u1.lastMove and u1.epSquare might
-  // be used uninitialized.
-  st1.lastMove = st->lastMove;
-  st1.epSquare = st->epSquare;
-
   if (is_check())
       return false;
 
@@ -1928,18 +1904,26 @@ bool Position::has_mate_threat(Color c) {
   MoveStack mlist[120];
   int count;
   bool result = false;
+  Bitboard dc = discovered_check_candidates(sideToMove);
+  Bitboard pinned = pinned_pieces(sideToMove);
 
-  // Generate legal moves
-  count = generate_legal_moves(*this, mlist);
+  // Generate pseudo-legal non-capture and capture check moves
+  count = generate_non_capture_checks(*this, mlist, dc);
+  count += generate_captures(*this, mlist + count);
 
   // Loop through the moves, and see if one of them is mate
   for (int i = 0; i < count; i++)
   {
-      do_move(mlist[i].move, st2);
+      Move move = mlist[i].move;
+
+      if (!pl_move_is_legal(move, pinned))
+          continue;
+
+      do_move(move, st2);
       if (is_mate())
           result = true;
 
-      undo_move(mlist[i].move);
+      undo_move(move);
   }
 
   // Undo null move, if necessary