-use std::{collections::HashMap, rc::Rc};
+use std::collections::HashMap;
use crate::{
- card::{Card, Cards},
+ card::Cards,
constants::{FLUSHES, HASH_ADJUST, HASH_VALUES, PERM7, UNIQUE5},
Algorithm, MyError, Rules,
};
pub struct Evaluator {
pub rules: Rules,
algorithm: Algorithm,
- hands: Vec<Rc<Cards>>,
- pub table: Rc<Cards>,
+ hands: Vec<Cards>,
+ pub table: Cards,
}
impl Default for Evaluator {
self
}
- self.hands.push(Rc::new(hand.clone()));
pub fn hand<'a>(&'a mut self, hand: &Cards) -> &'a mut Evaluator {
+ self.hands.push(hand.clone());
self
}
- for hand in hands {
- self.hands.push(Rc::new(hand.clone()))
- }
pub fn hands<'a>(&'a mut self, hands: &Vec<Cards>) -> &'a mut Evaluator {
+ self.hands.extend_from_slice(hands);
self
}
- self.table = Rc::new(table.clone());
pub fn table<'a>(&'a mut self, table: &Cards) -> &'a mut Evaluator {
+ self.table = table.clone();
self
}
- pub fn eval(&mut self) -> Result<HashMap<usize, u16>, MyError> {
- let hands: Vec<Cards> = self
- .hands
- .clone()
- .into_iter()
- .map(|h| Cards(h.as_ref().0.clone()))
- .collect();
- if hands.is_empty() {
- return Err(MyError::NoHands);
- }
- let table = &self.table.as_ref().0.clone();
- if hands.len() == 5 && matches!(self.rules, Rules::Holdem) {
- println!("Warning: card number in hands does not match the given Poker rules");
- println!("Switching rules to classic");
- self.rules = Rules::Classic;
- }
- let hand = &hands.get(0).unwrap().0;
- if hand.len() == 2 && matches!(self.rules, Rules::Classic) {
- println!("Warning: card number in hands does not match the given Poker rules");
- println!("Switching rules to holdem");
- self.rules = Rules::Holdem;
- }
- if matches!(self.rules, Rules::Holdem) && table.len() == 0 {
- return Err(MyError::NoTable);
+ pub fn eval(&self) -> Result<HashMap<usize, u16>, MyError> {
+ fn parse_args(evaluator: &Evaluator) -> Result<(Vec<Vec<u32>>, Vec<u32>), MyError> {
+ let hands: Vec<Vec<u32>> = evaluator
+ .hands
+ .clone()
+ .into_iter()
+ .map(|cards| cards.into_inner())
+ .collect();
+ if hands.is_empty() {
+ return Err(MyError::NoHands);
+ }
+ let table = evaluator.table.clone().into_inner();
+ if hands[0].len() == 5 && matches!(evaluator.rules, Rules::Holdem) {
+ println!("Warning: card number in hands does not match the given Poker rules");
+ return Err(MyError::UnmatchedCardsTable);
+ }
+ if hands[0].len() == 2 && matches!(evaluator.rules, Rules::Classic) {
+ println!("Warning: card number in hands does not match the given Poker rules");
+ return Err(MyError::UnmatchedCardsTable);
+ }
+ if matches!(evaluator.rules, Rules::Holdem) && table.len() == 0 {
+ return Err(MyError::NoTable);
+ }
+ Ok((hands, table))
}
+
+ let (hands, table) = parse_args(self)?;
+
let result = match self.rules {
- Rules::Classic => self
- .hands
+ Rules::Classic => hands
.iter()
- .map(|player| match self.algorithm {
- Algorithm::CactusKev => {
- self.eval_5hand(&player.as_ref().0[..5].try_into().unwrap())
- }
+ .map(|h| match self.algorithm {
+ Algorithm::CactusKev => self.eval_5hand(h.as_slice()).unwrap(),
})
.enumerate()
.collect(),
- Rules::Holdem => self
- .hands
- .iter()
- .map(|h| {
- h.as_ref()
- .0
- .iter()
- .chain(self.table.as_ref().0.iter())
- .cloned()
- .collect()
- })
- .map(|player: Vec<Card>| match self.algorithm {
- Algorithm::CactusKev => self.eval_7hand(&player.try_into().unwrap()),
+ Rules::Holdem => hands
+ .into_iter()
+ .map(|h| match self.algorithm {
+ Algorithm::CactusKev => self
+ .eval_7hand([h, table.clone()].concat().as_slice())
+ .unwrap(),
})
.enumerate()
.collect(),
Ok(result)
}
- pub fn eval_5hand(&self, cards: &[Card; 5]) -> u16 {
- let [c1, c2, c3, c4, c5]: &[u32; 5] = unsafe { std::mem::transmute(cards) };
- let 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]
+ pub fn eval_5hand(&self, cards: &[u32]) -> Result<u16, MyError> {
+ if let [c1, c2, c3, c4, c5] = cards[..5] {
+ let q = (c1 | c2 | c3 | c4 | c5) >> 16;
+ if c1 & c2 & c3 & c4 & c5 & 0xF000 != 0 {
+ Ok(FLUSHES[q as usize])
+ } else if UNIQUE5[q as usize] != 0 {
+ Ok(UNIQUE5[q as usize])
+ } else {
+ let q = (c1 & 0xff) * (c2 & 0xff) * (c3 & 0xff) * (c4 & 0xff) * (c5 & 0xff);
+ Ok(HASH_VALUES[Evaluator::find_fast(q) as usize])
+ }
} else {
- let q = (c1 & 0xff) * (c2 & 0xff) * (c3 & 0xff) * (c4 & 0xff) * (c5 & 0xff);
- HASH_VALUES[Evaluator::find_fast(q) as usize]
+ Err(MyError::ParseArrayError)
}
}
/// Non-optimized method of determining the best five-card hand possible of seven cards.
- pub fn eval_7hand(&self, cards: &[Card; 7]) -> u16 {
- let mut subhand: [Card; 5] = [Card(0); 5];
+ pub fn eval_7hand(&self, cards: &[u32]) -> Result<u16, MyError> {
+ 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 = self.eval_5hand(&subhand);
+ let q = self.eval_5hand(&subhand)?;
if q < best {
best = q;
}
}
- best
+ Ok(best)
}
fn find_fast(mut u: u32) -> u16 {