]> git.sesse.net Git - stockfish/blobdiff - src/movegen.cpp
Small optimization in generate_evasions()
[stockfish] / src / movegen.cpp
index 6c34d2728ef3db629f60265ea02af5e59cea0d42..198a36c5b15dd7b2779d1167430427655a807a70 100644 (file)
@@ -233,7 +233,7 @@ int generate_checks(const Position& pos, MoveStack* mlist, Bitboard dc) {
 
 /// generate_evasions() generates all check evasions when the side to move is
 /// in check.  Unlike the other move generation functions, this one generates
-/// only legal moves.  It returns the number of generated moves.  This
+/// only legal moves.  It returns the number of generated moves. This
 /// function is very ugly, and needs cleaning up some time later.  FIXME
 
 int generate_evasions(const Position& pos, MoveStack* mlist) {
@@ -249,34 +249,51 @@ int generate_evasions(const Position& pos, MoveStack* mlist) {
 
   assert(pos.piece_on(ksq) == king_of_color(us));
 
-  // Generate evasions for king
-  Bitboard b1 = pos.piece_attacks<KING>(ksq) & ~pos.pieces_of_color(us);
+  // The bitboard of occupied pieces without our king
   Bitboard b2 = pos.occupied_squares();
   clear_bit(&b2, ksq);
 
+  // Find squares attacked by slider checkers, we will
+  // remove them from king evasions set so to avoid a couple
+  // of cycles in the slow king evasions legality check loop.
+  Bitboard checkers = pos.checkers();
+  Bitboard checkersAttacks = EmptyBoardBB;
+  Bitboard b = checkers & (pos.queens() | pos.bishops());
+  while (b)
+  {
+      from = pop_1st_bit(&b);
+      checkersAttacks |= bishop_attacks_bb(from, b2);
+  }
+
+  b = checkers & (pos.queens() | pos.rooks());
+  while (b)
+  {
+      from = pop_1st_bit(&b);
+      checkersAttacks |= rook_attacks_bb(from, b2);
+  }
+
+  // Generate evasions for king
+  Bitboard b1 = pos.piece_attacks<KING>(ksq) & ~pos.pieces_of_color(us) & ~checkersAttacks;
   while (b1)
   {
-    to = pop_1st_bit(&b1);
-
-    // Make sure 'to' is not attacked by the other side. This is a bit ugly,
-    // because we can't use Position::square_is_attacked. Instead we use
-    // the low-level bishop_attacks_bb and rook_attacks_bb with the bitboard
-    // b2 (the occupied squares with the king removed) in order to test whether
-    // the king will remain in check on the destination square.
-    if (!(   (pos.piece_attacks<KNIGHT>(to) & pos.knights(them))
-          || (pos.pawn_attacks(us, to)      & pos.pawns(them))
-          || (bishop_attacks_bb(to, b2)     & pos.bishops_and_queens(them))
-          || (rook_attacks_bb(to, b2)       & pos.rooks_and_queens(them))
-          || (pos.piece_attacks<KING>(to)   & pos.kings(them))))
-
-        (*mlist++).move = make_move(ksq, to);
+      to = pop_1st_bit(&b1);
+
+      // Make sure 'to' is not attacked by the other side. This is a bit ugly,
+      // because we can't use Position::square_is_attacked. Instead we use
+      // the low-level bishop_attacks_bb and rook_attacks_bb with the bitboard
+      // b2 (the occupied squares with the king removed) in order to test whether
+      // the king will remain in check on the destination square.
+      if (!(   (pos.piece_attacks<KNIGHT>(to) & pos.knights(them))
+            || (pos.pawn_attacks(us, to)      & pos.pawns(them))
+            || (bishop_attacks_bb(to, b2)     & pos.bishops_and_queens(them))
+            || (rook_attacks_bb(to, b2)       & pos.rooks_and_queens(them))
+            || (pos.piece_attacks<KING>(to)   & pos.kings(them))))
+          (*mlist++).move = make_move(ksq, to);
   }
 
   // Generate evasions for other pieces only if not double check. We use a
   // simple bit twiddling hack here rather than calling count_1s in order to
   // save some time (we know that pos.checkers() has at most two nonzero bits).
-  Bitboard checkers = pos.checkers();
-
   if (!(checkers & (checkers - 1))) // Only one bit set?
   {
       Square checksq = first_1(checkers);
@@ -384,8 +401,8 @@ int generate_evasions(const Position& pos, MoveStack* mlist) {
 
 
 /// generate_legal_moves() computes a complete list of legal moves in the
-/// current position.  This function is not very fast, and should be used
-/// only in situations where performance is unimportant.  It wouldn't be
+/// current position. This function is not very fast, and should be used
+/// only in situations where performance is unimportant. It wouldn't be
 /// very hard to write an efficient legal move generator, but for the moment
 /// we don't need it.
 
@@ -741,10 +758,10 @@ namespace {
     b2 = b1 & TRank8BB;
     while (b2)
     {
-      to = pop_1st_bit(&b2);
-      (*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK);
-      (*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP);
-      (*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT);
+        to = pop_1st_bit(&b2);
+        (*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK);
+        (*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP);
+        (*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT);
     }
     b2 = b1 & ~TRank8BB;
     while (b2)
@@ -757,8 +774,8 @@ namespace {
     b2 = (Us == WHITE ? (b1 & TRank3BB) << 8 : (b1 & TRank3BB) >> 8) & emptySquares;
     while (b2)
     {
-      to = pop_1st_bit(&b2);
-      (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to);
+        to = pop_1st_bit(&b2);
+        (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to);
     }
     return mlist;
   }
@@ -775,8 +792,8 @@ namespace {
     // Find all friendly pawns not on the enemy king's file
     Bitboard b1 = pos.pawns(Us) & ~file_bb(ksq), b2, b3;
 
-    // Discovered checks, single pawn pushes
-    b2 = b3 = (Us == WHITE ? (b1 & dc) << 8 : (b1 & dc) >> 8) & ~TRank8BB & empty;
+    // Discovered checks, single pawn pushes, no promotions
+    b2 = b3 = (Us == WHITE ? (b1 & dc) << 8 : (b1 & dc) >> 8) & empty & ~TRank8BB;
     while (b3)
     {
         Square to = pop_1st_bit(&b3);
@@ -793,8 +810,7 @@ namespace {
 
     // Direct checks. These are possible only for pawns on neighboring files
     // of the enemy king
-
-    b1 &= (~dc & neighboring_files_bb(ksq)); // FIXME why ~dc ??
+    b1 &= (~dc & neighboring_files_bb(ksq));
 
     // Direct checks, single pawn pushes
     b2 = (Us == WHITE ? b1 << 8 : b1 >> 8) & empty;
@@ -946,11 +962,10 @@ namespace {
     File rookFile = (side == QUEEN_SIDE ? FILE_D : FILE_F);
     Color us = pos.side_to_move();
     Square ksq = pos.king_square(us);
-    Bitboard occ = pos.occupied_squares(), oppKingBB = EmptyBoardBB;
+    Bitboard occ = pos.occupied_squares();
 
-    set_bit(&oppKingBB, pos.king_square(opposite_color(us)));
     clear_bit(&occ, ksq); // Remove our king from the board
     Square rsq = make_square(rookFile, square_rank(ksq));
-    return (rook_attacks_bb(rsq, occ) & oppKingBB);
+    return bit_is_set(rook_attacks_bb(rsq, occ), pos.king_square(opposite_color(us)));
   }
 }