use ruchess::{fen, mve::Move, position::Position};
fn perft(pos: &mut Position, depth: u32) -> u64 {
if depth == 0 {
return 1;
}
if depth == 1 {
return pos.valid_moves().count() as u64;
}
let moves: Vec<Move> = pos.valid_moves().collect();
let mut total: u64 = 0;
for m in moves {
let undo = pos.make(&m);
total += perft(pos, depth - 1);
pos.unmake(undo);
}
total
}
fn fmt_move(m: &ruchess::mve::Move) -> String {
let promo = match m.promotion {
Some(p) => format!("{}", p.as_ascii()),
None => String::new(),
};
format!("{}{}{}", m.orig, m.dest, promo)
}
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
if args.len() < 2 {
eprintln!("usage: perft_divide <FEN> <depth>");
std::process::exit(2);
}
let fen_str = &args[0];
let depth: u32 = args[1].parse().expect("depth must be a number");
let pos = fen::parse(fen_str)
.expect("FEN should parse")
.without_repetition();
let moves: Vec<Move> = pos.valid_moves().collect();
let mut rows: Vec<(String, u64)> = moves
.into_iter()
.map(|m| {
let mut working = pos.clone();
let undo = working.make(&m);
let count = if depth == 0 {
1
} else {
perft(&mut working, depth - 1)
};
working.unmake(undo);
(fmt_move(&m), count)
})
.collect();
rows.sort_by(|a, b| a.0.cmp(&b.0));
let mut total: u64 = 0;
for (mv, n) in &rows {
println!("{mv}: {n}");
total += n;
}
println!("\nmoves: {}", rows.len());
println!("total: {total}");
}