From 0f5a538f0a8ba5b6e5b3a19ba40fca0a71566c11 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Thu, 19 Jun 2025 11:33:35 -0700 Subject: [PATCH] [explorer, perft, position] Move node count into a new PerftCounters struct --- explorer/src/main.rs | 4 +-- perft/src/main.rs | 5 ++-- position/src/perft.rs | 57 +++++++++++++++++++++++++++++++------------ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/explorer/src/main.rs b/explorer/src/main.rs index 4f98a63..0acb2a1 100644 --- a/explorer/src/main.rs +++ b/explorer/src/main.rs @@ -350,9 +350,9 @@ fn do_perft_command( .ok_or(CommandHandlingError::MissingArgument("depth"))?; let mut position = state.position.clone(); - let nodes_count = position.perft(depth); + let counters = position.perft(depth); - println!("nodes {nodes_count}"); + println!("{counters}"); Ok(CommandResult { should_continue: true, diff --git a/perft/src/main.rs b/perft/src/main.rs index dece54c..d1e7f77 100644 --- a/perft/src/main.rs +++ b/perft/src/main.rs @@ -7,6 +7,7 @@ use clap::Parser; #[derive(Parser, Debug)] #[command(name = "Perft")] struct Arguments { + #[arg(long, short, value_name = "INT")] depth: usize, #[arg(long, short, value_name = "FEN")] @@ -26,9 +27,9 @@ fn main() -> anyhow::Result<()> { println!("fen \"{}\"", position.to_fen_str().unwrap()); println!("depth {depth}"); - let nodes_searched = position.perft(depth); + let counters = position.perft(depth); - println!("nodes {nodes_searched}"); + println!("\n{counters}"); Ok(()) } diff --git a/position/src/perft.rs b/position/src/perft.rs index 97b3c51..3269a04 100644 --- a/position/src/perft.rs +++ b/position/src/perft.rs @@ -1,20 +1,29 @@ // Eryn Wells +use chessfriend_moves::Move; + use crate::{GeneratedMove, Position, ValidateMove}; +use std::fmt; + +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct PerftCounters { + nodes: u64, +} impl Position { - pub fn perft(&mut self, depth: usize) -> u64 { - self.perft_recursive(depth, depth) + pub fn perft(&mut self, depth: usize) -> PerftCounters { + self.perft_recursive(0, depth) } } impl Position { - fn perft_recursive(&mut self, depth: usize, max_depth: usize) -> u64 { - if depth == 0 { - return 1; - } + fn perft_recursive(&mut self, depth: usize, max_depth: usize) -> PerftCounters { + let mut counters = PerftCounters::default(); - let mut total_nodes_counted = 0u64; + if depth == max_depth { + counters.count_node(); + return counters; + } let legal_moves: Vec = self.all_legal_moves(None).collect(); @@ -25,21 +34,39 @@ impl Position { .make_move(ply, ValidateMove::No) .expect("unable to make generated move"); - let nodes_counted = if has_seen_position { - 1 + let recursive_counters = if has_seen_position { + let mut counters = PerftCounters::default(); + counters.count_node(); + counters } else { - self.perft_recursive(depth - 1, max_depth) + self.perft_recursive(depth + 1, max_depth) }; - total_nodes_counted += nodes_counted; - self.unmake_last_move().expect("unable to unmake last move"); - if depth == max_depth { - println!(" {ply} {nodes_counted}"); + counters.fold(&recursive_counters); + + if depth == 0 { + println!(" {ply}: {}", recursive_counters.nodes); } } - total_nodes_counted + counters + } +} + +impl PerftCounters { + fn count_node(&mut self) { + self.nodes += 1; + } + fn fold(&mut self, results: &Self) { + self.nodes += results.nodes; + } +} + +impl fmt::Display for PerftCounters { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "Perft Results")?; + write!(f, " Nodes: {}", self.nodes) } }