chessfriend/position/src/perft.rs
Eryn Wells 7744dd06f0 [position, perft] Move Perft into the position crate
Move the Perft trait into the position crate, and let the perft binary call into
that.

Amend Position::make_move to return a bool in the Ok case that indicates whether
the position has been seen before. Use this to decide whether to continue
recursing during the Perft run. I haven't seen that this makes a difference in
the counts returned by Perft yet.
2025-06-16 09:01:58 -07:00

67 lines
1.7 KiB
Rust

// Eryn Wells <eryn@erynwells.me>
use crate::{GeneratedMove, Position, ValidateMove};
pub trait Perft {
fn perft(&mut self, depth: usize) -> u64;
}
impl Perft for Position {
fn perft(&mut self, depth: usize) -> u64 {
if depth == 0 {
return 1;
}
let mut total_nodes_counted = 0u64;
let legal_moves: Vec<GeneratedMove> = self.all_legal_moves(None).collect();
for generated_ply in legal_moves {
let ply = generated_ply.ply();
let has_seen_position = self
.make_move(ply, ValidateMove::No)
.expect("unable to make generated move");
// Do not recursive into trees where board positions repeat.
let nodes_counted = if has_seen_position {
1
} else {
self.perft(depth - 1)
};
total_nodes_counted += nodes_counted;
self.unmake_last_move().expect("unable to unmake last move");
}
total_nodes_counted
}
}
impl Position {
fn perft_recursive(&mut self, depth: usize) -> u64 {
if depth == 0 {
return 1;
}
let mut total_nodes_counted: u64 = 0;
let legal_moves: Vec<GeneratedMove> = self.all_legal_moves(None).collect();
for generated_ply in legal_moves {
let ply = generated_ply.ply();
self.make_move(ply, ValidateMove::No)
.expect("unable to make generated move");
let nodes_counted = self.perft_recursive(depth - 1);
total_nodes_counted += nodes_counted;
self.unmake_last_move().expect("unable to unmake last move");
}
total_nodes_counted
}
}