]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Refactor Position::pinned_pieces() to use templates
[stockfish] / src / position.cpp
index 6de3f08c89e69b6baf72cc502343e85cfc2e363e..e33b65fc050e4988f646cbdc2324c9962ccb4eb8 100644 (file)
@@ -1,13 +1,14 @@
 /*
-  Glaurung, a UCI chess playing engine.
-  Copyright (C) 2004-2008 Tord Romstad
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008 Marco Costalba
 
-  Glaurung is free software: you can redistribute it and/or modify
+  Stockfish is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
 
-  Glaurung is distributed in the hope that it will be useful,
+  Stockfish is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
@@ -48,13 +49,6 @@ Key Position::zobSideToMove;
 Value Position::MgPieceSquareTable[16][64];
 Value Position::EgPieceSquareTable[16][64];
 
-const Piece_attacks_fn piece_attacks_fn[] =
-  { 0, 0, 
-    &Position::knight_attacks,
-    &Position::bishop_attacks,
-    &Position::rook_attacks,
-    &Position::queen_attacks,
-    &Position::king_attacks };
 
 ////
 //// Functions
@@ -302,40 +296,53 @@ void Position::copy(const Position &pos) {
 }
 
 
-/// Position:pinned_pieces() returns a bitboard of all pinned (against the
-/// king) pieces for the given color.
+/// Position:pinned_pieces<>() returns a bitboard of all pinned (against the
+/// king) pieces for the given color and for the given pinner type.
+template<PieceType Piece>
+Bitboard Position::pinned_pieces(Color c, Square ksq) const {
 
-Bitboard Position::pinned_pieces(Color c) const {
-  Bitboard b1, b2, pinned, pinners, sliders;
-  Square ksq = king_square(c), s;
-  Color them = opposite_color(c);
+  Square s;
+  Bitboard sliders, pinned = EmptyBoardBB;
+  
+  if (Piece == ROOK) // Resolved at compile time
+      sliders = rooks_and_queens(opposite_color(c)) & RookPseudoAttacks[ksq];
+  else
+      sliders = bishops_and_queens(opposite_color(c)) & BishopPseudoAttacks[ksq];
 
-  pinned = EmptyBoardBB;
-  b1 = occupied_squares();
+  if (sliders && (sliders & ~checkersBB))
+  {
+       // Our king blockers are candidate pinned pieces
+      Bitboard candidate_pinned = piece_attacks<Piece>(ksq) & pieces_of_color(c);
+
+      // Pinners are sliders, not checkers, that give check when 
+      // candidate pinned are removed.
+      Bitboard pinners =  sliders & ~checkersBB;
+      if (Piece == ROOK)
+          pinners &= rook_attacks_bb(ksq, occupied_squares() ^ candidate_pinned);
+      else
+          pinners &= bishop_attacks_bb(ksq, occupied_squares() ^ candidate_pinned);
 
-  sliders = rooks_and_queens(them) & ~checkers();
-  if(sliders & RookPseudoAttacks[ksq]) {
-    b2 = rook_attacks(ksq) & pieces_of_color(c);
-    pinners = rook_attacks_bb(ksq, b1 ^ b2) & sliders;
-    while(pinners) {
-      s = pop_1st_bit(&pinners);
-      pinned |= (squares_between(s, ksq) & b2);
-    }
+      // Finally for each pinner find the corresponding pinned piece
+      // among the candidates.
+      while (pinners)
+      {
+          s = pop_1st_bit(&pinners);
+          pinned |= (squares_between(s, ksq) & candidate_pinned);
+      }
   }
+  return pinned;
+}
 
-  sliders = bishops_and_queens(them) & ~checkers();
-  if(sliders & BishopPseudoAttacks[ksq]) {
-    b2 = bishop_attacks(ksq) & pieces_of_color(c);
-    pinners = bishop_attacks_bb(ksq, b1 ^ b2) & sliders;
-    while(pinners) {
-      s = pop_1st_bit(&pinners);
-      pinned |= (squares_between(s, ksq) & b2);
-    }
-  }
 
-  return pinned;
+/// Position:pinned_pieces() returns a bitboard of all pinned (against the
+/// king) pieces for the given color.
+Bitboard Position::pinned_pieces(Color c) const {
+
+  Square ksq = king_square(c);
+  return pinned_pieces<ROOK>(c, ksq) | pinned_pieces<BISHOP>(c, ksq);
 }
 
+
 /// Position:discovered_check_candidates() returns a bitboard containing all
 /// pieces for the given side which are candidates for giving a discovered
 /// check.  The code is almost the same as the function for finding pinned
@@ -350,7 +357,7 @@ Bitboard Position::discovered_check_candidates(Color c) const {
 
   sliders = rooks_and_queens(c);
   if(sliders & RookPseudoAttacks[ksq]) {
-    b2 = rook_attacks(ksq) & pieces_of_color(c);
+    b2 = piece_attacks<ROOK>(ksq) & pieces_of_color(c);
     checkers = rook_attacks_bb(ksq, b1 ^ b2) & sliders;
     while(checkers) {
       s = pop_1st_bit(&checkers);
@@ -360,7 +367,7 @@ Bitboard Position::discovered_check_candidates(Color c) const {
 
   sliders = bishops_and_queens(c);
   if(sliders & BishopPseudoAttacks[ksq]) {
-    b2 = bishop_attacks(ksq) & pieces_of_color(c);
+    b2 = piece_attacks<BISHOP>(ksq) & pieces_of_color(c);
     checkers = bishop_attacks_bb(ksq, b1 ^ b2) & sliders;
     while(checkers) {
       s = pop_1st_bit(&checkers);
@@ -378,10 +385,10 @@ Bitboard Position::discovered_check_candidates(Color c) const {
 bool Position::square_is_attacked(Square s, Color c) const {
   return
     (pawn_attacks(opposite_color(c), s) & pawns(c)) ||
-    (knight_attacks(s) & knights(c)) ||
-    (king_attacks(s) & kings(c)) ||
-    (rook_attacks(s) & rooks_and_queens(c)) ||
-    (bishop_attacks(s) & bishops_and_queens(c));
+    (piece_attacks<KNIGHT>(s) & knights(c)) ||
+    (piece_attacks<KING>(s)   & kings(c)) ||
+    (piece_attacks<ROOK>(s)   & rooks_and_queens(c)) ||
+    (piece_attacks<BISHOP>(s) & bishops_and_queens(c));
 }
 
 
@@ -392,12 +399,12 @@ bool Position::square_is_attacked(Square s, Color c) const {
 
 Bitboard Position::attacks_to(Square s) const {
   return
-    (black_pawn_attacks(s) & pawns(WHITE)) |
-    (white_pawn_attacks(s) & pawns(BLACK)) |
-    (knight_attacks(s) & pieces_of_type(KNIGHT)) |
-    (rook_attacks(s) & rooks_and_queens()) |
-    (bishop_attacks(s) & bishops_and_queens()) |
-    (king_attacks(s) & pieces_of_type(KING));
+    (pawn_attacks(BLACK, s) & pawns(WHITE)) |
+    (pawn_attacks(WHITE, s) & pawns(BLACK)) |
+    (piece_attacks<KNIGHT>(s) & pieces_of_type(KNIGHT)) |
+    (piece_attacks<ROOK>(s) & rooks_and_queens()) |
+    (piece_attacks<BISHOP>(s) & bishops_and_queens()) |
+    (piece_attacks<KING>(s) & pieces_of_type(KING));
 }
 
 Bitboard Position::attacks_to(Square s, Color c) const {
@@ -413,13 +420,13 @@ bool Position::piece_attacks_square(Square f, Square t) const {
   assert(square_is_ok(t));
 
   switch(piece_on(f)) {
-  case WP: return white_pawn_attacks_square(f, t);
-  case BP: return black_pawn_attacks_square(f, t);
-  case WN: case BN: return knight_attacks_square(f, t);
-  case WB: case BB: return bishop_attacks_square(f, t);
-  case WR: case BR: return rook_attacks_square(f, t);
-  case WQ: case BQ: return queen_attacks_square(f, t);
-  case WK: case BK: return king_attacks_square(f, t);
+  case WP: return pawn_attacks_square(WHITE, f, t);
+  case BP: return pawn_attacks_square(BLACK, f, t);
+  case WN: case BN: return piece_attacks_square<KNIGHT>(f, t);
+  case WB: case BB: return piece_attacks_square<BISHOP>(f, t);
+  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: return false;
   }
 
@@ -556,7 +563,7 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
 
       switch(move_promotion(m)) {
       case KNIGHT:
-        return knight_attacks_square(to, ksq);
+        return piece_attacks_square<KNIGHT>(to, ksq);
       case BISHOP:
         return bit_is_set(bishop_attacks_bb(to, b), ksq);
       case ROOK:
@@ -588,7 +595,7 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
       return true;
     // Normal check?
     else
-      return bit_is_set(knight_attacks(ksq), to);
+      return bit_is_set(piece_attacks<KNIGHT>(ksq), to);
 
   case BISHOP:
     // Discovered check?
@@ -596,7 +603,7 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
       return true;
     // Normal check?
     else
-      return bit_is_set(bishop_attacks(ksq), to);
+      return bit_is_set(piece_attacks<BISHOP>(ksq), to);
 
   case ROOK:
     // Discovered check?
@@ -604,13 +611,13 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
       return true;
     // Normal check?
     else
-      return bit_is_set(rook_attacks(ksq), to);
+      return bit_is_set(piece_attacks<ROOK>(ksq), to);
 
   case QUEEN:
     // Discovered checks are impossible!
     assert(!bit_is_set(dcCandidates, from));
     // Normal check?
-    return bit_is_set(queen_attacks(ksq), to);
+    return bit_is_set(piece_attacks<QUEEN>(ksq), to);
 
   case KING:
     // Discovered check?
@@ -675,13 +682,13 @@ bool Position::move_attacks_square(Move m, Square s) const {
   assert(square_is_occupied(f));
 
   switch(piece_on(f)) {
-  case WP: return white_pawn_attacks_square(t, s);
-  case BP: return black_pawn_attacks_square(t, s);
-  case WN: case BN: return knight_attacks_square(t, s);
-  case WB: case BB: return bishop_attacks_square(t, s);
-  case WR: case BR: return rook_attacks_square(t, s);
-  case WQ: case BQ: return queen_attacks_square(t, s);
-  case WK: case BK: return king_attacks_square(t, s);
+  case WP: return pawn_attacks_square(WHITE, t, s);
+  case BP: return pawn_attacks_square(BLACK, t, s);
+  case WN: case BN: return piece_attacks_square<KNIGHT>(t, s);
+  case WB: case BB: return piece_attacks_square<BISHOP>(t, s);
+  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);
   }
 
@@ -854,9 +861,9 @@ void Position::do_move(Move m, UndoInfo &u, Bitboard dcCandidates) {
     }
     if(piece == PAWN) {
       if(abs(int(to) - int(from)) == 16) {
-        if((us == WHITE && (white_pawn_attacks(from + DELTA_N) &
+        if((us == WHITE && (pawn_attacks(WHITE, from + DELTA_N) &
                             pawns(BLACK))) ||
-           (us == BLACK && (black_pawn_attacks(from + DELTA_S) &
+           (us == BLACK && (pawn_attacks(BLACK, from + DELTA_S) &
                             pawns(WHITE)))) {
           epSquare = Square((int(from) + int(to)) / 2);
           key ^= zobEp[epSquare];
@@ -889,45 +896,45 @@ void Position::do_move(Move m, UndoInfo &u, Bitboard dcCandidates) {
         set_bit(&checkersBB, to);
       if(bit_is_set(dcCandidates, from))
         checkersBB |=
-          ((rook_attacks(ksq) & rooks_and_queens(us)) |
-           (bishop_attacks(ksq) & bishops_and_queens(us)));
+          ((piece_attacks<ROOK>(ksq) & rooks_and_queens(us)) |
+           (piece_attacks<BISHOP>(ksq) & bishops_and_queens(us)));
       break;
 
     case KNIGHT:
-      if(bit_is_set(knight_attacks(ksq), to))
+      if(bit_is_set(piece_attacks<KNIGHT>(ksq), to))
         set_bit(&checkersBB, to);
       if(bit_is_set(dcCandidates, from))
         checkersBB |=
-          ((rook_attacks(ksq) & rooks_and_queens(us)) |
-           (bishop_attacks(ksq) & bishops_and_queens(us)));
+          ((piece_attacks<ROOK>(ksq) & rooks_and_queens(us)) |
+           (piece_attacks<BISHOP>(ksq) & bishops_and_queens(us)));
       break;
 
     case BISHOP:
-      if(bit_is_set(bishop_attacks(ksq), to))
+      if(bit_is_set(piece_attacks<BISHOP>(ksq), to))
         set_bit(&checkersBB, to);
       if(bit_is_set(dcCandidates, from))
         checkersBB |=
-          (rook_attacks(ksq) & rooks_and_queens(us));
+          (piece_attacks<ROOK>(ksq) & rooks_and_queens(us));
       break;
 
     case ROOK:
-      if(bit_is_set(rook_attacks(ksq), to))
+      if(bit_is_set(piece_attacks<ROOK>(ksq), to))
         set_bit(&checkersBB, to);
       if(bit_is_set(dcCandidates, from))
         checkersBB |=
-          (bishop_attacks(ksq) & bishops_and_queens(us));
+          (piece_attacks<BISHOP>(ksq) & bishops_and_queens(us));
       break;
 
     case QUEEN:
-      if(bit_is_set(queen_attacks(ksq), to))
+      if(bit_is_set(piece_attacks<QUEEN>(ksq), to))
         set_bit(&checkersBB, to);
       break;
 
     case KING:
       if(bit_is_set(dcCandidates, from))
         checkersBB |=
-          ((rook_attacks(ksq) & rooks_and_queens(us)) |
-           (bishop_attacks(ksq) & bishops_and_queens(us)));
+          ((piece_attacks<ROOK>(ksq) & rooks_and_queens(us)) |
+           (piece_attacks<BISHOP>(ksq) & bishops_and_queens(us)));
       break;
 
     default:
@@ -1637,10 +1644,10 @@ int Position::see(Square from, Square to) const {
   attackers =
     (rook_attacks_bb(to, occ) & rooks_and_queens()) |
     (bishop_attacks_bb(to, occ) & bishops_and_queens()) |
-    (knight_attacks(to) & knights()) |
-    (king_attacks(to) & kings()) |
-    (white_pawn_attacks(to) & pawns(BLACK)) |
-    (black_pawn_attacks(to) & pawns(WHITE));
+    (piece_attacks<KNIGHT>(to) & knights()) |
+    (piece_attacks<KING>(to) & kings()) |
+    (pawn_attacks(WHITE, to) & pawns(BLACK)) |
+    (pawn_attacks(BLACK, to) & pawns(WHITE));
   attackers &= occ;
 
   // If the opponent has no attackers, we are finished:
@@ -2116,7 +2123,7 @@ void Position::flipped_copy(const Position &pos) {
 /// Position::is_ok() performs some consitency checks for the position object.
 /// This is meant to be helpful when debugging.
 
-bool Position::is_ok() const {
+bool Position::is_ok(int* failedStep) const {
 
   // What features of the position should be verified?
   static const bool debugBitboards = false;
@@ -2131,23 +2138,30 @@ bool Position::is_ok() const {
   static const bool debugPieceCounts = false;
   static const bool debugPieceList = false;
 
+  if (failedStep) *failedStep = 1;
+
   // Side to move OK?
   if(!color_is_ok(side_to_move()))
     return false;
 
   // Are the king squares in the position correct?
+  if (failedStep) (*failedStep)++;
   if(piece_on(king_square(WHITE)) != WK)
     return false;
+
+  if (failedStep) (*failedStep)++;
   if(piece_on(king_square(BLACK)) != BK)
     return false;
 
   // Castle files OK?
+  if (failedStep) (*failedStep)++;
   if(!file_is_ok(initialKRFile))
     return false;
   if(!file_is_ok(initialQRFile))
     return false;
 
   // Do both sides have exactly one king?
+  if (failedStep) (*failedStep)++;
   if(debugKingCount) {
     int kingCount[2] = {0, 0};
     for(Square s = SQ_A1; s <= SQ_H8; s++)
@@ -2158,6 +2172,7 @@ bool Position::is_ok() const {
   }
 
   // Can the side to move capture the opponent's king?
+  if (failedStep) (*failedStep)++;
   if(debugKingCapture) {
     Color us = side_to_move();
     Color them = opposite_color(us);
@@ -2167,10 +2182,12 @@ bool Position::is_ok() const {
   }
 
   // Is there more than 2 checkers?
+  if (failedStep) (*failedStep)++;
   if(debugCheckerCount && count_1s(checkersBB) > 2)
     return false;
 
   // Bitboards OK?
+  if (failedStep) (*failedStep)++;
   if(debugBitboards) {
     // The intersection of the white and black pieces must be empty:
     if((pieces_of_color(WHITE) & pieces_of_color(BLACK))
@@ -2191,6 +2208,7 @@ bool Position::is_ok() const {
   }
 
   // En passant square OK?
+  if (failedStep) (*failedStep)++;
   if(ep_square() != SQ_NONE) {
     // The en passant square must be on rank 6, from the point of view of the
     // side to move.
@@ -2199,18 +2217,22 @@ bool Position::is_ok() const {
   }
 
   // Hash key OK?
+  if (failedStep) (*failedStep)++;
   if(debugKey && key != compute_key())
     return false;
 
   // Pawn hash key OK?
+  if (failedStep) (*failedStep)++;
   if(debugPawnKey && pawnKey != compute_pawn_key())
     return false;
 
   // Material hash key OK?
+  if (failedStep) (*failedStep)++;
   if(debugMaterialKey && materialKey != compute_material_key())
     return false;
 
   // Incremental eval OK?
+  if (failedStep) (*failedStep)++;
   if(debugIncrementalEval) {
     if(mgValue != compute_mg_value())
       return false;
@@ -2219,6 +2241,7 @@ bool Position::is_ok() const {
   }
 
   // Non-pawn material OK?
+  if (failedStep) (*failedStep)++;
   if(debugNonPawnMaterial) {
     if(npMaterial[WHITE] != compute_non_pawn_material(WHITE))
       return false;
@@ -2227,12 +2250,14 @@ bool Position::is_ok() const {
   }
 
   // Piece counts OK?
+  if (failedStep) (*failedStep)++;
   if(debugPieceCounts)
     for(Color c = WHITE; c <= BLACK; c++)
       for(PieceType pt = PAWN; pt <= KING; pt++)
         if(pieceCount[c][pt] != count_1s(pieces_of_color_and_type(c, pt)))
           return false;
 
+  if (failedStep) (*failedStep)++;
   if(debugPieceList) {
     for(Color c = WHITE; c <= BLACK; c++)
       for(PieceType pt = PAWN; pt <= KING; pt++)
@@ -2244,6 +2269,6 @@ bool Position::is_ok() const {
             return false;
         }
   }
-
+  if (failedStep) *failedStep = 0;
   return true;
 }