use consts::{DEFAULT_TT_SIZE, MAX_THREADS};
use std::collections::VecDeque;
use std::option::Option;
use num_cpus;
pub enum OptionWork {
ClearTT,
ResizeTT(usize),
Threads(usize),
}
impl OptionWork {
pub fn usable_while_searching(&self) -> bool {
match *self {
OptionWork::ClearTT => false,
OptionWork::ResizeTT(_) => false,
OptionWork::Threads(_) => false,
}
}
}
pub struct OptionsMap {
pub map: Vec<Box<dyn UCIOption>>,
pub work: VecDeque<OptionWork>,
}
impl OptionsMap {
pub fn new() -> Self {
let mut map = Vec::new();
let work = VecDeque::new();
map.push(OptionsMap::clear_hash());
map.push(OptionsMap::resize_hash());
map.push(OptionsMap::threads());
map.sort_by(|a, b| a.option_name().cmp(b.option_name()));
OptionsMap { map, work }
}
pub fn apply_option(&mut self, name: &str, value: &str) -> bool {
for op in self.map.iter() {
if op.option_name() == name {
if let Some(work) = op.mutate(value) {
self.work.push_back(work);
return true;
}
return false;
}
}
false
}
pub fn display_all(&self) {
for op in self.map.iter() {
println!("{}", op.display());
}
}
pub fn work(&mut self) -> Option<OptionWork> {
self.work.pop_front()
}
fn clear_hash() -> Box<dyn UCIOption> {
let mutator: fn() -> Option<OptionWork> = || Some(OptionWork::ClearTT);
Box::new(UCIButton {
option_name: "Clear Hash",
mutator,
})
}
fn resize_hash() -> Box<dyn UCIOption> {
let mutator: fn(i32) -> Option<OptionWork> =
|x: i32| Some(OptionWork::ResizeTT(x as usize));
Box::new(UCISpin {
option_name: "Hash",
default: DEFAULT_TT_SIZE as i32,
min: 1,
max: 8000,
mutator,
})
}
fn threads() -> Box<dyn UCIOption> {
let mutator: fn(i32) -> Option<OptionWork> = |x: i32| Some(OptionWork::Threads(x as usize));
Box::new(UCISpin {
option_name: "Threads",
default: num_cpus::get() as i32,
min: 1,
max: MAX_THREADS as i32,
mutator,
})
}
}
pub trait UCIOption {
fn option_type(&self) -> &'static str;
fn option_name(&self) -> &'static str;
fn partial_display(&self) -> Option<String>;
fn display(&self) -> String {
let mut display =
String::from("option name ") + self.option_name() + " type " + self.option_type();
if let Some(part_dis) = self.partial_display() {
display += " ";
display += &part_dis;
}
display
}
fn mutate(&self, val: &str) -> Option<OptionWork>;
}
pub struct UCIButton {
option_name: &'static str,
mutator: fn() -> Option<OptionWork>,
}
pub struct UCICheck {
option_name: &'static str,
default: bool,
mutator: fn(bool) -> Option<OptionWork>,
}
pub struct UCISpin {
option_name: &'static str,
default: i32,
max: i32,
min: i32,
mutator: fn(i32) -> Option<OptionWork>,
}
pub struct UCICombo {
option_name: &'static str,
default: &'static str,
values: &'static [&'static str],
mutator: fn(&str) -> Option<OptionWork>,
}
pub struct UCIText {
option_name: &'static str,
default: &'static str,
mutator: fn(&str) -> Option<OptionWork>,
}
impl UCIOption for UCIButton {
fn option_type(&self) -> &'static str {
"button"
}
fn option_name(&self) -> &'static str {
self.option_name
}
fn partial_display(&self) -> Option<String> {
None
}
fn mutate(&self, _val: &str) -> Option<OptionWork> {
(self.mutator)()
}
}
impl UCIOption for UCICheck {
fn option_type(&self) -> &'static str {
"check"
}
fn option_name(&self) -> &'static str {
self.option_name
}
fn partial_display(&self) -> Option<String> {
Some(String::from("default ") + &self.default.to_string())
}
fn mutate(&self, val: &str) -> Option<OptionWork> {
if val.contains("true") {
return (self.mutator)(true);
} else if val.contains("false") {
return (self.mutator)(false);
}
None
}
}
impl UCIOption for UCISpin {
fn option_type(&self) -> &'static str {
"spin"
}
fn option_name(&self) -> &'static str {
self.option_name
}
fn partial_display(&self) -> Option<String> {
Some(
String::from("default ")
+ &self.default.to_string()
+ " min "
+ &self.min.to_string()
+ " max "
+ &self.max.to_string(),
)
}
fn mutate(&self, val: &str) -> Option<OptionWork> {
if let Ok(integer) = val.parse::<i32>() {
if integer >= self.min && integer <= self.max {
return (self.mutator)(integer);
}
}
None
}
}
impl UCIOption for UCICombo {
fn option_type(&self) -> &'static str {
"combo"
}
fn option_name(&self) -> &'static str {
self.option_name
}
fn partial_display(&self) -> Option<String> {
let mut disp = String::from("default ") + self.default;
self.values.iter().for_each(|s| {
disp += " var ";
disp += *s;
});
Some(disp)
}
fn mutate(&self, val: &str) -> Option<OptionWork> {
if self.values.contains(&val) {
let f = self.mutator;
let ret = f(val);
return ret;
}
return None;
}
}
impl UCIOption for UCIText {
fn option_type(&self) -> &'static str {
"text"
}
fn option_name(&self) -> &'static str {
self.option_name
}
fn partial_display(&self) -> Option<String> {
Some(String::from("default ") + self.default)
}
fn mutate(&self, val: &str) -> Option<OptionWork> {
(self.mutator)(val)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_print() {
let all = OptionsMap::new();
all.display_all();
}
}