use rbp_core::*;
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct Odds(Chips, Chips);
impl Odds {
pub const fn new(n: Chips, d: Chips) -> Self {
Self(n, d)
}
pub fn numer(&self) -> Chips {
self.0
}
pub fn denom(&self) -> Chips {
self.1
}
fn gcd(a: Chips, b: Chips) -> (Chips, Chips) {
let (mut x, mut y) = (a, b);
while y != 0 {
(x, y) = (y, x % y);
}
(a / x, b / x)
}
pub fn ratio(&self) -> String {
format!("{}:{}", self.0, self.1)
}
pub const GRID: [Self; 10] = [
Self(1, 4), Self(1, 3), Self(1, 2), Self(2, 3), Self(3, 4), Self(1, 1), Self(5, 4), Self(3, 2), Self(2, 1), Self(3, 1), ];
}
impl From<Odds> for Probability {
fn from(odds: Odds) -> Self {
odds.0 as Probability / odds.1 as Probability
}
}
impl From<(Chips, Chips)> for Odds {
fn from((a, b): (Chips, Chips)) -> Self {
let (a, b) = Self::gcd(a, b);
Self(a, b)
}
}
impl TryFrom<&str> for Odds {
type Error = anyhow::Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match (s.strip_prefix('+'), s.strip_prefix('-')) {
(Some(x), _) => Ok(Self::new(1, x.parse()?)),
(_, Some(x)) => Ok(Self::new(x.parse()?, 1)),
_ => Err(anyhow::anyhow!("odds string missing + or -")),
}
}
}
impl std::fmt::Display for Odds {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let p = Probability::from(*self);
if p > 1.0 {
write!(f, "-{}", p.round() as Chips)
} else {
write!(f, "+{}", (1.0 / p).round() as Chips)
}
}
}
impl Arbitrary for Odds {
fn random() -> Self {
use rand::prelude::IndexedRandom;
let ref mut rng = rand::rng();
Self::GRID.choose(rng).copied().expect("GRID is empty")
}
}