diff --git a/src/attack.rs b/src/attack.rs index 0fd655b..5465188 100644 --- a/src/attack.rs +++ b/src/attack.rs @@ -4,7 +4,7 @@ use crate::{ NOT_FILE_AB, NOT_FILE_GH, NOT_FILE_H, }, board::Color, - square::coords_to_square, + square::{bitboard_to_coords, coords_to_square}, }; use u64 as Bitboard; @@ -87,10 +87,7 @@ const fn king_attacks(bitboard: Bitboard) -> Bitboard { pub fn mask_bishop_attacks(bitboard: Bitboard) -> Bitboard { let mut attacks = EMPTY; - let (rank_dst, file_dst) = match bitboard { - 0 => (0, 0), - _ => (lsb(bitboard) / 8, lsb(bitboard) % 8), - }; + let (rank_dst, file_dst) = bitboard_to_coords(bitboard); let mut add_attacks_in_direction = |rank_iter: Box>, file_iter: Box>| { @@ -118,10 +115,7 @@ pub fn mask_bishop_attacks(bitboard: Bitboard) -> Bitboard { pub fn mask_rook_attacks(bitboard: Bitboard) -> Bitboard { let mut attacks = EMPTY; - let (rank_dst, file_dst) = match bitboard { - 0 => (0, 0), - _ => (lsb(bitboard) / 8, lsb(bitboard) % 8), - }; + let (rank_dst, file_dst) = bitboard_to_coords(bitboard); let mut add_attacks_in_direction = |iter: Box>, is_vertical: bool| { @@ -145,10 +139,7 @@ pub fn mask_rook_attacks(bitboard: Bitboard) -> Bitboard { pub fn bishop_attacks_on_the_fly(bitboard: Bitboard, blocker: Bitboard) -> Bitboard { let mut attacks = EMPTY; - let (rank_dst, file_dst) = match bitboard { - 0 => (0, 0), - _ => (lsb(bitboard) / 8, lsb(bitboard) % 8), - }; + let (rank_dst, file_dst) = bitboard_to_coords(bitboard); let mut add_attacks_in_direction = |rank_iter: Box>, file_iter: Box>| { @@ -171,10 +162,7 @@ pub fn bishop_attacks_on_the_fly(bitboard: Bitboard, blocker: Bitboard) -> Bitbo pub fn rook_attacks_on_the_fly(bitboard: Bitboard, blocker: Bitboard) -> Bitboard { let mut attacks = EMPTY; - let (rank_dst, file_dst) = match bitboard { - 0 => (0, 0), - _ => (lsb(bitboard) / 8, lsb(bitboard) % 8), - }; + let (rank_dst, file_dst) = bitboard_to_coords(bitboard); let mut add_attacks_in_direction = |iter: Box>, is_vertical: bool| { diff --git a/src/board.rs b/src/board.rs index eb32679..72c919b 100644 --- a/src/board.rs +++ b/src/board.rs @@ -4,7 +4,7 @@ use crate::attack::{ fetch_bishop_attacks, fetch_king_attacks, fetch_knight_attacks, fetch_pawn_attacks, fetch_queen_attacks, fetch_rook_attacks, }; -use crate::bitboard::have_common_bit; +use crate::bitboard::{have_common_bit, lsb}; use crate::movegen::{ bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves, queen_pseudo_moves, rook_pseudo_moves, @@ -101,8 +101,13 @@ impl Board { ) || have_common_bit(opponent[Kind::King].bitboard, fetch_king_attacks(square)) } - pub fn is_move_legit(&self, square: usize, opponent_color: Color) -> bool { - !self.is_attacked(square, opponent_color) + pub fn king_under_check(&self, color: Color) -> bool { + let own_king_square = match color { + Color::White => lsb(self.white_pieces[Kind::King].bitboard), + Color::Black => lsb(self.black_pieces[Kind::King].bitboard), + }; + + self.is_attacked(own_king_square, Color::opponent_color(color)) } pub fn pseudo_moves_all(&self, color: Color) -> Vec { @@ -193,14 +198,14 @@ pub enum Kind { } impl Kind { - fn idx(&self) -> usize { + const fn idx(&self) -> usize { match self { - Kind::Pawn => 0, - Kind::Knight => 1, - Kind::Bishop => 2, - Kind::Rook => 3, - Kind::Queen => 4, - Kind::King => 5, + Self::Pawn => 0, + Self::Knight => 1, + Self::Bishop => 2, + Self::Rook => 3, + Self::Queen => 4, + Self::King => 5, } } } diff --git a/src/move.rs b/src/move.rs index 0ab7348..7888554 100644 --- a/src/move.rs +++ b/src/move.rs @@ -1,10 +1,10 @@ use core::fmt; use crate::{ - bitboard::{have_common_bit, lsb, square_to_bitboard}, + bitboard::{have_common_bit, square_to_bitboard}, board::{Board, Color, Kind, Piece}, square::{coords_to_square, square_to_algebraic, Square}, - state::Castle, + state::{Castle, State}, }; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] @@ -108,72 +108,66 @@ impl Move { } impl Board { - pub fn make_move(&mut self, mv: Move, color: Color) -> bool { - self.update_board_state(&mv, color); - - let pieces = match color { - Color::White => &self.white_pieces, - Color::Black => &self.black_pieces, - }; - - self.state.update_castling_state_quiet(mv.src, color); - self.state - .update_castling_state_capture(mv.dst, Color::opponent_color(color)); - self.state.change_side(); - - let own_king_square = lsb(pieces[Kind::King].bitboard); - self.is_move_legit(own_king_square, Color::opponent_color(color)) + pub fn make_move(&mut self, mv: &Move, color: Color) { + self.update_board_state(mv, color); } pub fn update_board_state(&mut self, mv: &Move, color: Color) { - let (own_pieces, opponent_pieces) = match color { - Color::White => (&mut self.white_pieces, &mut self.black_pieces), - Color::Black => (&mut self.black_pieces, &mut self.white_pieces), + let (own_pieces, opponent_pieces, en_passant_square) = match color { + Color::White => ( + &mut self.white_pieces, + &mut self.black_pieces, + Some(mv.src + 8), + ), + Color::Black => ( + &mut self.black_pieces, + &mut self.white_pieces, + Some(mv.src - 8), + ), }; + Self::update_game_state(&mut self.state, mv.src, mv.dst, color); + match &mv.move_type { MoveType::Quiet => { Self::move_piece(mv.src, mv.dst, own_pieces); - self.state.set_en_passant_target_square(None); } MoveType::Capture => { Self::move_piece(mv.src, mv.dst, own_pieces); Self::remove_piece(mv.dst, opponent_pieces); - self.state.set_en_passant_target_square(None); } MoveType::EnPassant => { Self::move_piece(mv.src, mv.dst, own_pieces); Self::remove_pawn_enpassant(mv.dst, opponent_pieces, color); - self.state.set_en_passant_target_square(None); } MoveType::DoublePush => { Self::move_piece(mv.src, mv.dst, own_pieces); - let en_passant = match color { - Color::White => Some(mv.src + 8), - Color::Black => Some(mv.src - 8), - }; - self.state.set_en_passant_target_square(en_passant); + self.state.set_en_passant_target_square(en_passant_square); } MoveType::Promotion(promote) => { Self::remove_piece(mv.src, own_pieces); - Self::promote_piece(mv.dst, own_pieces, *promote); - self.state.set_en_passant_target_square(None); + Self::promote_piece(mv.dst, own_pieces, promote); } MoveType::PromotionCapture(promote) => { Self::remove_piece(mv.src, own_pieces); Self::remove_piece(mv.dst, opponent_pieces); - Self::promote_piece(mv.dst, own_pieces, *promote); - self.state.set_en_passant_target_square(None); + Self::promote_piece(mv.dst, own_pieces, promote); } MoveType::Castle => { Self::move_piece(mv.src, mv.dst, own_pieces); Self::move_rook_castle(mv.dst, own_pieces); - self.state.set_en_passant_target_square(None); self.state.set_castling_ability(color, Castle::None) } } } + fn update_game_state(state: &mut State, src: usize, dst: usize, color: Color) { + state.set_en_passant_target_square(None); + state.update_castling_state_quiet(src, color); + state.update_castling_state_capture(dst, Color::opponent_color(color)); + state.change_side(); + } + fn move_piece(src: usize, dst: usize, pieces: &mut [Piece; 6]) { for p in pieces.iter_mut() { if have_common_bit(p.bitboard, square_to_bitboard(src)) { @@ -194,7 +188,7 @@ impl Board { Self::move_piece(rook_src, rook_dst, pieces); } - fn promote_piece(square: usize, pieces: &mut [Piece; 6], promote: Promote) { + fn promote_piece(square: usize, pieces: &mut [Piece; 6], promote: &Promote) { match promote { Promote::Knight => pieces[Kind::Knight].bitboard |= square_to_bitboard(square), Promote::Bishop => pieces[Kind::Bishop].bitboard |= square_to_bitboard(square), @@ -240,7 +234,7 @@ mod tests { fn test_make_move_quiet() -> Result<(), String> { let mut game = from_fen(FEN_QUIET[0])?; let mv = Move::new_with_type(9, 25, MoveType::DoublePush); - game.board.make_move(mv, Color::White); + game.board.make_move(&mv, Color::White); assert_eq!(game, from_fen(FEN_QUIET[1])?); Ok(()) @@ -255,7 +249,7 @@ mod tests { fn test_make_move_capture() -> Result<(), String> { let mut game = from_fen(FEN_CAPTURE[0])?; let mv = Move::new_with_type(21, 37, MoveType::Capture); - game.board.make_move(mv, Color::White); + game.board.make_move(&mv, Color::White); assert_eq!(game, from_fen(FEN_CAPTURE[1])?); Ok(()) @@ -270,7 +264,7 @@ mod tests { fn test_make_move_en_passant() -> Result<(), String> { let mut game = from_fen(FEN_EN_PASSANT[0])?; let mv = Move::new_with_type(30, 23, MoveType::EnPassant); - game.board.make_move(mv, Color::Black); + game.board.make_move(&mv, Color::Black); assert_eq!(game, from_fen(FEN_EN_PASSANT[1])?); Ok(()) @@ -285,7 +279,7 @@ mod tests { fn test_make_move_double_push() -> Result<(), String> { let mut game = from_fen(FEN_DOUBLE_PUSH[0])?; let mv = Move::new_with_type(10, 26, MoveType::DoublePush); - game.board.make_move(mv, Color::White); + game.board.make_move(&mv, Color::White); assert_eq!(game, from_fen(FEN_DOUBLE_PUSH[1])?); Ok(()) } @@ -299,7 +293,7 @@ mod tests { fn test_make_move_promotion() -> Result<(), String> { let mut game = from_fen(FEN_PROMOTION[0])?; let mv = Move::new_with_type(54, 62, MoveType::Promotion(Promote::Queen)); - game.board.make_move(mv, Color::White); + game.board.make_move(&mv, Color::White); assert_eq!(game, from_fen(FEN_PROMOTION[1])?); Ok(()) @@ -314,7 +308,7 @@ mod tests { fn test_make_move_promotion_capture() -> Result<(), String> { let mut game = from_fen(FEN_PROMOTION_CAPTURE[0])?; let mv = Move::new_with_type(54, 61, MoveType::PromotionCapture(Promote::Queen)); - game.board.make_move(mv, Color::White); + game.board.make_move(&mv, Color::White); assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE[1])?); Ok(()) @@ -329,7 +323,7 @@ mod tests { fn test_make_move_castle() -> Result<(), String> { let mut game = from_fen(FEN_CASTLE[0])?; let mv = Move::new_with_type(4, 6, MoveType::Castle); - game.board.make_move(mv, Color::White); + game.board.make_move(&mv, Color::White); assert_eq!(game, from_fen(FEN_CASTLE[1])?); Ok(()) } diff --git a/src/movegen.rs b/src/movegen.rs index 5cb8dde..c9c094a 100644 --- a/src/movegen.rs +++ b/src/movegen.rs @@ -40,24 +40,34 @@ pub fn pawn_pseudo_moves( moves } +fn add_promotion_moves(moves: &mut Vec, src: usize, dst: usize, capture: bool) { + let promotion_type = if capture { + MoveType::PromotionCapture + } else { + MoveType::Promotion + }; + + moves.extend([ + Move::new_with_type(src, dst, promotion_type(Promote::Knight)), + Move::new_with_type(src, dst, promotion_type(Promote::Bishop)), + Move::new_with_type(src, dst, promotion_type(Promote::Rook)), + Move::new_with_type(src, dst, promotion_type(Promote::Queen)), + ]); +} + fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec { let mut moves = vec![]; let empty = !occupancies; let mut single_push = (pawns << 8) & empty; while single_push != 0 { - let to = lsb(single_push); - let from = to - 8; + let dst = lsb(single_push); + let src = dst - 8; - if have_common_bit(square_to_bitboard(from), RANK_7) { - moves.extend([ - Move::new_with_type(from, to, MoveType::Promotion(Promote::Knight)), - Move::new_with_type(from, to, MoveType::Promotion(Promote::Bishop)), - Move::new_with_type(from, to, MoveType::Promotion(Promote::Rook)), - Move::new_with_type(from, to, MoveType::Promotion(Promote::Queen)), - ]); + if have_common_bit(square_to_bitboard(src), RANK_7) { + add_promotion_moves(&mut moves, src, dst, false); } else { - moves.push(Move::new(from, to)); + moves.push(Move::new(src, dst)); } single_push &= single_push - 1; } @@ -65,9 +75,9 @@ fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec { let single_push = (pawns << 8) & empty; let mut double_push = (single_push << 8) & empty & RANK_4; while double_push != 0 { - let to = lsb(double_push); - let from = to - 16; - moves.push(Move::new_with_type(from, to, MoveType::DoublePush)); + let dst = lsb(double_push); + let src = dst - 16; + moves.push(Move::new_with_type(src, dst, MoveType::DoublePush)); double_push &= double_push - 1; } moves @@ -79,18 +89,13 @@ fn black_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec { let mut single_push = (pawns >> 8) & empty; while single_push != 0 { - let to = lsb(single_push); - let from = to + 8; + let dst = lsb(single_push); + let src = dst + 8; - if have_common_bit(square_to_bitboard(from), RANK_2) { - moves.extend([ - Move::new_with_type(from, to, MoveType::Promotion(Promote::Knight)), - Move::new_with_type(from, to, MoveType::Promotion(Promote::Bishop)), - Move::new_with_type(from, to, MoveType::Promotion(Promote::Rook)), - Move::new_with_type(from, to, MoveType::Promotion(Promote::Queen)), - ]); + if have_common_bit(square_to_bitboard(src), RANK_2) { + add_promotion_moves(&mut moves, src, dst, false); } else { - moves.push(Move::new(from, to)); + moves.push(Move::new(src, dst)); } single_push &= single_push - 1; } @@ -98,9 +103,9 @@ fn black_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec { let single_push = (pawns >> 8) & empty; let mut double_push = (single_push >> 8) & empty & RANK_5; while double_push != 0 { - let to = lsb(double_push); - let from = to + 16; - moves.push(Move::new_with_type(from, to, MoveType::DoublePush)); + let dst = lsb(double_push); + let src = dst + 16; + moves.push(Move::new_with_type(src, dst, MoveType::DoublePush)); double_push &= double_push - 1; } moves @@ -116,41 +121,31 @@ fn white_pawn_capture_moves( let mut w_pawns_capture_west = pawns & ((opponent_occupancies >> 7) & NOT_FILE_A); while w_pawns_capture_east != 0 { - let from = lsb(w_pawns_capture_east); - let to = from + 9; + let src = lsb(w_pawns_capture_east); + let dst = src + 9; - if have_common_bit(square_to_bitboard(to), RANK_8) { - moves.extend([ - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)), - ]); + if have_common_bit(square_to_bitboard(dst), RANK_8) { + add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::new_with_type(from, to, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } w_pawns_capture_east &= w_pawns_capture_east - 1; } while w_pawns_capture_west != 0 { - let from = lsb(w_pawns_capture_west); - let to = from + 7; + let src = lsb(w_pawns_capture_west); + let dst = src + 7; - if have_common_bit(square_to_bitboard(to), RANK_8) { - moves.extend([ - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)), - ]); + if have_common_bit(square_to_bitboard(dst), RANK_8) { + add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::new_with_type(from, to, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } w_pawns_capture_west &= w_pawns_capture_west - 1; } if let Some(en_passant_sq) = en_passant_square { - let attacked_from = fetch_pawn_attacks(en_passant_sq, Color::Black); - let mut result = attacked_from & pawns; + let attacked_src = fetch_pawn_attacks(en_passant_sq, Color::Black); + let mut result = attacked_src & pawns; while result != 0 { moves.push(Move::new_with_type( lsb(result), @@ -173,41 +168,31 @@ fn black_pawn_capture_moves( let mut b_pawns_capture_west = pawns & ((opponent_occupancies << 9) & NOT_FILE_A); while b_pawns_capture_east != 0 { - let from = lsb(b_pawns_capture_east); - let to = from - 7; + let src = lsb(b_pawns_capture_east); + let dst = src - 7; - if have_common_bit(square_to_bitboard(to), RANK_1) { - moves.extend([ - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)), - ]); + if have_common_bit(square_to_bitboard(dst), RANK_1) { + add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::new_with_type(from, to, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } b_pawns_capture_east &= b_pawns_capture_east - 1; } while b_pawns_capture_west != 0 { - let from = lsb(b_pawns_capture_west); - let to = from - 9; - if have_common_bit(square_to_bitboard(to), RANK_1) { - moves.extend([ - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)), - Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)), - ]); + let src = lsb(b_pawns_capture_west); + let dst = src - 9; + if have_common_bit(square_to_bitboard(dst), RANK_1) { + add_promotion_moves(&mut moves, src, dst, true); } else { - moves.push(Move::new_with_type(from, to, MoveType::Capture)); + moves.push(Move::new_with_type(src, dst, MoveType::Capture)); } b_pawns_capture_west &= b_pawns_capture_west - 1; } if let Some(en_passant_square) = en_passant_square { - let attacked_from = fetch_pawn_attacks(en_passant_square, Color::White); - let mut result = attacked_from & pawns; + let attacked_src = fetch_pawn_attacks(en_passant_square, Color::White); + let mut result = attacked_src & pawns; while result != 0 { moves.push(Move::new_with_type( lsb(result), @@ -230,15 +215,15 @@ pub fn knight_pseudo_moves( while knights != 0 { let knight_square = lsb(knights); - let from = knight_square; + let src = knight_square; let mut attacks = fetch_knight_attacks(knight_square) & !own_occupancies; while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { - moves.push(Move::new(from, attack_sq)); + moves.push(Move::new(src, attack_sq)); } attacks &= attacks - 1; } @@ -257,15 +242,15 @@ pub fn bishop_pseudo_moves( while bishops != 0 { let bishop_square = lsb(bishops); - let from = bishop_square; + let src = bishop_square; let mut attacks = fetch_bishop_attacks(all_occupancies, bishop_square) & !own_occupancies; while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { - moves.push(Move::new(from, attack_sq)); + moves.push(Move::new(src, attack_sq)); } attacks &= attacks - 1; } @@ -284,15 +269,15 @@ pub fn rook_pseudo_moves( while rooks != 0 { let rook_square = lsb(rooks); - let from = rook_square; + let src = rook_square; let mut attacks = fetch_rook_attacks(all_occupancies, rook_square) & !own_occupancies; while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { - moves.push(Move::new(from, attack_sq)); + moves.push(Move::new(src, attack_sq)); } attacks &= attacks - 1; } @@ -311,15 +296,15 @@ pub fn queen_pseudo_moves( while queens != 0 { let queen_square = lsb(queens); - let from = queen_square; + let src = queen_square; let mut attacks = fetch_queen_attacks(all_occupancies, queen_square) & !own_occupancies; while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { - moves.push(Move::new(from, attack_sq)); + moves.push(Move::new(src, attack_sq)); } attacks &= attacks - 1; } @@ -337,16 +322,16 @@ pub fn king_pseudo_moves( ) -> Vec { let mut moves = vec![]; let king_square = lsb(king); - let from = king_square; + let src = king_square; let mut attacks = fetch_king_attacks(king_square) & !own_occupancies; let opponent_occupancies = all_occupancies ^ own_occupancies; while attacks != 0 { let attack_sq = lsb(attacks); if have_common_bit(square_to_bitboard(attack_sq), opponent_occupancies) { - moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture)); + moves.push(Move::new_with_type(src, attack_sq, MoveType::Capture)); } else { - moves.push(Move::new(from, attack_sq)); + moves.push(Move::new(src, attack_sq)); } attacks &= attacks - 1; } @@ -357,14 +342,14 @@ pub fn king_pseudo_moves( fn king_castling_moves(board: &Board, color: Color, all_occupancies: Bitboard) -> Vec { let mut moves = vec![]; - let (king_from, king_to_short, king_to_long, path_short, path_long) = match color { + let (king_src, king_dst_short, king_dst_long, path_short, path_long) = match color { Color::White => (4, 6, 2, 0x60_u64, 0xe_u64), Color::Black => (60, 62, 58, 0x6000000000000000_u64, 0xe00000000000000_u64), }; - let mut add_move_if_empty_path = |path_mask, king_to| { - if all_occupancies & path_mask == 0 { - moves.push(Move::new_with_type(king_from, king_to, MoveType::Castle)) + let mut add_move_if_empty_path = |path_mask, king_dst| { + if !have_common_bit(all_occupancies, path_mask) { + moves.push(Move::new_with_type(king_src, king_dst, MoveType::Castle)) } }; @@ -373,19 +358,19 @@ fn king_castling_moves(board: &Board, color: Color, all_occupancies: Bitboard) - king_and_adj_square_safety(board, color), ) { (Castle::Both, Castle::Both) => { - add_move_if_empty_path(path_short, king_to_short); - add_move_if_empty_path(path_long, king_to_long); + add_move_if_empty_path(path_short, king_dst_short); + add_move_if_empty_path(path_long, king_dst_long); } (Castle::Both, Castle::Short) | (Castle::Short, Castle::Short) | (Castle::Short, Castle::Both) => { - add_move_if_empty_path(path_short, king_to_short); + add_move_if_empty_path(path_short, king_dst_short); } (Castle::Both, Castle::Long) | (Castle::Long, Castle::Long) | (Castle::Long, Castle::Both) => { - add_move_if_empty_path(path_long, king_to_long); + add_move_if_empty_path(path_long, king_dst_long); } _ => (), }; diff --git a/src/perft.rs b/src/perft.rs index bf0be06..f586ee0 100644 --- a/src/perft.rs +++ b/src/perft.rs @@ -6,11 +6,14 @@ pub fn driver(game: &mut Game, nodes: &mut u64, depth: u8) { return; } - let pseudo_moves = game.board.pseudo_moves_all(game.board.state.next_turn()); + let color = game.board.state.next_turn(); + let pseudo_moves = game.board.pseudo_moves_all(color); for mv in pseudo_moves { let original_board = game.board.clone(); - if !game.board.make_move(mv, game.board.state.next_turn()) { + game.board.make_move(&mv, color); + + if game.board.king_under_check(color) { game.board = original_board; continue; } @@ -83,10 +86,6 @@ mod tests { fn test_perft_1() -> Result<(), String> { init_attacks(); - assert_eq!(perft(FEN_PERFT[0], 1)?, 20); - assert_eq!(perft(FEN_PERFT[0], 2)?, 400); - assert_eq!(perft(FEN_PERFT[0], 3)?, 8902); - assert_eq!(perft(FEN_PERFT[0], 4)?, 197281); assert_eq!(perft(FEN_PERFT[0], 5)?, 4865609); Ok(()) @@ -96,10 +95,6 @@ mod tests { fn test_perft_2() -> Result<(), String> { init_attacks(); - assert_eq!(perft(FEN_PERFT[1], 1)?, 48); - assert_eq!(perft(FEN_PERFT[1], 2)?, 2039); - assert_eq!(perft(FEN_PERFT[1], 3)?, 97862); - assert_eq!(perft(FEN_PERFT[1], 4)?, 4085603); assert_eq!(perft(FEN_PERFT[1], 5)?, 193690690); Ok(()) @@ -109,10 +104,6 @@ mod tests { fn test_perft_3() -> Result<(), String> { init_attacks(); - assert_eq!(perft(FEN_PERFT[2], 1)?, 14); - assert_eq!(perft(FEN_PERFT[2], 2)?, 191); - assert_eq!(perft(FEN_PERFT[2], 3)?, 2812); - assert_eq!(perft(FEN_PERFT[2], 4)?, 43238); assert_eq!(perft(FEN_PERFT[2], 5)?, 674624); Ok(()) @@ -122,10 +113,6 @@ mod tests { fn test_perft_4() -> Result<(), String> { init_attacks(); - assert_eq!(perft(FEN_PERFT[3], 1)?, 6); - assert_eq!(perft(FEN_PERFT[3], 2)?, 264); - assert_eq!(perft(FEN_PERFT[3], 3)?, 9467); - assert_eq!(perft(FEN_PERFT[3], 4)?, 422333); assert_eq!(perft(FEN_PERFT[3], 5)?, 15833292); Ok(()) @@ -135,10 +122,6 @@ mod tests { fn test_perft_5() -> Result<(), String> { init_attacks(); - assert_eq!(perft(FEN_PERFT[4], 1)?, 44); - assert_eq!(perft(FEN_PERFT[4], 2)?, 1486); - assert_eq!(perft(FEN_PERFT[4], 3)?, 62379); - assert_eq!(perft(FEN_PERFT[4], 4)?, 2103487); assert_eq!(perft(FEN_PERFT[4], 5)?, 89941194); Ok(()) @@ -148,10 +131,6 @@ mod tests { fn test_perft_6() -> Result<(), String> { init_attacks(); - assert_eq!(perft(FEN_PERFT[5], 1)?, 46); - assert_eq!(perft(FEN_PERFT[5], 2)?, 2079); - assert_eq!(perft(FEN_PERFT[5], 3)?, 89890); - assert_eq!(perft(FEN_PERFT[5], 4)?, 3894594); assert_eq!(perft(FEN_PERFT[5], 5)?, 164075551); Ok(()) diff --git a/src/search.rs b/src/search.rs index 7407351..53a97f4 100644 --- a/src/search.rs +++ b/src/search.rs @@ -5,11 +5,14 @@ pub fn search(game: &mut Game, depth: u8) { return; } - let pseudo_moves = game.board.pseudo_moves_all(game.board.state.next_turn()); + let color = game.board.state.next_turn(); + let pseudo_moves = game.board.pseudo_moves_all(color); for mv in pseudo_moves { let original_board = game.board.clone(); - if !game.board.make_move(mv, game.board.state.next_turn()) { + game.board.make_move(&mv, color); + + if game.board.king_under_check(color) { game.board = original_board; continue; } diff --git a/src/square.rs b/src/square.rs index ae77eb4..0cbe211 100644 --- a/src/square.rs +++ b/src/square.rs @@ -1,5 +1,7 @@ use u64 as Bitboard; +use crate::bitboard::lsb; + pub struct Square {} impl Square { @@ -80,6 +82,13 @@ pub const fn coords_to_square(rank: usize, file: usize) -> usize { rank * 8 + file } +pub const fn bitboard_to_coords(bitboard: Bitboard) -> (usize, usize) { + match bitboard { + 0 => (0, 0), + _ => (lsb(bitboard) / 8, lsb(bitboard) % 8), + } +} + pub fn square_to_algebraic(square: usize) -> String { let file = (square % 8) as u8; let rank = (square / 8) as u8; diff --git a/src/uci.rs b/src/uci.rs index 408dc6d..ae1daed 100644 --- a/src/uci.rs +++ b/src/uci.rs @@ -101,7 +101,7 @@ pub fn uci_position(mut position: SplitWhitespace) -> Result { for mv_str in position { let mv = Move::parse_from_str(mv_str)?; - game.board.make_move(mv, game.board.state.next_turn()); + game.board.make_move(&mv, game.board.state.next_turn()); } Ok(game)