Fix move generator bugs related to castling, enpassant, promotion
This commit is contained in:
54
src/board.rs
54
src/board.rs
@@ -4,7 +4,7 @@ use crate::attack::{
|
|||||||
get_bishop_attacks, get_king_attacks, get_knight_attacks, get_pawn_attacks, get_queen_attacks,
|
get_bishop_attacks, get_king_attacks, get_knight_attacks, get_pawn_attacks, get_queen_attacks,
|
||||||
get_rook_attacks,
|
get_rook_attacks,
|
||||||
};
|
};
|
||||||
use crate::game::State;
|
use crate::game::{Castle, State};
|
||||||
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,
|
||||||
@@ -88,12 +88,12 @@ impl Board {
|
|||||||
|
|
||||||
pub fn is_attacked(&self, sq: usize, opponent_color: Color) -> bool {
|
pub fn is_attacked(&self, sq: usize, opponent_color: Color) -> bool {
|
||||||
let all_occupancies = self.get_all_occupancies();
|
let all_occupancies = self.get_all_occupancies();
|
||||||
let enemy = match opponent_color {
|
let (enemy, own_color) = match opponent_color {
|
||||||
Color::Black => &self.black_pieces,
|
Color::Black => (&self.black_pieces, Color::White),
|
||||||
Color::White => &self.white_pieces,
|
Color::White => (&self.white_pieces, Color::Black),
|
||||||
};
|
};
|
||||||
|
|
||||||
enemy[Kind::Pawn.idx()].bitboard & get_pawn_attacks(sq, opponent_color) != 0
|
enemy[Kind::Pawn.idx()].bitboard & get_pawn_attacks(sq, own_color) != 0
|
||||||
|| enemy[Kind::Knight.idx()].bitboard & get_knight_attacks(sq) != 0
|
|| enemy[Kind::Knight.idx()].bitboard & get_knight_attacks(sq) != 0
|
||||||
|| enemy[Kind::Bishop.idx()].bitboard & get_bishop_attacks(all_occupancies, sq) != 0
|
|| enemy[Kind::Bishop.idx()].bitboard & get_bishop_attacks(all_occupancies, sq) != 0
|
||||||
|| enemy[Kind::Rook.idx()].bitboard & get_rook_attacks(all_occupancies, sq) != 0
|
|| enemy[Kind::Rook.idx()].bitboard & get_rook_attacks(all_occupancies, sq) != 0
|
||||||
@@ -156,14 +156,18 @@ impl Board {
|
|||||||
|
|
||||||
pub fn make_move(&mut self, mv: Move, color: Color) -> bool {
|
pub fn make_move(&mut self, mv: Move, color: Color) -> bool {
|
||||||
self.update_board_state(&mv, color);
|
self.update_board_state(&mv, color);
|
||||||
self.state.update_castling_state(mv.source as u8, color);
|
|
||||||
self.state.change_side();
|
|
||||||
|
|
||||||
let pieces = match color {
|
let pieces = match color {
|
||||||
Color::White => &self.white_pieces,
|
Color::White => &self.white_pieces,
|
||||||
Color::Black => &self.black_pieces,
|
Color::Black => &self.black_pieces,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.state
|
||||||
|
.update_castling_state_quiet(mv.source as u8, color);
|
||||||
|
self.state
|
||||||
|
.update_castling_state_capture(mv.target as u8, Color::opponent_color(color));
|
||||||
|
self.state.change_side();
|
||||||
|
|
||||||
let own_king_square = pieces[Kind::King.idx()].bitboard.trailing_zeros() as usize;
|
let own_king_square = pieces[Kind::King.idx()].bitboard.trailing_zeros() as usize;
|
||||||
self.is_move_legit(own_king_square, Color::opponent_color(color))
|
self.is_move_legit(own_king_square, Color::opponent_color(color))
|
||||||
}
|
}
|
||||||
@@ -191,7 +195,10 @@ impl Board {
|
|||||||
}
|
}
|
||||||
MoveType::DoublePush => {
|
MoveType::DoublePush => {
|
||||||
Board::move_piece(mv.source as u8, mv.target as u8, own_pieces);
|
Board::move_piece(mv.source as u8, mv.target as u8, own_pieces);
|
||||||
let en_passant = Some(mv.source as u8 + 8);
|
let en_passant = match color {
|
||||||
|
Color::White => Some((mv.source + 8) as u8),
|
||||||
|
Color::Black => Some((mv.source - 8) as u8),
|
||||||
|
};
|
||||||
self.state.set_en_passant_target_square(en_passant);
|
self.state.set_en_passant_target_square(en_passant);
|
||||||
}
|
}
|
||||||
MoveType::Promotion(promote) => {
|
MoveType::Promotion(promote) => {
|
||||||
@@ -209,6 +216,7 @@ impl Board {
|
|||||||
Board::move_piece(mv.source as u8, mv.target as u8, own_pieces);
|
Board::move_piece(mv.source as u8, mv.target as u8, own_pieces);
|
||||||
Board::move_rook_castle(mv.target as u8, own_pieces);
|
Board::move_rook_castle(mv.target as u8, own_pieces);
|
||||||
self.state.set_en_passant_target_square(None);
|
self.state.set_en_passant_target_square(None);
|
||||||
|
self.state.set_castling_ability(color, Castle::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,13 +238,7 @@ impl Board {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
for p in pieces.iter_mut() {
|
Board::move_piece(rook_source, rook_target, pieces);
|
||||||
if p.bitboard & 1_u64 << rook_source != 0 {
|
|
||||||
p.bitboard &= !(1_u64 << rook_source);
|
|
||||||
p.bitboard |= 1_u64 << rook_target;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn promote_piece(square: u8, pieces: &mut [Piece; 6], promote: Promote) {
|
fn promote_piece(square: u8, pieces: &mut [Piece; 6], promote: Promote) {
|
||||||
@@ -464,28 +466,6 @@ mod tests {
|
|||||||
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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_perftree_snapshots() -> Result<(), String> {
|
|
||||||
init_attacks();
|
|
||||||
|
|
||||||
let mut game = from_fen("rnbqkbnr/ppppp1pp/5p2/7Q/8/4P3/PPPP1PPP/RNB1KBNR w KQkq - 0 1")?;
|
|
||||||
for mv in game.board.pseudo_moves_all(Color::Black) {
|
|
||||||
if game.board.make_move_and_reset(mv, Color::Black) {
|
|
||||||
println!("{:?}", mv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut game = from_fen("rnbqkbnr/1ppppppp/p7/8/Q7/2P5/PP1PPPPP/RNB1KBNR w KQkq - 0 1")?;
|
|
||||||
for mv in game.board.pseudo_moves_all(Color::Black) {
|
|
||||||
if game.board.make_move_and_reset(mv, Color::Black) {
|
|
||||||
println!("{:?}", mv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/game.rs
37
src/game.rs
@@ -78,26 +78,37 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_castling_state(&mut self, square: u8, color: Color) {
|
pub fn update_castling_state_quiet(&mut self, source: u8, color: Color) {
|
||||||
if square == 0 || square == 7 {
|
self.update_castling_state_capture(source, color);
|
||||||
match (color, self.get_castling_ability(color)) {
|
|
||||||
(_, Castle::Both) => self.set_castling_ability(color, Castle::Long),
|
match (source, color) {
|
||||||
(_, Castle::Short) => self.set_castling_ability(color, Castle::None),
|
(4, Color::White) => self.set_castling_ability(color, Castle::None),
|
||||||
|
(60, Color::Black) => self.set_castling_ability(color, Castle::None),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_castling_state_capture(&mut self, target: u8, color: Color) {
|
||||||
|
let (short_square, long_square) = match color {
|
||||||
|
Color::White => (7, 0),
|
||||||
|
Color::Black => (63, 56),
|
||||||
|
};
|
||||||
|
|
||||||
|
if target == short_square {
|
||||||
|
match self.get_castling_ability(color) {
|
||||||
|
Castle::Both => self.set_castling_ability(color, Castle::Long),
|
||||||
|
Castle::Short => self.set_castling_ability(color, Castle::None),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if square == 56 || square == 63 {
|
if target == long_square {
|
||||||
match (color, self.get_castling_ability(color)) {
|
match self.get_castling_ability(color) {
|
||||||
(_, Castle::Both) => self.set_castling_ability(color, Castle::Short),
|
Castle::Both => self.set_castling_ability(color, Castle::Short),
|
||||||
(_, Castle::Short) => self.set_castling_ability(color, Castle::None),
|
Castle::Long => self.set_castling_ability(color, Castle::None),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if square == 4 || square == 60 {
|
|
||||||
self.set_castling_ability(color, Castle::None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_side(&mut self) {
|
pub fn change_side(&mut self) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
|||||||
let to = single_push_targets.trailing_zeros();
|
let to = single_push_targets.trailing_zeros();
|
||||||
let from = to - 8;
|
let from = to - 8;
|
||||||
|
|
||||||
if from as u64 & 0xff000000000000 != 0 {
|
if 1_u64 << from as u64 & 0xff000000000000 != 0 {
|
||||||
moves.extend([
|
moves.extend([
|
||||||
Move::new_with_type(from, to, MoveType::Promotion(Promote::Knight)),
|
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::Bishop)),
|
||||||
@@ -82,7 +82,7 @@ fn black_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
|||||||
let to = single_push_targets.trailing_zeros();
|
let to = single_push_targets.trailing_zeros();
|
||||||
let from = to + 8;
|
let from = to + 8;
|
||||||
|
|
||||||
if from as u64 & 0xff000000000000 != 0 {
|
if 1_u64 << from as u64 & 0xff00 != 0 {
|
||||||
moves.extend([
|
moves.extend([
|
||||||
Move::new_with_type(from, to, MoveType::Promotion(Promote::Knight)),
|
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::Bishop)),
|
||||||
@@ -119,7 +119,7 @@ fn white_pawn_capture_moves(
|
|||||||
let from = w_pawns_capture_east.trailing_zeros();
|
let from = w_pawns_capture_east.trailing_zeros();
|
||||||
let to = from + 9;
|
let to = from + 9;
|
||||||
|
|
||||||
if from as u64 & 0xff000000000000 != 0 {
|
if 1_u64 << to as u64 & 0xff00000000000000 != 0 {
|
||||||
moves.extend([
|
moves.extend([
|
||||||
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
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::Bishop)),
|
||||||
@@ -135,7 +135,7 @@ fn white_pawn_capture_moves(
|
|||||||
let from = w_pawns_capture_west.trailing_zeros();
|
let from = w_pawns_capture_west.trailing_zeros();
|
||||||
let to = from + 7;
|
let to = from + 7;
|
||||||
|
|
||||||
if from as u64 & 0xff000000000000 != 0 {
|
if 1_u64 << to as u64 & 0xff00000000000000 != 0 {
|
||||||
moves.extend([
|
moves.extend([
|
||||||
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
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::Bishop)),
|
||||||
@@ -150,13 +150,14 @@ fn white_pawn_capture_moves(
|
|||||||
|
|
||||||
if let Some(en_passant_square) = en_passant_square {
|
if let Some(en_passant_square) = en_passant_square {
|
||||||
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::Black);
|
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::Black);
|
||||||
let result = attacked_from & pawns;
|
let mut result = attacked_from & pawns;
|
||||||
if result != 0 {
|
while result != 0 {
|
||||||
moves.push(Move::new_with_type(
|
moves.push(Move::new_with_type(
|
||||||
result.trailing_zeros(),
|
result.trailing_zeros(),
|
||||||
en_passant_square as u32,
|
en_passant_square as u32,
|
||||||
MoveType::EnPassant,
|
MoveType::EnPassant,
|
||||||
));
|
));
|
||||||
|
result &= result - 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
moves
|
moves
|
||||||
@@ -174,7 +175,7 @@ fn black_pawn_capture_moves(
|
|||||||
while b_pawns_capture_east != 0 {
|
while b_pawns_capture_east != 0 {
|
||||||
let from = b_pawns_capture_east.trailing_zeros();
|
let from = b_pawns_capture_east.trailing_zeros();
|
||||||
let to = from - 7;
|
let to = from - 7;
|
||||||
if from as u64 & 0xff00 != 0 {
|
if 1_u64 << to as u64 & 0xff != 0 {
|
||||||
moves.extend([
|
moves.extend([
|
||||||
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
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::Bishop)),
|
||||||
@@ -190,7 +191,7 @@ fn black_pawn_capture_moves(
|
|||||||
while b_pawns_capture_west != 0 {
|
while b_pawns_capture_west != 0 {
|
||||||
let from = b_pawns_capture_west.trailing_zeros();
|
let from = b_pawns_capture_west.trailing_zeros();
|
||||||
let to = from - 9;
|
let to = from - 9;
|
||||||
if from as u64 & 0xff00 != 0 {
|
if 1_u64 << to as u64 & 0xff != 0 {
|
||||||
moves.extend([
|
moves.extend([
|
||||||
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
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::Bishop)),
|
||||||
@@ -205,13 +206,14 @@ fn black_pawn_capture_moves(
|
|||||||
|
|
||||||
if let Some(en_passant_square) = en_passant_square {
|
if let Some(en_passant_square) = en_passant_square {
|
||||||
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::White);
|
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::White);
|
||||||
let result = attacked_from & pawns;
|
let mut result = attacked_from & pawns;
|
||||||
if result != 0 {
|
while result != 0 {
|
||||||
moves.push(Move::new_with_type(
|
moves.push(Move::new_with_type(
|
||||||
result.trailing_zeros(),
|
result.trailing_zeros(),
|
||||||
en_passant_square as u32,
|
en_passant_square as u32,
|
||||||
MoveType::EnPassant,
|
MoveType::EnPassant,
|
||||||
));
|
));
|
||||||
|
result &= result - 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
moves
|
moves
|
||||||
@@ -373,11 +375,16 @@ fn king_castling_moves(board: &Board, color: Color, all_occupancies: Bitboard) -
|
|||||||
add_move_if_empty_path(path_short, king_to_short);
|
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_long, king_to_long);
|
||||||
}
|
}
|
||||||
(Castle::Both, Castle::Short) | (Castle::Short, Castle::Short) => {
|
|
||||||
|
(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_to_short);
|
||||||
}
|
}
|
||||||
(Castle::Both, Castle::Long) | (Castle::Long, Castle::Long) => {
|
(Castle::Both, Castle::Long)
|
||||||
add_move_if_empty_path(path_long, king_to_long)
|
| (Castle::Long, Castle::Long)
|
||||||
|
| (Castle::Long, Castle::Both) => {
|
||||||
|
add_move_if_empty_path(path_long, king_to_long);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
@@ -386,7 +393,7 @@ fn king_castling_moves(board: &Board, color: Color, all_occupancies: Bitboard) -
|
|||||||
|
|
||||||
fn king_and_adj_square_safety(board: &Board, color: Color) -> Castle {
|
fn king_and_adj_square_safety(board: &Board, color: Color) -> Castle {
|
||||||
let (king_at, opponent_color) = match color {
|
let (king_at, opponent_color) = match color {
|
||||||
Color::White => (3, Color::Black),
|
Color::White => (4, Color::Black),
|
||||||
Color::Black => (60, Color::White),
|
Color::Black => (60, Color::White),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -394,12 +401,12 @@ fn king_and_adj_square_safety(board: &Board, color: Color) -> Castle {
|
|||||||
return Castle::None;
|
return Castle::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let short_attacked = board.is_attacked(king_at - 1, opponent_color);
|
let short_attacked = board.is_attacked(king_at + 1, opponent_color);
|
||||||
let long_attacked = board.is_attacked(king_at + 1, opponent_color);
|
let long_attacked = board.is_attacked(king_at - 1, opponent_color);
|
||||||
match (short_attacked, long_attacked) {
|
match (short_attacked, long_attacked) {
|
||||||
(true, true) => Castle::None,
|
(true, true) => Castle::None,
|
||||||
(true, false) => Castle::Short,
|
(true, false) => Castle::Long,
|
||||||
(false, true) => Castle::Long,
|
(false, true) => Castle::Short,
|
||||||
(false, false) => Castle::Both,
|
(false, false) => Castle::Both,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -495,7 +502,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Bishop);
|
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Bishop);
|
||||||
actual.sort();
|
actual.sort();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -594,16 +601,4 @@ mod tests {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_random() -> Result<(), String> {
|
|
||||||
init_attacks();
|
|
||||||
let game = from_fen("rnbqkbnr/ppppp1pp/5p2/7Q/8/4P3/PPPP1PPP/RNB1KBNR w KQkq - 0 1")?;
|
|
||||||
|
|
||||||
for mv in game.board.pseudo_moves_all(Color::Black) {
|
|
||||||
println!("{:?}", mv);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
196
src/perft.rs
196
src/perft.rs
@@ -1,14 +1,13 @@
|
|||||||
use crate::game::Game;
|
use crate::game::Game;
|
||||||
|
|
||||||
pub fn perft_driver(game: &mut Game, nodes: &mut u64, depth: u8) {
|
pub fn driver(game: &mut Game, nodes: &mut u64, depth: u8) {
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
*nodes += 1;
|
*nodes += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pseudo_moves =
|
let pseudo_moves = game.board.pseudo_moves_all(game.board.state.next_turn());
|
||||||
game.board.pseudo_moves_all(game.board.state.next_turn());
|
|
||||||
|
|
||||||
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()) {
|
if !game.board.make_move(mv, game.board.state.next_turn()) {
|
||||||
@@ -16,20 +15,22 @@ pub fn perft_driver(game: &mut Game, nodes: &mut u64, depth: u8) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print_perftree(mv.source, mv.target, depth, nodes);
|
print_perftree(mv.source, mv.target, depth, nodes);
|
||||||
|
|
||||||
perft_driver(game, nodes, depth - 1);
|
driver(game, nodes, depth - 1);
|
||||||
game.board = original_board;
|
game.board = original_board;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn print_perftree(source: u32, target: u32, depth: u8, nodes: &mut u64) {
|
fn print_perftree(source: u32, target: u32, depth: u8, nodes: &mut u64) {
|
||||||
println!(
|
// println!(
|
||||||
"{}{} - depth: {}",
|
// "{}{} - depth: {} - nodes: {}",
|
||||||
square_to_notation(source as u8),
|
// square_to_notation(source as u8),
|
||||||
square_to_notation(target as u8),
|
// square_to_notation(target as u8),
|
||||||
depth
|
// depth,
|
||||||
);
|
// nodes
|
||||||
|
// );
|
||||||
|
|
||||||
if depth == MAX_DEPTH {
|
if depth == MAX_DEPTH {
|
||||||
println!(
|
println!(
|
||||||
"{}{} {}",
|
"{}{} {}",
|
||||||
@@ -39,16 +40,15 @@ pub fn perft_driver(game: &mut Game, nodes: &mut u64, depth: u8) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_DEPTH: u8 = 4;
|
const MAX_DEPTH: u8 = 3;
|
||||||
|
|
||||||
pub fn perftree_script() {
|
pub fn perftree_script() {
|
||||||
let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
let fen = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1";
|
||||||
let mut game = crate::fen::from_fen(fen).unwrap();
|
let mut game = crate::fen::from_fen(fen).unwrap();
|
||||||
let (mut nodes, depth): (u64, u8) = (0, MAX_DEPTH);
|
let (mut nodes, depth): (u64, u8) = (0, MAX_DEPTH);
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
driver(&mut game, &mut nodes, depth);
|
||||||
println!();
|
println!();
|
||||||
println!("{}", nodes)
|
println!("{}", nodes)
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ pub fn square_to_notation(square: u8) -> &'static str {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::{attack::init_attacks, fen::from_fen};
|
use crate::{attack::init_attacks, fen::from_fen};
|
||||||
|
|
||||||
use super::perft_driver;
|
use super::driver;
|
||||||
|
|
||||||
// Examples from https://www.chessprogramming.org/Perft_Results
|
// Examples from https://www.chessprogramming.org/Perft_Results
|
||||||
const FEN_PERFT: [&str; 6] = [
|
const FEN_PERFT: [&str; 6] = [
|
||||||
@@ -93,164 +93,90 @@ mod tests {
|
|||||||
"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10",
|
"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10",
|
||||||
];
|
];
|
||||||
|
|
||||||
#[test]
|
fn perft(fen: &str, depth: u8) -> Result<u64, String> {
|
||||||
fn test_perft_driver_1() -> Result<(), String> {
|
|
||||||
init_attacks();
|
init_attacks();
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[0])?;
|
let mut game = from_fen(fen)?;
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 1);
|
let mut nodes = 0;
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
driver(&mut game, &mut nodes, depth);
|
||||||
assert_eq!(nodes , 20);
|
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[0])?;
|
Ok(nodes)
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 2);
|
}
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
assert_eq!(nodes, 400);
|
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[0])?;
|
#[test]
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 3);
|
fn test_perft_1() -> Result<(), String> {
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
init_attacks();
|
||||||
assert_eq!(nodes, 8902);
|
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[0])?;
|
assert_eq!(perft(FEN_PERFT[0], 1)?, 20);
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 4);
|
assert_eq!(perft(FEN_PERFT[0], 2)?, 400);
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
assert_eq!(perft(FEN_PERFT[0], 3)?, 8902);
|
||||||
assert_eq!(nodes, 197281);
|
assert_eq!(perft(FEN_PERFT[0], 4)?, 197281);
|
||||||
|
assert_eq!(perft(FEN_PERFT[0], 5)?, 4865609);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_perft_driver_2() -> Result<(), String> {
|
fn test_perft_2() -> Result<(), String> {
|
||||||
init_attacks();
|
init_attacks();
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[1])?;
|
assert_eq!(perft(FEN_PERFT[1], 1)?, 48);
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 1);
|
assert_eq!(perft(FEN_PERFT[1], 2)?, 2039);
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
assert_eq!(perft(FEN_PERFT[1], 3)?, 97862);
|
||||||
assert_eq!(nodes, 48);
|
assert_eq!(perft(FEN_PERFT[1], 4)?, 4085603);
|
||||||
|
assert_eq!(perft(FEN_PERFT[1], 5)?, 193690690);
|
||||||
let mut game = from_fen(FEN_PERFT[1])?;
|
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 2);
|
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
assert_eq!(nodes, 2039);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[1])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 3);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 97862);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[1])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 4);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 4085603);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_perft_driver_3() -> Result<(), String> {
|
fn test_perft_3() -> Result<(), String> {
|
||||||
init_attacks();
|
init_attacks();
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[2])?;
|
assert_eq!(perft(FEN_PERFT[2], 1)?, 14);
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 1);
|
assert_eq!(perft(FEN_PERFT[2], 2)?, 191);
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
assert_eq!(perft(FEN_PERFT[2], 3)?, 2812);
|
||||||
// assert_eq!(nodes, 14);
|
assert_eq!(perft(FEN_PERFT[2], 4)?, 43238);
|
||||||
|
assert_eq!(perft(FEN_PERFT[2], 5)?, 674624);
|
||||||
// let mut game = from_fen(FEN_PERFT[2])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 2);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 191);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[2])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 3);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 2812);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[2])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 4);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 43238);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_perft_driver_4() -> Result<(), String> {
|
fn test_perft_4() -> Result<(), String> {
|
||||||
init_attacks();
|
init_attacks();
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[3])?;
|
assert_eq!(perft(FEN_PERFT[3], 1)?, 6);
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 1);
|
assert_eq!(perft(FEN_PERFT[3], 2)?, 264);
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
assert_eq!(perft(FEN_PERFT[3], 3)?, 9467);
|
||||||
assert_eq!(nodes , 6);
|
assert_eq!(perft(FEN_PERFT[3], 4)?, 422333);
|
||||||
|
assert_eq!(perft(FEN_PERFT[3], 5)?, 15833292);
|
||||||
// let mut game = from_fen(FEN_PERFT[3])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 2);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 264);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[3])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 3);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 9467);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[3])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 4);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 422333);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_perft_driver_5() -> Result<(), String> {
|
fn test_perft_5() -> Result<(), String> {
|
||||||
init_attacks();
|
init_attacks();
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[4])?;
|
assert_eq!(perft(FEN_PERFT[4], 1)?, 44);
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 1);
|
assert_eq!(perft(FEN_PERFT[4], 2)?, 1486);
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
assert_eq!(perft(FEN_PERFT[4], 3)?, 62379);
|
||||||
// assert_eq!(nodes , 44);
|
assert_eq!(perft(FEN_PERFT[4], 4)?, 2103487);
|
||||||
|
assert_eq!(perft(FEN_PERFT[4], 5)?, 89941194);
|
||||||
// let mut game = from_fen(FEN_PERFT[4])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 2);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 1486);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[4])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 3);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 62379);
|
|
||||||
|
|
||||||
// let mut game = from_fen(FEN_PERFT[4])?;
|
|
||||||
// let (mut nodes, depth): (u64, u8) = (0, 4);
|
|
||||||
// perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
// assert_eq!(nodes, 2103487);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_perft_driver_6() -> Result<(), String> {
|
fn test_perft_6() -> Result<(), String> {
|
||||||
init_attacks();
|
init_attacks();
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[5])?;
|
assert_eq!(perft(FEN_PERFT[5], 1)?, 46);
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 1);
|
assert_eq!(perft(FEN_PERFT[5], 2)?, 2079);
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
assert_eq!(perft(FEN_PERFT[5], 3)?, 89890);
|
||||||
assert_eq!(nodes , 46);
|
assert_eq!(perft(FEN_PERFT[5], 4)?, 3894594);
|
||||||
|
assert_eq!(perft(FEN_PERFT[5], 5)?, 164075551);
|
||||||
let mut game = from_fen(FEN_PERFT[5])?;
|
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 2);
|
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
assert_eq!(nodes, 2079);
|
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[5])?;
|
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 3);
|
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
assert_eq!(nodes, 89890);
|
|
||||||
|
|
||||||
let mut game = from_fen(FEN_PERFT[5])?;
|
|
||||||
let (mut nodes, depth): (u64, u8) = (0, 4);
|
|
||||||
perft_driver(&mut game, &mut nodes, depth);
|
|
||||||
assert_eq!(nodes, 3894594);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user