Add perft function and fix move generator bugs using perftree
This commit is contained in:
@@ -173,8 +173,8 @@ pub fn bishop_attacks_on_the_fly(bitboard: Bitboard, blocker: Bitboard) -> Bitbo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(rank, file) = (target_rank.saturating_sub(1), target_file + 1);
|
file = target_file + 1;
|
||||||
for (rank, file) in (0..=rank).rev().zip(file..=7) {
|
for (rank, file) in (0..target_rank).rev().zip(file..=7) {
|
||||||
let attack_square = 1_u64 << (rank * 8 + file);
|
let attack_square = 1_u64 << (rank * 8 + file);
|
||||||
attacks |= attack_square;
|
attacks |= attack_square;
|
||||||
if attack_square & blocker != 0 {
|
if attack_square & blocker != 0 {
|
||||||
@@ -182,8 +182,8 @@ pub fn bishop_attacks_on_the_fly(bitboard: Bitboard, blocker: Bitboard) -> Bitbo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(rank, file) = (target_rank + 1, target_file.saturating_sub(1));
|
rank = target_rank + 1;
|
||||||
for (rank, file) in (rank..=7).zip((0..=file).rev()) {
|
for (rank, file) in (rank..=7).zip((0..target_file).rev()) {
|
||||||
let attack_square = 1_u64 << (rank * 8 + file);
|
let attack_square = 1_u64 << (rank * 8 + file);
|
||||||
attacks |= attack_square;
|
attacks |= attack_square;
|
||||||
if attack_square & blocker != 0 {
|
if attack_square & blocker != 0 {
|
||||||
@@ -191,8 +191,7 @@ pub fn bishop_attacks_on_the_fly(bitboard: Bitboard, blocker: Bitboard) -> Bitbo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(rank, file) = (target_rank.saturating_sub(1), target_file.saturating_sub(1));
|
for (rank, file) in (0..target_rank).rev().zip((0..target_file).rev()) {
|
||||||
for (rank, file) in (0..=rank).rev().zip((0..=file).rev()) {
|
|
||||||
let attack_square = 1_u64 << (rank * 8 + file);
|
let attack_square = 1_u64 << (rank * 8 + file);
|
||||||
attacks |= attack_square;
|
attacks |= attack_square;
|
||||||
if attack_square & blocker != 0 {
|
if attack_square & blocker != 0 {
|
||||||
@@ -233,7 +232,6 @@ pub fn rook_attacks_on_the_fly(bitboard: Bitboard, blocker: Bitboard) -> Bitboar
|
|||||||
}
|
}
|
||||||
|
|
||||||
(rank, file) = (target_rank.saturating_sub(1), target_file.saturating_sub(1));
|
(rank, file) = (target_rank.saturating_sub(1), target_file.saturating_sub(1));
|
||||||
|
|
||||||
for rank in (0..=rank).rev() {
|
for rank in (0..=rank).rev() {
|
||||||
let attack_square = 1_u64 << (rank * 8 + target_file);
|
let attack_square = 1_u64 << (rank * 8 + target_file);
|
||||||
attacks |= attack_square;
|
attacks |= attack_square;
|
||||||
@@ -257,9 +255,9 @@ pub fn set_occupancy(index: u64, bits_in_mask: u8, mut attack_mask: Bitboard) ->
|
|||||||
|
|
||||||
for count in 0..bits_in_mask {
|
for count in 0..bits_in_mask {
|
||||||
let square = attack_mask.trailing_zeros() as u8;
|
let square = attack_mask.trailing_zeros() as u8;
|
||||||
attack_mask &= !1_u64 << (square);
|
attack_mask &= !(1_u64 << square);
|
||||||
if index & (1_u64 << (count)) != 0 {
|
if index & (1_u64 << count) != 0 {
|
||||||
occupancy |= 1_u64 << (square);
|
occupancy |= 1_u64 << square;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,11 +330,10 @@ pub fn init_bishop_attacks() {
|
|||||||
for sq in 0..64 {
|
for sq in 0..64 {
|
||||||
bishop_masks[sq] = mask_bishop_attacks(1_u64 << (sq));
|
bishop_masks[sq] = mask_bishop_attacks(1_u64 << (sq));
|
||||||
let attack_mask = bishop_masks[sq];
|
let attack_mask = bishop_masks[sq];
|
||||||
let relevant_bits_count = attack_mask.count_ones() as u8;
|
let occupancy_indices = 1_u64 << BISHOP_RELEVANT_BITS[sq];
|
||||||
let occupancy_indices = 1_u64 << (relevant_bits_count);
|
|
||||||
|
|
||||||
for idx in 0..occupancy_indices {
|
for idx in 0..occupancy_indices {
|
||||||
let occupancy = set_occupancy(idx, relevant_bits_count, attack_mask);
|
let occupancy = set_occupancy(idx, BISHOP_RELEVANT_BITS[sq], attack_mask);
|
||||||
unsafe {
|
unsafe {
|
||||||
let magic_index =
|
let magic_index =
|
||||||
occupancy.wrapping_mul(BISHOP_MAGIC[sq]) >> (64 - BISHOP_RELEVANT_BITS[sq]);
|
occupancy.wrapping_mul(BISHOP_MAGIC[sq]) >> (64 - BISHOP_RELEVANT_BITS[sq]);
|
||||||
@@ -470,6 +467,11 @@ mod tests {
|
|||||||
let attacks = bishop_attacks_on_the_fly(bishop_d4.bitboard, blocker_c5);
|
let attacks = bishop_attacks_on_the_fly(bishop_d4.bitboard, blocker_c5);
|
||||||
assert_eq!(attacks, 0x8040201400142241);
|
assert_eq!(attacks, 0x8040201400142241);
|
||||||
|
|
||||||
|
let bishop_a1 = Piece::new(0x0, Kind::Bishop, Color::White);
|
||||||
|
let blocker_none = 0x0_u64;
|
||||||
|
let attacks = bishop_attacks_on_the_fly(bishop_a1.bitboard, blocker_none);
|
||||||
|
assert_eq!(attacks, 0x8040201008040200);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
39
src/board.rs
39
src/board.rs
@@ -115,7 +115,6 @@ impl Board {
|
|||||||
moves.extend(self.pseudo_moves(color, Kind::King));
|
moves.extend(self.pseudo_moves(color, Kind::King));
|
||||||
moves
|
moves
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pseudo_moves(&self, color: Color, kind: Kind) -> Vec<Move> {
|
pub fn pseudo_moves(&self, color: Color, kind: Kind) -> Vec<Move> {
|
||||||
let all_occupancies = self.get_all_occupancies();
|
let all_occupancies = self.get_all_occupancies();
|
||||||
let (pieces, enemy_occupancies, own_occupancies) = match color {
|
let (pieces, enemy_occupancies, own_occupancies) = match color {
|
||||||
@@ -147,20 +146,18 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_move_and_reset(&mut self, mv: Move, color: Color) -> Vec<Board> {
|
pub fn make_move_and_reset(&mut self, mv: Move, color: Color) -> bool {
|
||||||
let mut board_variants = vec![];
|
|
||||||
let original_board = self.clone();
|
let original_board = self.clone();
|
||||||
if self.make_move(mv, color) {
|
let result = self.make_move(mv, color);
|
||||||
board_variants.push(self.clone());
|
|
||||||
}
|
|
||||||
*self = original_board;
|
*self = original_board;
|
||||||
board_variants
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
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.update_castling_state(mv.source as u8, color);
|
||||||
self.state.next_turn();
|
self.state.change_side();
|
||||||
|
|
||||||
let pieces = match color {
|
let pieces = match color {
|
||||||
Color::White => &self.white_pieces,
|
Color::White => &self.white_pieces,
|
||||||
@@ -180,10 +177,12 @@ impl Board {
|
|||||||
match &mv.move_type {
|
match &mv.move_type {
|
||||||
MoveType::Quiet => {
|
MoveType::Quiet => {
|
||||||
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);
|
||||||
|
self.state.set_en_passant_target_square(None);
|
||||||
}
|
}
|
||||||
MoveType::Capture => {
|
MoveType::Capture => {
|
||||||
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::remove_piece(mv.target as u8, opponent_pieces);
|
Board::remove_piece(mv.target as u8, opponent_pieces);
|
||||||
|
self.state.set_en_passant_target_square(None);
|
||||||
}
|
}
|
||||||
MoveType::EnPassant => {
|
MoveType::EnPassant => {
|
||||||
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);
|
||||||
@@ -198,15 +197,18 @@ impl Board {
|
|||||||
MoveType::Promotion(promote) => {
|
MoveType::Promotion(promote) => {
|
||||||
Board::remove_piece(mv.source as u8, own_pieces);
|
Board::remove_piece(mv.source as u8, own_pieces);
|
||||||
Board::promote_piece(mv.target as u8, own_pieces, *promote);
|
Board::promote_piece(mv.target as u8, own_pieces, *promote);
|
||||||
|
self.state.set_en_passant_target_square(None);
|
||||||
}
|
}
|
||||||
MoveType::PromotionCapture(promote) => {
|
MoveType::PromotionCapture(promote) => {
|
||||||
Board::remove_piece(mv.source as u8, own_pieces);
|
Board::remove_piece(mv.source as u8, own_pieces);
|
||||||
Board::remove_piece(mv.target as u8, opponent_pieces);
|
Board::remove_piece(mv.target as u8, opponent_pieces);
|
||||||
Board::promote_piece(mv.target as u8, own_pieces, *promote);
|
Board::promote_piece(mv.target as u8, own_pieces, *promote);
|
||||||
|
self.state.set_en_passant_target_square(None);
|
||||||
}
|
}
|
||||||
MoveType::Castle => {
|
MoveType::Castle => {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,4 +467,25 @@ mod tests {
|
|||||||
|
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,13 +100,17 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_turn(&mut self) {
|
pub fn change_side(&mut self) {
|
||||||
self.side_to_move = match self.side_to_move {
|
self.side_to_move = match self.side_to_move {
|
||||||
Color::White => Color::Black,
|
Color::White => Color::Black,
|
||||||
Color::Black => Color::White,
|
Color::Black => Color::White,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn next_turn(&self) -> Color {
|
||||||
|
self.side_to_move
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_en_passant_target_square(&mut self, sq: Option<u8>) {
|
pub fn set_en_passant_target_square(&mut self, sq: Option<u8>) {
|
||||||
self.en_passant_target_square = sq;
|
self.en_passant_target_square = sq;
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@@ -5,10 +5,13 @@ pub mod game;
|
|||||||
pub mod magic;
|
pub mod magic;
|
||||||
pub mod r#move;
|
pub mod r#move;
|
||||||
pub mod movegen;
|
pub mod movegen;
|
||||||
|
pub mod perft;
|
||||||
use game::Game;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let game = Game::new();
|
attack::init_attacks();
|
||||||
game.run();
|
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if args.len() == 2 && args[1] == "perft" {
|
||||||
|
perft::perftree_script()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,11 +151,13 @@ 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 result = attacked_from & pawns;
|
||||||
moves.push(Move::new_with_type(
|
if result != 0 {
|
||||||
result.trailing_zeros(),
|
moves.push(Move::new_with_type(
|
||||||
en_passant_square as u32,
|
result.trailing_zeros(),
|
||||||
MoveType::EnPassant,
|
en_passant_square as u32,
|
||||||
));
|
MoveType::EnPassant,
|
||||||
|
));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
moves
|
moves
|
||||||
}
|
}
|
||||||
@@ -204,11 +206,13 @@ 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 result = attacked_from & pawns;
|
||||||
moves.push(Move::new_with_type(
|
if result != 0 {
|
||||||
result.trailing_zeros(),
|
moves.push(Move::new_with_type(
|
||||||
en_passant_square as u32,
|
result.trailing_zeros(),
|
||||||
MoveType::EnPassant,
|
en_passant_square as u32,
|
||||||
));
|
MoveType::EnPassant,
|
||||||
|
));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
moves
|
moves
|
||||||
}
|
}
|
||||||
@@ -351,12 +355,12 @@ 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_from, king_to_short, king_to_long, path_short, path_long) = match color {
|
||||||
Color::White => (4, 2, 6, 0x60_u64, 0xe_u64),
|
Color::White => (4, 6, 2, 0x60_u64, 0xe_u64),
|
||||||
Color::Black => (60, 58, 62, 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_to| {
|
||||||
if all_occupancies & path_mask != 0 {
|
if all_occupancies & path_mask == 0 {
|
||||||
moves.push(Move::new_with_type(king_from, king_to, MoveType::Castle))
|
moves.push(Move::new_with_type(king_from, king_to, MoveType::Castle))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -590,4 +594,16 @@ 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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
257
src/perft.rs
Normal file
257
src/perft.rs
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
use crate::game::Game;
|
||||||
|
|
||||||
|
pub fn perft_driver(game: &mut Game, nodes: &mut u64, depth: u8) {
|
||||||
|
if depth == 0 {
|
||||||
|
*nodes += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pseudo_moves =
|
||||||
|
game.board.pseudo_moves_all(game.board.state.next_turn());
|
||||||
|
|
||||||
|
for mv in pseudo_moves {
|
||||||
|
let original_board = game.board.clone();
|
||||||
|
if !game.board.make_move(mv, game.board.state.next_turn()) {
|
||||||
|
game.board = original_board;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print_perftree(mv.source, mv.target, depth, nodes);
|
||||||
|
|
||||||
|
perft_driver(game, nodes, depth - 1);
|
||||||
|
game.board = original_board;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn print_perftree(source: u32, target: u32, depth: u8, nodes: &mut u64) {
|
||||||
|
println!(
|
||||||
|
"{}{} - depth: {}",
|
||||||
|
square_to_notation(source as u8),
|
||||||
|
square_to_notation(target as u8),
|
||||||
|
depth
|
||||||
|
);
|
||||||
|
if depth == MAX_DEPTH {
|
||||||
|
println!(
|
||||||
|
"{}{} {}",
|
||||||
|
square_to_notation(source as u8),
|
||||||
|
square_to_notation(target as u8),
|
||||||
|
nodes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_DEPTH: u8 = 4;
|
||||||
|
|
||||||
|
pub fn perftree_script() {
|
||||||
|
let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
|
let mut game = crate::fen::from_fen(fen).unwrap();
|
||||||
|
let (mut nodes, depth): (u64, u8) = (0, MAX_DEPTH);
|
||||||
|
perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
println!();
|
||||||
|
println!("{}", nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub fn square_to_notation(square: u8) -> &'static str {
|
||||||
|
let mut map: HashMap<u8, &str> = HashMap::new();
|
||||||
|
map.insert(0, "a1"); map.insert(1, "b1"); map.insert(2, "c1"); map.insert(3, "d1");
|
||||||
|
map.insert(4, "e1"); map.insert(5, "f1"); map.insert(6, "g1"); map.insert(7, "h1");
|
||||||
|
map.insert(8, "a2"); map.insert(9, "b2"); map.insert(10, "c2"); map.insert(11, "d2");
|
||||||
|
map.insert(12, "e2"); map.insert(13, "f2"); map.insert(14, "g2"); map.insert(15, "h2");
|
||||||
|
map.insert(16, "a3"); map.insert(17, "b3"); map.insert(18, "c3"); map.insert(19, "d3");
|
||||||
|
map.insert(20, "e3"); map.insert(21, "f3"); map.insert(22, "g3"); map.insert(23, "h3");
|
||||||
|
map.insert(24, "a4"); map.insert(25, "b4"); map.insert(26, "c4"); map.insert(27, "d4");
|
||||||
|
map.insert(28, "e4"); map.insert(29, "f4"); map.insert(30, "g4"); map.insert(31, "h4");
|
||||||
|
map.insert(32, "a5"); map.insert(33, "b5"); map.insert(34, "c5"); map.insert(35, "d5");
|
||||||
|
map.insert(36, "e5"); map.insert(37, "f5"); map.insert(38, "g5"); map.insert(39, "h5");
|
||||||
|
map.insert(40, "a6"); map.insert(41, "b6"); map.insert(42, "c6"); map.insert(43, "d6");
|
||||||
|
map.insert(44, "e6"); map.insert(45, "f6"); map.insert(46, "g6"); map.insert(47, "h6");
|
||||||
|
map.insert(48, "a7"); map.insert(49, "b7"); map.insert(50, "c7"); map.insert(51, "d7");
|
||||||
|
map.insert(52, "e7"); map.insert(53, "f7"); map.insert(54, "g7"); map.insert(55, "h7");
|
||||||
|
map.insert(56, "a8"); map.insert(57, "b8"); map.insert(58, "c8"); map.insert(59, "d8");
|
||||||
|
map.insert(60, "e8"); map.insert(61, "f8"); map.insert(62, "g8"); map.insert(63, "h8");
|
||||||
|
map.get(&square).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{attack::init_attacks, fen::from_fen};
|
||||||
|
|
||||||
|
use super::perft_driver;
|
||||||
|
|
||||||
|
// Examples from https://www.chessprogramming.org/Perft_Results
|
||||||
|
const FEN_PERFT: [&str; 6] = [
|
||||||
|
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
||||||
|
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1",
|
||||||
|
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1",
|
||||||
|
"r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1",
|
||||||
|
"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8",
|
||||||
|
"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_perft_driver_1() -> Result<(), String> {
|
||||||
|
init_attacks();
|
||||||
|
|
||||||
|
let mut game = from_fen(FEN_PERFT[0])?;
|
||||||
|
let (mut nodes, depth): (u64, u8) = (0, 1);
|
||||||
|
perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
assert_eq!(nodes , 20);
|
||||||
|
|
||||||
|
let mut game = from_fen(FEN_PERFT[0])?;
|
||||||
|
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])?;
|
||||||
|
let (mut nodes, depth): (u64, u8) = (0, 3);
|
||||||
|
perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
assert_eq!(nodes, 8902);
|
||||||
|
|
||||||
|
let mut game = from_fen(FEN_PERFT[0])?;
|
||||||
|
let (mut nodes, depth): (u64, u8) = (0, 4);
|
||||||
|
perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
assert_eq!(nodes, 197281);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_perft_driver_2() -> Result<(), String> {
|
||||||
|
init_attacks();
|
||||||
|
|
||||||
|
let mut game = from_fen(FEN_PERFT[1])?;
|
||||||
|
let (mut nodes, depth): (u64, u8) = (0, 1);
|
||||||
|
perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
assert_eq!(nodes, 48);
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_perft_driver_3() -> Result<(), String> {
|
||||||
|
init_attacks();
|
||||||
|
|
||||||
|
// let mut game = from_fen(FEN_PERFT[2])?;
|
||||||
|
// let (mut nodes, depth): (u64, u8) = (0, 1);
|
||||||
|
// perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
// assert_eq!(nodes, 14);
|
||||||
|
|
||||||
|
// 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_perft_driver_4() -> Result<(), String> {
|
||||||
|
init_attacks();
|
||||||
|
|
||||||
|
let mut game = from_fen(FEN_PERFT[3])?;
|
||||||
|
let (mut nodes, depth): (u64, u8) = (0, 1);
|
||||||
|
perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
assert_eq!(nodes , 6);
|
||||||
|
|
||||||
|
// 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_perft_driver_5() -> Result<(), String> {
|
||||||
|
init_attacks();
|
||||||
|
|
||||||
|
// let mut game = from_fen(FEN_PERFT[4])?;
|
||||||
|
// let (mut nodes, depth): (u64, u8) = (0, 1);
|
||||||
|
// perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
// assert_eq!(nodes , 44);
|
||||||
|
|
||||||
|
// 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_perft_driver_6() -> Result<(), String> {
|
||||||
|
init_attacks();
|
||||||
|
|
||||||
|
let mut game = from_fen(FEN_PERFT[5])?;
|
||||||
|
let (mut nodes, depth): (u64, u8) = (0, 1);
|
||||||
|
perft_driver(&mut game, &mut nodes, depth);
|
||||||
|
assert_eq!(nodes , 46);
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user