diff --git a/engine/src/bitboard.rs b/engine/src/bitboard.rs index 7da5b04..d79d167 100644 --- a/engine/src/bitboard.rs +++ b/engine/src/bitboard.rs @@ -7,4 +7,5 @@ mod movegen; pub mod board; pub(in super) mod bitmove; -pub(in super) mod movebuffer; \ No newline at end of file +pub(in super) mod movebuffer; +pub(in super) mod makemove; \ No newline at end of file diff --git a/engine/src/bitboard/board.rs b/engine/src/bitboard/board.rs index 483f1c4..ff80f61 100644 --- a/engine/src/bitboard/board.rs +++ b/engine/src/bitboard/board.rs @@ -1,3 +1,5 @@ +use crate::bitboard::utils::notation_from_square_number; + use super::utils::try_get_square_number_from_notation; pub struct Board { @@ -12,6 +14,7 @@ pub struct Board { } impl Board { + pub const EMPTY_SQUARE: u8 = 12; pub fn new_clear() -> Self { let mut bit_board: Self = Self { @@ -159,6 +162,57 @@ impl Board { return if self.side_to_move == 0 { self.bitboards[5].trailing_zeros() } else { self.bitboards[11].trailing_zeros() }; } + pub fn fen(&self) -> String { + let mut fen = String::new(); + + for row in (0..8).rev() { + let mut empty = 0; + for col in 0..8 { + let sq = row * 8 + col; + if let Some(piece) = self.get_piece_character(sq) { + if empty > 0 { + fen.push_str(&empty.to_string()); + empty = 0; + } + fen.push(piece); + } else { + empty += 1; + if col == 7 { + fen.push_str(&empty.to_string()); + } + } + } + if row > 0 { + fen.push('/'); + } + } + + fen.push(' '); + if self.side_to_move() == 0 { fen.push('w'); } else { fen.push('b'); } + + fen.push(' '); + if self.castling_rights() == 0 { + fen.push('-'); + } else { + if self.castling_rights() & (1 << 3) != 0 { fen.push('K'); } + if self.castling_rights() & (1 << 2) != 0 { fen.push('Q'); } + if self.castling_rights() & (1 << 1) != 0 { fen.push('k'); } + if self.castling_rights() & (1 << 0) != 0 { fen.push('q'); } + } + + fen.push(' '); + if self.en_passant_square() == 0 { + fen.push('-'); + } else { + let sq = self.en_passant_square().trailing_zeros(); + fen.push_str(¬ation_from_square_number(sq as u8)); + } + + fen.push_str(" 0 1"); + + return fen; + } + fn calc_occupancy(&mut self) { self.occupancy = [0u64; 3]; for b in 0..6 { @@ -196,4 +250,46 @@ impl Board { _ => () } } + pub fn get_piece_character(&self, index: i32) -> Option { + let sq = 1 << index; + + if (self.bitboards[0] & sq) != 0 { + return Some('P'); + } + if (self.bitboards[1] & sq) != 0 { + return Some('N'); + } + if (self.bitboards[2] & sq) != 0 { + return Some('B'); + } + if (self.bitboards[3] & sq) != 0 { + return Some('R'); + } + if (self.bitboards[4] & sq) != 0 { + return Some('Q'); + } + if (self.bitboards[5] & sq) != 0 { + return Some('K'); + } + if (self.bitboards[6] & sq) != 0 { + return Some('p'); + } + if (self.bitboards[7] & sq) != 0 { + return Some('n'); + } + if (self.bitboards[8] & sq) != 0 { + return Some('b'); + } + if (self.bitboards[9] & sq) != 0 { + return Some('r'); + } + if (self.bitboards[10] & sq) != 0 { + return Some('q'); + } + if (self.bitboards[11] & sq) != 0 { + return Some('k'); + } + + return None; + } } \ No newline at end of file diff --git a/engine/src/bitboard/makemove.rs b/engine/src/bitboard/makemove.rs new file mode 100644 index 0000000..f896377 --- /dev/null +++ b/engine/src/bitboard/makemove.rs @@ -0,0 +1,38 @@ +mod quiets; +mod captures; +mod castles; + +use super::bitmove::BitMoveType; +use super::bitmove::BitMove; +use super::board::Board; + +impl Board { + + #[inline] + pub fn make_move(&mut self, played_move: &BitMove) { + let move_type = played_move.move_type(); + + match move_type { + BitMoveType::Quiet => { + self.make_quiet(played_move); + } + BitMoveType::Capture => { + self.make_capture(played_move); + } + BitMoveType::Castle => { + self.make_castle(played_move); + } + BitMoveType::EnPassant => { + + } + } + + self.occupancy[2] = self.occupancy[0] | self.occupancy[1]; + + if self.en_passant_square != 0 { + self.en_passant_square = 0u64; + } + + self.side_to_move = 1 - self.side_to_move; + } +} \ No newline at end of file diff --git a/engine/src/bitboard/makemove/captures.rs b/engine/src/bitboard/makemove/captures.rs new file mode 100644 index 0000000..66814bd --- /dev/null +++ b/engine/src/bitboard/makemove/captures.rs @@ -0,0 +1,82 @@ +use super::*; + +impl Board { + pub fn make_capture(&mut self, played_move: &BitMove) { + let main_from: usize = played_move.from_square() as usize; + let main_to: usize = played_move.to_square() as usize; + let main_piece: usize = self.piece_board(main_from as u8) as usize; + let friendly_occupancy = main_piece/6; + + let color_offset = self.side_to_move * 6; + let castling_offset = 2 - 2 * self.side_to_move as usize; + let castling_rights = self.castling_rights >> castling_offset; + + let mut taken_piece = 0u8; + + taken_piece = self.piece_board(main_to as u8); + let secondary_piece = taken_piece as usize; + let secondary_from = main_to; + + let opponent_castling_offset = 2 * self.side_to_move as usize; + let opponent_castling_rights = self.castling_rights >> opponent_castling_offset; + + let opponent_occupancy = 1 - self.side_to_move as usize; + + self.bitboards[main_piece] &= !(1 << main_from); + self.occupancy[friendly_occupancy] &= !(1 << main_from); + self.piece_board[main_from] = Self::EMPTY_SQUARE; + + self.bitboards[secondary_piece] &= !(1 << secondary_from); + self.occupancy[opponent_occupancy] &= !(1 << secondary_from); + self.piece_board[secondary_from] = Self::EMPTY_SQUARE; + + if opponent_castling_rights != 0 + && secondary_piece == 9 - color_offset as usize{ + + let back_rank_offset = 56 - 56 * self.side_to_move as usize; + if opponent_castling_rights & 0b01 != 0 + && secondary_from == back_rank_offset { + self.castling_rights &= !(1 << opponent_castling_offset); + } + else if opponent_castling_rights & 0b10 != 0 + && secondary_from == 7 + back_rank_offset { + self.castling_rights &= !(2 << opponent_castling_offset); + } + } + + if let Some(promotion_piece) = played_move.promotion_piece() { + let promotion_piece = (color_offset + promotion_piece) as usize; + self.bitboards[promotion_piece] |= 1 << main_to; + self.occupancy[friendly_occupancy] |= 1 << main_to; + self.piece_board[main_to] = promotion_piece as u8; + } + else { + self.bitboards[main_piece] |= 1 << main_to; + self.occupancy[friendly_occupancy] |= 1 << main_to; + self.piece_board[main_to] = main_piece as u8; + + if main_piece == 5 + color_offset as usize + && castling_rights != 0 { + if castling_rights & 0b1 != 0 { + self.castling_rights &= !(1 << castling_offset); + } + if castling_rights & 0b10 != 0 { + self.castling_rights &= !(2 << castling_offset); + } + } + else if main_piece == 3 + color_offset as usize + && castling_rights != 0 { + let back_rank_offset = 56 * self.side_to_move as usize; + + if castling_rights & 0b10 != 0 + && main_from == 7 + back_rank_offset { + self.castling_rights &= !(2 << castling_offset); + } + else if castling_rights & 0b1 != 0 + && main_from == back_rank_offset { + self.castling_rights &= !(1 << castling_offset); + } + } + } + } +} \ No newline at end of file diff --git a/engine/src/bitboard/makemove/castles.rs b/engine/src/bitboard/makemove/castles.rs new file mode 100644 index 0000000..5025631 --- /dev/null +++ b/engine/src/bitboard/makemove/castles.rs @@ -0,0 +1,35 @@ +use super::*; + +impl Board { + pub fn make_castle(&mut self, played_move: &BitMove) { + let main_from: usize = played_move.from_square() as usize; + let main_to: usize = played_move.to_square() as usize; + let main_piece: usize = self.piece_board(main_from as u8) as usize; + let friendly_occupancy = main_piece/6; + + let castling_offset = 2 - 2 * self.side_to_move as usize; + + let secondary_piece: usize = main_piece - 2; + let is_kingside = main_to%8 > 4; + let secondary_from: usize = if is_kingside { main_to + 1 } else { main_to - 2 }; + let secondary_to: usize = if is_kingside { main_to - 1 } else { main_to + 1 }; + + self.bitboards[main_piece] |= 1 << main_to; + self.occupancy[friendly_occupancy] |= 1 << main_to; + self.piece_board[main_to] = main_piece as u8; + + self.bitboards[main_piece] &= !(1 << main_from); + self.occupancy[friendly_occupancy] &= !(1 << main_from); + self.piece_board[main_from] = Self::EMPTY_SQUARE; + + self.bitboards[secondary_piece] |= 1 << secondary_to; + self.occupancy[friendly_occupancy] |= 1 << secondary_to; + self.piece_board[secondary_to] = secondary_piece as u8; + + self.bitboards[secondary_piece] &= !(1 << secondary_from); + self.occupancy[friendly_occupancy] &= !(1 << secondary_from); + self.piece_board[secondary_from] = Self::EMPTY_SQUARE; + + self.castling_rights &= !(3 << castling_offset); + } +} \ No newline at end of file diff --git a/engine/src/bitboard/makemove/quiets.rs b/engine/src/bitboard/makemove/quiets.rs new file mode 100644 index 0000000..7fe5107 --- /dev/null +++ b/engine/src/bitboard/makemove/quiets.rs @@ -0,0 +1,61 @@ +use super::*; + +impl Board { + pub fn make_quiet(&mut self, played_move: &BitMove) { + let main_from: usize = played_move.from_square() as usize; + let main_to: usize = played_move.to_square() as usize; + let main_piece: usize = self.piece_board(main_from as u8) as usize; + let friendly_occupancy = main_piece/6; + + let color_offset = self.side_to_move * 6; + let castling_offset = 2 - 2 * self.side_to_move as usize; + let castling_rights = self.castling_rights >> castling_offset; + + self.bitboards[main_piece] &= !(1 << main_from); + self.occupancy[friendly_occupancy] &= !(1 << main_from); + self.piece_board[main_from] = Self::EMPTY_SQUARE; + + if let Some(promotion_piece) = played_move.promotion_piece() { + let promotion_piece = (color_offset + promotion_piece) as usize; + self.bitboards[promotion_piece] |= 1 << main_to; + self.occupancy[friendly_occupancy] |= 1 << main_to; + self.piece_board[main_to] = promotion_piece as u8; + } + else { + self.bitboards[main_piece] |= 1 << main_to; + self.occupancy[friendly_occupancy] |= 1 << main_to; + self.piece_board[main_to] = main_piece as u8; + + if main_piece == 0 && (main_to - main_from) == 16 { + let new_en_passant = main_to - 8; + self.en_passant_square = 1 << new_en_passant; + } + else if main_piece == 6 && (main_from - main_to) == 16 { + let new_en_passant = main_to + 8; + self.en_passant_square = 1 << new_en_passant; + } + else if main_piece == 5 + color_offset as usize + && castling_rights != 0 { + if castling_rights & 0b1 != 0 { + self.castling_rights &= !(1 << castling_offset); + } + if castling_rights & 0b10 != 0 { + self.castling_rights &= !(2 << castling_offset); + } + } + else if main_piece == 3 + color_offset as usize + && castling_rights != 0 { + let back_rank_offset = 56 * self.side_to_move as usize; + + if castling_rights & 0b10 != 0 + && main_from == 7 + back_rank_offset { + self.castling_rights &= !(2 << castling_offset); + } + else if castling_rights & 0b1 != 0 + && main_from == back_rank_offset { + self.castling_rights &= !(1 << castling_offset); + } + } + } + } +} \ No newline at end of file diff --git a/engine/src/lib.rs b/engine/src/lib.rs index f3f6d39..d603e16 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -43,8 +43,13 @@ pub fn is_game_over(fen: &str) -> Option { } pub fn get_board_after_move(fen: &str, chess_move: &ChessMove) -> String { + let mut board = Board::build(fen); + let played_move = chess_move.to_bitmove(); + println!("get_board_after_move answered"); - return String::from("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + board.make_move(&played_move); + + return board.fen(); } #[cfg(test)] diff --git a/server/Cargo.lock b/server/Cargo.lock index 027f4a3..1037c3d 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -768,7 +768,6 @@ dependencies = [ "env_logger", "futures-util", "log", - "futures-util", "rand 0.9.2", "serde", "serde_json",