diff --git a/src/board/bitboard.rs b/src/board/bitboard.rs index b7fe7cb..24d5b78 100644 --- a/src/board/bitboard.rs +++ b/src/board/bitboard.rs @@ -21,6 +21,13 @@ pub const fn square_to_bitboard_wrapping(square: usize) -> Bitboard { 1_u64.wrapping_shl(square as u32) } +pub const fn bitboard_to_coords(bitboard: Bitboard) -> (usize, usize) { + match bitboard { + 0 => (0, 0), + _ => (lsb(bitboard) / 8, lsb(bitboard) % 8), + } +} + pub const fn lsb(bitboard: Bitboard) -> usize { bitboard.trailing_zeros() as usize } diff --git a/src/board/board.rs b/src/board/board.rs index 6ba5179..059492e 100644 --- a/src/board/board.rs +++ b/src/board/board.rs @@ -167,6 +167,18 @@ impl Board { pub fn set_state(&mut self, state: State) { self.state = state; } + + pub fn piece_type_at(&self, square: usize, color: Color) -> Option { + let pieces = match color { + Color::White => &self.white_pieces, + Color::Black => &self.black_pieces, + }; + + pieces + .iter() + .find(|p| have_common_bit(p.bitboard, square_to_bitboard(square))) + .map(|p| p.piece_type) + } } impl Default for Board { @@ -216,6 +228,8 @@ impl PieceType { } use std::ops::{Index, IndexMut}; +use super::bitboard::square_to_bitboard; + impl Index for [Piece] { type Output = Piece; diff --git a/src/board/game.rs b/src/board/game.rs index 08054c3..3aa5e0b 100644 --- a/src/board/game.rs +++ b/src/board/game.rs @@ -1,7 +1,7 @@ use crate::board::fen::from_fen; use String as FenError; -use super::board::Board; +use super::board::{Board, Color}; #[derive(Debug, PartialEq, Eq)] pub struct Game { @@ -22,6 +22,10 @@ impl Game { pub const fn run(&self) { Board::new(); } + + pub const fn current_player(&self) -> Color { + self.board.state.current_player() + } } impl Default for Game { diff --git a/src/board/square.rs b/src/board/square.rs index 86b4416..0e6cca2 100644 --- a/src/board/square.rs +++ b/src/board/square.rs @@ -1,7 +1,3 @@ -use u64 as Bitboard; - -use crate::board::bitboard::lsb; - pub struct Square {} impl Square { @@ -82,13 +78,6 @@ pub const fn coords_to_square(rank: usize, file: usize) -> usize { rank * 8 + file } -pub const fn bitboard_to_coords(bitboard: Bitboard) -> (usize, usize) { - match bitboard { - 0 => (0, 0), - _ => (lsb(bitboard) / 8, lsb(bitboard) % 8), - } -} - pub fn square_to_algebraic(square: usize) -> String { let file = (square % 8) as u8; let rank = (square / 8) as u8; diff --git a/src/board/state.rs b/src/board/state.rs index a00001c..41f22df 100644 --- a/src/board/state.rs +++ b/src/board/state.rs @@ -3,10 +3,10 @@ use crate::{board::board::Color, movegen::r#move::MoveType}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct State { side_to_move: Color, - castling_ability: [Castle; 2], - en_passant_target_square: Option, - halfmove_clock: u8, - fullmove_counter: u8, + pub castling_ability: [Castle; 2], + pub en_passant_target_square: Option, + pub halfmove_clock: u8, + pub fullmove_counter: u8, } impl State { @@ -40,6 +40,17 @@ impl State { self.en_passant_target_square } + pub fn set_en_passant_target_square(&mut self, square: Option) { + self.en_passant_target_square = square; + } + + pub const fn castling_ability(&self, color: Color) -> Castle { + match color { + Color::White => self.castling_ability[0], + Color::Black => self.castling_ability[1], + } + } + pub fn set_castling_ability(&mut self, color: Color, castle: Castle) { match color { Color::White => self.castling_ability[0] = castle, @@ -95,26 +106,23 @@ impl State { } } - pub fn change_side(&mut self) { + pub fn revert_full_move(&mut self, color: Color) { + match color { + Color::White => (), + Color::Black => self.fullmove_counter -= 1, + } + } + + pub fn change_side(&mut self) -> Color { self.side_to_move = match self.side_to_move { Color::White => Color::Black, Color::Black => Color::White, - } - } - - pub const fn next_turn(&self) -> Color { + }; self.side_to_move } - pub fn set_en_passant_target_square(&mut self, square: Option) { - self.en_passant_target_square = square; - } - - pub const fn castling_ability(&self, color: Color) -> Castle { - match color { - Color::White => self.castling_ability[0], - Color::Black => self.castling_ability[1], - } + pub const fn current_player(&self) -> Color { + self.side_to_move } } diff --git a/src/interface/uci.rs b/src/interface/uci.rs index 082f4f8..25b0e5c 100644 --- a/src/interface/uci.rs +++ b/src/interface/uci.rs @@ -101,7 +101,7 @@ pub fn uci_position(position: &mut SplitWhitespace) -> Result { for mv_str in position { let mv = Move::parse_from_str(mv_str)?; - game.board.make_move(&mv, game.board.state.next_turn()); + game.board.make_move(&mv); } Ok(game) diff --git a/src/movegen/attack.rs b/src/movegen/attack.rs index 04c86d9..465a7b4 100644 --- a/src/movegen/attack.rs +++ b/src/movegen/attack.rs @@ -1,10 +1,10 @@ use crate::board::{ bitboard::{ have_common_bit, lsb, square_to_bitboard, square_to_bitboard_wrapping, EMPTY, NOT_FILE_A, - NOT_FILE_AB, NOT_FILE_GH, NOT_FILE_H, + NOT_FILE_AB, NOT_FILE_GH, NOT_FILE_H, bitboard_to_coords }, board::Color, - square::{bitboard_to_coords, coords_to_square}, + square::coords_to_square, }; use u64 as Bitboard; diff --git a/src/movegen/move.rs b/src/movegen/move.rs index 3e1bdf2..e56efc5 100644 --- a/src/movegen/move.rs +++ b/src/movegen/move.rs @@ -15,6 +15,17 @@ pub enum Promote { Queen, } +impl Promote { + pub fn into_piece_type(&self) -> PieceType { + match self { + Promote::Knight => PieceType::Knight, + Promote::Rook => PieceType::Rook, + Promote::Bishop => PieceType::Bishop, + Promote::Queen => PieceType::Queen, + } + } +} + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum MoveType { Quiet, @@ -108,11 +119,8 @@ impl Move { } impl Board { - pub fn make_move(&mut self, mv: &Move, color: Color) { - self.update_board_state(mv, color); - } - - pub fn update_board_state(&mut self, mv: &Move, color: Color) { + pub fn make_move(&mut self, mv: &Move) { + let color = self.state.current_player(); let (own_pieces, opponent_pieces, en_passant_square) = match color { Color::White => ( &mut self.white_pieces, @@ -172,13 +180,13 @@ impl Board { } fn move_piece(src: usize, dst: usize, pieces: &mut [Piece; 6]) { - for p in pieces.iter_mut() { - if have_common_bit(p.bitboard, square_to_bitboard(src)) { + pieces + .iter_mut() + .filter(|p| have_common_bit(p.bitboard, square_to_bitboard(src))) + .for_each(|p| { p.bitboard &= !square_to_bitboard(src); p.bitboard |= square_to_bitboard(dst); - break; - } - } + }); } fn move_rook_castle(king_dst: usize, pieces: &mut [Piece; 6]) { @@ -201,12 +209,12 @@ impl Board { } fn remove_piece(square: usize, pieces: &mut [Piece; 6]) { - for p in pieces.iter_mut() { - if have_common_bit(p.bitboard, square_to_bitboard(square)) { - p.bitboard &= !(square_to_bitboard(square)); - break; - } - } + pieces + .iter_mut() + .filter(|p| have_common_bit(p.bitboard, square_to_bitboard(square))) + .for_each(|p| { + p.bitboard &= !square_to_bitboard(square); + }); } fn remove_pawn_enpassant(square: usize, pieces: &mut [Piece; 6], color: Color) { @@ -225,7 +233,7 @@ impl Board { #[cfg(test)] mod tests { - use crate::board::{board::Color, fen::from_fen, square::Square}; + use crate::board::{fen::from_fen, square::Square}; use crate::movegen::r#move::{Move, MoveType, Promote}; const FEN_QUIET: [&str; 2] = [ @@ -237,7 +245,7 @@ mod tests { fn test_make_move_quiet() -> Result<(), String> { let mut game = from_fen(FEN_QUIET[0])?; let mv = Move::new_with_type(9, 25, MoveType::DoublePush); - game.board.make_move(&mv, Color::White); + game.board.make_move(&mv); assert_eq!(game, from_fen(FEN_QUIET[1])?); Ok(()) @@ -252,7 +260,7 @@ mod tests { fn test_make_move_capture() -> Result<(), String> { let mut game = from_fen(FEN_CAPTURE[0])?; let mv = Move::new_with_type(21, 37, MoveType::Capture); - game.board.make_move(&mv, Color::White); + game.board.make_move(&mv); assert_eq!(game, from_fen(FEN_CAPTURE[1])?); Ok(()) @@ -267,7 +275,7 @@ mod tests { fn test_make_move_en_passant() -> Result<(), String> { let mut game = from_fen(FEN_EN_PASSANT[0])?; let mv = Move::new_with_type(30, 23, MoveType::EnPassant); - game.board.make_move(&mv, Color::Black); + game.board.make_move(&mv); assert_eq!(game, from_fen(FEN_EN_PASSANT[1])?); Ok(()) @@ -282,7 +290,7 @@ mod tests { fn test_make_move_double_push() -> Result<(), String> { let mut game = from_fen(FEN_DOUBLE_PUSH[0])?; let mv = Move::new_with_type(10, 26, MoveType::DoublePush); - game.board.make_move(&mv, Color::White); + game.board.make_move(&mv); assert_eq!(game, from_fen(FEN_DOUBLE_PUSH[1])?); Ok(()) } @@ -296,7 +304,7 @@ mod tests { fn test_make_move_promotion() -> Result<(), String> { let mut game = from_fen(FEN_PROMOTION[0])?; let mv = Move::new_with_type(54, 62, MoveType::Promotion(Promote::Queen)); - game.board.make_move(&mv, Color::White); + game.board.make_move(&mv); assert_eq!(game, from_fen(FEN_PROMOTION[1])?); Ok(()) @@ -311,7 +319,7 @@ mod tests { fn test_make_move_promotion_capture() -> Result<(), String> { let mut game = from_fen(FEN_PROMOTION_CAPTURE[0])?; let mv = Move::new_with_type(54, 61, MoveType::PromotionCapture(Promote::Queen)); - game.board.make_move(&mv, Color::White); + game.board.make_move(&mv); assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE[1])?); Ok(()) @@ -326,7 +334,7 @@ mod tests { fn test_make_move_castle() -> Result<(), String> { let mut game = from_fen(FEN_CASTLE[0])?; let mv = Move::new_with_type(4, 6, MoveType::Castle); - game.board.make_move(&mv, Color::White); + game.board.make_move(&mv); assert_eq!(game, from_fen(FEN_CASTLE[1])?); Ok(()) } diff --git a/src/search/perft.rs b/src/search/perft.rs index 9177c43..8adf3a5 100644 --- a/src/search/perft.rs +++ b/src/search/perft.rs @@ -6,12 +6,12 @@ pub fn driver(game: &mut Game, nodes: &mut u64, depth: u8) { return; } - let color = game.board.state.next_turn(); + let color = game.current_player(); let pseudo_moves = game.board.pseudo_moves_all(color); for mv in pseudo_moves { let original_board = game.board.clone(); - game.board.make_move(&mv, color); + game.board.make_move(&mv); if game.board.king_under_check(color) { game.board = original_board; diff --git a/src/search/search.rs b/src/search/search.rs index fb2f286..eda2ddf 100644 --- a/src/search/search.rs +++ b/src/search/search.rs @@ -5,12 +5,12 @@ pub fn search(game: &mut Game, depth: u8) { return; } - let color = game.board.state.next_turn(); + let color = game.current_player(); let pseudo_moves = game.board.pseudo_moves_all(color); for mv in pseudo_moves { let original_board = game.board.clone(); - game.board.make_move(&mv, color); + game.board.make_move(&mv); if game.board.king_under_check(color) { game.board = original_board;