Skip to content

Commit a0f98c9

Browse files
authored
chore: rework structure of engine commands (#359)
Split code into modules to reduce complexity of `main()` for the `engine-cli`. bench: 1287259
1 parent d52d25c commit a0f98c9

5 files changed

Lines changed: 113 additions & 82 deletions

File tree

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,27 @@ const BENCHMARKS: [&str; 56] = [
9090
"4r1k1/8/2p5/2p1Rpq1/6P1/1PP4Q/P5K1/RN1r4 b - - 0 1",
9191
];
9292

93-
pub(crate) fn bench(depth: u8, epd_file: &Option<String>) {
93+
#[derive(clap::Args, Debug)]
94+
pub(crate) struct BenchArgs {
95+
#[arg(short, long, default_value = "10")]
96+
depth: u8,
97+
98+
#[arg(short, long)]
99+
epd_file: Option<String>,
100+
}
101+
102+
/// Execute the bench command with the bench arguments.
103+
pub(crate) fn execute(args: BenchArgs) {
104+
// Spawn bench on a thread with 8 MiB stack to match the UCI handler.
105+
let handle = std::thread::Builder::new()
106+
.name("bench".to_string())
107+
.stack_size(8 * 1024 * 1024)
108+
.spawn(move || run_bench(args.depth, &args.epd_file))
109+
.unwrap();
110+
handle.join().unwrap();
111+
}
112+
113+
fn run_bench(depth: u8, epd_file: &Option<String>) {
94114
let benchmark_strings: Vec<String> = match epd_file {
95115
Some(file) => {
96116
let str = std::fs::read_to_string(file).unwrap();

engine-cli/src/commands/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub(crate) mod bench;
2+
pub(crate) mod perft;
3+
pub(crate) mod split_perft;

engine-cli/src/commands/perft.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Part of the byte-knight project.
2+
// Author: Paul Tsouchlos (ptsouchlos) (developer.paul.123@gmail.com)
3+
// GNU General Public License v3.0 or later
4+
// https://www.gnu.org/licenses/gpl-3.0-standalone.html
5+
6+
use chess::definitions::DEFAULT_FEN;
7+
8+
use crate::perft;
9+
10+
#[derive(clap::Args, Debug)]
11+
pub(crate) struct PerftArgs {
12+
#[arg(short, long, default_value_t = 6)]
13+
depth: usize,
14+
#[arg(
15+
short,
16+
long,
17+
default_value_t = DEFAULT_FEN.to_string()
18+
)]
19+
fen: String,
20+
#[arg(short, long)]
21+
epd_file: Option<String>,
22+
}
23+
24+
pub(crate) fn execute(args: PerftArgs) {
25+
let board = &mut chess::board::Board::from_fen(&args.fen).unwrap();
26+
if let Some(epd) = args.epd_file {
27+
perft::process_epd_file(&epd);
28+
} else {
29+
for i in 1..args.depth + 1 {
30+
let now = std::time::Instant::now();
31+
let nodes = chess::perft::perft(board, i, false).unwrap();
32+
let elapsed = now.elapsed();
33+
let nps = nodes as f64 / elapsed.as_secs_f64();
34+
println!(
35+
"perft {} = {:>12} {:.2} sec {:>12} nps",
36+
i,
37+
nodes,
38+
elapsed.as_secs_f64(),
39+
nps.round()
40+
);
41+
}
42+
}
43+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Part of the byte-knight project.
2+
// Author: Paul Tsouchlos (ptsouchlos) (developer.paul.123@gmail.com)
3+
// GNU General Public License v3.0 or later
4+
// https://www.gnu.org/licenses/gpl-3.0-standalone.html
5+
6+
use chess::definitions::DEFAULT_FEN;
7+
8+
#[derive(clap::Args, Debug)]
9+
pub(crate) struct SplitPerftArgs {
10+
#[arg(short, long, default_value_t = 6)]
11+
depth: usize,
12+
#[arg(
13+
short,
14+
long,
15+
default_value_t = DEFAULT_FEN.to_string()
16+
)]
17+
fen: String,
18+
#[arg(short, long, default_value_t = false)]
19+
print_moves: bool,
20+
}
21+
22+
pub(crate) fn execute(args: SplitPerftArgs) {
23+
println!("running split perft at depth {}", args.depth);
24+
let board = &mut chess::board::Board::from_fen(&args.fen).unwrap();
25+
let move_results = chess::perft::split_perft(board, args.depth, args.print_moves).unwrap();
26+
for res in &move_results {
27+
println!("{}: {}", res.mv.to_long_algebraic(), res.nodes);
28+
}
29+
println!();
30+
// print the total nodes
31+
println!("{}", move_results.iter().map(|r| r.nodes).sum::<u64>());
32+
}

engine-cli/src/main.rs

Lines changed: 14 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
// GNU General Public License v3.0 or later
44
// https://www.gnu.org/licenses/gpl-3.0-standalone.html
55

6-
mod bench;
6+
mod commands;
77
mod input_handler;
88
mod perft;
99
mod uci_handler;
1010

11-
use crate::uci_handler::UciHandler;
12-
use chess::definitions::DEFAULT_FEN;
11+
use crate::{
12+
commands::{bench::BenchArgs, perft::PerftArgs, split_perft::SplitPerftArgs},
13+
uci_handler::UciHandler,
14+
};
15+
1316
use clap::{Parser, Subcommand};
1417
use engine::defs::About;
1518

@@ -28,39 +31,12 @@ struct Options {
2831
#[command(about = "Available commands")]
2932
enum Command {
3033
#[command(about = "Run fixed depth search")]
31-
Bench {
32-
#[arg(short, long, default_value = "10")]
33-
depth: u8,
34-
35-
#[arg(short, long)]
36-
epd_file: Option<String>,
37-
},
38-
Perft {
39-
#[arg(short, long, default_value_t = 6)]
40-
depth: usize,
41-
#[arg(
42-
short,
43-
long,
44-
default_value_t = DEFAULT_FEN.to_string()
45-
)]
46-
fen: String,
47-
#[arg(short, long)]
48-
epd_file: Option<String>,
49-
},
50-
SplitPerft {
51-
#[arg(short, long, default_value_t = 6)]
52-
depth: usize,
53-
#[arg(
54-
short,
55-
long,
56-
default_value_t = DEFAULT_FEN.to_string()
57-
)]
58-
fen: String,
59-
#[arg(short, long, default_value_t = false)]
60-
print_moves: bool,
61-
},
34+
Bench(BenchArgs),
35+
Perft(PerftArgs),
36+
SplitPerft(SplitPerftArgs),
6237
}
6338

39+
/// Run the UCI handler for the engine.
6440
fn run_uci() {
6541
// Spawn UCI handler on a thread with 8 MiB stack — the search is deeply recursive
6642
// and the default main thread stack size is insufficient on some platforms.
@@ -82,53 +58,10 @@ fn main() {
8258
let args = Options::parse();
8359
match args.command {
8460
Some(command) => match command {
85-
Command::Bench { depth, epd_file } => {
86-
// Spawn bench on a thread with 8 MiB stack to match the UCI handler.
87-
let handle = std::thread::Builder::new()
88-
.name("bench".to_string())
89-
.stack_size(8 * 1024 * 1024)
90-
.spawn(move || bench::bench(depth, &epd_file))
91-
.unwrap();
92-
handle.join().unwrap();
93-
}
94-
Command::Perft {
95-
depth,
96-
fen,
97-
epd_file,
98-
} => {
99-
let board = &mut chess::board::Board::from_fen(&fen).unwrap();
100-
if let Some(epd) = epd_file {
101-
perft::process_epd_file(&epd);
102-
} else {
103-
for i in 1..depth + 1 {
104-
let now = std::time::Instant::now();
105-
let nodes = chess::perft::perft(board, i, false).unwrap();
106-
let elapsed = now.elapsed();
107-
let nps = nodes as f64 / elapsed.as_secs_f64();
108-
println!(
109-
"perft {} = {:>12} {:.2} sec {:>12} nps",
110-
i,
111-
nodes,
112-
elapsed.as_secs_f64(),
113-
nps.round()
114-
);
115-
}
116-
}
117-
}
118-
Command::SplitPerft {
119-
depth,
120-
fen,
121-
print_moves,
122-
} => {
123-
println!("running split perft at depth {}", depth);
124-
let board = &mut chess::board::Board::from_fen(&fen).unwrap();
125-
let move_results = chess::perft::split_perft(board, depth, print_moves).unwrap();
126-
for res in &move_results {
127-
println!("{}: {}", res.mv.to_long_algebraic(), res.nodes);
128-
}
129-
println!();
130-
// print the total nodes
131-
println!("{}", move_results.iter().map(|r| r.nodes).sum::<u64>());
61+
Command::Bench(bench_args) => commands::bench::execute(bench_args),
62+
Command::Perft(perft_args) => commands::perft::execute(perft_args),
63+
Command::SplitPerft(split_perft_args) => {
64+
commands::split_perft::execute(split_perft_args)
13265
}
13366
},
13467
None => run_uci(),

0 commit comments

Comments
 (0)