From 81ed2dae0ea1fca3ed25280488d2b611357a07b7 Mon Sep 17 00:00:00 2001 From: kraktus Date: Thu, 18 Aug 2022 16:17:30 +0200 Subject: [PATCH] Move `perft` into the crate, and test it --- src/lib.rs | 2 +- src/main.rs | 37 +------------------------------------ src/retroboard.rs | 44 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 727fbff..1acd855 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ mod unmove; pub use crate::unmove::{MoveKind, UnMove, UnMoveList}; mod retroboard; -pub use crate::retroboard::RetroBoard; +pub use crate::retroboard::{perft, RetroBoard}; mod retropocket; pub use crate::retropocket::{ParseRetroPocketError, RetroPocket, RetroPockets}; diff --git a/src/main.rs b/src/main.rs index c427b90..334733d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,42 +1,7 @@ use std::time::Instant; use retroboard::shakmaty::{fen::Fen, perft as shakmaty_perft, CastlingMode, Chess}; -use retroboard::RetroBoard; -/// From shakmaty code source -/// Counts legal move paths of a given length. -/// -/// Shorter paths (due to mate or stalemate) are not counted. -/// Computing perft numbers is useful for comparing, testing and -/// debugging move generation correctness and performance. -/// -/// The method used here is simply recursively enumerating the entire tree of -/// legal moves. While this is fine for testing there is much -/// faster specialized software. -/// -/// Warning: Computing perft numbers can take a long time, even at moderate -/// depths. The simple recursive algorithm can also overflow the stack at -/// high depths, but this will only come into consideration in the rare case -/// that high depths are feasible at all. -fn perft(r: &RetroBoard, depth: u32) -> u64 { - if depth < 1 { - 1 - } else { - let moves = r.legal_unmoves(); - - if depth == 1 { - moves.len() as u64 - } else { - moves - .iter() - .map(|m| { - let mut child = r.clone(); - child.push(m); - perft(&child, depth - 1) - }) - .sum() - } - } -} +use retroboard::{perft, RetroBoard}; fn _shakmaty(fen: &str) { let pos: Chess = fen diff --git a/src/retroboard.rs b/src/retroboard.rs index 44cde1a..59399f3 100644 --- a/src/retroboard.rs +++ b/src/retroboard.rs @@ -567,6 +567,42 @@ fn closest_further_square(bb: Bitboard, of: Square) -> (Square, Square) { } } +/// From shakmaty code source +/// Counts legal move paths of a given length. +/// +/// Shorter paths (due to mate or stalemate) are not counted. +/// Computing perft numbers is useful for comparing, testing and +/// debugging move generation correctness and performance. +/// +/// The method used here is simply recursively enumerating the entire tree of +/// legal moves. While this is fine for testing there is much +/// faster specialized software. +/// +/// Warning: Computing perft numbers can take a long time, even at moderate +/// depths. The simple recursive algorithm can also overflow the stack at +/// high depths, but this will only come into consideration in the rare case +/// that high depths are feasible at all. +pub fn perft(r: &RetroBoard, depth: u32) -> u64 { + if depth < 1 { + 1 + } else { + let moves = r.legal_unmoves(); + + if depth == 1 { + moves.len() as u64 + } else { + moves + .iter() + .map(|m| { + let mut child = r.clone(); + child.push(m); + perft(&child, depth - 1) + }) + .sum() + } + } +} + #[cfg(test)] mod tests { // use pretty_assertions::{assert_eq, assert_ne}; @@ -1050,6 +1086,7 @@ mod tests { } // does not take into account internal positions, contrary to `test_final_unmoves` + // As it names says it is behavior identical to `perft` but with additional debug built-in in case it fails fn perft_debug(r: RetroBoard, depth: u32) -> Option { if depth < 1 { Some(1) @@ -1097,10 +1134,9 @@ mod tests { } else { RetroBoard::new(fen, white_p, black_p).expect("Valid retroboard") }; - assert_eq!(perft_debug(r.clone(), 0), Some(1)); - assert_eq!(perft_debug(r.clone(), 1), Some(24)); - assert_eq!(perft_debug(r.clone(), 2), Some(3951)); - // assert_eq!(perft_debug(r, 3), Some(640054)) + assert_eq!(perft_debug(r.clone(), 0), Some(perft(&r, 0))); + assert_eq!(perft_debug(r.clone(), 1), Some(perft(&r, 1))); + assert_eq!(perft_debug(r.clone(), 2), Some(perft(&r, 2))); } } }