[board] Get king moves from the bitboard library
This commit is contained in:
parent
b95c34f51e
commit
769886086c
3 changed files with 172 additions and 50 deletions
|
@ -9,6 +9,14 @@ use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
|
||||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||||
pub(crate) struct BitBoard(pub(super) u64);
|
pub(crate) struct BitBoard(pub(super) u64);
|
||||||
|
|
||||||
|
macro_rules! moves_getter {
|
||||||
|
($getter_name:ident) => {
|
||||||
|
pub fn $getter_name(sq: Square) -> BitBoard {
|
||||||
|
library().$getter_name(sq)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl BitBoard {
|
impl BitBoard {
|
||||||
pub const fn empty() -> BitBoard {
|
pub const fn empty() -> BitBoard {
|
||||||
BitBoard(0)
|
BitBoard(0)
|
||||||
|
@ -28,9 +36,11 @@ impl BitBoard {
|
||||||
FILES[file]
|
FILES[file]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn knight_moves(sq: Square) -> BitBoard {
|
moves_getter!(knight_moves);
|
||||||
library().knight_moves(sq)
|
moves_getter!(bishop_moves);
|
||||||
}
|
moves_getter!(rook_moves);
|
||||||
|
moves_getter!(queen_moves);
|
||||||
|
moves_getter!(king_moves);
|
||||||
|
|
||||||
pub fn from_square(sq: Square) -> BitBoard {
|
pub fn from_square(sq: Square) -> BitBoard {
|
||||||
BitBoard(1 << sq.index())
|
BitBoard(1 << sq.index())
|
||||||
|
|
|
@ -30,83 +30,195 @@ static mut MOVE_LIBRARY: MoveLibrary = MoveLibrary::new();
|
||||||
static MOVE_LIBRARY_INIT: Once = Once::new();
|
static MOVE_LIBRARY_INIT: Once = Once::new();
|
||||||
|
|
||||||
pub(super) fn library() -> &'static MoveLibrary {
|
pub(super) fn library() -> &'static MoveLibrary {
|
||||||
|
static MOVE_LIBRARY_INIT: Once = Once::new();
|
||||||
|
static mut MOVE_LIBRARY: MoveLibrary = MoveLibrary::new();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
MOVE_LIBRARY_INIT.call_once(|| {
|
MOVE_LIBRARY_INIT.call_once(|| {
|
||||||
MOVE_LIBRARY.initialize_if_needed();
|
MOVE_LIBRARY.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
&MOVE_LIBRARY
|
&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 {
|
pub(super) struct MoveLibrary {
|
||||||
is_initialized: bool,
|
// Rays
|
||||||
|
diagonal_rays: [DiagonalRays; 64],
|
||||||
|
orthogonal_rays: [OrthogonalRays; 64],
|
||||||
|
|
||||||
// Piecewise move tables
|
// Piecewise move tables
|
||||||
king_moves: [BitBoard; 64],
|
|
||||||
knight_moves: [BitBoard; 64],
|
knight_moves: [BitBoard; 64],
|
||||||
|
bishop_moves: [BitBoard; 64],
|
||||||
|
rook_moves: [BitBoard; 64],
|
||||||
|
queen_moves: [BitBoard; 64],
|
||||||
|
king_moves: [BitBoard; 64],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveLibrary {
|
impl MoveLibrary {
|
||||||
const fn new() -> MoveLibrary {
|
const fn new() -> MoveLibrary {
|
||||||
MoveLibrary {
|
MoveLibrary {
|
||||||
is_initialized: false,
|
diagonal_rays: [DiagonalRays::new(); 64],
|
||||||
king_moves: [BitBoard::empty(); 64],
|
orthogonal_rays: [OrthogonalRays::new(); 64],
|
||||||
knight_moves: [BitBoard::empty(); 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 initialize_if_needed(&mut self) {
|
fn init(&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 {
|
for i in 0..64 {
|
||||||
let king = BitBoard::new(1 << i);
|
self.init_orthogonal_rays(i);
|
||||||
let mut attacks = king.shift_east_one() | king.shift_west_one();
|
self.init_diagonal_rays(i);
|
||||||
|
self.init_knight_moves(i as usize);
|
||||||
let king = king | attacks;
|
self.init_bishop_moves(i as usize);
|
||||||
attacks |= king.shift_north_one() | king.shift_south_one();
|
self.init_rook_moves(i as usize);
|
||||||
|
self.init_queen_moves(i as usize);
|
||||||
self.king_moves[i] = attacks;
|
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
|
/// Calculate bitboards representing knight moves from each square on the
|
||||||
/// board. The algorithm is described on the [Chess Programming Wiki][cpw].
|
/// board. The algorithm is described on the [Chess Programming Wiki][cpw].
|
||||||
///
|
///
|
||||||
/// [cpw]: https://www.chessprogramming.org/Knight_Pattern
|
/// [cpw]: https://www.chessprogramming.org/Knight_Pattern
|
||||||
fn initialize_knight_moves(&mut self) {
|
fn init_knight_moves(&mut self, idx: usize) {
|
||||||
for i in 0..64 {
|
let knight = BitBoard::new(1 << idx);
|
||||||
let knight = BitBoard::new(1 << i);
|
|
||||||
|
|
||||||
let east = knight.shift_east_one();
|
let east = knight.shift_east_one();
|
||||||
let west = knight.shift_west_one();
|
let west = knight.shift_west_one();
|
||||||
|
|
||||||
let mut attacks = (east | west).shift_north(2);
|
let mut attacks = (east | west).shift_north(2);
|
||||||
attacks |= (east | west).shift_south(2);
|
attacks |= (east | west).shift_south(2);
|
||||||
|
|
||||||
let east = east.shift_east_one();
|
let east = east.shift_east_one();
|
||||||
let west = west.shift_west_one();
|
let west = west.shift_west_one();
|
||||||
|
|
||||||
attacks |= (east | west).shift_north_one();
|
attacks |= (east | west).shift_north_one();
|
||||||
attacks |= (east | west).shift_south_one();
|
attacks |= (east | west).shift_south_one();
|
||||||
|
|
||||||
self.knight_moves[i] = attacks;
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn knight_moves(&self, sq: Square) -> BitBoard {
|
library_getter!(knight_moves);
|
||||||
self.knight_moves[sq.index() as usize]
|
library_getter!(bishop_moves);
|
||||||
}
|
library_getter!(rook_moves);
|
||||||
|
library_getter!(queen_moves);
|
||||||
|
library_getter!(king_moves);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,13 +87,13 @@ impl<'a> KingMoveGenerator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_bitboards(&mut self) {
|
fn generate_bitboards(&mut self) {
|
||||||
let mut king = self
|
let king = self
|
||||||
.position
|
.position
|
||||||
.bitboard_for_piece(Piece::king(self.color))
|
.bitboard_for_piece(Piece::king(self.color))
|
||||||
.clone();
|
.occupied_squares()
|
||||||
let mut all_moves = king.shift_east_one() | king.shift_west_one();
|
.next()
|
||||||
king |= all_moves;
|
.unwrap();
|
||||||
all_moves |= king.shift_north_one() | king.shift_south_one();
|
let all_moves = BitBoard::king_moves(king);
|
||||||
|
|
||||||
let empty_squares = self.position.empty_squares();
|
let empty_squares = self.position.empty_squares();
|
||||||
let opposing_pieces = self.position.bitboard_for_color(self.color.other());
|
let opposing_pieces = self.position.bitboard_for_color(self.color.other());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue