+use std::iter::from_fn;
+
+use rand::{rng, seq::SliceRandom};
+use strum::VariantArray;
+
+#[derive(VariantArray, Clone, Copy)]
+enum Color {
+ Spade,
+ Heart,
+ Diamond,
+ Clubs,
+}
+
+#[derive(VariantArray, Clone, Copy)]
+enum CardKind {
+ Two,
+ Three,
+ Four,
+ Five,
+ Six,
+ Seven,
+ Eight,
+ Nine,
+ Ten,
+ Jack,
+ Queen,
+ King,
+ Ace,
+}
+
+#[derive(Clone, Copy)]
+struct Card {
+ color: Color,
+ kind: CardKind,
+}
+
+enum PlayAction {
+ Fold,
+ CheckCall,
+ Raise(u64),
+}
+
+struct Player {
+ money: u64,
+ folded: bool,
+ curr_bet: u64,
+ hand: [Card; 2],
+ strategy: Box<dyn Fn(usize, &Game) -> PlayAction>,
+}
+
+impl Player {
+ fn bet(&mut self, amount: u64) {
+ if self.folded {
+ return;
+ }
+ let amount = amount.min(self.money);
+ self.money -= amount;
+ self.folded = self.money == 0;
+ self.curr_bet += amount;
+ }
+}
+
+#[derive(VariantArray, Clone, Copy)]
+enum GameState {
+ PreFlop,
+ Flop,
+ Turn,
+ River,
+}
+
+struct Game {
+ players: Vec<Player>,
+ deck: Vec<Card>,
+ board: Vec<Card>,
+ sb: u64,
+ bb: u64,
+}
+
+impl Game {
+ fn should_showdown(&mut self) -> bool {
+ self.players.iter().filter(|p| !p.folded).count() == 1
+ }
+ fn betting_step(&mut self, step: GameState) {
+ let mut i = 0;
+ let mut amount_to_match = self
+ .players
+ .iter()
+ .max_by_key(|p| p.curr_bet)
+ .unwrap()
+ .curr_bet;
+ let mut bet_end = 0;
+ if let GameState::PreFlop = step {
+ self.players[0].bet(self.sb);
+ self.players[0].bet(self.bb);
+ amount_to_match += self.bb;
+ bet_end = 2;
+ i += 2;
+ }
+ while !self.should_showdown() {
+ if self.players[i].folded {
+ i = (i + 1) % self.players.len();
+ continue;
+ }
+ match (self.players[i].strategy)(i, &*self) {
+ PlayAction::Fold => self.players[i].folded = true,
+ PlayAction::CheckCall => {
+ let amount = amount_to_match - self.players[i].curr_bet;
+ self.players[i].bet(amount)
+ }
+ PlayAction::Raise(n) => {
+ let amount = amount_to_match - self.players[i].curr_bet + n;
+ self.players[i].bet(amount);
+ amount_to_match += n;
+ }
+ }
+ i = (i + 1) % self.players.len();
+ if i == bet_end {
+ break;
+ }
+ }
+ }
+ fn deal_step(&mut self, step: GameState) {
+ match step {
+ GameState::PreFlop => {
+ self.board.clear();
+ self.deck.clear();
+ self.deck.extend(CardKind::VARIANTS.iter().flat_map(|kind| {
+ Color::VARIANTS.into_iter().map(|color| Card {
+ color: *color,
+ kind: *kind,
+ })
+ }));
+ self.deck.shuffle(&mut rng());
+ for player in &mut self.players {
+ player.hand = [self.deck.pop().unwrap(), self.deck.pop().unwrap()]
+ }
+ }
+ GameState::Flop => self.board.extend(from_fn(|| self.deck.pop()).take(3)),
+ GameState::Turn => self.board.extend(self.deck.pop()),
+ GameState::River => self.board.extend(self.deck.pop()),
+ }
+ }
+ fn play_round(&mut self) {
+ for step in GameState::VARIANTS {
+ self.deal_step(*step);
+ self.betting_step(*step);
+ if self.should_showdown() {
+ break;
+ }
+ }
+ self.round_showdown();
+ }
+ fn round_showdown(&mut self) {}
+ fn play(&mut self) -> Option<Player> {
+ loop {
+ self.players.rotate_left(1);
+ self.players.retain(|p| p.money != 0);
+ if self.players.len() < 2 {
+ return self.players.pop();
+ }
+ }
+ }
+}
+
+fn main() {
+ println!("Hello, world!");
+}