Encode Move into a u16
This commit is contained in:
@@ -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<Move> {
|
||||
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),
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<usize>,
|
||||
) {
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -11,8 +11,8 @@ use crate::board::{
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub enum Promote {
|
||||
Knight,
|
||||
Rook,
|
||||
Bishop,
|
||||
Rook,
|
||||
Queen,
|
||||
}
|
||||
|
||||
@@ -27,29 +27,129 @@ 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 {
|
||||
pub src: usize,
|
||||
pub dst: usize,
|
||||
pub move_type: MoveType,
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Move {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}{}", to_algebraic(self.src), to_algebraic(self.dst))?;
|
||||
// https://www.chessprogramming.org/Encoding_Moves#From-To_Based
|
||||
#[rustfmt::skip]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
#[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,
|
||||
}
|
||||
|
||||
if let MoveType::Promotion(piece) | MoveType::PromotionCapture(piece) = &self.move_type {
|
||||
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',
|
||||
@@ -60,44 +160,21 @@ impl fmt::Debug for Move {
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl fmt::Debug for Move {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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<Promote, String> {
|
||||
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);
|
||||
|
||||
|
||||
@@ -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<Move>, src: usize, dst: usize, capture: bool) {
|
||||
let promotion_type = if capture {
|
||||
MoveType::PromotionCapture
|
||||
} else {
|
||||
MoveType::Promotion
|
||||
};
|
||||
|
||||
if capture {
|
||||
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)),
|
||||
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 {
|
||||
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),
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
||||
@@ -77,7 +80,7 @@ fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
||||
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<Move> {
|
||||
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();
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user