]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Refactor Position::pinned_pieces() to use templates
[stockfish] / src / position.cpp
index 8d63c52f10b92512ebf5589ce33243e43eddcd6c..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.
@@ -70,7 +71,7 @@ Position::Position(const std::string &fen) {
 
 void Position::from_fen(const std::string &fen) {
 
-  static const std::string piecesStr = "KQRBNPkqrbnp";
+  static const std::string pieceLetters = "KQRBNPkqrbnp";
   static const Piece pieces[] = { WK, WQ, WR, WB, WN, WP, BK, BQ, BR, BB, BN, BP };
 
   clear();
@@ -93,7 +94,7 @@ void Position::from_fen(const std::string &fen) {
           rank--;
           continue;
       }
-      size_t idx = piecesStr.find(fen[i]);
+      size_t idx = pieceLetters.find(fen[i]);
       if (idx == std::string::npos)
       {
            std::cout << "Error in FEN at character " << i << std::endl;
@@ -106,7 +107,7 @@ void Position::from_fen(const std::string &fen) {
 
   // Side to move
   i++;
-  if (fen[i] != 'w' && fen[i] == 'b')
+  if (fen[i] != 'w' && fen[i] != 'b')
   {
       std::cout << "Error in FEN at character " << i << std::endl;
       return;
@@ -214,40 +215,50 @@ void Position::from_fen(const std::string &fen) {
 /// probably only useful for debugging.
 
 const std::string Position::to_fen() const {
-  char pieceLetters[] = " PNBRQK  pnbrqk";
-  std::string result;
+
+  static const std::string pieceLetters = " PNBRQK  pnbrqk";
+  std::string fen;
   int skip;
 
-  for(Rank rank = RANK_8; rank >= RANK_1; rank--) {
-    skip = 0;
-    for(File file = FILE_A; file <= FILE_H; file++) {
-      Square square = make_square(file, rank);
-      if(square_is_occupied(square)) {
-        if(skip > 0) result += (char)skip + '0';
-        result += pieceLetters[piece_on(square)];
-        skip = 0;
+  for (Rank rank = RANK_8; rank >= RANK_1; rank--)
+  {
+      skip = 0;
+      for (File file = FILE_A; file <= FILE_H; file++)
+      {
+          Square sq = make_square(file, rank);
+          if (!square_is_occupied(sq))
+          {   skip++;
+              continue;
+          }
+          if (skip > 0)
+          {
+              fen += (char)skip + '0';
+              skip = 0;
+          }
+          fen += pieceLetters[piece_on(sq)];         
       }
-      else skip++;
-    }
-    if(skip > 0) result += (char)skip + '0';
-    result += (rank > RANK_1)? '/' : ' ';
-  }
+      if (skip > 0)
+          fen += (char)skip + '0';
 
-  result += (sideToMove == WHITE)? 'w' : 'b';
-  result += ' ';
-  if(castleRights == NO_CASTLES) result += '-';
-  else {
-    if(can_castle_kingside(WHITE)) result += 'K';
-    if(can_castle_queenside(WHITE)) result += 'Q';
-    if(can_castle_kingside(BLACK)) result += 'k';
-    if(can_castle_queenside(BLACK)) result += 'q';
+      fen += (rank > RANK_1 ? '/' : ' ');
   }
+  fen += (sideToMove == WHITE ? 'w' : 'b') + ' ';
+  if (castleRights != NO_CASTLES)
+  {
+    if (can_castle_kingside(WHITE))  fen += 'K';
+    if (can_castle_queenside(WHITE)) fen += 'Q';
+    if (can_castle_kingside(BLACK))  fen += 'k';
+    if (can_castle_queenside(BLACK)) fen += 'q';
+  } else
+      fen += '-';
+
+  fen += ' ';
+  if (ep_square() != SQ_NONE)
+      fen += square_to_string(ep_square());
+  else
+      fen += '-';
 
-  result += ' ';
-  if(ep_square() == SQ_NONE) result += '-';
-  else result += square_to_string(ep_square());
-
-  return result;
+  return fen;
 }
 
 
@@ -285,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
@@ -333,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);
@@ -343,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);
@@ -361,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));
 }
 
 
@@ -375,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 {
@@ -396,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;
   }
 
@@ -539,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:
@@ -571,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?
@@ -579,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?
@@ -587,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?
@@ -658,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);
   }
 
@@ -837,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];
@@ -872,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:
@@ -1620,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:
@@ -2099,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;
@@ -2114,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++)
@@ -2141,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);
@@ -2150,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))
@@ -2174,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.
@@ -2182,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;
@@ -2202,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;
@@ -2210,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++)
@@ -2227,6 +2269,6 @@ bool Position::is_ok() const {
             return false;
         }
   }
-
+  if (failedStep) *failedStep = 0;
   return true;
 }