--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "chacha20"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "rand_core",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "rand_core",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "poker"
+version = "0.1.0"
+dependencies = [
+ "rand",
+ "strum",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rand"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
+dependencies = [
+ "chacha20",
+ "getrandom",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+
+[[package]]
+name = "strum"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
--- /dev/null
+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!");
+}