-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.rs
116 lines (101 loc) · 3.4 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Integration tests using the UCI protocol
use std::io::BufRead;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
use std::thread;
use std::time::Instant;
use colored::Colorize;
/// how long to let the test run for before killing it, in ms
pub const TEST_DURATION: u64 = 120_000;
/// test using a sequence of UCI commands, with metrics captured and printed to
/// stdout.
pub fn test_uci(sequence: &[&str]) {
let exec = PathBuf::from(env!("CARGO_BIN_EXE_chesseng"));
let mut cmd = Command::new(exec);
cmd.stdin(Stdio::piped());
cmd.stdout(Stdio::piped());
#[allow(clippy::zombie_processes)]
let mut child = cmd.spawn().unwrap();
let stdin = child.stdin.take().unwrap();
let stdout = child.stdout.take().unwrap();
let mut reader = std::io::BufReader::new(stdout);
let mut writer = std::io::BufWriter::new(stdin);
for seq in sequence.iter() {
writer.write_all(seq.as_bytes()).unwrap();
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
}
let _killer = thread::spawn(move || {
thread::sleep(std::time::Duration::from_millis(TEST_DURATION));
if let Err(e) = writer.write_all(b"quit\n") {
eprintln!("killer encountered error: {e}");
}
if let Err(e) = writer.flush() {
eprintln!("killer encountered error: {e}");
}
});
let mut max_depth = 0;
let mut nodes_searched = 0;
let start = Instant::now();
let print_results = |depth, nodes| {
println!(
"{}",
format!(" duration: {}ms ", start.elapsed().as_millis())
.black()
.bold()
.on_bright_green()
);
println!(
"{}",
format!(" max depth: {}", depth)
.black()
.bold()
.on_bright_green()
);
println!(
"{}",
format!(" total nodes searched: {}", nodes)
.black()
.bold()
.on_bright_green()
);
};
loop {
let mut line = String::new();
reader.read_line(&mut line).unwrap();
let parts = line.split_whitespace().collect::<Vec<&str>>();
if parts.len() > 1 && parts[0] == "bestmove" {
println!("Best move: {}", parts[1]);
print_results(max_depth, nodes_searched);
break;
} else if parts.len() > 1 && parts[0] == "info" {
println!(
"{}",
format!(
"engine_info ({}ms): {}",
start.elapsed().as_millis(),
line.trim()
)
.black()
.on_cyan()
);
if let Some(idx) = parts.iter().position(|&x| x == "depth") {
let depth = parts[idx + 1].parse::<u32>().unwrap();
if depth > max_depth {
max_depth = depth;
}
}
if let Some(idx) = parts.iter().position(|&x| x == "nodes") {
let nodes = parts[idx + 1].parse::<u64>().unwrap();
nodes_searched += nodes;
}
} else if parts.iter().any(|x| x.eq_ignore_ascii_case("quitting")) {
print_results(max_depth, nodes_searched);
break;
}
}
println!("killing child");
child.kill().unwrap();
}