diff --git a/engine/src/bitboard.rs b/engine/src/bitboard.rs index 67d128d..890ddc2 100644 --- a/engine/src/bitboard.rs +++ b/engine/src/bitboard.rs @@ -1,2 +1,3 @@ mod attackmaps; -mod utils; \ No newline at end of file +mod utils; +pub mod board; \ No newline at end of file diff --git a/engine/src/bitboard/board.rs b/engine/src/bitboard/board.rs new file mode 100644 index 0000000..7ceb4d6 --- /dev/null +++ b/engine/src/bitboard/board.rs @@ -0,0 +1,182 @@ +use super::utils::try_get_square_number_from_notation; + +pub struct Board { + pub(in super) bitboards: [u64; 12], // 0-5 -> white pieces (P, N, B, R, Q, K), 6-11 -> black pieces (p, n, b, r, q, k) + pub(in super) piece_board: [u8; 64], // same as board indexes, 12 -> empty square + pub(in super) occupancy: [u64; 3], // 0 -> white, 1 -> black, 2 -> combined + pub(in super) castling_rights: u8, // 0b0000_KQkq + pub(in super) pinned_squares: [u8; 64], // 0 -> E-W, 1 -> NE-SW, 2 -> N-S, 3 -> SE-NW, 4 -> no pin + pub(in super) pin_mask: u64, // 1 -> pin, 0 -> no pin + pub(in super) en_passant_square: u64, // 1 -> ep square, 0 -> no ep square + pub(in super) side_to_move: u8 // 0 -> white to play, 1 -> black to play +} + +impl Board { + + pub fn new_clear() -> Self { + let mut bit_board: Self = Self { + bitboards: [0x0000_0000_0000_0000; 12], + piece_board: [12; 64], + occupancy: [0x0000_0000_0000_0000; 3], + castling_rights: 0b0000_0000, + pinned_squares: [4; 64], + pin_mask: 0u64, + en_passant_square: 0x0000_0000_0000_0000, + side_to_move: 0 + }; + + return bit_board; + } + pub fn new() -> Self { + let mut bit_board: Board = Self { + bitboards: [0x0000_0000_0000_FF00, + 0x0000_0000_0000_0042, + 0x0000_0000_0000_0024, + 0x0000_0000_0000_0081, + 0x0000_0000_0000_0008, + 0x0000_0000_0000_0010, + 0x00FF_0000_0000_0000, + 0x4200_0000_0000_0000, + 0x2400_0000_0000_0000, + 0x8100_0000_0000_0000, + 0x0800_0000_0000_0000, + 0x1000_0000_0000_0000], + piece_board: [12; 64], + occupancy: [0; 3], + castling_rights: 0b0000_1111, + pinned_squares: [4; 64], + pin_mask: 0u64, + en_passant_square: 0x0000_0000_0000_0000, + side_to_move: 0 + }; + bit_board.calc_occupancy(); + bit_board.calc_piece_board(); + + return bit_board; + } + pub fn build(fen: &str) -> Self { + let mut board: Board = Board::new_clear(); + + let mut col: i32 = 0; + let mut row: i32 = 7; + let pieces: [char; 12] = ['p', 'n', 'b', 'r', 'q', 'k', 'P', 'N', 'B', 'R', 'Q', 'K']; + let mut coming_up: &str = fen; + + for (i, c) in coming_up.chars().enumerate() { + if pieces.contains(&c) { + // board.place_piece(row*8 + col, c); + col += 1; + } + else if ('1'..='8').contains(&c) { + col += c.to_string().parse::().unwrap(); + } + else if c == '/' { + row -= 1; + col = 0; + } + else { + coming_up = &coming_up[i+1..]; + break; + } + } + board.calc_occupancy(); + + match coming_up.chars().next().unwrap() { + 'w' => board.side_to_move = 0, + 'b' => board.side_to_move = 1, + _ => panic!("invalid fen notation / to be handled later") + } + coming_up = &coming_up[2..]; + + for (i, c) in coming_up.chars().enumerate() { + match c { + 'K' => board.castling_rights |= 1 << 3, + 'Q' => board.castling_rights |= 1 << 2, + 'k' => board.castling_rights |= 1 << 1, + 'q' => board.castling_rights |= 1, + '-' => { + coming_up = &coming_up[i+2..]; + break; + } + _ => { + coming_up = &coming_up[i+1..]; + break; + } + } + } + match coming_up.chars().next().unwrap() { + '-' => { + coming_up = &coming_up[1..]; + } + _ => { + let notation = coming_up.split(' ').next().unwrap(); + if let Ok(epsq_index) = try_get_square_number_from_notation(notation) { + board.en_passant_square = 1 << epsq_index; + } + } + } + // board.calc_pinned_squares(); + board.calc_piece_board(); + + return board; + } + + #[inline(always)] + pub fn bitboards(&self, index: usize) -> u64 { + return self.bitboards[index]; + } + #[inline(always)] + pub fn piece_board(&self, sq: u8) -> u8 { + return self.piece_board[sq as usize]; + } + #[inline(always)] + pub fn occupancy(&self, side: usize) -> u64 { + return self.occupancy[side]; + } + #[inline(always)] + pub fn castling_rights(&self) -> u8 { + return self.castling_rights; + } + #[inline(always)] + pub fn pinned_squares(&self, sq: usize) -> u8 { + return self.pinned_squares[sq]; + } + #[inline(always)] + pub fn pin_mask(&self) -> u64 { + return self.pin_mask; + } + #[inline(always)] + pub fn en_passant_square(&self) -> u64 { + return self.en_passant_square; + } + #[inline(always)] + pub fn side_to_move(&self) -> u8 { + return self.side_to_move; + } + + #[inline(always)] + pub fn current_king_square(&self) -> u32 { + return if self.side_to_move == 0 { self.bitboards[5].trailing_zeros() } else { self.bitboards[11].trailing_zeros() }; + } + + fn calc_occupancy(&mut self) { + self.occupancy = [0u64; 3]; + for b in 0..6 { + self.occupancy[0] |= self.bitboards[b]; + } + for b in 6..12 { + self.occupancy[1] |= self.bitboards[b]; + } + self.occupancy[2] = self.occupancy[0] | self.occupancy[1]; + } + fn calc_piece_board(&mut self) { + for sq in 0..64 { + for b in 0..12 { + if (self.bitboards[b as usize] & 1 << sq) != 0 { + self.piece_board[sq] = b; + } + } + } + } + +} \ No newline at end of file diff --git a/engine/src/bitboard/utils.rs b/engine/src/bitboard/utils.rs index a30e503..25d7ba8 100644 --- a/engine/src/bitboard/utils.rs +++ b/engine/src/bitboard/utils.rs @@ -27,6 +27,27 @@ pub fn notation_from_square_number(sq: u8) -> String { return notation; } +pub fn try_get_square_number_from_notation(notation: &str) -> Result { + + let file = match notation.chars().nth(0).unwrap() { + 'a' => 0, + 'b' => 1, + 'c' => 2, + 'd' => 3, + 'e' => 4, + 'f' => 5, + 'g' => 6, + 'h' => 7, + _ => { return Result::Err(()); } + }; + if let Some(rank) = notation.chars().nth(1) { + return Result::Ok(file + 8 * (rank.to_digit(10).unwrap() as u8) - 8); + } + else { + return Result::Err(()); + } +} + // <----- TESTS ----->