Test for opponent being in check during validation

This commit is contained in:
Bruno BELANYI 2022-07-30 11:58:18 +02:00
parent f13d44b8e3
commit 168d9e69ab

View file

@ -1,4 +1,9 @@
use crate::{error::Error, movegen::magic::king_moves};
use crate::{
error::Error,
movegen::{
bishop_moves, knight_moves, magic::king_moves, naive::pawn::pawn_captures, rook_moves,
},
};
use super::{Bitboard, CastleRights, Color, File, FromFen, Move, Piece, Rank, Square};
@ -274,10 +279,50 @@ impl ChessBoard {
return false;
}
// FIXME: check for opponent being in check.
// Check that the opponent is not currently in check.
if (self.compute_checkers(!self.current_player())) != Bitboard::EMPTY {
return false;
}
true
}
/// Compute all pieces that are currently threatening the given [Color]'s king.
fn compute_checkers(&self, color: Color) -> Bitboard {
// Unwrap is fine, there should always be exactly one king per color
let king = (self.piece_occupancy(Piece::King) & self.color_occupancy(color))
.try_into_square()
.unwrap();
let opponent = !color;
// No need to remove our pieces from the generated moves, we just want to check if we
// intersect with the opponent's pieces, rather than generate only valid moves.
let bishops = {
let queens = self.piece_occupancy(Piece::Queen) & self.color_occupancy(opponent);
let bishops = self.piece_occupancy(Piece::Bishop) & self.color_occupancy(opponent);
let bishop_attacks = bishop_moves(king, self.combined_occupancy());
(queens | bishops) & bishop_attacks
};
let rooks = {
let queens = self.piece_occupancy(Piece::Queen) & self.color_occupancy(opponent);
let rooks = self.piece_occupancy(Piece::Rook) & self.color_occupancy(opponent);
let rook_attacks = rook_moves(king, self.combined_occupancy());
(queens | rooks) & rook_attacks
};
let knights = {
let knights = self.piece_occupancy(Piece::Knight) & self.color_occupancy(opponent);
let knight_attacks = knight_moves(king);
knights & knight_attacks
};
let pawns = {
let pawns = self.piece_occupancy(Piece::Pawn) & self.color_occupancy(opponent);
let pawn_attacks = pawn_captures(color, king);
pawns & pawn_attacks
};
bishops | rooks | knights | pawns
}
}
/// Use the starting position as a default value, corresponding to the
@ -652,6 +697,34 @@ mod test {
assert!(!position.is_valid());
}
#[test]
fn invalid_opponent_in_check() {
let position = ChessBoard {
piece_occupancy: [
// King
Square::E1 | Square::E8,
// Queen
Square::E7.into_bitboard(),
// Rook
Bitboard::EMPTY,
// Bishop
Bitboard::EMPTY,
// Knight
Bitboard::EMPTY,
// Pawn
Bitboard::EMPTY,
],
color_occupancy: [Square::E1 | Square::E7, Square::E8.into_bitboard()],
combined_occupancy: Square::E1 | Square::E7 | Square::E8,
castle_rights: [CastleRights::NoSide; 2],
en_passant: None,
half_move_clock: 0,
total_plies: 0,
side: Color::White,
};
assert!(!position.is_valid());
}
#[test]
fn fen_default_position() {
let default_position = ChessBoard::default();