pub mod constants;
use std::{
+ collections::HashMap,
convert::{TryFrom, TryInto},
+ rc::Rc,
+ str::FromStr,
sync::{Arc, Mutex},
thread,
};
use wasm_bindgen::prelude::*;
+#[derive(Debug)]
+pub enum MyError {
+ InvalidLength,
+}
+
+impl std::error::Error for MyError {}
+
+impl std::fmt::Display for MyError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Invalid number of cards")
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Rules {
+ Classic,
+ Holdem,
+}
+
+impl Default for Rules {
+ fn default() -> Self {
+ Self::Classic
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Algorithm {
+ Suffecool,
+}
+
+impl Default for Algorithm {
+ fn default() -> Self {
+ Self::Suffecool
+ }
+}
+
+#[derive(Debug)]
+pub struct Evaluator {
+ pub rules: Rules,
+ algorithm: Algorithm,
+ hands: Vec<Rc<Hand>>,
+ pub table: Rc<Hand>,
+}
+
+impl Default for Evaluator {
+ fn default() -> Self {
+ Self {
+ rules: Default::default(),
+ algorithm: Default::default(),
+ hands: Default::default(),
+ table: Default::default(),
+ }
+ }
+}
+
+impl Evaluator {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn with_rules<'a>(&'a mut self, rules: &Rules) -> &'a mut Evaluator {
+ self.rules = *rules;
+ self
+ }
+
+ pub fn with_algorithm<'a>(&'a mut self, algorithm: &Algorithm) -> &'a mut Evaluator {
+ self.algorithm = *algorithm;
+ self
+ }
+
+ pub fn with_hand<'a>(&'a mut self, hand: &Hand) -> &'a mut Evaluator {
+ self.hands.push(Rc::new(hand.clone()));
+ self
+ }
+
+ pub fn with_hands<'a>(&'a mut self, hands: &Vec<Hand>) -> &'a mut Evaluator {
+ for hand in hands {
+ self.hands.push(Rc::new(hand.clone()))
+ }
+ self
+ }
+
+ pub fn with_table<'a>(&'a mut self, table: &Hand) -> &'a mut Evaluator {
+ self.table = Rc::new(table.clone());
+ self
+ }
+
+ pub fn eval(&self) -> HashMap<usize, u16> {
+ // match cards.len() {
+ // 7 => Ok(eval_7hand(&cards.try_into().unwrap())),
+ // 5 => Ok(eval_5hand(&cards.try_into().unwrap())),
+ // _ => Err(MyError::InvalidLength),
+ // }
+ let result = match self.rules {
+ Rules::Classic => self
+ .hands
+ .iter()
+ .map(|player| match self.algorithm {
+ Algorithm::Suffecool => {
+ self.eval_5hand(player.as_ref().cards[..].try_into().unwrap())
+ }
+ })
+ .enumerate()
+ .collect(),
+ Rules::Holdem => self
+ .hands
+ .iter()
+ .map(|h| {
+ h.as_ref()
+ .cards
+ .iter()
+ .chain(self.table.as_ref().cards.iter())
+ .cloned()
+ .collect()
+ })
+ .map(|player: Vec<u32>| match self.algorithm {
+ Algorithm::Suffecool => self.eval_7hand(&player[..].try_into().unwrap()),
+ })
+ .enumerate()
+ .collect(),
+ };
+ result
+ }
+
+ pub fn eval_5hand(&self, cards: &[u32; 5]) -> u16 {
+ if let [c1, c2, c3, c4, c5] = cards[..5] {
+ let mut q = (c1 | c2 | c3 | c4 | c5) >> 16;
+ if c1 & c2 & c3 & c4 & c5 & 0xF000 != 0 {
+ FLUSHES[q as usize]
+ } else if UNIQUE5[q as usize] != 0 {
+ UNIQUE5[q as usize]
+ } else {
+ q = (c1 & 0xff) * (c2 & 0xff) * (c3 & 0xff) * (c4 & 0xff) * (c5 & 0xff);
+ HASH_VALUES[find_fast((q as usize).try_into().unwrap()) as usize]
+ }
+ } else {
+ 9999
+ }
+ }
+
+ /// Non-optimized method of determining the best five-card hand possible of seven cards.
+ pub fn eval_7hand(&self, cards: &[u32; 7]) -> u16 {
+ let mut subhand: [u32; 5] = [0; 5];
+ let mut best = 9999;
+
+ for i in 0..21 {
+ for j in 0..5 {
+ subhand[j] = cards[..][PERM7[i][j] as usize];
+ }
+ let q = eval_5hand(&subhand);
+ if q < best {
+ best = q;
+ }
+ }
+ best
+ }
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct Hand {
+ pub cards: Vec<u32>,
+}
+
+impl Hand {
+ pub fn new() -> Self {
+ Self { cards: Vec::new() }
+ }
+
+ pub fn with_cards<'a>(&'a mut self, cards: Vec<u32>) -> &'a mut Hand {
+ for card in cards {
+ self.cards.push(card.clone());
+ }
+ self
+ }
+
+ pub fn with_rules<'a>(&'a mut self, rules: &Rules, deck: &mut Vec<u32>) -> &'a mut Hand {
+ match rules {
+ Rules::Classic => {
+ self.with_cards(deck.split_off(deck.len() - 5));
+ }
+
+ Rules::Holdem => {
+ self.with_cards(deck.split_off(deck.len() - 2));
+ }
+ };
+ self
+ }
+}
+
+impl FromStr for Hand {
+ type Err = MyError;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(Self {
+ cards: s
+ .trim()
+ .split_whitespace()
+ .map(|c| parse_card(c).expect("Could not parse card from string"))
+ .collect::<Vec<_>>(),
+ })
+ }
+}
+
/// Initializes a deck of 52 cards as an integer vector of lenght 52.
///
/// The order in which the cards are returned is not random.