diff --git a/src/board/board.rs b/src/board/board.rs index d3a056a..b003522 100644 --- a/src/board/board.rs +++ b/src/board/board.rs @@ -11,7 +11,7 @@ use crate::movegen::move_generator::{ bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves, queen_pseudo_moves, rook_pseudo_moves, }; -use crate::movegen::r#move::{Move, MoveType, Promote}; +use crate::movegen::r#move::{Move, Promote}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Board { @@ -86,12 +86,7 @@ impl Board { pub fn pseudo_moves_all_captures(&self) -> Vec { self.pseudo_moves_all() .into_iter() - .filter(|m| { - matches!( - m.move_type, - MoveType::Capture | MoveType::PromotionCapture(_) - ) - }) + .filter(|m| m.is_capture()) .collect() } @@ -168,7 +163,7 @@ impl Board { self.color[self.state.next_player()] &= !square_to_bitboard(square); } - pub fn promote_piece(&mut self, square: usize, promote: &Promote) { + pub fn promote_piece(&mut self, square: usize, promote: Promote) { match promote { Promote::Knight => self.pieces[PieceType::Knight] |= square_to_bitboard(square), Promote::Bishop => self.pieces[PieceType::Bishop] |= square_to_bitboard(square), diff --git a/src/board/game.rs b/src/board/game.rs index ae6c6b2..c551f67 100644 --- a/src/board/game.rs +++ b/src/board/game.rs @@ -64,88 +64,98 @@ impl Game { let hash = &mut self.hash; let mailbox = &mut self.mailbox; let color = board.state.current_player(); - let pawn_move = board.is_pawn_move(mv.src); + let pawn_move = board.is_pawn_move(mv.src()); let mut en_passant_square = None; let ep_capture = match color { - Color::White => mv.dst.saturating_sub(8), - Color::Black => mv.dst + 8, + Color::White => (mv.dst()).saturating_sub(8), + Color::Black => mv.dst() + 8, }; let old_castling_ability = board.state.castling_ability; - - let piece_at_src = mailbox - .piece_at(mv.src) - .unwrap_or_else(|| panic!("Expected piece at: {}", mv.src)); - let piece_at_dst = mailbox.piece_at(mv.dst); - match &mv.move_type { + let piece_at_src = mailbox.piece_at(mv.src()).expect("No piece at src."); + let piece_at_dst = mailbox.piece_at(mv.dst()); + match MoveType::from_move(mv) { MoveType::Quiet => { - board.move_piece(mv.src, mv.dst, piece_at_src.0); - hash.update_quiet(mv.src, mv.dst, piece_at_src.0, color); + board.move_piece(mv.src(), mv.dst(), piece_at_src.0); + hash.update_quiet(mv.src(), mv.dst(), piece_at_src.0, color); hash.drop_en_passant_hash(board.state.en_passant_square()); - mailbox.set_piece_at(mv.dst, Some(piece_at_src)); + mailbox.set_piece_at(mv.dst(), Some(piece_at_src)); } MoveType::Capture => { - let piece_at_dst = - piece_at_dst.unwrap_or_else(|| panic!("Expected piece at: {}", mv.dst)); - board.remove_opponent_piece(mv.dst, piece_at_dst.0); - hash.update_capture(mv.src, mv.dst, piece_at_src.0, piece_at_dst.0, color); - board.move_piece(mv.src, mv.dst, piece_at_src.0); + let piece_at_dst = piece_at_dst.expect("No piece at dst."); + board.remove_opponent_piece(mv.dst(), piece_at_dst.0); + hash.update_capture(mv.src(), mv.dst(), piece_at_src.0, piece_at_dst.0, color); + board.move_piece(mv.src(), mv.dst(), piece_at_src.0); hash.drop_en_passant_hash(board.state.en_passant_square()); - mailbox.set_piece_at(mv.dst, Some(piece_at_src)); + mailbox.set_piece_at(mv.dst(), Some(piece_at_src)); } MoveType::EnPassant => { - board.move_piece(mv.src, mv.dst, PieceType::Pawn); + board.move_piece(mv.src(), mv.dst(), PieceType::Pawn); board.remove_opponent_piece(ep_capture, PieceType::Pawn); - hash.update_en_passant(mv.src, mv.dst, ep_capture, color); + hash.update_en_passant(mv.src(), mv.dst(), ep_capture, color); hash.drop_en_passant_hash(board.state.en_passant_square()); - mailbox.set_piece_at(mv.dst, Some((PieceType::Pawn, color))); + mailbox.set_piece_at(mv.dst(), Some((PieceType::Pawn, color))); mailbox.set_piece_at(ep_capture, None); } MoveType::DoublePush => { - board.move_piece(mv.src, mv.dst, piece_at_src.0); + board.move_piece(mv.src(), mv.dst(), piece_at_src.0); en_passant_square = match color { - Color::White => Some(mv.src + 8), - Color::Black => Some(mv.src.saturating_sub(8)), + Color::White => Some(mv.src() + 8), + Color::Black => Some(mv.src().saturating_sub(8)), }; - hash.update_double_push(mv.src, mv.dst, color, en_passant_square); + hash.update_double_push(mv.src(), mv.dst(), color, en_passant_square); hash.drop_en_passant_hash(board.state.en_passant_square()); - mailbox.set_piece_at(mv.dst, Some(piece_at_src)); + mailbox.set_piece_at(mv.dst(), Some(piece_at_src)); } - MoveType::Promotion(promote) => { - board.remove_own_piece(mv.src, piece_at_src.0); - board.promote_piece(mv.dst, promote); - hash.update_promotion(mv.src, mv.dst, promote, color); + MoveType::PromotionKnight + | MoveType::PromotionBishop + | MoveType::PromotionRook + | MoveType::PromotionQueen => { + let promote = mv.promotion_type(); + board.remove_own_piece(mv.src(), piece_at_src.0); + board.promote_piece(mv.dst(), promote); + hash.update_promotion(mv.src(), mv.dst(), promote, color); hash.drop_en_passant_hash(board.state.en_passant_square()); - mailbox.set_piece_at(mv.dst, Some((promote.into_piece_type(), color))); + mailbox.set_piece_at(mv.dst(), Some((promote.into_piece_type(), color))); } - MoveType::PromotionCapture(promote) => { - let piece_at_dst = - piece_at_dst.unwrap_or_else(|| panic!("Expected piece at: {}", mv.dst)); - board.remove_own_piece(mv.src, piece_at_src.0); - board.remove_opponent_piece(mv.dst, piece_at_dst.0); - board.promote_piece(mv.dst, promote); - hash.update_promotion_capture(mv.src, mv.dst, piece_at_dst.0, promote, color); + MoveType::PromotionCaptureKnight + | MoveType::PromotionCaptureBishop + | MoveType::PromotionCaptureRook + | MoveType::PromotionCaptureQueen => { + let piece_at_dst = piece_at_dst.expect("No piece at dst."); + let promote = mv.promotion_type(); + board.remove_own_piece(mv.src(), piece_at_src.0); + board.remove_opponent_piece(mv.dst(), piece_at_dst.0); + board.promote_piece(mv.dst(), promote); + hash.update_promotion_capture(mv.src(), mv.dst(), piece_at_dst.0, &promote, color); hash.drop_en_passant_hash(board.state.en_passant_square()); - mailbox.set_piece_at(mv.dst, Some((promote.into_piece_type(), color))); + mailbox.set_piece_at(mv.dst(), Some((promote.into_piece_type(), color))); } - MoveType::Castle => { - board.move_piece(mv.src, mv.dst, piece_at_src.0); - 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), + MoveType::KingCastle | MoveType::QueenCastle => { + board.move_piece(mv.src(), mv.dst(), piece_at_src.0); + 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, PieceType::Rook); board.state.set_castling_ability(color, Castle::None); - hash.update_castle(mv.src, mv.dst, piece_at_src.0, rook_src, rook_dst, color); + hash.update_castle( + mv.src(), + mv.dst(), + piece_at_src.0, + rook_src, + rook_dst, + color, + ); hash.drop_en_passant_hash(board.state.en_passant_square()); - mailbox.set_piece_at(mv.dst, Some(piece_at_src)); + mailbox.set_piece_at(mv.dst(), Some(piece_at_src)); mailbox.set_piece_at(rook_src, None); mailbox.set_piece_at(rook_dst, Some((PieceType::Rook, color))); } } - mailbox.set_piece_at(mv.src, None); + mailbox.set_piece_at(mv.src(), None); board .state .update_game_state(mv, color, pawn_move, en_passant_square); @@ -180,69 +190,75 @@ impl Game { let mv = move_parameters .mv .expect("Expected move parameters from history stack"); - let piece_at_dst = mailbox.piece_at(mv.dst).expect("Expected set piece"); - match &mv.move_type { + let piece_at_dst = mailbox.piece_at(mv.dst()).expect("No piece at dst."); + match MoveType::from_move(&mv) { MoveType::Quiet | MoveType::DoublePush => { - board.move_piece(mv.dst, mv.src, piece_at_dst.0); - mailbox.set_piece_at(mv.src, mailbox.piece_at(mv.dst)); - mailbox.set_piece_at(mv.dst, None); + board.move_piece(mv.dst(), mv.src(), piece_at_dst.0); + mailbox.set_piece_at(mv.src(), mailbox.piece_at(mv.dst())); + mailbox.set_piece_at(mv.dst(), None); } MoveType::Capture => { let captured_piece = move_parameters .captured_piece .expect("Expected captured piece to unmake Capture"); - board.move_piece(mv.dst, mv.src, piece_at_dst.0); - board.insert_opponent_piece(mv.dst, captured_piece.0); - mailbox.set_piece_at(mv.src, move_parameters.moving_piece); - mailbox.set_piece_at(mv.dst, Some(captured_piece)); + board.move_piece(mv.dst(), mv.src(), piece_at_dst.0); + board.insert_opponent_piece(mv.dst(), captured_piece.0); + mailbox.set_piece_at(mv.src(), move_parameters.moving_piece); + mailbox.set_piece_at(mv.dst(), Some(captured_piece)); } - MoveType::Promotion(_) => { + MoveType::PromotionKnight + | MoveType::PromotionBishop + | MoveType::PromotionRook + | MoveType::PromotionQueen => { let promoted_piece = move_parameters .promoted_piece .expect("Expected promoted piece to unmake Promotion"); - board.remove_own_piece(mv.dst, promoted_piece.0); - board.insert_own_piece(mv.src, PieceType::Pawn); + board.remove_own_piece(mv.dst(), promoted_piece.0); + board.insert_own_piece(mv.src(), PieceType::Pawn); - mailbox.set_piece_at(mv.src, Some((PieceType::Pawn, color_before_move))); - mailbox.set_piece_at(mv.dst, None); + mailbox.set_piece_at(mv.src(), Some((PieceType::Pawn, color_before_move))); + mailbox.set_piece_at(mv.dst(), None); } - MoveType::PromotionCapture(_) => { + MoveType::PromotionCaptureKnight + | MoveType::PromotionCaptureBishop + | MoveType::PromotionCaptureRook + | MoveType::PromotionCaptureQueen => { 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"); - board.remove_own_piece(mv.dst, promoted_piece.0); - board.insert_opponent_piece(mv.dst, captured_piece.0); - board.insert_own_piece(mv.src, PieceType::Pawn); - mailbox.set_piece_at(mv.src, Some((PieceType::Pawn, color_before_move))); - mailbox.set_piece_at(mv.dst, Some(captured_piece)); + board.remove_own_piece(mv.dst(), promoted_piece.0); + board.insert_opponent_piece(mv.dst(), captured_piece.0); + board.insert_own_piece(mv.src(), PieceType::Pawn); + mailbox.set_piece_at(mv.src(), Some((PieceType::Pawn, color_before_move))); + mailbox.set_piece_at(mv.dst(), Some(captured_piece)); } MoveType::EnPassant => { let enemy_pawn_square = match color_before_move { - Color::White => mv.dst - 8, - Color::Black => mv.dst + 8, + Color::White => mv.dst() - 8, + Color::Black => mv.dst() + 8, }; - board.move_piece(mv.dst, mv.src, piece_at_dst.0); + board.move_piece(mv.dst(), mv.src(), piece_at_dst.0); board.insert_opponent_piece(enemy_pawn_square, PieceType::Pawn); - mailbox.set_piece_at(mv.src, Some((PieceType::Pawn, color_before_move))); + mailbox.set_piece_at(mv.src(), Some((PieceType::Pawn, color_before_move))); mailbox.set_piece_at( enemy_pawn_square, Some((PieceType::Pawn, color_before_move.opponent())), ); } - MoveType::Castle => { - 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), + MoveType::KingCastle | MoveType::QueenCastle => { + 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(mv.dst, mv.src, piece_at_dst.0); + board.move_piece(mv.dst(), mv.src(), piece_at_dst.0); board.remove_own_piece(rook_dst, PieceType::Rook); board.insert_own_piece(rook_src, PieceType::Rook); - mailbox.set_piece_at(mv.src, mailbox.piece_at(mv.dst)); - mailbox.set_piece_at(mv.dst, None); + mailbox.set_piece_at(mv.src(), mailbox.piece_at(mv.dst())); + mailbox.set_piece_at(mv.dst(), None); mailbox.set_piece_at(rook_src, Some((PieceType::Rook, color_before_move))); mailbox.set_piece_at(rook_dst, None); } @@ -303,7 +319,7 @@ impl Default for Game { mod tests { use crate::{ board::{fen::from_fen, square::Square}, - movegen::r#move::{MoveType, Promote}, + movegen::r#move::MoveType, }; use super::*; @@ -327,7 +343,7 @@ mod tests { #[test] fn test_make_move_capture() -> Result<(), String> { let mut game = from_fen(FEN)?; - let f3f5 = Move::with_type(Square::F3, Square::F5, MoveType::Capture); + let f3f5 = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture); game.make_move(&f3f5); assert_eq!(game, from_fen(FEN_CAPTURE)?); @@ -341,7 +357,7 @@ mod tests { #[test] fn test_make_move_en_passant() -> Result<(), String> { let mut game = from_fen(FEN)?; - let h5g6 = Move::with_type(Square::H5, Square::G6, MoveType::EnPassant); + let h5g6 = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant); game.make_move(&h5g6); assert_eq!(game, from_fen(FEN_EN_PASSANT)?); @@ -355,7 +371,7 @@ mod tests { #[test] fn test_make_move_double_push() -> Result<(), String> { let mut game = from_fen(FEN)?; - let b2b4 = Move::with_type(Square::B2, Square::B4, MoveType::DoublePush); + let b2b4 = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); game.make_move(&b2b4); assert_eq!(game, from_fen(FEN_DOUBLE_PUSH)?); @@ -367,7 +383,7 @@ mod tests { #[test] fn test_make_move_promotion() -> Result<(), String> { let mut game = from_fen(FEN)?; - let c7c8 = Move::with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen)); + let c7c8 = Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionQueen); game.make_move(&c7c8); assert_eq!(game, from_fen(FEN_PROMOTION)?); @@ -380,11 +396,7 @@ mod tests { #[test] fn test_make_move_promotion_capture() -> Result<(), String> { let mut game = from_fen(FEN)?; - let c7b8 = Move::with_type( - Square::C7, - Square::B8, - MoveType::PromotionCapture(Promote::Queen), - ); + let c7b8 = Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureQueen); game.make_move(&c7b8); assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE)?); @@ -396,7 +408,7 @@ mod tests { #[test] fn test_make_move_castle() -> Result<(), String> { let mut game = from_fen(FEN)?; - let e1g1 = Move::with_type(Square::E1, Square::G1, MoveType::Castle); + let e1g1 = Move::new_with_type(Square::E1, Square::G1, MoveType::KingCastle); game.make_move(&e1g1); assert_eq!(game, from_fen(FEN_CASTLE)?); Ok(()) @@ -409,13 +421,13 @@ mod tests { fn test_unmake_quiet_and_double_push() -> Result<(), String> { let mut game = from_fen(FEN_1)?; let game_before_make = game.clone(); - let mv = Move::with_type(Square::B2, Square::B3, MoveType::Quiet); + let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); - let mv = Move::with_type(Square::B2, Square::B4, MoveType::DoublePush); + let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); game.make_move(&mv); game.unmake_move(); @@ -428,23 +440,19 @@ mod tests { fn test_unmake_capture_and_promotion() -> Result<(), String> { let mut game = from_fen(FEN_1)?; let game_before_make = game.clone(); - let mv = Move::with_type(Square::D3, Square::B5, MoveType::Capture); + let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); - let mv = Move::with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen)); + let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionQueen); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); - let mv = Move::with_type( - Square::C7, - Square::B8, - MoveType::PromotionCapture(Promote::Queen), - ); + let mv = Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureQueen); game.make_move(&mv); game.unmake_move(); @@ -457,7 +465,7 @@ mod tests { fn test_unmake_en_passant() -> Result<(), String> { let mut game = from_fen(FEN_2)?; let game_before_make = game.clone(); - let mv = Move::with_type(Square::A4, Square::B3, MoveType::EnPassant); + let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant); game.make_move(&mv); game.unmake_move(); @@ -470,7 +478,7 @@ mod tests { fn test_unmake_castle() -> Result<(), String> { let mut game = from_fen(FEN_1)?; let game_before_make = game.clone(); - let mv = Move::with_type(Square::E1, Square::C1, MoveType::Castle); + let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::KingCastle); game.make_move(&mv); game.unmake_move(); diff --git a/src/board/history.rs b/src/board/history.rs index 3847b75..ef7a8b9 100644 --- a/src/board/history.rs +++ b/src/board/history.rs @@ -95,18 +95,23 @@ impl MoveParameters { } fn add_moving_piece(&mut self, mailbox: &Mailbox, mv: &Move) { - self.moving_piece = mailbox.piece_at(mv.src); + self.moving_piece = mailbox.piece_at(mv.src()); } fn add_captured_piece(&mut self, mailbox: &Mailbox, mv: &Move) { - if let MoveType::Capture | MoveType::PromotionCapture(_) = mv.move_type { - self.captured_piece = mailbox.piece_at(mv.dst) + if let MoveType::Capture + | MoveType::PromotionCaptureKnight + | MoveType::PromotionCaptureBishop + | MoveType::PromotionCaptureRook + | MoveType::PromotionCaptureQueen = MoveType::from_move(mv) + { + self.captured_piece = mailbox.piece_at(mv.dst()) } } fn add_promoted_piece(&mut self, mv: &Move, color: Color) { - if let MoveType::Promotion(promote) | MoveType::PromotionCapture(promote) = mv.move_type { - self.promoted_piece = Some((promote.into_piece_type(), color)); + if mv.is_promotion() { + self.promoted_piece = Some((mv.promotion_type().into_piece_type(), color)); } } diff --git a/src/board/state.rs b/src/board/state.rs index 74518f4..7b143fb 100644 --- a/src/board/state.rs +++ b/src/board/state.rs @@ -1,7 +1,4 @@ -use crate::{ - board::board::Color, - movegen::r#move::{Move, MoveType}, -}; +use crate::{board::board::Color, movegen::r#move::Move}; #[derive(Debug, PartialEq, Eq, Clone)] pub struct State { @@ -47,16 +44,16 @@ impl State { en_passant_square: Option, ) { self.set_en_passant_square(en_passant_square); - self.update_castling_state_quiet(mv.src, color); - self.update_castling_state_capture(mv.dst, color.opponent()); - self.update_half_move(mv.move_type, pawn_move); + self.update_castling_state_quiet(mv.src(), color); + self.update_castling_state_capture(mv.dst(), color.opponent()); + self.update_half_move(mv.is_capture(), pawn_move); self.update_full_move(color); self.change_side(); } pub fn update_null_game_state(&mut self, color: Color) { self.set_en_passant_square(None); - self.update_half_move(MoveType::Quiet, false); + self.update_half_move(false, false); self.update_full_move(color); self.change_side(); } @@ -117,8 +114,8 @@ impl State { } } - pub fn update_half_move(&mut self, move_type: MoveType, pawn_move: bool) { - if move_type == MoveType::Capture || pawn_move { + pub fn update_half_move(&mut self, is_capture: bool, is_pawn_move: bool) { + if is_capture || is_pawn_move { self.halfmove_clock = 0; } else { self.halfmove_clock += 1; diff --git a/src/board/zobrist.rs b/src/board/zobrist.rs index b3c4aa7..261622f 100644 --- a/src/board/zobrist.rs +++ b/src/board/zobrist.rs @@ -163,7 +163,7 @@ impl ZobristHash { } } - pub fn update_promotion(&mut self, src: usize, dst: usize, promote: &Promote, color: Color) { + pub fn update_promotion(&mut self, src: usize, dst: usize, promote: Promote, color: Color) { let keys = zobrist_keys(); self.0 ^= keys.square_piece_color[src][PieceType::Pawn][color]; self.0 ^= keys.square_piece_color[dst][promote.into_piece_type()][color]; @@ -211,7 +211,7 @@ impl ZobristHash { mod tests { use crate::{ board::{fen::from_fen, square::Square}, - movegen::r#move::{Move, MoveType, Promote}, + movegen::r#move::{Move, MoveType}, }; const FEN: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R w KQk g6 0 1"; @@ -244,7 +244,11 @@ mod tests { #[test] fn test_update_capture() -> Result<(), String> { let mut incremental = from_fen(FEN)?; - incremental.make_move(&Move::with_type(Square::F3, Square::F5, MoveType::Capture)); + incremental.make_move(&Move::new_with_type( + Square::F3, + Square::F5, + MoveType::Capture, + )); let from_scratch = from_fen(FEN_CAPTURE)?; assert_eq!(incremental.hash, from_scratch.hash); @@ -258,7 +262,7 @@ mod tests { #[test] fn test_update_en_passant() -> Result<(), String> { let mut incremental = from_fen(FEN)?; - incremental.make_move(&Move::with_type( + incremental.make_move(&Move::new_with_type( Square::H5, Square::G6, MoveType::EnPassant, @@ -276,7 +280,7 @@ mod tests { #[test] fn test_update_double_push() -> Result<(), String> { let mut incremental = from_fen(FEN)?; - incremental.make_move(&Move::with_type( + incremental.make_move(&Move::new_with_type( Square::B2, Square::B4, MoveType::DoublePush, @@ -293,10 +297,10 @@ mod tests { #[test] fn test_update_promotion() -> Result<(), String> { let mut incremental = from_fen(FEN)?; - incremental.make_move(&Move::with_type( + incremental.make_move(&Move::new_with_type( Square::C7, Square::C8, - MoveType::Promotion(Promote::Queen), + MoveType::PromotionQueen, )); let from_scratch = from_fen(FEN_PROMOTION)?; @@ -311,10 +315,10 @@ mod tests { #[test] fn test_update_promotion_capture() -> Result<(), String> { let mut incremental = from_fen(FEN)?; - incremental.make_move(&Move::with_type( + incremental.make_move(&Move::new_with_type( Square::C7, Square::B8, - MoveType::PromotionCapture(Promote::Queen), + MoveType::PromotionCaptureQueen, )); let from_scratch = from_fen(FEN_PROMOTION_CAPTURE)?; @@ -328,7 +332,11 @@ mod tests { #[test] fn test_update_castle() -> Result<(), String> { let mut incremental = from_fen(FEN)?; - incremental.make_move(&Move::with_type(Square::E1, Square::G1, MoveType::Castle)); + incremental.make_move(&Move::new_with_type( + Square::E1, + Square::G1, + MoveType::KingCastle, + )); let from_scratch = from_fen(FEN_CASTLE)?; assert_eq!(incremental.hash, from_scratch.hash); diff --git a/src/movegen/move.rs b/src/movegen/move.rs index a02219b..f55c94e 100644 --- a/src/movegen/move.rs +++ b/src/movegen/move.rs @@ -11,8 +11,8 @@ use crate::board::{ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Promote { Knight, - Rook, Bishop, + Rook, Queen, } @@ -27,77 +27,154 @@ impl Promote { } } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] -pub enum MoveType { - Quiet, - Capture, - DoublePush, - Promotion(Promote), - PromotionCapture(Promote), - EnPassant, - Castle, +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +pub struct Move(u16); + +impl Move { + pub const fn new(src: usize, dst: usize) -> Self { + Self((src << 10 | dst << 4) as u16) + } + + pub const fn new_with_type(src: usize, dst: usize, move_type: MoveType) -> Self { + Self((src << 10 | dst << 4 | (move_type as u8) as usize) as u16) + } + + pub const fn is_capture(&self) -> bool { + self.0 & 0b0100 != 0 + } + + pub const fn is_promotion(&self) -> bool { + self.0 & 0b1000 != 0 + } + + pub const fn src(&self) -> usize { + (self.0 as usize) >> 10 + } + + pub const fn dst(&self) -> usize { + (self.0 as usize) >> 4 & 0b111111 + } + + pub const fn promo_piece(&self) -> usize { + (self.0 as usize) & 0b11 + } + + pub const fn move_type(&self) -> usize { + (self.0 as usize) & 0b1111 + } + + pub fn promotion_type(&self) -> Promote { + match self.promo_piece() { + 0b00 => Promote::Knight, + 0b01 => Promote::Bishop, + 0b10 => Promote::Rook, + 0b11 => Promote::Queen, + _ => unreachable!(), + } + } } +// https://www.chessprogramming.org/Encoding_Moves#From-To_Based +#[rustfmt::skip] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] -pub struct Move { - pub src: usize, - pub dst: usize, - pub move_type: MoveType, +#[repr(u8)] +pub enum MoveType { + Quiet = 0b0000, + DoublePush = 0b0001, + KingCastle = 0b0010, + QueenCastle = 0b0011, + Capture = 0b0100, + EnPassant = 0b0101, + PromotionKnight = 0b1000, + PromotionBishop = 0b1001, + PromotionRook = 0b1010, + PromotionQueen = 0b1011, + PromotionCaptureKnight = 0b1100, + PromotionCaptureBishop = 0b1101, + PromotionCaptureRook = 0b1110, + PromotionCaptureQueen = 0b1111, +} + +impl MoveType { + pub const fn new_promo(promo_piece: Promote) -> Self { + match promo_piece { + Promote::Knight => Self::PromotionKnight, + Promote::Bishop => Self::PromotionBishop, + Promote::Rook => Self::PromotionRook, + Promote::Queen => Self::PromotionQueen, + } + } + + pub const fn new_promo_capture(promo_piece: Promote) -> Self { + match promo_piece { + Promote::Knight => Self::PromotionCaptureKnight, + Promote::Bishop => Self::PromotionCaptureBishop, + Promote::Rook => Self::PromotionCaptureRook, + Promote::Queen => Self::PromotionCaptureQueen, + } + } + + pub fn from_move(mv: &Move) -> Self { + if mv.is_promotion() { + if mv.is_capture() { + match mv.promotion_type() { + Promote::Knight => Self::PromotionCaptureKnight, + Promote::Bishop => Self::PromotionCaptureBishop, + Promote::Rook => Self::PromotionCaptureRook, + Promote::Queen => Self::PromotionCaptureQueen, + } + } else { + match mv.promotion_type() { + Promote::Knight => Self::PromotionKnight, + Promote::Bishop => Self::PromotionBishop, + Promote::Rook => Self::PromotionRook, + Promote::Queen => Self::PromotionQueen, + } + } + } else { + match mv.move_type() { + 0b0000 => Self::Quiet, + 0b0001 => Self::DoublePush, + 0b0010 => Self::KingCastle, + 0b0011 => Self::QueenCastle, + 0b0100 => Self::Capture, + 0b0101 => Self::EnPassant, + _ => unreachable!(), + } + } + } +} + +fn format_move(mv: &Move, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}{}", to_algebraic(mv.src()), to_algebraic(mv.dst()))?; + + if mv.is_promotion() { + let piece = mv.promotion_type(); + let promote_char = match piece { + Promote::Knight => 'n', + Promote::Bishop => 'b', + Promote::Rook => 'r', + Promote::Queen => 'q', + }; + write!(f, "{promote_char}")?; + } + + Ok(()) } impl fmt::Debug for Move { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}{}", to_algebraic(self.src), to_algebraic(self.dst))?; - - if let MoveType::Promotion(piece) | MoveType::PromotionCapture(piece) = &self.move_type { - let promote_char = match piece { - Promote::Knight => 'n', - Promote::Bishop => 'b', - Promote::Rook => 'r', - Promote::Queen => 'q', - }; - write!(f, "{promote_char}")?; - } - - Ok(()) + format_move(self, f) } } impl fmt::Display for Move { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}{}", to_algebraic(self.src), to_algebraic(self.dst))?; - - if let MoveType::Promotion(piece) | MoveType::PromotionCapture(piece) = &self.move_type { - let promote_char = match piece { - Promote::Knight => 'n', - Promote::Bishop => 'b', - Promote::Rook => 'r', - Promote::Queen => 'q', - }; - write!(f, "{promote_char}")?; - } - - Ok(()) + format_move(self, f) } } impl Move { - pub const fn new(src: usize, dst: usize) -> Self { - Self { - src, - dst, - move_type: MoveType::Quiet, - } - } - - pub const fn with_type(src: usize, dst: usize, move_type: MoveType) -> Self { - Self { - src, - dst, - move_type, - } - } - #[allow(clippy::unwrap_used)] pub fn parse_promotion(mut mv_chars: Chars<'_>) -> Result { match mv_chars.next().unwrap() { @@ -114,20 +191,16 @@ impl Move { if mv.len() != 4 && mv.len() != 5 { return Err("Invalid move characters length".to_string()); } - let mut mv_chars = mv.chars(); let src_file = (mv_chars.next().unwrap() as usize) - ('a' as usize); let src_rank = (mv_chars.next().unwrap() as usize) - ('1' as usize); let dst_file = (mv_chars.next().unwrap() as usize) - ('a' as usize); let dst_rank = (mv_chars.next().unwrap() as usize) - ('1' as usize); - let src = from_coords(src_rank, src_file); let dst = from_coords(dst_rank, dst_file); - let promote_into = (mv.len() == 5) .then(|| Self::parse_promotion(mv_chars)) .transpose()?; - Ok(Self::build_with_type(&game.mailbox, src, dst, promote_into)) } @@ -139,54 +212,49 @@ impl Move { ) -> Self { let moving = mailbox.piece_at(src); let captured = mailbox.piece_at(dst); - match (captured, promote_into) { - (Some(_), None) => return Self::with_type(src, dst, MoveType::Capture), - (None, Some(promote_into)) => { - return Self::with_type(src, dst, MoveType::Promotion(promote_into)) + (Some(_), None) => return Self::new_with_type(src, dst, MoveType::Capture), + (None, Some(promote)) => { + return Self::new_with_type(src, dst, MoveType::new_promo(promote)) } - (Some(_), Some(promote_into)) => { - return Self::with_type(src, dst, MoveType::PromotionCapture(promote_into)) + (Some(_), Some(promote)) => { + return Self::new_with_type(src, dst, MoveType::new_promo_capture(promote)) } _ => (), } if let Some((PieceType::Pawn, _)) = moving { if src.abs_diff(dst) == 16 { - return Self::with_type(src, dst, MoveType::DoublePush); + return Self::new_with_type(src, dst, MoveType::DoublePush); } - if captured.is_none() && src.abs_diff(dst) != 8 { - return Self::with_type(src, dst, MoveType::EnPassant); + return Self::new_with_type(src, dst, MoveType::EnPassant); } } if let Some((PieceType::King, _)) = moving { if src.abs_diff(dst) == 2 { - return Self::with_type(src, dst, MoveType::Castle); + return if dst > src { + Self::new_with_type(src, dst, MoveType::KingCastle) + } else { + Self::new_with_type(src, dst, MoveType::QueenCastle) + }; } } - Self::new(src, dst) } pub fn parse_into_str(&self) -> String { format!("{self:?}") } - - pub const fn is_capture(&self) -> bool { - matches!( - self.move_type, - MoveType::Capture | MoveType::PromotionCapture(_) - ) - } } #[cfg(test)] mod tests { + use super::Move; use crate::board::fen::from_fen; use crate::board::square::Square; - use crate::movegen::r#move::{Move, MoveType, Promote}; + use crate::movegen::r#move::MoveType; const FEN: &'static str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R w KQk g6 0 1"; @@ -207,7 +275,7 @@ mod tests { let game = from_fen(FEN)?; let mv_str = "d3b5"; let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::with_type(Square::D3, Square::B5, MoveType::Capture); + let expected = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture); assert_eq!(expected, actual); @@ -219,7 +287,7 @@ mod tests { let game = from_fen(FEN)?; let mv_str = "h5g6"; let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::with_type(Square::H5, Square::G6, MoveType::EnPassant); + let expected = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant); assert_eq!(expected, actual); @@ -231,7 +299,7 @@ mod tests { let game = from_fen(FEN)?; let mv_str = "b2b4"; let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::with_type(Square::B2, Square::B4, MoveType::DoublePush); + let expected = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); assert_eq!(expected, actual); @@ -243,7 +311,7 @@ mod tests { let game = from_fen(FEN)?; let mv_str = "c7c8q"; let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen)); + let expected = Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionQueen); assert_eq!(expected, actual); @@ -255,11 +323,7 @@ mod tests { let game = from_fen(FEN)?; let mv_str = "c7b8q"; let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::with_type( - Square::C7, - Square::B8, - MoveType::PromotionCapture(Promote::Queen), - ); + let expected = Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureQueen); assert_eq!(expected, actual); diff --git a/src/movegen/move_generator.rs b/src/movegen/move_generator.rs index 7ec53d8..66c9f26 100644 --- a/src/movegen/move_generator.rs +++ b/src/movegen/move_generator.rs @@ -8,7 +8,7 @@ use crate::movegen::attack_generator::{ fetch_bishop_attacks, fetch_king_attacks, fetch_knight_attacks, fetch_pawn_attacks, fetch_queen_attacks, fetch_rook_attacks, }; -use crate::movegen::r#move::{Move, MoveType, Promote}; +use crate::movegen::r#move::{Move, MoveType}; use u64 as Bitboard; pub fn pawn_pseudo_moves( @@ -41,18 +41,21 @@ pub fn pawn_pseudo_moves( } fn add_promotion_moves(moves: &mut Vec, src: usize, dst: usize, capture: bool) { - let promotion_type = if capture { - MoveType::PromotionCapture + if capture { + moves.extend([ + Move::new_with_type(src, dst, MoveType::PromotionCaptureKnight), + Move::new_with_type(src, dst, MoveType::PromotionCaptureBishop), + Move::new_with_type(src, dst, MoveType::PromotionCaptureRook), + Move::new_with_type(src, dst, MoveType::PromotionCaptureQueen), + ]); } else { - MoveType::Promotion + moves.extend([ + Move::new_with_type(src, dst, MoveType::PromotionKnight), + Move::new_with_type(src, dst, MoveType::PromotionBishop), + Move::new_with_type(src, dst, MoveType::PromotionRook), + Move::new_with_type(src, dst, MoveType::PromotionQueen), + ]); }; - - moves.extend([ - Move::with_type(src, dst, promotion_type(Promote::Knight)), - Move::with_type(src, dst, promotion_type(Promote::Bishop)), - Move::with_type(src, dst, promotion_type(Promote::Rook)), - Move::with_type(src, dst, promotion_type(Promote::Queen)), - ]); } fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec { @@ -77,7 +80,7 @@ fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec { while double_push != 0 { let dst = lsb(double_push); let src = dst - 16; - moves.push(Move::with_type(src, dst, MoveType::DoublePush)); + moves.push(Move::new_with_type(src, dst, MoveType::DoublePush)); double_push &= double_push - 1; } moves @@ -105,7 +108,7 @@ fn black_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec { while double_push != 0 { let dst = lsb(double_push); let src = dst + 16; - moves.push(Move::with_type(src, dst, MoveType::DoublePush)); + moves.push(Move::new_with_type(src, dst, MoveType::DoublePush)); double_push &= double_push - 1; } moves @@ -127,7 +130,7 @@ fn white_pawn_capture_moves( if have_common_bit(square_to_bitboard(dst), RANK_8) { add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::with_type(src, dst, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } w_pawns_capture_east &= w_pawns_capture_east - 1; } @@ -138,7 +141,7 @@ fn white_pawn_capture_moves( if have_common_bit(square_to_bitboard(dst), RANK_8) { add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::with_type(src, dst, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } w_pawns_capture_west &= w_pawns_capture_west - 1; } @@ -147,7 +150,7 @@ fn white_pawn_capture_moves( let attacked_src = fetch_pawn_attacks(en_passant_sq, Color::Black); let mut result = attacked_src & pawns; while result != 0 { - moves.push(Move::with_type( + moves.push(Move::new_with_type( lsb(result), en_passant_sq, MoveType::EnPassant, @@ -174,7 +177,7 @@ fn black_pawn_capture_moves( if have_common_bit(square_to_bitboard(dst), RANK_1) { add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::with_type(src, dst, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } b_pawns_capture_east &= b_pawns_capture_east - 1; } @@ -185,7 +188,7 @@ fn black_pawn_capture_moves( if have_common_bit(square_to_bitboard(dst), RANK_1) { add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::with_type(src, dst, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } b_pawns_capture_west &= b_pawns_capture_west - 1; } @@ -194,7 +197,7 @@ fn black_pawn_capture_moves( let attacked_src = fetch_pawn_attacks(en_passant_square, Color::White); let mut result = attacked_src & pawns; while result != 0 { - moves.push(Move::with_type( + moves.push(Move::new_with_type( lsb(result), en_passant_square, MoveType::EnPassant, @@ -221,7 +224,7 @@ pub fn knight_pseudo_moves( while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::with_type(src, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { moves.push(Move::new(src, attack_sq)); } @@ -248,7 +251,7 @@ pub fn bishop_pseudo_moves( while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::with_type(src, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { moves.push(Move::new(src, attack_sq)); } @@ -275,7 +278,7 @@ pub fn rook_pseudo_moves( while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::with_type(src, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { moves.push(Move::new(src, attack_sq)); } @@ -302,7 +305,7 @@ pub fn queen_pseudo_moves( while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::with_type(src, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { moves.push(Move::new(src, attack_sq)); } @@ -329,7 +332,7 @@ pub fn king_pseudo_moves( while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::with_type(src, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { moves.push(Move::new(src, attack_sq)); } @@ -349,7 +352,19 @@ fn king_castling_moves(board: &Board, color: Color, all_occupancies: Bitboard) - let mut add_move_if_empty_path = |path_mask, king_dst| { if !have_common_bit(all_occupancies, path_mask) { - moves.push(Move::with_type(king_src, king_dst, MoveType::Castle)); + if king_dst > king_src { + moves.push(Move::new_with_type( + king_src, + king_dst, + MoveType::KingCastle, + )); + } else { + moves.push(Move::new_with_type( + king_src, + king_dst, + MoveType::QueenCastle, + )); + } } }; @@ -408,19 +423,19 @@ mod tests { let new_game = from_fen(FEN_PAWN_MOVES)?; let expected = vec![ Move::new(9, 17), - Move::with_type(9, 25, MoveType::DoublePush), + Move::new_with_type(9, 25, MoveType::DoublePush), Move::new(10, 18), - Move::with_type(10, 26, MoveType::DoublePush), + Move::new_with_type(10, 26, MoveType::DoublePush), Move::new(14, 22), - Move::with_type(14, 30, MoveType::DoublePush), + Move::new_with_type(14, 30, MoveType::DoublePush), Move::new(15, 23), - Move::with_type(15, 31, MoveType::DoublePush), + Move::new_with_type(15, 31, MoveType::DoublePush), Move::new(29, 37), Move::new(32, 40), - Move::with_type(32, 41, MoveType::Capture), - Move::with_type(36, 43, MoveType::Capture), + Move::new_with_type(32, 41, MoveType::Capture), + Move::new_with_type(36, 43, MoveType::Capture), Move::new(36, 44), - Move::with_type(36, 45, MoveType::Capture), + Move::new_with_type(36, 45, MoveType::Capture), ]; let mut actual = new_game.board.pseudo_moves(Color::White, PieceType::Pawn); @@ -428,12 +443,12 @@ mod tests { assert_eq!(expected, actual); let expected = vec![ - Move::with_type(41, 32, MoveType::Capture), + Move::new_with_type(41, 32, MoveType::Capture), Move::new(41, 33), Move::new(43, 35), - Move::with_type(43, 36, MoveType::Capture), + Move::new_with_type(43, 36, MoveType::Capture), Move::new(48, 40), - Move::with_type(55, 39, MoveType::DoublePush), + Move::new_with_type(55, 39, MoveType::DoublePush), Move::new(55, 47), ]; let mut actual = new_game.board.pseudo_moves(Color::Black, PieceType::Pawn); @@ -457,7 +472,7 @@ mod tests { Move::new(21, 11), Move::new(21, 31), Move::new(21, 36), - Move::with_type(21, 38, MoveType::Capture), + Move::new_with_type(21, 38, MoveType::Capture), ]; let mut actual = new_game.board.pseudo_moves(Color::White, PieceType::Knight); actual.sort(); @@ -483,7 +498,7 @@ mod tests { Move::new(26, 35), Move::new(26, 40), Move::new(26, 44), - Move::with_type(26, 53, MoveType::Capture), + Move::new_with_type(26, 53, MoveType::Capture), ]; let mut actual = new_game.board.pseudo_moves(Color::White, PieceType::Bishop); actual.sort(); @@ -504,14 +519,14 @@ mod tests { Move::new(11, 35), Move::new(11, 43), Move::new(11, 51), - Move::with_type(11, 59, MoveType::Capture), + Move::new_with_type(11, 59, MoveType::Capture), Move::new(12, 13), Move::new(12, 14), Move::new(12, 15), Move::new(12, 20), Move::new(12, 28), Move::new(12, 36), - Move::with_type(12, 44, MoveType::Capture), + Move::new_with_type(12, 44, MoveType::Capture), ]; let mut actual = new_game.board.pseudo_moves(Color::White, PieceType::Rook); actual.sort(); @@ -534,7 +549,7 @@ mod tests { Move::new(17, 25), Move::new(17, 33), Move::new(17, 41), - Move::with_type(17, 49, MoveType::Capture), + Move::new_with_type(17, 49, MoveType::Capture), ]; let mut actual = new_game.board.pseudo_moves(Color::White, PieceType::Queen); actual.sort(); @@ -567,7 +582,10 @@ mod tests { assert_eq!(expected, actual); let new_game_2 = from_fen(FEN_KING_MOVES[1])?; - let expected = vec![Move::with_type(4, 2, MoveType::Castle), Move::new(4, 3)]; + let expected = vec![ + Move::new_with_type(4, 2, MoveType::QueenCastle), + Move::new(4, 3), + ]; let mut actual = new_game_2.board.pseudo_moves(Color::White, PieceType::King); actual.sort(); assert_eq!(expected, actual); @@ -578,7 +596,7 @@ mod tests { Move::new(60, 53), Move::new(60, 59), Move::new(60, 61), - Move::with_type(60, 62, MoveType::Castle), + Move::new_with_type(60, 62, MoveType::KingCastle), ]; let mut actual = new_game_3.board.pseudo_moves(Color::Black, PieceType::King); actual.sort(); diff --git a/src/search/move_ordering.rs b/src/search/move_ordering.rs index 37bb646..a874514 100644 --- a/src/search/move_ordering.rs +++ b/src/search/move_ordering.rs @@ -14,8 +14,8 @@ pub fn score_move( return -90; } - let aggressor = mailbox.piece_at(mv.src).expect("No aggressor found."); - mailbox.piece_at(mv.dst).map_or(100, |victim| { + let aggressor = mailbox.piece_at(mv.src()).expect("No aggressor found."); + mailbox.piece_at(mv.dst()).map_or(100, |victim| { aggressor.0.idx() as i32 - (victim.0.idx() * 8) as i32 }) } @@ -34,9 +34,9 @@ mod tests { #[test] fn test_score_move() -> Result<(), String> { let game = from_fen(FEN)?; - let queen_takes_pawn = Move::with_type(Square::F3, Square::F5, MoveType::Capture); - let pawn_takes_queen = Move::with_type(Square::H5, Square::G6, MoveType::Capture); - let castle = Move::with_type(Square::E1, Square::C1, MoveType::Castle); + let queen_takes_pawn = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture); + let pawn_takes_queen = Move::new_with_type(Square::H5, Square::G6, MoveType::Capture); + let castle = Move::new_with_type(Square::E1, Square::C1, MoveType::QueenCastle); let mut moves = vec![castle, queen_takes_pawn, pawn_takes_queen]; moves.sort_unstable_by_key(|mv| score_move(&game.mailbox, *mv, None, None));