diff --git a/src/board/board.rs b/src/board/board.rs index 988c0e8..187d73f 100644 --- a/src/board/board.rs +++ b/src/board/board.rs @@ -164,30 +164,6 @@ impl Board { self.state = state; } - pub fn piece_type_at_color(&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) - } - - pub fn piece_type_at(&self, square: usize) -> Option { - if let Some(at_white) = self.piece_type_at_color(square, Color::White) { - return Some(at_white); - } - - if let Some(at_black) = self.piece_type_at_color(square, Color::Black) { - return Some(at_black); - } - - None - } - pub fn update_game_state( state: &mut State, mv: &Move, @@ -212,6 +188,10 @@ impl Board { p.bitboard &= !square_to_bitboard(src); p.bitboard |= square_to_bitboard(dst); }); + + //TODO: + // pieces[piece_type].bitboard &= !square_to_bitboard(src); + // pieces[piece_type].bitboard |= square_to_bitboard(dst); } pub fn remove_own_piece(&mut self, square: usize) { @@ -234,16 +214,6 @@ impl Board { }); } - pub fn move_rook_castle(&mut self, king_dst: usize) { - let (rook_src, rook_dst) = match king_dst { - Square::C1 | Square::C8 => (king_dst - 2, king_dst + 1), - Square::G1 | Square::G8 => (king_dst + 1, king_dst - 1), - _ => return, - }; - - self.move_piece(rook_src, rook_dst); - } - pub fn promote_piece(&mut self, square: usize, promote: &Promote) { let pieces = self.own_pieces(); match promote { @@ -254,15 +224,6 @@ impl Board { }; } - pub fn remove_pawn_enpassant(&mut self, square: usize, color: Color) { - let piece_to_remove = match color { - Color::White => square - 8, - Color::Black => square + 8, - }; - - self.remove_opponent_piece(piece_to_remove); - } - pub fn is_pawn_move(&mut self, square: usize) -> bool { let pieces = self.own_pieces(); have_common_bit(square_to_bitboard(square), pieces[PieceType::Pawn].bitboard) @@ -331,7 +292,6 @@ impl PieceType { use std::ops::{Index, IndexMut}; use super::bitboard::square_to_bitboard; -use super::square::Square; impl Index for [Piece] { type Output = Piece; @@ -365,7 +325,7 @@ impl Color { #[cfg(test)] mod tests { use crate::{ - board::fen::from_fen, + board::{fen::from_fen, square::Square}, movegen::{attack_generator::init_attacks, r#move::MoveType}, }; diff --git a/src/board/fen.rs b/src/board/fen.rs index e343db9..5b34fea 100644 --- a/src/board/fen.rs +++ b/src/board/fen.rs @@ -25,9 +25,13 @@ pub fn from_fen(fen: &str) -> Result { halfmove_clock, fullmove_counter, )); + + let mailbox = Mailbox::new_from_board(&board); + Ok(Game { board, history: History::new(), + mailbox, }) } @@ -127,6 +131,7 @@ fn castling_ability(castling: &str) -> Result<[Castle; 2], FenError> { use std::collections::HashMap; use super::history::History; +use super::mailbox::Mailbox; fn en_passant_square(square: &str) -> Result, FenError> { let mut sqr = square.chars(); diff --git a/src/board/game.rs b/src/board/game.rs index 4e30f73..b7cad58 100644 --- a/src/board/game.rs +++ b/src/board/game.rs @@ -8,6 +8,7 @@ use super::{ bitboard::square_to_bitboard, board::{Board, Color, PieceType}, history::{History, MoveParameters}, + mailbox::Mailbox, square::Square, state::Castle, }; @@ -20,17 +21,19 @@ impl PartialEq for Game { } } -#[derive(Debug, Eq)] +#[derive(Debug, Clone, Eq)] pub struct Game { pub board: Board, pub history: History, + pub mailbox: Mailbox, } impl Game { - pub const fn new() -> Self { + pub fn new() -> Self { Self { board: Board::new(), history: History::new(), + mailbox: Mailbox::new_from_board(&Board::new()), } } @@ -43,24 +46,34 @@ impl Game { } pub fn make_move(&mut self, mv: &Move) { + self.history + .push_move_parameters(MoveParameters::build(&self, mv)); + let board = &mut self.board; + let mailbox = &mut self.mailbox; let color = board.state.current_player(); let pawn_move = board.is_pawn_move(mv.src); let mut en_passant_square = None; - self.history - .push_move_parameters(MoveParameters::build(board, mv)); match &mv.move_type { MoveType::Quiet => { board.move_piece(mv.src, mv.dst); + mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src)); } MoveType::Capture => { board.move_piece(mv.src, mv.dst); board.remove_opponent_piece(mv.dst); + mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src)); } MoveType::EnPassant => { board.move_piece(mv.src, mv.dst); - board.remove_pawn_enpassant(mv.dst, color); + let piece_to_remove = match color { + Color::White => mv.dst - 8, + Color::Black => mv.dst + 8, + }; + board.remove_opponent_piece(piece_to_remove); + mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src)); + mailbox.set_piece_at(piece_to_remove, None); } MoveType::DoublePush => { board.move_piece(mv.src, mv.dst); @@ -68,29 +81,45 @@ impl Game { Color::White => Some(mv.src + 8), Color::Black => Some(mv.src.saturating_sub(8)), }; + mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src)); } MoveType::Promotion(promote) => { board.remove_own_piece(mv.src); board.promote_piece(mv.dst, promote); + mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type())); } MoveType::PromotionCapture(promote) => { board.remove_own_piece(mv.src); board.remove_opponent_piece(mv.dst); board.promote_piece(mv.dst, promote); + mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type())); } MoveType::Castle => { board.move_piece(mv.src, mv.dst); - board.move_rook_castle(mv.dst); + let (rook_src, rook_dst) = match mv.dst { + Square::C1 | Square::C8 => (mv.dst - 2, mv.dst + 1), + Square::G1 | Square::G8 => (mv.dst + 1, mv.dst - 1), + _ => return, + }; + board.move_piece(rook_src, rook_dst); board.state.set_castling_ability(color, Castle::None); + mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src)); + mailbox.set_piece_at(rook_src, None); + mailbox.set_piece_at(rook_dst, Some(PieceType::Rook)); } } + mailbox.set_piece_at(mv.src, None); Board::update_game_state(&mut board.state, mv, color, pawn_move, en_passant_square); } pub fn unmake_move(&mut self) { let board = &mut self.board; - let move_parameters = &mut self.history.pop_move_parameters().unwrap_or_default(); + let mailbox = &mut self.mailbox; + let move_parameters = &mut self + .history + .pop_move_parameters() + .expect("History stack is empty"); let color_before_move = board.state.change_side(); board.state.revert_full_move(color_before_move); board.state.en_passant_square = move_parameters.en_passant_square; @@ -108,27 +137,42 @@ impl Game { match &mv.move_type { MoveType::Quiet | MoveType::DoublePush => { board.move_piece(mv.dst, mv.src); + mailbox.set_piece_at(mv.src, mailbox.find_piece_at(mv.dst)); + mailbox.set_piece_at(mv.dst, None); } - MoveType::Capture | MoveType::Promotion(_) | MoveType::PromotionCapture(_) => { - if let (Some(captured_piece_type), Some(promoted_piece_type)) = ( - move_parameters.captured_piece, - move_parameters.promoted_piece, - ) { - let (own_pieces, opponent_pieces) = board.all_pieces(); - - opponent_pieces[captured_piece_type].bitboard |= square_to_bitboard(mv.dst); - own_pieces[promoted_piece_type].bitboard &= !square_to_bitboard(mv.dst); - own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src); - } else if let Some(captured_piece_type) = move_parameters.captured_piece { - board.move_piece(mv.dst, mv.src); - let opponent_pieces = board.opponent_pieces(); - opponent_pieces[captured_piece_type].bitboard |= square_to_bitboard(mv.dst); - } else if let Some(promoted_piece_type) = move_parameters.promoted_piece { - let own_pieces = board.own_pieces(); - - own_pieces[promoted_piece_type].bitboard &= !square_to_bitboard(mv.dst); - own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src); - } + MoveType::Capture => { + let captured_piece = move_parameters + .captured_piece + .expect("Expected captured piece to unmake Capture"); + board.move_piece(mv.dst, mv.src); + let opponent_pieces = board.opponent_pieces(); + opponent_pieces[captured_piece].bitboard |= square_to_bitboard(mv.dst); + mailbox.set_piece_at(mv.src, move_parameters.moved_piece); + mailbox.set_piece_at(mv.dst, Some(captured_piece)); + } + MoveType::Promotion(_) => { + let promoted_piece = move_parameters + .promoted_piece + .expect("Expected promoted piece to unmake Promotion"); + let own_pieces = board.own_pieces(); + own_pieces[promoted_piece].bitboard &= !square_to_bitboard(mv.dst); + own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src); + mailbox.set_piece_at(mv.src, Some(PieceType::Pawn)); + mailbox.set_piece_at(mv.dst, None); + } + MoveType::PromotionCapture(_) => { + let promoted_piece = move_parameters + .promoted_piece + .expect("Expected promoted piece to unmake PromotionCapture"); + let captured_piece = move_parameters + .captured_piece + .expect("Expected captured piece to unmake PromotionCapture"); + let (own_pieces, opponent_pieces) = board.all_pieces(); + opponent_pieces[captured_piece].bitboard |= square_to_bitboard(mv.dst); + own_pieces[promoted_piece].bitboard &= !square_to_bitboard(mv.dst); + own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src); + mailbox.set_piece_at(mv.src, Some(PieceType::Pawn)); + mailbox.set_piece_at(mv.dst, Some(captured_piece)); } MoveType::EnPassant => { board.move_piece(mv.dst, mv.src); @@ -138,6 +182,8 @@ impl Game { }; let opponent_pieces = board.opponent_pieces(); opponent_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(enemy_pawn_square); + mailbox.set_piece_at(mv.src, Some(PieceType::Pawn)); + mailbox.set_piece_at(enemy_pawn_square, Some(PieceType::Pawn)); } MoveType::Castle => { board.move_piece(mv.dst, mv.src); @@ -149,6 +195,10 @@ impl Game { let own_pieces = board.own_pieces(); own_pieces[PieceType::Rook].bitboard &= !square_to_bitboard(rook_dst); own_pieces[PieceType::Rook].bitboard |= square_to_bitboard(rook_src); + mailbox.set_piece_at(mv.src, mailbox.find_piece_at(mv.dst)); + mailbox.set_piece_at(mv.dst, None); + mailbox.set_piece_at(rook_src, Some(PieceType::Rook)); + mailbox.set_piece_at(rook_dst, None); } } } diff --git a/src/board/history.rs b/src/board/history.rs index 2643039..c7bbac2 100644 --- a/src/board/history.rs +++ b/src/board/history.rs @@ -1,7 +1,8 @@ -use crate::movegen::r#move::{Move, MoveType, Promote}; +use crate::movegen::r#move::{Move, MoveType}; use super::{ - board::{Board, Color, PieceType}, + board::PieceType, + game::Game, state::{Castle, State}, }; @@ -29,6 +30,7 @@ impl History { #[derive(Debug, Clone, PartialEq, Eq)] pub struct MoveParameters { pub mv: Option, + pub moved_piece: Option, pub captured_piece: Option, pub promoted_piece: Option, pub castling_ability: Option<[Castle; 2]>, @@ -40,6 +42,7 @@ impl MoveParameters { pub const fn new() -> Self { Self { mv: None, + moved_piece: None, captured_piece: None, promoted_piece: None, castling_ability: None, @@ -48,11 +51,13 @@ impl MoveParameters { } } - pub fn build(board: &Board, mv: &Move) -> Self { + pub fn build(game: &Game, mv: &Move) -> Self { let mut move_parameters = Self::new(); move_parameters.add_move(*mv); - move_parameters.add_irreversible_parameters(board.state); - move_parameters.add_capture_and_promotion_piece(board, *mv, board.state.current_player()); + move_parameters.add_irreversible_parameters(game.board.state); + move_parameters.add_moved_piece(game, mv); + move_parameters.add_captured_piece(game, mv); + move_parameters.add_promoted_piece(mv); move_parameters } @@ -61,31 +66,27 @@ impl MoveParameters { self.mv = Some(mv); } - fn add_captured_piece(&mut self, board: &Board, dst: usize, color: Color) { - self.captured_piece = board.piece_type_at_color(dst, color); + fn add_moved_piece(&mut self, game: &Game, mv: &Move) { + self.moved_piece = game.mailbox.find_piece_at(mv.src); } - fn add_promoted_piece(&mut self, promote: Promote) { - self.promoted_piece = Some(promote.into_piece_type()); + fn add_captured_piece(&mut self, game: &Game, mv: &Move) { + if let MoveType::Capture | MoveType::PromotionCapture(_) = mv.move_type { + self.captured_piece = game.mailbox.find_piece_at(mv.dst) + } } - pub fn add_irreversible_parameters(&mut self, state: State) { + fn add_promoted_piece(&mut self, mv: &Move) { + if let MoveType::Promotion(promote) | MoveType::PromotionCapture(promote) = mv.move_type { + self.promoted_piece = Some(promote.into_piece_type()) + } + } + + fn add_irreversible_parameters(&mut self, state: State) { self.castling_ability = Some(state.castling_ability); self.en_passant_square = state.en_passant_square; self.halfmove_clock = Some(state.halfmove_clock); } - - pub fn add_capture_and_promotion_piece(&mut self, board: &Board, mv: Move, color: Color) { - match mv.move_type { - MoveType::Capture => self.add_captured_piece(board, mv.dst, color.opponent()), - MoveType::Promotion(piece) => self.add_promoted_piece(piece), - MoveType::PromotionCapture(piece) => { - self.add_promoted_piece(piece); - self.add_captured_piece(board, mv.dst, color.opponent()); - } - _ => (), - } - } } impl Default for MoveParameters { @@ -107,18 +108,18 @@ mod tests { #[test] fn test_unmake_quiet_and_double_push() -> Result<(), String> { let mut game = from_fen(FEN)?; - let board_before_make = game.board.clone(); + let game_before_make = game.clone(); let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet); game.make_move(&mv); game.unmake_move(); - assert_eq!(board_before_make, game.board); + assert_eq!(game_before_make, game); let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); game.make_move(&mv); game.unmake_move(); - assert_eq!(board_before_make, game.board); + assert_eq!(game_before_make, game); Ok(()) } @@ -126,18 +127,18 @@ mod tests { #[test] fn test_unmake_capture_and_promotion() -> Result<(), String> { let mut game = from_fen(FEN)?; - let board_before_make = game.board.clone(); + let game_before_make = game.clone(); let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture); game.make_move(&mv); game.unmake_move(); - assert_eq!(board_before_make, game.board); + assert_eq!(game_before_make, game); let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen)); game.make_move(&mv); game.unmake_move(); - assert_eq!(board_before_make, game.board); + assert_eq!(game_before_make, game); let mv = Move::new_with_type( Square::C7, @@ -147,7 +148,7 @@ mod tests { game.make_move(&mv); game.unmake_move(); - assert_eq!(board_before_make, game.board); + assert_eq!(game_before_make, game); Ok(()) } @@ -155,12 +156,12 @@ mod tests { #[test] fn test_unmake_en_passant() -> Result<(), String> { let mut game = from_fen(FEN_2)?; - let board_before_make = game.board.clone(); + let game_before_make = game.clone(); let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant); game.make_move(&mv); game.unmake_move(); - assert_eq!(board_before_make, game.board); + assert_eq!(game_before_make, game); Ok(()) } @@ -168,12 +169,12 @@ mod tests { #[test] fn test_unmake_castle() -> Result<(), String> { let mut game = from_fen(FEN)?; - let board_before_make = game.board.clone(); + let game_before_make = game.clone(); let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::Castle); game.make_move(&mv); game.unmake_move(); - assert_eq!(board_before_make, game.board); + assert_eq!(game_before_make, game); Ok(()) } diff --git a/src/board/mailbox.rs b/src/board/mailbox.rs new file mode 100644 index 0000000..803ce17 --- /dev/null +++ b/src/board/mailbox.rs @@ -0,0 +1,101 @@ +use super::{ + bitboard::{have_common_bit, square_to_bitboard}, + board::{Board, PieceType}, + square::Square, +}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Mailbox { + pub mailbox: [Option; 64], +} + +impl Mailbox { + pub const fn new() -> Self { + Self { + mailbox: [None; 64], + } + } + + pub fn new_from_board(board: &Board) -> Self { + let mut mailbox: [Option; 64] = [None; 64]; + for square in Square::A1..=Square::H8 { + mailbox[square] = board + .white_pieces + .iter() + .chain(board.black_pieces.iter()) + .find(|p| have_common_bit(p.bitboard, square_to_bitboard(square))) + .map(|p| p.piece_type); + } + + Self { mailbox } + } + + pub fn set_piece_at(&mut self, square: usize, piece_type: Option) { + self.mailbox[square] = piece_type; + } + + pub const fn find_piece_at(&self, square: usize) -> Option { + self.mailbox[square] + } +} + +#[cfg(test)] +mod tests { + use crate::board::{board::PieceType, fen::from_fen, square::Square}; + + use super::Mailbox; + + const FEN_MATE_IN_1: &str = "8/8/8/8/8/4q1k1/8/5K2 b - - 0 1"; + const FEN_STARTPOS: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + + #[test] + fn test_new_from_board() -> Result<(), String> { + let game = from_fen(FEN_MATE_IN_1)?; + let mailbox = Mailbox::new_from_board(&game.board); + #[rustfmt::skip] + let expected: [Option; 64] = [ + None, None, None, None, None, Some(PieceType::King), None, None, + None, None, None, None, None, None, None, None, + None, None, None, None, Some(PieceType::Queen), None, Some(PieceType::King), None, + None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, + ]; + + assert_eq!(expected, mailbox.mailbox); + + let game = from_fen(FEN_STARTPOS)?; + let mailbox = Mailbox::new_from_board(&game.board); + #[rustfmt::skip] + let expected: [Option; 64] = [ + Some(PieceType::Rook), Some(PieceType::Knight), Some(PieceType::Bishop), Some(PieceType::Queen), + Some(PieceType::King), Some(PieceType::Bishop), Some(PieceType::Knight), Some(PieceType::Rook), + Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), + Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), + None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, + Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), + Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), + Some(PieceType::Rook), Some(PieceType::Knight), Some(PieceType::Bishop), Some(PieceType::Queen), + Some(PieceType::King), Some(PieceType::Bishop), Some(PieceType::Knight), Some(PieceType::Rook), + ]; + + assert_eq!(expected, mailbox.mailbox); + + Ok(()) + } + + #[test] + fn test_find_piece_at() -> Result<(), String> { + let game = from_fen(FEN_MATE_IN_1)?; + let mailbox = Mailbox::new_from_board(&game.board); + + assert_eq!(PieceType::King, mailbox.find_piece_at(Square::F1).unwrap()); + + Ok(()) + } +} diff --git a/src/board/mod.rs b/src/board/mod.rs index e06049c..d631b67 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -3,5 +3,6 @@ pub mod board; pub mod fen; pub mod game; pub mod history; +pub mod mailbox; pub mod square; pub mod state; diff --git a/src/interface/uci.rs b/src/interface/uci.rs index a011831..aa30a18 100644 --- a/src/interface/uci.rs +++ b/src/interface/uci.rs @@ -110,7 +110,7 @@ pub fn uci_position(position: &mut SplitWhitespace) -> Result { } for mv_str in position { - let mv = Move::parse_from_str(&game.board, mv_str)?; + let mv = Move::parse_from_str(&game, mv_str)?; game.make_move(&mv); } @@ -231,7 +231,7 @@ mod tests { fn test_uci_go() -> Result<(), String> { init_attacks(); let mut game = from_fen(FEN_MATE_IN_1)?; - let command_go = "go depth 4"; + let command_go = "go depth 2"; let mut parts = command_go.split_whitespace(); let response = uci_go(&mut parts, &mut game)?; diff --git a/src/movegen/move.rs b/src/movegen/move.rs index c48070e..510390b 100644 --- a/src/movegen/move.rs +++ b/src/movegen/move.rs @@ -2,7 +2,8 @@ use core::fmt; use std::str::Chars; use crate::board::{ - board::{Board, PieceType}, + board::PieceType, + game::Game, square::{coords_to_square, square_to_algebraic}, }; @@ -62,6 +63,9 @@ impl fmt::Debug for Move { write!(f, "{promote_char}")?; } + #[cfg(debug_assertions)] + write!(f, ", debug_field: {:?}", self.move_type)?; + Ok(()) } } @@ -93,7 +97,7 @@ impl Move { } } - pub fn parse_from_str(board: &Board, mv: &str) -> Result { + pub fn parse_from_str(game: &Game, mv: &str) -> Result { if mv.len() != 4 && mv.len() != 5 { return Err("Invalid move characters length".to_string()); } @@ -113,17 +117,12 @@ impl Move { None }; - Ok(Self::build_with_type(board, src, dst, promote_into)) + Ok(Self::build_with_type(game, src, dst, promote_into)) } - fn build_with_type( - board: &Board, - src: usize, - dst: usize, - promote_into: Option, - ) -> Self { - let moving = board.piece_type_at(src); - let captured = board.piece_type_at(dst); + fn build_with_type(game: &Game, src: usize, dst: usize, promote_into: Option) -> Self { + let moving = game.mailbox.find_piece_at(src); + let captured = game.mailbox.find_piece_at(dst); match (captured, promote_into) { (Some(_), None) => return Self::new_with_type(src, dst, MoveType::Capture), @@ -170,7 +169,7 @@ mod tests { fn test_parse_from_str_quiet() -> Result<(), String> { let game = from_fen(FEN)?; let mv_str = "b2b3"; - let actual = Move::parse_from_str(&game.board, &mv_str)?; + let actual = Move::parse_from_str(&game, &mv_str)?; let expected = Move::new(Square::B2, Square::B3); assert_eq!(expected, actual); @@ -182,7 +181,7 @@ mod tests { fn test_parse_from_str_capture() -> Result<(), String> { let game = from_fen(FEN)?; let mv_str = "d3b5"; - let actual = Move::parse_from_str(&game.board, &mv_str)?; + let actual = Move::parse_from_str(&game, &mv_str)?; let expected = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture); assert_eq!(expected, actual); @@ -194,7 +193,7 @@ mod tests { fn test_parse_from_str_en_passant() -> Result<(), String> { let game = from_fen(FEN)?; let mv_str = "h5g6"; - let actual = Move::parse_from_str(&game.board, &mv_str)?; + let actual = Move::parse_from_str(&game, &mv_str)?; let expected = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant); assert_eq!(expected, actual); @@ -206,7 +205,7 @@ mod tests { fn test_parse_from_str_double_push() -> Result<(), String> { let game = from_fen(FEN)?; let mv_str = "b2b4"; - let actual = Move::parse_from_str(&game.board, &mv_str)?; + let actual = Move::parse_from_str(&game, &mv_str)?; let expected = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); assert_eq!(expected, actual); @@ -218,7 +217,7 @@ mod tests { fn test_parse_from_str_promotion() -> Result<(), String> { let game = from_fen(FEN)?; let mv_str = "c7c8q"; - let actual = Move::parse_from_str(&game.board, &mv_str)?; + let actual = Move::parse_from_str(&game, &mv_str)?; let expected = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen)); @@ -231,7 +230,7 @@ mod tests { fn test_parse_from_str_promotion_capture() -> Result<(), String> { let game = from_fen(FEN)?; let mv_str = "c7b8q"; - let actual = Move::parse_from_str(&game.board, &mv_str)?; + let actual = Move::parse_from_str(&game, &mv_str)?; let expected = Move::new_with_type( Square::C7, Square::B8, @@ -248,7 +247,7 @@ mod tests { fn test_parse_from_str_panic_1() { let game = from_fen(FEN); let mv_str = "c7c8qq"; - Move::parse_from_str(&game.unwrap().board, &mv_str).unwrap(); + Move::parse_from_str(&game.unwrap(), &mv_str).unwrap(); } #[test] @@ -256,6 +255,6 @@ mod tests { fn test_parse_from_str_panic_2() -> () { let game = from_fen(FEN); let mv_str = "c7c8w"; - Move::parse_from_str(&game.unwrap().board, &mv_str).unwrap(); + Move::parse_from_str(&game.unwrap(), &mv_str).unwrap(); } } diff --git a/src/search/move_ordering.rs b/src/search/move_ordering.rs index 5b8b113..a317cde 100644 --- a/src/search/move_ordering.rs +++ b/src/search/move_ordering.rs @@ -1,4 +1,4 @@ -use crate::{board::board::Board, movegen::r#move::Move}; +use crate::{board::game::Game, movegen::r#move::Move}; // Rows: Aggressors (P, N, B, R, Q, K) // Columns: Victims (K, Q, R, B, N, P) @@ -12,8 +12,11 @@ const MVV_LVA: [[usize; 6]; 6] = [ [5, 4, 3, 2, 1, 0], ]; -pub fn score_by_mvv_lva(board: &Board, mv: Move) -> usize { - match (board.piece_type_at(mv.src), board.piece_type_at(mv.dst)) { +pub fn score_by_mvv_lva(game: &Game, mv: Move) -> usize { + match ( + game.mailbox.find_piece_at(mv.src), + game.mailbox.find_piece_at(mv.dst), + ) { (Some(aggressor), Some(victim)) => MVV_LVA[aggressor.idx()][victim.idx()], _ => 0, } @@ -33,7 +36,7 @@ mod tests { fn test_score_by_mvv_lva() -> Result<(), String> { let game = from_fen(FEN)?; let f3f5 = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture); - let actual = score_by_mvv_lva(&game.board, f3f5); + let actual = score_by_mvv_lva(&game, f3f5); let expected = MVV_LVA[PieceType::Queen.idx()][PieceType::Pawn.idx()]; assert_eq!(expected, actual); diff --git a/src/search/negamax.rs b/src/search/negamax.rs index d4a37b8..7cdc5e2 100644 --- a/src/search/negamax.rs +++ b/src/search/negamax.rs @@ -23,7 +23,7 @@ pub fn negamax( let mut legal_moves = 0; let mut pseudo_legal_moves = game.board.pseudo_moves_all(); - pseudo_legal_moves.sort_unstable_by_key(|mv| score_by_mvv_lva(&game.board, *mv)); + pseudo_legal_moves.sort_unstable_by_key(|mv| score_by_mvv_lva(&game, *mv)); for mv in pseudo_legal_moves { game.make_move(&mv); diff --git a/src/search/quiescence.rs b/src/search/quiescence.rs index 4ede767..ec2d94e 100644 --- a/src/search/quiescence.rs +++ b/src/search/quiescence.rs @@ -30,7 +30,7 @@ pub fn quiescence(game: &mut Game, mut alpha: i32, beta: i32) -> (Option, }) .collect(); - captures.sort_unstable_by_key(|mv| score_by_mvv_lva(&game.board, *mv)); + captures.sort_unstable_by_key(|mv| score_by_mvv_lva(&game, *mv)); for mv in captures { game.make_move(&mv);