2023-12-31 09:26:20 -08:00
|
|
|
// Eryn Wells <eryn@erynwells.me>
|
|
|
|
|
|
|
|
|
|
use super::BitBoard;
|
2024-01-01 09:25:31 -08:00
|
|
|
use crate::Square;
|
|
|
|
|
use std::sync::Once;
|
2023-12-31 09:26:20 -08:00
|
|
|
|
|
|
|
|
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),
|
|
|
|
|
];
|
2024-01-01 09:25:31 -08:00
|
|
|
|
|
|
|
|
static mut MOVE_LIBRARY: MoveLibrary = MoveLibrary::new();
|
|
|
|
|
static MOVE_LIBRARY_INIT: Once = Once::new();
|
|
|
|
|
|
|
|
|
|
pub(super) fn library() -> &'static MoveLibrary {
|
|
|
|
|
unsafe {
|
|
|
|
|
MOVE_LIBRARY_INIT.call_once(|| {
|
|
|
|
|
MOVE_LIBRARY.initialize_if_needed();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
&MOVE_LIBRARY
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) struct MoveLibrary {
|
|
|
|
|
is_initialized: bool,
|
|
|
|
|
|
|
|
|
|
// Piecewise move tables
|
|
|
|
|
king_moves: [BitBoard; 64],
|
|
|
|
|
knight_moves: [BitBoard; 64],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MoveLibrary {
|
|
|
|
|
const fn new() -> MoveLibrary {
|
|
|
|
|
MoveLibrary {
|
|
|
|
|
is_initialized: false,
|
|
|
|
|
king_moves: [BitBoard::empty(); 64],
|
|
|
|
|
knight_moves: [BitBoard::empty(); 64],
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn initialize_if_needed(&mut self) {
|
|
|
|
|
if self.is_initialized {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.do_initialization();
|
|
|
|
|
self.is_initialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn do_initialization(&mut self) {
|
|
|
|
|
self.initialize_king_moves();
|
|
|
|
|
self.initialize_knight_moves();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn initialize_king_moves(&mut self) {
|
|
|
|
|
for i in 0..64 {
|
|
|
|
|
let king = BitBoard::new(1 << i);
|
|
|
|
|
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[i] = 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 initialize_knight_moves(&mut self) {
|
|
|
|
|
for i in 0..64 {
|
|
|
|
|
let knight = BitBoard::new(1 << i);
|
|
|
|
|
|
|
|
|
|
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[i] = attacks;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn knight_moves(&self, sq: Square) -> BitBoard {
|
|
|
|
|
self.knight_moves[sq.index() as usize]
|
|
|
|
|
}
|
|
|
|
|
}
|