diff --git a/board/src/move.rs b/board/src/move.rs index 4f06000..ade1ff8 100644 --- a/board/src/move.rs +++ b/board/src/move.rs @@ -169,11 +169,11 @@ impl Move { } pub fn is_quiet(&self) -> bool { - self.special() == 0b00 + self.flags() == Kind::Quiet.discriminant() } pub fn is_double_push(&self) -> bool { - self.special() == 0b01 + self.flags() == Kind::DoublePush.discriminant() } pub fn is_castle(&self) -> bool { @@ -181,7 +181,7 @@ impl Move { } pub fn castle(&self) -> Option { - match self.special() { + match self.flags() { 0b0010 => Some(Castle::KingSide), 0b0011 => Some(Castle::QueenSide), _ => None, @@ -193,7 +193,7 @@ impl Move { } pub fn is_en_passant(&self) -> bool { - (self.0 & 0b0101) == 0b0101 + self.flags() == 0b0101 } pub fn is_promotion(&self) -> bool { @@ -214,6 +214,11 @@ impl Move { }) } + #[inline] + fn flags(&self) -> u16 { + self.0 & 0b1111 + } + #[inline] fn special(&self) -> u16 { self.0 & 0b11 @@ -240,8 +245,10 @@ impl MoveBuilder { pub fn new(piece: Piece, from: Square, to: Square) -> Self { let kind = match piece.shape() { Shape::Pawn => { - let is_white_double_push = from.rank() == Rank::Two && to.rank() == Rank::Four; - let is_black_double_push = from.rank() == Rank::Seven && to.rank() == Rank::Five; + let from_rank = from.rank(); + let to_rank = to.rank(); + let is_white_double_push = from_rank == Rank::Two && to_rank == Rank::Four; + let is_black_double_push = from_rank == Rank::Seven && to_rank == Rank::Five; if is_white_double_push || is_black_double_push { Kind::DoublePush } else { @@ -478,3 +485,82 @@ mod move_formatter { test_algebraic_formatter!(long_bishop_capture, Long, White Bishop A2 x E6, Black Knight, "Ba2xe6"); } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::piece; + + macro_rules! assert_flag { + ($move:expr, $left:expr, $right:expr) => { + assert_eq!($left, $right, "{:?}", $move) + }; + } + + macro_rules! assert_flags { + ($move:expr, $quiet:expr, $double_push:expr, $en_passant:expr, $capture:expr, $castle:expr, $promotion:expr) => { + assert_flag!($move, $move.is_quiet(), $quiet); + assert_flag!($move, $move.is_quiet(), $quiet); + assert_flag!($move, $move.is_double_push(), $double_push); + assert_flag!($move, $move.is_en_passant(), $en_passant); + assert_flag!($move, $move.is_capture(), $capture); + assert_flag!($move, $move.is_castle(), $castle); + assert_flag!($move, $move.is_promotion(), $promotion); + }; + } + + #[test] + fn move_flags_quiet() { + let mv = MoveBuilder::new(piece!(White Pawn), Square::A4, Square::A5).build(); + assert_flags!(mv, true, false, false, false, false, false); + } + + #[test] + fn move_flags_double_push() { + let mv = MoveBuilder::new(piece!(White Pawn), Square::C2, Square::C4).build(); + assert_flags!(mv, false, true, false, false, false, false); + } + + #[test] + fn move_flags_capture() { + let mv = MoveBuilder::new(piece!(White Pawn), Square::A4, Square::B5) + .capturing(piece!(Black Bishop on B5)) + .build(); + assert_flags!(mv, false, false, false, true, false, false); + } + + #[test] + fn move_flags_en_passant_capture() { + let mv = MoveBuilder::new(piece!(White Pawn), Square::A5, Square::B6) + .capturing_en_passant(piece!(Black Pawn on B5)) + .build(); + assert_flags!(mv, false, false, true, true, false, false); + } + + #[test] + fn move_flags_promotion() { + let mv = MoveBuilder::new(piece!(White Pawn), Square::H7, Square::H8) + .promoting_to(Shape::Queen) + .build(); + assert_flags!(mv, false, false, false, false, false, true); + assert_eq!(mv.promotion(), Some(Shape::Queen)); + } + + #[test] + fn move_flags_capture_promotion() { + let mv = MoveBuilder::new(piece!(White Pawn), Square::H7, Square::G8) + .capturing(piece!(Black Knight on G8)) + .promoting_to(Shape::Queen) + .build(); + assert_flags!(mv, false, false, false, true, false, true); + assert_eq!(mv.promotion(), Some(Shape::Queen)); + } + + #[test] + fn move_flags_castle() { + let mv = MoveBuilder::new(piece!(Black King), Square::E8, Square::G8) + .castle(Castle::KingSide) + .build(); + assert_flags!(mv, false, false, false, false, true, false); + } +}