use crate::board::{MoveList, Position};
use crate::types::{Bitboard, Color, Square};
use super::checks::generate_checks_for_color;
use super::drops::generate_drops_color;
use super::evasions::generate_evasions_for_color;
use super::pieces::{
generate_br_moves, generate_gold_hdk_moves, generate_knight_moves, generate_lance_moves,
generate_pawn_moves, generate_silver_moves,
};
use super::types::{Evasions, EvasionsAll, MoveGenType, NonEvasionsAll};
use super::{Black, ColorMarker, MoveSink, White};
#[inline]
pub fn generate_moves<T: MoveGenType + 'static>(pos: &Position, list: &mut MoveList) {
generate_moves_into::<T, _>(pos, list);
}
#[allow(clippy::too_many_lines)]
#[inline]
pub fn generate_moves_into<T: MoveGenType + 'static, S: MoveSink>(pos: &Position, sink: &mut S) {
match pos.turn() {
Color::BLACK => generate_moves_color::<T, Black>(pos, sink),
Color::WHITE => generate_moves_color::<T, White>(pos, sink),
}
}
pub fn generate_legal_all(pos: &Position, list: &mut MoveList) {
generate_legal_all_into(pos, list);
}
pub fn generate_legal_all_into<S: MoveSink>(pos: &Position, sink: &mut S) {
match pos.turn() {
Color::BLACK => generate_legal_all_for_color::<Black>(pos, sink),
Color::WHITE => generate_legal_all_for_color::<White>(pos, sink),
}
}
pub fn generate_legal_evasions(pos: &Position, list: &mut MoveList) {
generate_legal_evasions_into(pos, list);
}
pub fn generate_legal_evasions_into<S: MoveSink>(pos: &Position, sink: &mut S) {
debug_assert!(!pos.checkers().is_empty(), "generate_legal_evasions_into expects check");
match pos.turn() {
Color::BLACK => generate_legal_evasions_for_color::<Evasions, Black>(pos, sink),
Color::WHITE => generate_legal_evasions_for_color::<Evasions, White>(pos, sink),
}
}
pub fn generate_legal_evasions_all(pos: &Position, list: &mut MoveList) {
generate_legal_evasions_all_into(pos, list);
}
pub fn generate_legal_evasions_all_into<S: MoveSink>(pos: &Position, sink: &mut S) {
debug_assert!(!pos.checkers().is_empty(), "generate_legal_evasions_all_into expects check");
match pos.turn() {
Color::BLACK => generate_legal_evasions_for_color::<EvasionsAll, Black>(pos, sink),
Color::WHITE => generate_legal_evasions_for_color::<EvasionsAll, White>(pos, sink),
}
}
#[inline]
fn generate_legal_evasions_for_color<T: MoveGenType + 'static, C: ColorMarker>(
pos: &Position,
sink: &mut impl MoveSink,
) {
generate_evasions_for_color::<T, C>(pos, sink);
retain_generated_legal_for_color::<C>(pos, sink);
}
#[inline]
fn generate_legal_all_for_color<C: ColorMarker>(pos: &Position, list: &mut impl MoveSink) {
if !pos.checkers().is_empty() {
generate_evasions_for_color::<EvasionsAll, C>(pos, list);
} else {
generate_non_evasions_all_for_color::<C>(pos, list);
}
retain_generated_legal_for_color::<C>(pos, list);
}
#[inline(never)]
pub(super) fn generate_non_evasions_all_for_color<C: ColorMarker>(
pos: &Position,
list: &mut impl MoveSink,
) {
let us = C::COLOR;
let bb = pos.bitboards();
let our_pieces = bb.color_pieces(us);
let occupied = bb.occupied();
let target = !our_pieces;
let pawn_target = target;
generate_pawn_moves::<NonEvasionsAll, C>(pos, list, pawn_target);
generate_lance_moves::<NonEvasionsAll, C>(pos, list, target, occupied);
generate_knight_moves::<NonEvasionsAll, C>(pos, list, target);
generate_silver_moves::<NonEvasionsAll, C>(pos, list, target);
generate_br_moves::<NonEvasionsAll, C>(pos, list, target, occupied);
generate_gold_hdk_moves::<NonEvasionsAll, C>(pos, list, target, occupied);
generate_drops_color::<NonEvasionsAll, C>(pos, list);
}
#[inline]
fn retain_generated_legal_for_color<C: ColorMarker>(pos: &Position, list: &mut impl MoveSink) {
let us = C::COLOR;
let king_sq = pos.king_square(us);
let blockers = pos.blockers_for_king(us);
list.retain_unordered(|mv16| {
if mv16.is_drop() {
return true;
}
let from = mv16.from_sq();
if from == king_sq {
if king_sq.is_none() {
return true;
}
return if C::IS_BLACK {
!pos.is_attacked_by_color_with_king_for::<false>(mv16.to_sq(), king_sq)
} else {
!pos.is_attacked_by_color_with_king_for::<true>(mv16.to_sq(), king_sq)
};
}
if !blockers.test(from) {
return true;
}
if king_sq.is_none() {
return true;
}
Bitboard::is_aligned(from, mv16.to_sq(), king_sq)
});
}
#[allow(clippy::too_many_lines)]
#[inline]
fn generate_moves_color<T: MoveGenType + 'static, C: ColorMarker>(
pos: &Position,
list: &mut impl MoveSink,
) {
use crate::types::Bitboard;
let us = C::COLOR;
let them = C::THEM;
let bb = pos.bitboards();
if T::IS_RECAPTURES {
return;
}
let is_checks = T::IS_CHECKS;
let is_legal = T::IS_LEGAL;
if T::QUIET_CHECKS && !T::CAPTURES && !T::QUIETS {
let all = T::is_generate_all_legal();
generate_checks_for_color::<C>(pos, list, all, true);
if !pos.checkers().is_empty() {
list.retain_unordered(|m| pos.is_pseudo_legal_move(m, all));
}
return;
}
if is_checks {
let all = T::is_generate_all_legal();
generate_checks_for_color::<C>(pos, list, all, false);
if !pos.checkers().is_empty() {
list.retain_unordered(|m| pos.is_pseudo_legal_move(m, all));
}
return;
}
if T::EVASIONS {
debug_assert!(T::CAPTURES && T::QUIETS, "EVASIONS must generate both captures and quiets.");
generate_evasions_for_color::<T, C>(pos, list);
if is_legal {
retain_generated_legal_for_color::<C>(pos, list);
}
return;
}
if is_legal && !pos.checkers().is_empty() {
if T::is_generate_all_legal() {
generate_evasions_for_color::<EvasionsAll, C>(pos, list);
} else {
generate_evasions_for_color::<Evasions, C>(pos, list);
}
retain_generated_legal_for_color::<C>(pos, list);
return;
}
let our_pieces = bb.color_pieces(us);
let their_pieces = bb.color_pieces(them);
let occupied = bb.occupied();
let target = if T::CAPTURES && T::QUIETS {
!our_pieces } else if T::CAPTURES {
their_pieces } else if T::QUIETS {
!occupied } else {
return; };
let enemy_territory = Bitboard::promotion_zone(us);
let pawn_target = if T::IS_QUIETS_PRO_MINUS {
(!occupied).and_not(enemy_territory)
} else if T::IS_CAPTURE_PLUS_PRO {
enemy_territory.and_not(our_pieces) | their_pieces
} else {
target
};
generate_pawn_moves::<T, C>(pos, list, pawn_target);
generate_lance_moves::<T, C>(pos, list, target, occupied);
generate_knight_moves::<T, C>(pos, list, target);
generate_silver_moves::<T, C>(pos, list, target);
generate_br_moves::<T, C>(pos, list, target, occupied); generate_gold_hdk_moves::<T, C>(pos, list, target, occupied);
if T::QUIETS {
generate_drops_color::<T, C>(pos, list);
}
if is_legal {
retain_generated_legal_for_color::<C>(pos, list);
}
}
#[inline]
pub fn generate_moves_to<T: MoveGenType + 'static>(
pos: &Position,
target_sq: Square,
list: &mut MoveList,
) {
generate_moves_to_into::<T, _>(pos, target_sq, list);
}
#[allow(clippy::too_many_lines)]
#[inline]
pub fn generate_moves_to_into<T: MoveGenType + 'static, S: MoveSink>(
pos: &Position,
target_sq: Square,
sink: &mut S,
) {
match pos.turn() {
Color::BLACK => generate_moves_to_color::<T, Black>(pos, target_sq, sink),
Color::WHITE => generate_moves_to_color::<T, White>(pos, target_sq, sink),
}
}
#[allow(clippy::too_many_lines)]
#[inline]
fn generate_moves_to_color<T: MoveGenType + 'static, C: ColorMarker>(
pos: &Position,
target_sq: Square,
list: &mut impl MoveSink,
) {
use crate::types::Bitboard;
debug_assert!(T::IS_RECAPTURES, "generate_moves_to is for Recaptures only");
let us = C::COLOR;
let bb = pos.bitboards();
let is_legal = T::IS_LEGAL;
if target_sq.is_none() {
return;
}
let occupied = bb.occupied();
let target = Bitboard::from_square(target_sq);
let enemy_territory = Bitboard::promotion_zone(us);
let pawn_target = if T::IS_QUIETS_PRO_MINUS {
(!occupied).and_not(enemy_territory)
} else if T::IS_CAPTURE_PLUS_PRO {
enemy_territory.and_not(bb.color_pieces(us)) | bb.color_pieces(us.flip())
} else {
target
};
generate_pawn_moves::<T, C>(pos, list, pawn_target);
generate_lance_moves::<T, C>(pos, list, target, occupied);
generate_knight_moves::<T, C>(pos, list, target);
generate_silver_moves::<T, C>(pos, list, target);
generate_br_moves::<T, C>(pos, list, target, occupied);
generate_gold_hdk_moves::<T, C>(pos, list, target, occupied);
if is_legal {
retain_generated_legal_for_color::<C>(pos, list);
}
}