[board] Implement a BitBoard MoveLibrary
This struct computes and stores piece moves per square to speed up computation of move lists. Initialize a `static mut` instance once via std::sync::Once, and return a static reference to it. So far, it computes king and knight moves. Make BitBoard::empty() and MoveLibrary::new() const functions, enabling static construction of the MOVE_LIBRARY instance without needing to wrap it in an Option.
This commit is contained in:
		
							parent
							
								
									4a54d8b877
								
							
						
					
					
						commit
						06bfc4ac57
					
				
					 2 changed files with 93 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
// Eryn Wells <eryn@erynwells.me>
 | 
			
		||||
 | 
			
		||||
use super::library::{FILES, RANKS};
 | 
			
		||||
use super::library::{library, FILES, RANKS};
 | 
			
		||||
use super::BitScanner;
 | 
			
		||||
use crate::Square;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
 | 
			
		|||
pub(crate) struct BitBoard(pub(super) u64);
 | 
			
		||||
 | 
			
		||||
impl BitBoard {
 | 
			
		||||
    pub fn empty() -> BitBoard {
 | 
			
		||||
    pub const fn empty() -> BitBoard {
 | 
			
		||||
        BitBoard(0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +28,10 @@ impl BitBoard {
 | 
			
		|||
        FILES[file]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn knight_moves(sq: Square) -> BitBoard {
 | 
			
		||||
        library().knight_moves(sq)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn from_square(sq: Square) -> BitBoard {
 | 
			
		||||
        BitBoard(1 << sq.index())
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
// Eryn Wells <eryn@erynwells.me>
 | 
			
		||||
 | 
			
		||||
use super::BitBoard;
 | 
			
		||||
use crate::Square;
 | 
			
		||||
use std::sync::Once;
 | 
			
		||||
 | 
			
		||||
pub(super) const RANKS: [BitBoard; 8] = [
 | 
			
		||||
    BitBoard(0xFF << 0 * 8),
 | 
			
		||||
| 
						 | 
				
			
			@ -23,3 +25,88 @@ pub(super) const FILES: [BitBoard; 8] = [
 | 
			
		|||
    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 {
 | 
			
		||||
    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]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue