From 13fe7ee4df30f5bc15189870ebf5d166e26d9906 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 22 May 2011 10:57:06 +0100 Subject: [PATCH] Bug wrong evasion detection for king moves When we are in check and we move the king then testing with pl_move_is_legal(m, pinned) is not enough becuase we cannot rely on attackers_to() but we have to explicitly remove the king form the occupied bitboard to catch as invalid moves like b1a1 when opposite queen is on c1. Our move generator already produces correct evasions so we just need to add the extra verification to move_is_legal(). No functional change. Signed-off-by: Marco Costalba --- src/position.cpp | 82 ++++++++++++++++++++++++++---------------------- src/position.h | 2 +- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index ceface34..52aa93eb 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -490,6 +490,16 @@ Bitboard Position::attackers_to(Square s) const { | (attacks_from(s) & pieces(KING)); } +Bitboard Position::attackers_to(Square s, Bitboard occ) const { + + return (attacks_from(s, BLACK) & pieces(PAWN, WHITE)) + | (attacks_from(s, WHITE) & pieces(PAWN, BLACK)) + | (attacks_from(s) & pieces(KNIGHT)) + | (rook_attacks_bb(s, occ) & pieces(ROOK, QUEEN)) + | (bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN)) + | (attacks_from(s) & pieces(KING)); +} + /// Position::attacks_from() computes a bitboard of all attacks /// of a given piece put in a given square. @@ -570,6 +580,12 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { assert(move_is_ok(m)); assert(pinned == pinned_pieces(side_to_move())); + Color us = side_to_move(); + Square from = move_from(m); + + assert(color_of_piece_on(from) == us); + assert(piece_on(king_square(us)) == make_piece(us, KING)); + // En passant captures are a tricky special case. Because they are // rather uncommon, we do it simply by testing whether the king is attacked // after the move is made @@ -596,12 +612,6 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { && !(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, them)); } - Color us = side_to_move(); - Square from = move_from(m); - - assert(color_of_piece_on(from) == us); - assert(piece_on(king_square(us)) == make_piece(us, KING)); - // If the moving piece is a king, check whether the destination // square is attacked by the opponent. Castling moves are checked // for legality during move generation. @@ -616,31 +626,6 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { } -/// Position::pl_move_is_evasion() tests whether a pseudo-legal move is a legal evasion - -bool Position::pl_move_is_evasion(Move m, Bitboard pinned) const -{ - assert(in_check()); - - Color us = side_to_move(); - Square from = move_from(m); - Square to = move_to(m); - - // King moves and en-passant captures are verified in pl_move_is_legal() - if (type_of_piece_on(from) == KING || move_is_ep(m)) - return pl_move_is_legal(m, pinned); - - Bitboard target = checkers(); - Square checksq = pop_1st_bit(&target); - - if (target) // double check ? - return false; - - // Our move must be a blocking evasion or a capture of the checking piece - target = squares_between(checksq, king_square(us)) | checkers(); - return bit_is_set(target, to) && pl_move_is_legal(m, pinned); -} - /// Position::move_is_legal() takes a position and a (not necessarily pseudo-legal) /// move and tests whether the move is legal. This version is not very fast and /// should be used only in non time-critical paths. @@ -754,8 +739,34 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const { else if (!bit_is_set(attacks_from(pc, from), to)) return false; + if (in_check()) + { + // In case of king moves under check we have to remove king so to catch + // as invalid moves like b1a1 when opposite queen is on c1. + if (type_of_piece_on(from) == KING) + { + Bitboard b = occupied_squares(); + clear_bit(&b, from); + if (attackers_to(move_to(m), b) & pieces_of_color(opposite_color(us))) + return false; + } + else + { + Bitboard target = checkers(); + Square checksq = pop_1st_bit(&target); + + if (target) // double check ? In this case a king move is required + return false; + + // Our move must be a blocking evasion or a capture of the checking piece + target = squares_between(checksq, king_square(us)) | checkers(); + if (!bit_is_set(target, move_to(m))) + return false; + } + } + // The move is pseudo-legal, check if it is also legal - return in_check() ? pl_move_is_evasion(m, pinned) : pl_move_is_legal(m, pinned); + return pl_move_is_legal(m, pinned); } @@ -1548,12 +1559,7 @@ int Position::see(Move m) const { // Find all attackers to the destination square, with the moving piece // removed, but possibly an X-ray attacker added behind it. clear_bit(&occupied, from); - attackers = (rook_attacks_bb(to, occupied) & pieces(ROOK, QUEEN)) - | (bishop_attacks_bb(to, occupied)& pieces(BISHOP, QUEEN)) - | (attacks_from(to) & pieces(KNIGHT)) - | (attacks_from(to) & pieces(KING)) - | (attacks_from(to, WHITE) & pieces(PAWN, BLACK)) - | (attacks_from(to, BLACK) & pieces(PAWN, WHITE)); + attackers = attackers_to(to, occupied); // If the opponent has no attackers we are finished stm = opposite_color(color_of_piece_on(from)); diff --git a/src/position.h b/src/position.h index 5935181b..e560a097 100644 --- a/src/position.h +++ b/src/position.h @@ -178,6 +178,7 @@ public: // Information about attacks to or from a given square Bitboard attackers_to(Square s) const; + Bitboard attackers_to(Square s, Bitboard occ) const; Bitboard attacks_from(Piece p, Square s) const; static Bitboard attacks_from(Piece p, Square s, Bitboard occ); template Bitboard attacks_from(Square s) const; @@ -185,7 +186,6 @@ public: // Properties of moves bool pl_move_is_legal(Move m, Bitboard pinned) const; - bool pl_move_is_evasion(Move m, Bitboard pinned) const; bool move_is_legal(const Move m) const; bool move_is_legal(const Move m, Bitboard pinned) const; bool move_gives_check(Move m) const; -- 2.39.2