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