1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-07-11 19:49:14 +00:00

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 <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2011-05-22 10:57:06 +01:00
parent 21fc66c246
commit 13fe7ee4df
2 changed files with 45 additions and 39 deletions

View file

@ -490,6 +490,16 @@ Bitboard Position::attackers_to(Square s) const {
| (attacks_from<KING>(s) & pieces(KING)); | (attacks_from<KING>(s) & pieces(KING));
} }
Bitboard Position::attackers_to(Square s, Bitboard occ) const {
return (attacks_from<PAWN>(s, BLACK) & pieces(PAWN, WHITE))
| (attacks_from<PAWN>(s, WHITE) & pieces(PAWN, BLACK))
| (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
| (rook_attacks_bb(s, occ) & pieces(ROOK, QUEEN))
| (bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN))
| (attacks_from<KING>(s) & pieces(KING));
}
/// Position::attacks_from() computes a bitboard of all attacks /// Position::attacks_from() computes a bitboard of all attacks
/// of a given piece put in a given square. /// 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(move_is_ok(m));
assert(pinned == pinned_pieces(side_to_move())); 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 // En passant captures are a tricky special case. Because they are
// rather uncommon, we do it simply by testing whether the king is attacked // rather uncommon, we do it simply by testing whether the king is attacked
// after the move is made // 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)); && !(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 // If the moving piece is a king, check whether the destination
// square is attacked by the opponent. Castling moves are checked // square is attacked by the opponent. Castling moves are checked
// for legality during move generation. // 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) /// 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 /// move and tests whether the move is legal. This version is not very fast and
/// should be used only in non time-critical paths. /// 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)) else if (!bit_is_set(attacks_from(pc, from), to))
return false; 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 // 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 // Find all attackers to the destination square, with the moving piece
// removed, but possibly an X-ray attacker added behind it. // removed, but possibly an X-ray attacker added behind it.
clear_bit(&occupied, from); clear_bit(&occupied, from);
attackers = (rook_attacks_bb(to, occupied) & pieces(ROOK, QUEEN)) attackers = attackers_to(to, occupied);
| (bishop_attacks_bb(to, occupied)& pieces(BISHOP, QUEEN))
| (attacks_from<KNIGHT>(to) & pieces(KNIGHT))
| (attacks_from<KING>(to) & pieces(KING))
| (attacks_from<PAWN>(to, WHITE) & pieces(PAWN, BLACK))
| (attacks_from<PAWN>(to, BLACK) & pieces(PAWN, WHITE));
// If the opponent has no attackers we are finished // If the opponent has no attackers we are finished
stm = opposite_color(color_of_piece_on(from)); stm = opposite_color(color_of_piece_on(from));

View file

@ -178,6 +178,7 @@ public:
// Information about attacks to or from a given square // Information about attacks to or from a given square
Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s) const;
Bitboard attackers_to(Square s, Bitboard occ) const;
Bitboard attacks_from(Piece p, Square s) const; Bitboard attacks_from(Piece p, Square s) const;
static Bitboard attacks_from(Piece p, Square s, Bitboard occ); static Bitboard attacks_from(Piece p, Square s, Bitboard occ);
template<PieceType> Bitboard attacks_from(Square s) const; template<PieceType> Bitboard attacks_from(Square s) const;
@ -185,7 +186,6 @@ public:
// Properties of moves // Properties of moves
bool pl_move_is_legal(Move m, Bitboard pinned) const; 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) const;
bool move_is_legal(const Move m, Bitboard pinned) const; bool move_is_legal(const Move m, Bitboard pinned) const;
bool move_gives_check(Move m) const; bool move_gives_check(Move m) const;