use crate::board::Board;
use crate::movegen::{apply_move, generate_pseudo_legal_moves};
use crate::types::{Move, PieceType};
use super::attackers::{any_move_is_checkmate, get_direct_attackers, with_side_to_move};
use super::piece_safety::get_unsafe_pieces;
use super::types::BoardPiece;
fn relative_unsafe_piece_attacks(
board: &Board,
threatened_piece: &BoardPiece,
acting_color: crate::types::Color,
last_captured_value: Option<i32>,
) -> Vec<Vec<super::types::BoardPiece>> {
get_unsafe_pieces(board, acting_color, last_captured_value)
.into_iter()
.filter(|up| {
up.square != threatened_piece.square
&& up.piece.piece_type.value() >= threatened_piece.piece.piece_type.value()
})
.map(|up| get_direct_attackers(board, up.square, acting_color.opposite()))
.collect()
}
pub fn move_creates_greater_threat(
board: &Board,
threatened_piece: &BoardPiece,
acting_move: &Move,
) -> bool {
let acting_color = threatened_piece.piece.color;
let acting_board = with_side_to_move(board, acting_color);
let prev_relative_attacks = relative_unsafe_piece_attacks(
&acting_board, threatened_piece, acting_color, None,
);
let pseudo = generate_pseudo_legal_moves(&acting_board);
if !pseudo.iter().any(|m| m == acting_move) {
return false;
}
let after_board = apply_move(&acting_board, acting_move);
let captured_value = board
.piece_at(acting_move.to)
.map(|p| p.piece_type.value());
let new_relative_attacks = relative_unsafe_piece_attacks(
&after_board, threatened_piece, acting_color, captured_value,
);
let has_new_threats = new_relative_attacks.len() > prev_relative_attacks.len();
if has_new_threats {
return true;
}
let is_low_value = threatened_piece.piece.piece_type.value() < PieceType::Queen.value();
is_low_value && any_move_is_checkmate(&after_board)
}
pub fn move_leaves_greater_threat(
board: &Board,
threatened_piece: &BoardPiece,
acting_move: &Move,
) -> bool {
let acting_color = threatened_piece.piece.color;
let acting_board = with_side_to_move(board, acting_color);
let pseudo = generate_pseudo_legal_moves(&acting_board);
if !pseudo.iter().any(|m| m == acting_move) {
return false;
}
let after_board = apply_move(&acting_board, acting_move);
let captured_value = board
.piece_at(acting_move.to)
.map(|p| p.piece_type.value());
let relative_attacks = relative_unsafe_piece_attacks(
&after_board, threatened_piece, acting_color, captured_value,
);
if !relative_attacks.is_empty() {
return true;
}
let is_low_value = threatened_piece.piece.piece_type.value() < PieceType::Queen.value();
is_low_value && any_move_is_checkmate(&after_board)
}
pub fn has_danger_levels(
board: &Board,
threatened_piece: &BoardPiece,
acting_moves: &[Move],
equality_strategy: DangerEqualityStrategy,
) -> bool {
if acting_moves.is_empty() {
return false;
}
acting_moves.iter().all(|mv| match equality_strategy {
DangerEqualityStrategy::Creates => {
move_creates_greater_threat(board, threatened_piece, mv)
}
DangerEqualityStrategy::Leaves => {
move_leaves_greater_threat(board, threatened_piece, mv)
}
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DangerEqualityStrategy {
Creates,
Leaves,
}