use async_trait::async_trait;
use crate::arena::GameState;
use crate::arena::action::Action;
mod distribution;
mod estimators;
mod world;
pub use distribution::{HandDistribution, HoleCombo, WeightedCombos, all_hole_combos};
pub use estimators::{KnownHandsEstimator, UniformRandomEstimator};
pub use world::sample_world;
pub struct GameLog<'a> {
pub actions: &'a [Action],
}
#[derive(Debug, Clone, Default)]
pub struct OpponentRanges {
per_seat: Vec<Option<HandDistribution>>,
}
impl OpponentRanges {
pub fn new(per_seat: Vec<Option<HandDistribution>>) -> Self {
Self { per_seat }
}
pub fn get(&self, seat: usize) -> Option<&HandDistribution> {
self.per_seat.get(seat).and_then(|o| o.as_ref())
}
}
#[async_trait]
pub trait HandDistributionEstimator: Send + Sync {
async fn estimate(
&self,
game_state: &GameState,
history: Option<&GameLog<'_>>,
) -> OpponentRanges;
fn needs_history(&self) -> bool {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn opponent_ranges_get_is_bounds_safe() {
let ranges = OpponentRanges::new(vec![None, None]);
assert!(ranges.get(0).is_none());
assert!(ranges.get(99).is_none());
}
#[test]
fn estimator_is_object_safe() {
fn _assert(_: std::sync::Arc<dyn HandDistributionEstimator>) {}
}
}