use std::hint::black_box; use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use othello::{board::BitBoard, game::Team}; const JONS: [&str; 20] = [ "///3bw/3wb", "///////6bw", "///////wb", "wwwwwwww/wwwwwwww/////", "//1b2w/1bwwww/1bwbww/1bwwww/1b3/", "///3bw/2bbw/3b//", "///////bww", "////bwwwww1b///", "www/wbw/www////", "///3b/2bwb/3b//", "5bw//////", "///////wb", "7w/6b/5b", "w/1b/2b", "/////5w/6w/7b", "/////2w/1w/b", "b/w/w/w//b//", "////bwwwww1b///", "///3w///", "///////", ]; const JON_NAMES: [&str; 20] = [ "starting_position", "near_endgame", "corner_setup_a1", "white_dominance", "complex_midgame", "after_first_move", "edge_capture", "long_horizontal", "surrounded_black", "white_surrounded", "corner_setup_h8", "corner_setup_h1", "diagonal_line", "short_diagonal", "anti_diagonal", "anti_diagonal_short", "vertical_capture", "long_horizontal_alt", "single_piece", "empty_board", ]; fn bench_available_black(c: &mut Criterion) { let mut group = c.benchmark_group("available_black"); for (i, jon) in JONS.iter().enumerate() { let bb = BitBoard::from_jon(jon).expect("Valid JON"); group.bench_with_input( BenchmarkId::new("position", JON_NAMES[i]), &bb, |b, board| { b.iter(|| black_box(board.available(black_box(Team::Black)))); }, ); } group.finish(); } fn bench_available_white(c: &mut Criterion) { let mut group = c.benchmark_group("available_white"); for (i, jon) in JONS.iter().enumerate() { let bb = BitBoard::from_jon(jon).expect("Valid JON"); group.bench_with_input( BenchmarkId::new("position", JON_NAMES[i]), &bb, |b, board| { b.iter(|| black_box(board.available(black_box(Team::White)))); }, ); } group.finish(); } fn bench_available_both_teams(c: &mut Criterion) { let mut group = c.benchmark_group("available_both_teams"); for (i, jon) in JONS.iter().enumerate() { let bb = BitBoard::from_jon(jon).expect("Valid JON"); group.bench_with_input( BenchmarkId::new("position", JON_NAMES[i]), &bb, |b, board| { b.iter(|| { let black_moves = black_box(board.available(Team::Black)); let white_moves = black_box(board.available(Team::White)); black_box((black_moves, white_moves)) }); }, ); } group.finish(); } fn bench_available_starting_only(c: &mut Criterion) { let bb = BitBoard::default(); c.bench_function("starting_position_black", |b| { b.iter(|| black_box(bb.available(black_box(Team::Black)))); }); c.bench_function("starting_position_white", |b| { b.iter(|| black_box(bb.available(black_box(Team::White)))); }); } fn bench_available_worst_case(c: &mut Criterion) { // Positions that might be slower due to more pieces or complexity let worst_cases = [ ("complex_midgame", "//1b2w/1bwwww/1bwbww/1bwwww/1b3/"), ("white_dominance", "wwwwwwww/wwwwwwww/////"), ("long_capture", "////bwwwww1b///"), ]; let mut group = c.benchmark_group("available_worst_case"); for (name, jon) in worst_cases.iter() { let bb = BitBoard::from_jon(jon).expect("Valid JON"); group.bench_with_input(BenchmarkId::new("black", name), &bb, |b, board| { b.iter(|| black_box(board.available(Team::Black))); }); group.bench_with_input(BenchmarkId::new("white", name), &bb, |b, board| { b.iter(|| black_box(board.available(Team::White))); }); } group.finish(); } fn bench_available_best_case(c: &mut Criterion) { // Positions that should be fast (empty board, single piece, etc.) let best_cases = [ ("empty_board", "///////"), ("single_piece", "///3w///"), ("corner_only", "///////wb"), ]; let mut group = c.benchmark_group("available_best_case"); for (name, jon) in best_cases.iter() { let bb = BitBoard::from_jon(jon).expect("Valid JON"); group.bench_with_input(BenchmarkId::new("black", name), &bb, |b, board| { b.iter(|| black_box(board.available(Team::Black))); }); group.bench_with_input(BenchmarkId::new("white", name), &bb, |b, board| { b.iter(|| black_box(board.available(Team::White))); }); } group.finish(); } fn bench_available_all_positions_sequential(c: &mut Criterion) { let boards: Vec = JONS .iter() .map(|jon| BitBoard::from_jon(jon).expect("Valid JON")) .collect(); c.bench_function("all_positions_black_sequential", |b| { b.iter(|| { for board in &boards { black_box(board.available(Team::Black)); } }); }); c.bench_function("all_positions_white_sequential", |b| { b.iter(|| { for board in &boards { black_box(board.available(Team::White)); } }); }); } criterion_group!( benches, bench_available_black, bench_available_white, bench_available_both_teams, bench_available_starting_only, bench_available_worst_case, bench_available_best_case, bench_available_all_positions_sequential, ); criterion_main!(benches);