use super::card::Card;
use super::deck::Deck;
use super::hand::Hand;
use super::hands::HandIterator;
use super::street::Street;
use super::strength::Strength;
use crate::cards::rank::Rank;
use std::cmp::Ordering;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, PartialOrd, Ord)]
pub struct Canonical(Observation);
impl From<Observation> for Canonical {
fn from(o: Observation) -> Self {
if Self::is_canonical(o) {
Self(o)
} else {
todo!()
}
}
}
impl Canonical {
pub fn is_canonical(o: Observation) -> bool {
todo!()
}
pub fn enumerate(street: Street) -> Vec<Observation> {
Observation::enumerate(street)
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, PartialOrd, Ord)]
pub struct Observation {
secret: Hand,
public: Hand,
}
impl Observation {
pub fn enumerate(street: Street) -> Vec<Observation> {
let n = match street {
Street::Flop => 3,
Street::Turn => 4,
Street::Rive => 5,
_ => unreachable!("no other transitions"),
};
let mut observations = Vec::new();
for hole in HandIterator::from((2usize, Hand::from(0u64))) {
for board in HandIterator::from((n, hole)) {
observations.push(Observation::from((hole, board)));
}
}
observations
}
pub fn equity(&self) -> f32 {
assert!(self.street() == Street::Rive);
let hand = Hand::add(self.public, self.secret);
let hero = Strength::from(hand);
let opponents = HandIterator::from((2usize, hand));
let n = opponents.combinations();
opponents
.map(|oppo| Hand::add(self.public, oppo))
.map(|hand| Strength::from(hand))
.map(|oppo| match &hero.cmp(&oppo) {
Ordering::Greater => 2,
Ordering::Equal => 1,
Ordering::Less => 0,
})
.sum::<u32>() as f32
/ n as f32
/ 2 as f32
}
pub fn outnodes(&self) -> Vec<Observation> {
let excluded = Hand::add(self.public, self.secret);
let expanded = match self.street() {
Street::Pref => 3,
Street::Flop => 1,
Street::Turn => 1,
_ => unreachable!("no children for river"),
};
HandIterator::from((expanded, excluded))
.map(|reveal| Hand::add(self.public, reveal))
.map(|public| Observation::from((self.secret, public)))
.collect::<Vec<Self>>()
}
pub fn street(&self) -> Street {
match self.public.size() {
0 => Street::Pref,
3 => Street::Flop,
4 => Street::Turn,
5 => Street::Rive,
_ => unreachable!("no other sizes"),
}
}
}
impl From<Observation> for i64 {
fn from(observation: Observation) -> Self {
Vec::<Card>::from(observation.public)
.iter()
.chain(Vec::<Card>::from(observation.secret).iter())
.copied()
.map(|card| 1 + u8::from(card) as u64) .fold(0u64, |acc, card| acc << 8 | card) as i64
}
}
impl From<i64> for Observation {
fn from(bits: i64) -> Self {
let mut i = 0;
let mut bits = bits as u64;
let mut secret = Hand::from(0u64);
let mut public = Hand::from(0u64);
while bits > 0 {
let card = ((bits & Rank::MASK as u64) - 1) as u8;
let hand = Hand::from(u64::from(Card::from(card)));
if i < 2 {
secret = Hand::add(secret, hand);
} else {
public = Hand::add(public, hand);
}
i += 1;
bits >>= 8;
}
assert!(secret.size() == 2);
assert!(public.size() <= 5);
Observation { secret, public }
}
}
impl From<(Hand, Hand)> for Observation {
fn from((secret, public): (Hand, Hand)) -> Self {
assert!(secret.size() == 2);
assert!(public.size() <= 5);
Observation { secret, public }
}
}
impl From<Street> for Observation {
fn from(street: Street) -> Self {
let n = match street {
Street::Pref => 0,
Street::Flop => 3,
Street::Turn => 4,
Street::Rive => 5,
};
let mut deck = Deck::new();
let public = Hand::from((0..n).map(|_| deck.draw()).collect::<Vec<Card>>());
let secret = Hand::from((0..2).map(|_| deck.draw()).collect::<Vec<Card>>());
Self::from((secret, public))
}
}
impl From<Observation> for Hand {
fn from(observation: Observation) -> Self {
Hand::add(observation.secret, observation.public)
}
}
impl std::fmt::Display for Observation {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} + {}", self.secret, self.public)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bijective_i64() {
let encoded = Observation::from(Street::Flop);
let decoded = Observation::from(i64::from(encoded));
assert!(encoded.secret == decoded.secret);
assert!(encoded.public == decoded.public);
}
#[test]
fn bijective_canonical() {}
#[test]
fn injective_canonical() {}
}