From 962216440c186d067d8946112acab847ccb7249f Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 23 Feb 2009 15:19:51 +0100 Subject: [PATCH 1/1] Teach SEE about pinned pieces Remove pinned pieces from attacks when calculating SEE value. Algorithm is not perfect, there should be no false positives, but can happen that we miss to remove a pinned piece. Currently we don't cach 100% of cases, but is a tradeoff between speed and accuracy. In any case we stay on the safe side, so we remove an attacker when we are sure it is pinned. About only 0,5% of cases are affected by this patch, not a lot given the hard work: this is a difficult patch! Signed-off-by: Marco Costalba --- src/position.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index cc0f42e9..0a275b5e 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1491,7 +1491,7 @@ void Position::undo_null_move() { /// Position::see() is a static exchange evaluator: It tries to estimate the -/// material gain or loss resulting from a move. There are three versions of +/// 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 captures. @@ -1528,6 +1528,11 @@ int Position::see(Square from, Square to) const { Color us = (from != SQ_NONE ? color_of_piece_on(from) : opposite_color(color_of_piece_on(to))); Color them = opposite_color(us); + // Initialize pinned and pinners bitboards + Bitboard pinned[2], pinners[2]; + pinned[us] = pinned_pieces(us, pinners[us]); + pinned[them] = pinned_pieces(them, pinners[them]); + // Initialize pieces Piece piece = piece_on(from); Piece capture = piece_on(to); @@ -1560,6 +1565,17 @@ int Position::see(Square from, Square to) const { | (pawn_attacks(WHITE, to) & pawns(BLACK)) | (pawn_attacks(BLACK, to) & pawns(WHITE)); + // Remove our pinned pieces from attacks if the captured piece is not + // a pinner, otherwise we could remove a valid "capture the pinner" attack. + if (pinned[us] != EmptyBoardBB && !bit_is_set(pinners[us], to)) + attackers &= ~pinned[us]; + + // Remove opponent pinned pieces from attacks if the moving piece is not + // a pinner, otherwise we could remove a piece that is no more pinned + // due to our pinner piece is moving away. + if (pinned[them] != EmptyBoardBB && !bit_is_set(pinners[them], from)) + attackers &= ~pinned[them]; + if (from != SQ_NONE) break; @@ -1597,7 +1613,7 @@ int Position::see(Square from, Square to) const { swapList[0] = seeValues[capture]; do { - // Locate the least valuable attacker for the side to move. The loop + // Locate the least valuable attacker for the side to move. The loop // below looks like it is potentially infinite, but it isn't. We know // that the side to move still has at least one attacker left. for (pt = PAWN; !(attackers & pieces_of_color_and_type(c, pt)); pt++) @@ -1622,6 +1638,12 @@ int Position::see(Square from, Square to) const { lastCapturingPieceValue = seeValues[pt]; c = opposite_color(c); + // Remove pinned pieces from attackers + if ( pinned[c] != EmptyBoardBB + && !bit_is_set(pinners[c], to) + && !(pinners[c] & attackers)) + attackers &= ~pinned[c]; + // Stop after a king capture if (pt == KING && (attackers & pieces_of_color(c))) { -- 2.39.2