use crate::board::Board;
use crate::movegen::{apply_move, generate_pseudo_legal_moves};
use crate::types::{Color, Move, MoveFlag, PieceType, Square, file_of, rank_of};
use super::types::BoardPiece;
pub fn get_direct_attackers(board: &Board, square: Square, by_color: Color) -> Vec<BoardPiece> {
let attacker_board = with_side_to_move(board, by_color);
generate_pseudo_legal_moves(&attacker_board)
.into_iter()
.filter(|mv| capture_square(mv) == square)
.filter_map(|mv| {
board.piece_at(mv.from).map(|p| BoardPiece::new(p, mv.from))
})
.collect::<Vec<_>>()
.into_iter()
.fold(Vec::new(), |mut acc, bp| {
if !acc.iter().any(|x: &BoardPiece| x.square == bp.square) {
acc.push(bp);
}
acc
})
}
pub fn get_attackers(board: &Board, square: Square, by_color: Color) -> Vec<BoardPiece> {
let mut all_attackers = get_direct_attackers(board, square, by_color);
let mut frontier: Vec<(Board, Square, PieceType)> = all_attackers
.iter()
.map(|bp| (board.clone(), bp.square, bp.piece.piece_type))
.collect();
while let Some((ref_board, front_sq, front_type)) = frontier.pop() {
if front_type == PieceType::King {
continue;
}
let mut scratch = ref_board.clone();
scratch.set_piece(front_sq, None);
let revealed = get_direct_attackers(&scratch, square, by_color)
.into_iter()
.filter(|bp| !all_attackers.iter().any(|a| a.square == bp.square))
.collect::<Vec<_>>();
for bp in revealed {
frontier.push((scratch.clone(), bp.square, bp.piece.piece_type));
all_attackers.push(bp);
}
}
all_attackers
}
pub fn capture_square(mv: &Move) -> Square {
if mv.flag == MoveFlag::EnPassant {
let rank = rank_of(mv.from);
let file = file_of(mv.to);
rank * 8 + file
} else {
mv.to
}
}
pub fn with_side_to_move(board: &Board, color: Color) -> Board {
let mut b = board.clone();
b.side_to_move = color;
b
}
pub fn try_apply_move(board: &Board, mv: &Move) -> Option<Board> {
let pseudo = generate_pseudo_legal_moves(board);
if pseudo.iter().any(|m| m == mv) {
Some(apply_move(board, mv))
} else {
None
}
}
pub fn any_move_is_checkmate(board: &Board) -> bool {
use crate::movegen::{generate_legal_moves, is_in_check};
let moves = generate_legal_moves(board);
moves.iter().any(|mv| {
let next = apply_move(board, mv);
let legal_responses = generate_legal_moves(&next);
legal_responses.is_empty() && is_in_check(&next, next.side_to_move)
})
}