use rand::seq::SliceRandom;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
enum Rank {
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King,
    Ace,
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
struct Card {
    rank: Rank,
    suit: Suit,
}

struct Deck {
    cards: Vec<Card>,
}

impl Deck {
    fn new() -> Self {
        let mut cards = Vec::with_capacity(52);
        for &suit in &[Suit::Clubs, Suit::Diamonds, Suit::Hearts, Suit::Spades] {
            for &rank in &[
                Rank::Two, Rank::Three, Rank::Four, Rank::Five, Rank::Six,
                Rank::Seven, Rank::Eight, Rank::Nine, Rank::Ten, Rank::Jack,
                Rank::Queen, Rank::King, Rank::Ace,
            ] {
                cards.push(Card { rank, suit });
            }
        }
        Self { cards }
    }

    fn shuffle(&mut self) {
        let mut rng = rand::thread_rng();
        self.cards.shuffle(&mut rng);
        println!("Shuffled the deck.");
    }

    fn deal(&mut self) -> Option<Card> {
        self.cards.pop()
    }
}

#[derive(Debug)]
struct GameState {
    player_hands: [Vec<Card>; 2],
    community_cards: Vec<Card>,
    pot: u32,
    current_player: usize,
}

impl GameState {
    fn new(deck: &mut Deck) -> Self {
        let mut player_hands = [Vec::new(), Vec::new()];
        for hand in player_hands.iter_mut() {
            if let Some(card) = deck.deal() {
                hand.push(card);
            }
            if let Some(card) = deck.deal() {
                hand.push(card);
            }
        }

        println!("Dealt hands: {:?}", player_hands);

        Self {
            player_hands,
            community_cards: Vec::new(),
            pot: 100, // Starting pot for simulations
            current_player: 0,
        }
    }

    fn is_terminal(&self) -> bool {
        self.community_cards.len() >= 3 // Simplified termination
    }

    fn utility(&self, _player: usize) -> f64 {
        self.pot as f64 / 2.0 // Placeholder utility calculation
    }
}

#[derive(Clone, Debug, PartialEq)]
enum Action {
    Fold,
    Call,
    Bet(f32),
}

#[derive(Debug)]
struct InfoSet {
    private_cards: [Card; 2],
    public_cards: Vec<Card>,
    betting_history: Vec<Action>,
    position: Position,
}

impl Hash for InfoSet {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.private_cards.hash(state);
        self.public_cards.hash(state);
        for action in &self.betting_history {
            match action {
                Action::Fold => 0.hash(state),
                Action::Call => 1.hash(state),
                Action::Bet(amount) => amount.to_bits().hash(state),
            }
        }
        self.position.hash(state);
    }
}

impl PartialEq for InfoSet {
    fn eq(&self, other: &Self) -> bool {
        self.private_cards == other.private_cards
            && self.public_cards == other.public_cards
            && self.betting_history.len() == other.betting_history.len()
            && self.position == other.position
    }
}

impl Eq for InfoSet {}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
enum Position {
    Dealer,
    SmallBlind,
}

struct RegretTable {
    table: HashMap<u64, [f64; 4]>,
}

impl RegretTable {
    fn new() -> Self {
        Self {
            table: HashMap::new(),
        }
    }

    fn get_mut(&mut self, key: u64) -> &mut [f64; 4] {
        self.table.entry(key).or_insert([0.0, 0.0, 0.0, 0.0])
    }
}

struct StrategyTable {
    table: HashMap<u64, [f64; 4]>,
}

impl StrategyTable {
    fn new() -> Self {
        Self {
            table: HashMap::new(),
        }
    }

    fn get_or_create(&mut self, infoset: &InfoSet) -> [f64; 4] {
        let strategy = self.table.entry(compute_infoset_key(infoset)).or_insert([1.0, 1.0, 1.0, 1.0]);
        normalize(strategy)
    }
}

fn normalize(strategy: &mut [f64; 4]) -> [f64; 4] {
    let sum: f64 = strategy.iter().sum();
    if sum > 0.0 {
        for v in strategy.iter_mut() {
            *v /= sum;
        }
    } else {
        let default_value = 1.0 / strategy.len() as f64;
        *strategy = [default_value; 4];
    }
    *strategy
}

fn compute_infoset_key<H: Hash>(t: &H) -> u64 {
    let mut s = std::collections::hash_map::DefaultHasher::new();
    t.hash(&mut s);
    s.finish()
}

fn cfr(
    state: &GameState,
    player: usize,
    history: &Vec<Action>,
    probabilities: [f64; 2],
    regrets: &mut RegretTable,
    strategies: &mut StrategyTable,
) -> f64 {
    if state.is_terminal() {
        return state.utility(player);
    }

    let infoset = InfoSet {
        private_cards: [state.player_hands[player][0], state.player_hands[player][1]],
        public_cards: state.community_cards.clone(),
        betting_history: history.clone(),
        position: if player == 0 { Position::Dealer } else { Position::SmallBlind },
    };

    let strategy = strategies.get_or_create(&infoset);
    let mut node_utilities = [0.0; 4];
    let mut node_value = 0.0;

    let pot_size: f32 = state.pot as f32;

    for (i, action) in [Action::Fold, Action::Call, Action::Bet(0.5 * pot_size), Action::Bet(1.0 * pot_size)].iter().enumerate() {
        let mut next_history = history.clone();
        next_history.push(action.clone());

        if next_history.len() > 1 {
            continue;
        }

        let action_probability = strategy[i];
        let new_probabilities = if player == 0 {
            [action_probability * probabilities[0], probabilities[1]]
        } else {
            [probabilities[0], action_probability * probabilities[1]]
        };

        let result_value = cfr(state, player, &next_history, new_probabilities, regrets, strategies);
        node_utilities[i] = result_value;
        node_value += action_probability * result_value;
    }

    let current_regrets = regrets.get_mut(compute_infoset_key(&infoset));
    for (i, action_util) in node_utilities.iter().enumerate() {
        let regret = action_util - node_value;
        current_regrets[i] += probabilities[1 - player] * regret;
    }

    node_value
}

fn train(iterations: u32) {
    let mut regrets = RegretTable::new();
    let mut strategies = StrategyTable::new();

    for i in 0..iterations {
        println!("Iteration: {}", i + 1);

        let mut deck = Deck::new();
        deck.shuffle();

        let game_state = GameState::new(&mut deck);
        
        for player in 0..2 {
            cfr(
                &game_state,
                player,
                &vec![],
                [1.0, 1.0],
                &mut regrets,
                &mut strategies,
            );
        }
    }

    for (key, strategy) in strategies.table.iter() {
        println!("InfoSet: {}, Strategy: {:?}", key, strategy);
    }
}

fn main() {
    train(5);  // Reduced iterations for quick execution
}

this is our code. what we should do next?