diff --git a/crates/logic/src/cube.rs b/crates/logic/src/cube.rs index 4dee422..d34533e 100644 --- a/crates/logic/src/cube.rs +++ b/crates/logic/src/cube.rs @@ -1,8 +1,10 @@ use engine::probabilities::Probabilities; +#[cfg(feature = "web")] use serde::Serialize; +#[cfg(feature = "web")] use utoipa::ToSchema; -#[derive(Serialize, ToSchema)] +#[cfg_attr(feature = "web", derive(Serialize, ToSchema))] /// Information about proper cube decisions. Currently quick and dirty calculations. pub struct CubeInfo { /// `true` if the player `x` should double, `false` if no double yet or too good. @@ -22,3 +24,12 @@ impl From<&Probabilities> for CubeInfo { Self { double, accept } } } + +impl CubeInfo { + pub fn double(&self) -> bool { + self.double + } + pub fn accept(&self) -> bool { + self.accept + } +} diff --git a/crates/logic/src/lib.rs b/crates/logic/src/lib.rs index 354adcd..ecc0a85 100644 --- a/crates/logic/src/lib.rs +++ b/crates/logic/src/lib.rs @@ -1,4 +1,3 @@ pub mod bg_move; -#[cfg(feature = "web")] pub mod cube; pub mod wildbg_api; diff --git a/crates/logic/src/wildbg_api.rs b/crates/logic/src/wildbg_api.rs index 061b842..fdb9dc1 100644 --- a/crates/logic/src/wildbg_api.rs +++ b/crates/logic/src/wildbg_api.rs @@ -1,4 +1,5 @@ use crate::bg_move::BgMove; +use crate::cube::CubeInfo; use engine::composite::CompositeEvaluator; use engine::dice::Dice; use engine::evaluator::Evaluator; @@ -37,6 +38,10 @@ impl WildbgApi { let new_position = self.evaluator.best_position(position, dice, value); BgMove::new(position, &new_position.sides_switched(), dice) } + + pub fn cube_info(&self, position: &Position) -> CubeInfo { + CubeInfo::from(&self.evaluator.eval(position)) + } } #[cfg(test)] diff --git a/crates/wildbg-c/src/lib.rs b/crates/wildbg-c/src/lib.rs index 0bf63d8..bd95d0a 100644 --- a/crates/wildbg-c/src/lib.rs +++ b/crates/wildbg-c/src/lib.rs @@ -4,6 +4,7 @@ use engine::dice::Dice; use engine::position::Position; use engine::probabilities::Probabilities; use logic::bg_move::{BgMove, MoveDetail}; +use logic::cube::CubeInfo; use logic::wildbg_api::{WildbgApi, WildbgConfig}; // When this file is changed, recreate the header file by executing this from the project's root: @@ -148,6 +149,22 @@ impl From<&MoveDetail> for CMoveDetail { } } +#[repr(C)] +#[derive(Default)] +pub struct CCubeInfo { + should_double: bool, + should_accept: bool, +} + +impl From<&CubeInfo> for CCubeInfo { + fn from(value: &CubeInfo) -> Self { + Self { + should_double: value.double(), + should_accept: value.accept(), + } + } +} + type Error = &'static str; /// Returns the best move for the given position. @@ -199,6 +216,21 @@ pub extern "C" fn probabilities(wildbg: &Wildbg, pips: &[c_int; 26]) -> CProbabi } } +#[no_mangle] +pub extern "C" fn cube_info(wildbg: &Wildbg, pips: &[c_int; 26]) -> CCubeInfo { + let pips = pips.map(|pip| pip as i8); + match Position::try_from(pips) { + Ok(position) => (&wildbg.api.cube_info(&position)).into(), + Err(error) => { + eprintln!("{}", error); + CCubeInfo { + should_double: false, + should_accept: false, + } + } + } +} + #[cfg(test)] mod tests { diff --git a/crates/wildbg-c/wildbg.h b/crates/wildbg-c/wildbg.h index 4a25d98..218edb6 100644 --- a/crates/wildbg-c/wildbg.h +++ b/crates/wildbg-c/wildbg.h @@ -70,6 +70,11 @@ typedef struct CProbabilities { float lose_bg; } CProbabilities; +typedef struct CCubeInfo { + bool should_double; + bool should_accept; +} CCubeInfo; + /** * Loads the neural nets into memory and returns a pointer to the API. * Returns `NULL` if the neural nets cannot be found. @@ -109,3 +114,5 @@ struct CMove best_move(const struct Wildbg *wildbg, */ struct CProbabilities probabilities(const struct Wildbg *wildbg, const int (*pips)[26]); + +struct CCubeInfo cube_info(const struct Wildbg *wildbg, const int (*pips)[26]);