pub mod drop_mate;
pub mod helpers;
pub mod move_mate;
pub mod tables;
use crate::bitboard::{
Bitboard, RANK_BB, bishop_effect, king_effect, lance_effect, line_bb, rook_effect,
};
use crate::position::Position;
use crate::types::{Color, Move, Square};
#[inline]
pub fn can_promote(c: Color, from: Square, to: Square) -> bool {
let enemy = enemy_field(c);
enemy.contains(from) || enemy.contains(to)
}
#[inline]
pub fn can_promote_to(c: Color, to: Square) -> bool {
enemy_field(c).contains(to)
}
#[inline]
pub fn aligned(s1: Square, s2: Square, s3: Square) -> bool {
let line = line_bb(s1, s2);
line.contains(s3)
}
#[inline]
pub fn rook_step_effect(sq: Square) -> Bitboard {
rook_effect(sq, Bitboard::EMPTY)
}
#[inline]
pub fn bishop_step_effect(sq: Square) -> Bitboard {
bishop_effect(sq, Bitboard::EMPTY)
}
#[inline]
pub fn lance_step_effect(us: Color, sq: Square) -> Bitboard {
lance_effect(us, sq, Bitboard::EMPTY)
}
#[inline]
pub fn cross45_step_effect(sq: Square) -> Bitboard {
bishop_step_effect(sq) & king_effect(sq)
}
#[inline]
pub fn queen_step_effect(sq: Square) -> Bitboard {
rook_step_effect(sq) | bishop_step_effect(sq)
}
#[inline]
fn enemy_field(us: Color) -> Bitboard {
match us {
Color::Black => RANK_BB[0] | RANK_BB[1] | RANK_BB[2],
Color::White => RANK_BB[6] | RANK_BB[7] | RANK_BB[8],
}
}
pub fn mate_1ply(pos: &mut Position) -> Option<Move> {
if pos.in_check() {
return None;
}
let us = pos.side_to_move();
if let Some(mv) = drop_mate::check_drop_mate(pos, us) {
return Some(mv);
}
if let Some(mv) = move_mate::check_move_mate(pos, us) {
return Some(mv);
}
None
}
pub fn init() {
let _ = &*tables::CHECK_CAND_BB;
let _ = &*tables::CHECK_AROUND_BB;
let _ = &*tables::NEXT_SQUARE;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_module_structure() {
init();
}
#[test]
fn test_aligned() {
let s1 = Square::SQ_55;
let s2 = Square::new(crate::types::File::File5, crate::types::Rank::Rank1);
let s3 = Square::new(crate::types::File::File5, crate::types::Rank::Rank9);
assert!(aligned(s1, s2, s3));
let other = Square::new(crate::types::File::File4, crate::types::Rank::Rank4);
assert!(!aligned(s1, s2, other));
}
#[test]
fn test_can_promote() {
let from = Square::new(crate::types::File::File5, crate::types::Rank::Rank3);
let to = Square::new(crate::types::File::File5, crate::types::Rank::Rank4);
assert!(can_promote(Color::Black, from, to));
assert!(can_promote_to(Color::White, from.inverse()));
}
fn mate_by_new(sfen: &str) -> Option<Move> {
let mut pos = Position::new();
pos.set_sfen(sfen).unwrap();
super::mate_1ply(&mut pos)
}
#[test]
fn test_hirate_no_mate() {
let sfen = crate::position::SFEN_HIRATE;
assert_eq!(mate_by_new(sfen), None);
}
#[test]
fn test_drop_mate_gold_corner() {
let sfen = "7Pk/6R2/9/9/9/9/9/9/4K4 b G 1";
let new_mv = mate_by_new(sfen);
assert!(new_mv.is_some());
}
#[test]
fn test_move_mate_gold_like_2hop() {
let sfen = "ln1gk2nl/1rs6/2pppp+R+B1/p7p/9/2P5P/P1+pP+bPP2/3G2S2/LN2KG1NL w GSs5p 38";
let mv = mate_by_new(sfen);
assert!(mv.is_some(), "mate_1ply should find 7g6h mate");
assert_eq!(mv.unwrap().to_usi(), "7g6h");
}
}