use crate::analysis::outs::Outs;
use crate::games::holdem::case_eval::CaseEval;
use crate::games::holdem::seat::Seat;
use crate::games::holdem::seat_eval::SeatEval;
use crate::types::card_slot;
use crate::types::card_slot::CardSlot;
use crate::types::playing_card::PlayingCard;
use crate::types::playing_cards::PlayingCards;
use crate::types::poker_cards::PokerCards;
use crate::types::slots::hole_cards::HoleCards;
use ckc_rs::HandError;
use itertools::Itertools;
use log::debug;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct Seats(Vec<Seat>);
impl Seats {
#[must_use]
pub fn seat(number: usize) -> Seats {
let mut players = Seats::default();
for _ in 0..number {
players.add(HoleCards::default());
}
players
}
pub fn from_index(index: &'static str) -> Result<Seats, HandError> {
Seats::try_from(index)
}
#[must_use]
pub fn case_eval(&self, cycle: &PlayingCards) -> CaseEval {
let mut case_eval = CaseEval::default();
debug!("Case Eval: {}", cycle);
for seat in &self.0 {
let cards = cycle.clone().combine(&seat.to_playing_cards());
let best_for_player = cards.eval_7cards();
let eval = best_for_player.unwrap();
debug!(" Player {} {}", seat.number, eval);
case_eval.push(SeatEval::new_from_eval(seat.clone(), eval));
}
case_eval
}
#[must_use]
pub fn case_eval_with_outs(&self, out: PlayingCard, cycle: &PlayingCards) -> (Outs, CaseEval) {
let case_eval = self.case_eval(cycle);
let outs = Seats::get_outs(out, &case_eval);
(outs, case_eval)
}
#[must_use]
pub fn get_outs(out: PlayingCard, case_eval: &CaseEval) -> Outs {
let mut outs = Outs::default();
for seat in case_eval.winners().iter() {
outs.add(seat.seat.number, out);
}
outs
}
#[must_use]
pub fn dealt(&self) -> PlayingCards {
let mut cards = PlayingCards::default();
for player in self.iter() {
cards.append(&player.to_playing_cards());
}
cards
}
#[must_use]
pub fn get(&self, player: usize) -> Option<&HoleCards> {
match self.0.get(player) {
Some(seat) => Some(&seat.hole_cards),
None => None,
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &Seat> {
self.0.iter()
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn len_for_player(&self, player: usize) -> Option<usize> {
let player = self.0.get(player);
player.map(card_slot::CardSlot::len)
}
#[must_use]
pub fn take_for_player(&self, player: usize, card: PlayingCard) -> bool {
let player = self.0.get(player);
match player {
Some(p) => p.take(card),
None => false,
}
}
pub fn add(&mut self, hole_cards: HoleCards) {
self.0
.push(Seat::new_with_hole_cards(self.len(), hole_cards));
}
pub fn add_from_index(&mut self, index: &'static str) {
self.0.push(Seat::from_index(self.len(), index));
}
#[must_use]
pub fn is_active(&self, seat: usize) -> bool {
match self.0.get(seat) {
Some(hand) => hand.is_dealt(),
None => false,
}
}
#[must_use]
pub fn is_dealt(&self) -> bool {
for i in 0..self.0.len() {
if !self.is_active(i) {
return false;
}
}
true
}
#[must_use]
pub fn fold_player(&self, player: usize) -> Option<PlayingCards> {
self.0.get(player).map(card_slot::CardSlot::fold)
}
}
impl CardSlot for Seats {
fn take(&self, card: PlayingCard) -> bool {
for i in 0..self.len() {
if let Some(0) = self.len_for_player(i) {
return self.take_for_player(i, card);
}
}
for i in 0..self.len() {
if let Some(1) = self.len_for_player(i) {
return self.take_for_player(i, card);
}
}
false
}
fn fold(&self) -> PlayingCards {
let mut poker_cards = PlayingCards::default();
for i in 0..self.len() {
poker_cards.append(&self.fold_player(i).unwrap());
}
poker_cards
}
fn is_dealt(&self) -> bool {
for player in self.0.clone() {
if !player.is_dealt() {
return false;
}
}
true
}
fn to_playing_cards(&self) -> PlayingCards {
let mut cards = PlayingCards::default();
for player in self.0.clone() {
cards.append(&player.to_playing_cards());
}
cards
}
}
impl Default for Seats {
fn default() -> Seats {
Seats::from(Vec::default())
}
}
impl fmt::Display for Seats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let joined = Itertools::join(&mut self.0.iter(), ", ");
write!(f, "[{}]", joined)
}
}
impl From<Vec<Seat>> for Seats {
fn from(value: Vec<Seat>) -> Self {
Seats(value)
}
}
impl TryFrom<&'static str> for Seats {
type Error = HandError;
fn try_from(value: &'static str) -> Result<Self, Self::Error> {
let poker_cards = PokerCards::try_from(value);
match poker_cards {
Ok(cards) => Seats::try_from(cards),
Err(e) => Err(e),
}
}
}
impl TryFrom<PokerCards> for Seats {
type Error = HandError;
fn try_from(value: PokerCards) -> Result<Self, Self::Error> {
let mut cards = value;
if cards.len() % 2 == 0 {
let num_of_players = cards.len() / 2;
let players = Seats::seat(num_of_players);
for i in 0..num_of_players {
let _ = players.take_for_player(i, PlayingCard::from(cards.pull()));
let _ = players.take_for_player(i, PlayingCard::from(cards.pull()));
}
Ok(players)
} else {
Err(HandError::InvalidIndex)
}
}
}
impl TryFrom<PlayingCards> for Seats {
type Error = HandError;
fn try_from(value: PlayingCards) -> Result<Self, Self::Error> {
let mut cards = value;
if cards.len() % 2 == 0 {
let num_of_players = cards.len() / 2;
let players = Seats::seat(num_of_players);
for i in 0..num_of_players {
let _ = players.take_for_player(i, cards.draw_one());
let _ = players.take_for_player(i, cards.draw_one());
}
Ok(players)
} else {
Err(HandError::InvalidIndex)
}
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod holdem_players_tests {
use super::*;
#[test]
fn seat() {
let players = Seats::seat(3);
assert_eq!(
"[Seat 0: __ __, Seat 1: __ __, Seat 2: __ __]",
players.to_string()
);
}
#[test]
fn from_index() {
let index = "4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦";
let players = Seats::try_from(index);
assert!(players.is_ok());
assert_eq!(
"[Seat 0: 4♥ K♣, Seat 1: 5♥ 3♠, Seat 2: 8♦ 9♠, Seat 3: 8♠ J♦]",
players.unwrap().to_string()
)
}
#[test]
fn from_index__invalid_card() {
let index = "4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦ 9♥ 9♦ 2♦ 5♠ JK";
let players = Seats::from_index(index);
assert!(players.is_err());
assert_eq!(players.unwrap_err(), HandError::InvalidCard)
}
#[test]
fn from_index__wrong_number_of_cards() {
let index = "4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦ 9♥ 9♦ 2♦ 5♠ 7♦";
let players = Seats::from_index(index);
assert!(players.is_err());
assert_eq!(players.unwrap_err(), HandError::InvalidIndex)
}
#[test]
fn is_active() {
let players = Seats::seat(2);
assert!(!players.is_active(0));
assert!(!players.is_active(1));
assert!(!players.is_dealt());
let taken = players.take_for_player(0, PlayingCard::from(PlayingCard::ACE_DIAMONDS));
assert!(taken);
let taken = players.take_for_player(0, PlayingCard::from(PlayingCard::ACE_CLUBS));
assert!(taken);
assert!(players.is_active(0));
assert!(!players.is_dealt());
let taken = players.take_for_player(1, PlayingCard::from(PlayingCard::KING_SPADES));
assert!(taken);
let taken = players.take_for_player(1, PlayingCard::from(PlayingCard::KING_CLUBS));
assert!(taken);
assert!(players.is_active(1));
assert!(players.is_dealt());
assert_eq!("[Seat 0: A♦ A♣, Seat 1: K♠ K♣]", players.to_string());
}
#[test]
fn take() {
let players = Seats::seat(3);
let mut cards = PlayingCards::try_from("4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦").unwrap();
assert!(players.take(cards.draw_one()));
assert!(players.take(cards.draw_one()));
assert_eq!(
"[Seat 0: 4♥ __, Seat 1: K♣ __, Seat 2: __ __]",
players.to_string()
);
assert!(players.take(cards.draw_one()));
assert!(players.take(cards.draw_one()));
assert_eq!(
"[Seat 0: 4♥ 3♠, Seat 1: K♣ __, Seat 2: 5♥ __]",
players.to_string()
);
assert!(players.take(cards.draw_one()));
assert!(players.take(cards.draw_one()));
assert_eq!(
"[Seat 0: 4♥ 3♠, Seat 1: K♣ 8♦, Seat 2: 5♥ 9♠]",
players.to_string()
);
assert!(!players.take(cards.draw_one()));
assert_eq!(
"[Seat 0: 4♥ 3♠, Seat 1: K♣ 8♦, Seat 2: 5♥ 9♠]",
players.to_string()
);
}
#[test]
fn fold() {
let index = "4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦";
let players = Seats::from_index(index).unwrap();
let folded = players.fold();
assert_eq!("4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦", folded.to_string());
assert_eq!(
"[Seat 0: __ __, Seat 1: __ __, Seat 2: __ __, Seat 3: __ __]",
players.to_string()
);
assert!(!players.is_dealt());
}
#[test]
fn to_poker_cards() {
let index = "4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦";
let players = Seats::from_index(index).unwrap();
assert_eq!(
"4♥ K♣ 5♥ 3♠ 8♦ 9♠ 8♠ J♦",
players.to_playing_cards().to_string()
);
assert!(players.is_dealt());
}
#[test]
fn display() {
let players = Seats::from_index("AS KS AD KD").unwrap();
assert_eq!("[Seat 0: A♠ K♠, Seat 1: A♦ K♦]", players.to_string());
}
#[test]
fn display__blank() {
assert_eq!(
"[Seat 0: __ __, Seat 1: __ __, Seat 2: __ __]",
format!("{}", Seats::seat(3))
)
}
}