// Eryn Wells use super::BitBoard; use crate::Square; use std::sync::Once; pub(super) const RANKS: [BitBoard; 8] = [ BitBoard(0xFF << 0 * 8), BitBoard(0xFF << 1 * 8), BitBoard(0xFF << 2 * 8), BitBoard(0xFF << 3 * 8), BitBoard(0xFF << 4 * 8), BitBoard(0xFF << 5 * 8), BitBoard(0xFF << 6 * 8), BitBoard(0xFF << 7 * 8), ]; pub(super) const FILES: [BitBoard; 8] = [ BitBoard(0x0101010101010101 << 0), BitBoard(0x0101010101010101 << 1), BitBoard(0x0101010101010101 << 2), BitBoard(0x0101010101010101 << 3), BitBoard(0x0101010101010101 << 4), BitBoard(0x0101010101010101 << 5), BitBoard(0x0101010101010101 << 6), BitBoard(0x0101010101010101 << 7), ]; static mut MOVE_LIBRARY: MoveLibrary = MoveLibrary::new(); static MOVE_LIBRARY_INIT: Once = Once::new(); pub(super) fn library() -> &'static MoveLibrary { static MOVE_LIBRARY_INIT: Once = Once::new(); static mut MOVE_LIBRARY: MoveLibrary = MoveLibrary::new(); unsafe { MOVE_LIBRARY_INIT.call_once(|| { MOVE_LIBRARY.init(); }); &MOVE_LIBRARY } } #[derive(Clone, Copy, Debug)] struct OrthogonalRays { positive_rank: BitBoard, positive_file: BitBoard, negative_rank: BitBoard, negative_file: BitBoard, } impl OrthogonalRays { const fn new() -> OrthogonalRays { OrthogonalRays { positive_rank: BitBoard::empty(), positive_file: BitBoard::empty(), negative_rank: BitBoard::empty(), negative_file: BitBoard::empty(), } } } #[derive(Clone, Copy, Debug)] struct DiagonalRays { positive_diagonal: BitBoard, positive_antidiagonal: BitBoard, negative_diagonal: BitBoard, negative_antidiagonal: BitBoard, } impl DiagonalRays { const fn new() -> DiagonalRays { DiagonalRays { positive_diagonal: BitBoard::empty(), positive_antidiagonal: BitBoard::empty(), negative_diagonal: BitBoard::empty(), negative_antidiagonal: BitBoard::empty(), } } } macro_rules! library_getter { ($name:ident) => { pub(super) fn $name(&self, sq: Square) -> BitBoard { self.$name[sq.index() as usize] } }; } #[derive(Debug)] pub(super) struct MoveLibrary { // Rays diagonal_rays: [DiagonalRays; 64], orthogonal_rays: [OrthogonalRays; 64], // Piecewise move tables knight_moves: [BitBoard; 64], bishop_moves: [BitBoard; 64], rook_moves: [BitBoard; 64], queen_moves: [BitBoard; 64], king_moves: [BitBoard; 64], } impl MoveLibrary { const fn new() -> MoveLibrary { MoveLibrary { diagonal_rays: [DiagonalRays::new(); 64], orthogonal_rays: [OrthogonalRays::new(); 64], knight_moves: [BitBoard::empty(); 64], bishop_moves: [BitBoard::empty(); 64], rook_moves: [BitBoard::empty(); 64], queen_moves: [BitBoard::empty(); 64], king_moves: [BitBoard::empty(); 64], } } fn init(&mut self) { for i in 0..64 { self.init_orthogonal_rays(i); self.init_diagonal_rays(i); self.init_knight_moves(i as usize); self.init_bishop_moves(i as usize); self.init_rook_moves(i as usize); self.init_queen_moves(i as usize); self.init_king_moves(i as usize); } } fn init_orthogonal_rays(&mut self, idx: u8) { let sq = Square::from_index_unsafe(idx); let sq_bb = BitBoard::from_square(sq); let ortho_rays = &mut self.orthogonal_rays[idx as usize]; ortho_rays.positive_file = Self::generate_ray(sq_bb, BitBoard::shift_north_one); ortho_rays.negative_file = Self::generate_ray(sq_bb, BitBoard::shift_south_one); ortho_rays.positive_rank = Self::generate_ray(sq_bb, BitBoard::shift_east_one); ortho_rays.negative_rank = Self::generate_ray(sq_bb, BitBoard::shift_west_one); } fn init_diagonal_rays(&mut self, idx: u8) { let sq = Square::from_index_unsafe(idx); let sq_bb = BitBoard::from_square(sq); let diag_rays = &mut self.diagonal_rays[idx as usize]; diag_rays.positive_diagonal = Self::generate_ray(sq_bb, BitBoard::shift_north_east_one); diag_rays.positive_antidiagonal = Self::generate_ray(sq_bb, BitBoard::shift_north_west_one); diag_rays.negative_diagonal = Self::generate_ray(sq_bb, BitBoard::shift_south_west_one); diag_rays.negative_antidiagonal = Self::generate_ray(sq_bb, BitBoard::shift_south_east_one); } fn init_king_moves(&mut self, idx: usize) { let king = BitBoard::new(1 << idx); let mut attacks = king.shift_east_one() | king.shift_west_one(); let king = king | attacks; attacks |= king.shift_north_one() | king.shift_south_one(); self.king_moves[idx] = attacks; } /// Calculate bitboards representing knight moves from each square on the /// board. The algorithm is described on the [Chess Programming Wiki][cpw]. /// /// [cpw]: https://www.chessprogramming.org/Knight_Pattern fn init_knight_moves(&mut self, idx: usize) { let knight = BitBoard::new(1 << idx); let east = knight.shift_east_one(); let west = knight.shift_west_one(); let mut attacks = (east | west).shift_north(2); attacks |= (east | west).shift_south(2); let east = east.shift_east_one(); let west = west.shift_west_one(); attacks |= (east | west).shift_north_one(); attacks |= (east | west).shift_south_one(); self.knight_moves[idx] = attacks; } fn init_bishop_moves(&mut self, idx: usize) { let diag_rays = self.diagonal_rays[idx]; self.bishop_moves[idx] = diag_rays.positive_diagonal | diag_rays.negative_diagonal | diag_rays.positive_antidiagonal | diag_rays.negative_antidiagonal; } fn init_rook_moves(&mut self, idx: usize) { let ortho_rays = self.orthogonal_rays[idx]; self.rook_moves[idx] = ortho_rays.positive_rank | ortho_rays.negative_rank | ortho_rays.positive_file | ortho_rays.negative_file; } fn init_queen_moves(&mut self, idx: usize) { let rook_moves = self.rook_moves[idx]; let bishop_moves = self.bishop_moves[idx]; self.queen_moves[idx] = rook_moves | bishop_moves; } #[inline] fn generate_ray(sq: BitBoard, shift: fn(&BitBoard) -> BitBoard) -> BitBoard { let mut ray = BitBoard::empty(); let mut iter = shift(&sq); while !iter.is_empty() { ray |= iter; iter = shift(&iter); } ray } library_getter!(knight_moves); library_getter!(bishop_moves); library_getter!(rook_moves); library_getter!(queen_moves); library_getter!(king_moves); }