use std::ops::Not;
use serde::Serialize;
use serde_json::{Value, json};
use serde_with::skip_serializing_none;
use crate::{Bonus, Config, Player, Rules};
#[derive(Debug, Clone, Serialize)]
#[serde(into = "Value")]
pub enum Request {
Analyze(AnalysisRequest),
QueryVersion {
id: String,
},
ClearCache {
id: String,
},
Terminate {
id: String,
terminate_id: String,
turn_numbers: Option<Vec<usize>>,
},
TerminateAll {
id: String,
turn_numbers: Option<Vec<usize>>,
},
QueryModels {
id: String,
},
}
impl From<Request> for Value {
fn from(request: Request) -> Self {
match request {
Request::Analyze(request) => {
serde_json::to_value(request).expect("request should be serializable")
}
Request::QueryVersion { id } => json!({
"id": id,
"action": "query_version",
}),
Request::ClearCache { id } => json!({
"id": id,
"action": "clear_cache",
}),
Request::Terminate {
id,
terminate_id,
turn_numbers,
} => {
let mut value = json!({
"id": id,
"action": "terminate",
"terminateId": terminate_id,
}
);
if let Some(turn_numbers) = turn_numbers {
value
.as_object_mut()
.expect("value should be an object")
.insert("turnNumbers".to_string(), json!(turn_numbers));
}
value
}
Request::TerminateAll { id, turn_numbers } => {
let mut value = json!({
"id": id,
"action": "terminate_all",
}
);
if let Some(turn_numbers) = turn_numbers {
value
.as_object_mut()
.expect("value should be an object")
.insert("turnNumbers".to_string(), json!(turn_numbers));
}
value
}
Request::QueryModels { id } => json!({
"id": id,
"action": "query_models",
}),
}
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AnalysisRequest {
pub id: String,
pub rules: Rules,
pub komi: Option<f64>,
pub white_handicap_bonus: Option<Bonus>,
pub board_x_size: u8,
pub board_y_size: u8,
pub initial_stones: Option<Vec<(Player, String)>>,
pub initial_player: Option<Player>,
pub moves: Vec<(Player, String)>,
pub analyze_turns: Option<Vec<usize>>,
pub max_visits: Option<u32>,
pub root_policy_temperature: Option<f64>,
pub root_fpu_reduction_max: Option<f64>,
#[serde(rename = "analysisPVLen")]
pub analysis_pv_len: Option<usize>,
#[serde(skip_serializing_if = "Not::not")]
pub include_ownership: bool,
#[serde(skip_serializing_if = "Not::not")]
pub include_ownership_stdev: bool,
#[serde(skip_serializing_if = "Not::not")]
pub include_moves_ownership: bool,
#[serde(skip_serializing_if = "Not::not")]
pub include_moves_ownership_stdev: bool,
#[serde(skip_serializing_if = "Not::not")]
pub include_policy: bool,
#[serde(rename = "includePVVisits", skip_serializing_if = "Not::not")]
pub include_pv_visits: bool,
#[serde(skip_serializing_if = "Not::not")]
pub include_no_result_value: bool,
pub avoid_moves: Option<Vec<RestrictedMoves>>,
pub allow_moves: Option<Vec<RestrictedMoves>>,
pub override_settings: Option<Config>,
pub report_during_search_every: Option<f64>,
pub priority: Option<i32>,
pub priorities: Option<Vec<i32>>,
}
impl AnalysisRequest {
pub fn new(
id: String,
rules: Rules,
board_x_size: u8,
board_y_size: u8,
moves: Vec<(Player, String)>,
) -> Self {
Self {
id,
rules,
komi: None,
white_handicap_bonus: None,
board_x_size,
board_y_size,
initial_stones: None,
initial_player: None,
moves,
analyze_turns: None,
max_visits: None,
root_policy_temperature: None,
root_fpu_reduction_max: None,
analysis_pv_len: None,
include_ownership: false,
include_ownership_stdev: false,
include_moves_ownership: false,
include_moves_ownership_stdev: false,
include_policy: false,
include_pv_visits: false,
include_no_result_value: false,
avoid_moves: None,
allow_moves: None,
override_settings: None,
report_during_search_every: None,
priority: None,
priorities: None,
}
}
pub fn with_komi(mut self, komi: f64) -> Self {
self.komi = Some(komi);
self
}
pub fn with_white_handicap_bonus(mut self, bonus: Bonus) -> Self {
self.white_handicap_bonus = Some(bonus);
self
}
pub fn with_initial_stones(mut self, initial_stones: Vec<(Player, String)>) -> Self {
self.initial_stones = Some(initial_stones);
self
}
pub fn with_initial_player(mut self, initial_player: Player) -> Self {
self.initial_player = Some(initial_player);
self
}
pub fn with_analyze_turns(mut self, analyze_turns: Vec<usize>) -> Self {
self.analyze_turns = Some(analyze_turns);
self
}
pub fn with_max_visits(mut self, max_visits: u32) -> Self {
self.max_visits = Some(max_visits);
self
}
pub fn with_root_policy_temperature(mut self, root_policy_temperature: f64) -> Self {
self.root_policy_temperature = Some(root_policy_temperature);
self
}
pub fn with_root_fpu_reduction_max(mut self, root_fpu_reduction_max: f64) -> Self {
self.root_fpu_reduction_max = Some(root_fpu_reduction_max);
self
}
pub fn with_analysis_pv_len(mut self, analysis_pv_len: usize) -> Self {
self.analysis_pv_len = Some(analysis_pv_len);
self
}
pub fn with_ownership(mut self) -> Self {
self.include_ownership = true;
self
}
pub fn with_ownership_stdev(mut self) -> Self {
self.include_ownership_stdev = true;
self
}
pub fn with_moves_ownership(mut self) -> Self {
self.include_moves_ownership = true;
self
}
pub fn with_moves_ownership_stdev(mut self) -> Self {
self.include_moves_ownership_stdev = true;
self
}
pub fn with_policy(mut self) -> Self {
self.include_policy = true;
self
}
pub fn with_pv_visits(mut self) -> Self {
self.include_pv_visits = true;
self
}
pub fn with_no_result_value(mut self) -> Self {
self.include_no_result_value = true;
self
}
pub fn with_avoid_moves(mut self, avoid_moves: Vec<RestrictedMoves>) -> Self {
self.avoid_moves = Some(avoid_moves);
self
}
pub fn with_allow_moves(mut self, allow_moves: Vec<RestrictedMoves>) -> Self {
self.allow_moves = Some(allow_moves);
self
}
pub fn with_override_settings(mut self, config: Config) -> Self {
self.override_settings = Some(config);
self
}
pub fn with_report_during_search_every(mut self, seconds: f64) -> Self {
self.report_during_search_every = Some(seconds);
self
}
pub fn with_priority(mut self, priority: i32) -> Self {
self.priority = Some(priority);
self
}
pub fn with_priorities(mut self, priorities: Vec<i32>) -> Self {
self.priorities = Some(priorities);
self
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RestrictedMoves {
pub player: Player,
pub moves: Vec<String>,
pub until_depth: u32,
}