1use super::*;
2use rbp_cards::*;
3use rbp_core::*;
4use std::ops::Not;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct Game {
30 pot: Chips,
31 board: Board,
32 seats: [Seat; N],
33 dealer: Position,
34 ticker: Position,
35}
36
37impl Default for Game {
38 fn default() -> Self {
39 let mut deck = Deck::new();
40 Self {
41 pot: 0,
42 board: Board::empty(),
43 seats: [(); N]
44 .map(|_| deck.hole())
45 .map(|h| (h, STACK))
46 .map(Seat::from),
47 dealer: 0usize,
48 ticker: 0usize,
49 }
50 }
51}
52
53impl Game {
55 pub fn root() -> Self {
60 let mut game = Self::default();
61 game.act(game.posts());
62 game.act(game.posts());
63 game
64 }
65 pub fn wipe(mut self, hole: Hole) -> Self {
69 for seat in self.seats.iter_mut() {
70 seat.reset_cards(hole);
71 }
72 self
73 }
74 pub fn assume(mut self, hero: Turn, hole: Hole) -> Self {
83 self.seats
84 .iter_mut()
85 .enumerate()
86 .filter(|(i, _)| Turn::Choice(*i) != hero)
87 .for_each(|(_, seat)| seat.reset_cards(hole));
88 self
89 }
90 pub fn ffwd(mut self, target: Street) -> Self {
104 while self.street() < target {
105 match self.turn() {
106 Turn::Terminal => panic!("reached terminal before target street"),
107 Turn::Chance => {
108 let action = self.reveal();
109 self.act(action);
110 }
111 Turn::Choice(_) => {
112 let action = self.passive();
113 self.act(action);
114 }
115 }
116 }
117 debug_assert_eq!(self.street(), target, "overshot target street");
118 self
119 }
120}
121
122impl Game {
124 pub fn n(&self) -> usize {
126 self.seats.len()
127 }
128 pub fn pot(&self) -> Chips {
130 self.pot
131 }
132 pub fn seats(&self) -> [Seat; N] {
134 self.seats
135 }
136 pub fn board(&self) -> Board {
138 self.board
139 }
140 pub fn turn(&self) -> Turn {
142 if self.must_stop() {
143 Turn::Terminal
144 } else if self.must_deal() {
145 Turn::Chance
146 } else {
147 Turn::Choice(self.actor_idx())
148 }
149 }
150 pub fn actor(&self) -> &Seat {
152 self.actor_ref()
153 }
154 pub fn sweat(&self) -> Observation {
156 Observation::from((
157 Hand::from(self.actor().cards()), Hand::from(self.board()), ))
160 }
161 pub fn dealer(&self) -> Turn {
163 Turn::Choice(self.dealer)
164 }
165 pub fn street(&self) -> Street {
167 self.board.street()
168 }
169}
170
171impl Game {
173 pub fn consume(&mut self, action: Action) -> Self {
175 self.act(action);
176 self.clone()
177 }
178 pub fn apply(&self, action: Action) -> Self {
182 self.try_apply(action).expect("valid action")
183 }
184 pub fn try_apply(&self, action: Action) -> anyhow::Result<Self> {
189 if !self.is_allowed(&action) {
190 return Err(anyhow::anyhow!(
191 "illegal action {:?} in state {:?}",
192 action,
193 self.turn()
194 ));
195 }
196 let mut child = self.clone();
197 child.act(action);
198 Ok(child)
199 }
200 pub fn legal(&self) -> Vec<Action> {
205 if self.must_stop() {
207 return vec![];
208 }
209 if self.must_deal() {
210 return vec![self.reveal()];
211 }
212 if self.must_post() {
213 return vec![self.posts()];
214 }
215 let mut options = Vec::new();
217 if self.may_raise() {
218 options.push(self.raise());
219 }
220 if self.may_shove() {
221 options.push(self.shove());
222 }
223 if self.may_call() {
224 options.push(self.calls());
225 }
226 if self.may_fold() {
227 options.push(self.folds());
228 }
229 if self.may_check() {
230 options.push(self.check());
231 }
232 debug_assert!(options.len() > 0);
233 options
234 }
235 pub fn is_allowed(&self, action: &Action) -> bool {
239 match action {
243 Action::Raise(raise) => {
244 self.may_raise()
245 && self.must_stop().not()
246 && self.must_deal().not()
247 && raise.clone() >= self.to_raise()
248 && raise.clone() <= self.to_shove() - 1
249 }
250 Action::Draw(cards) => {
251 self.must_deal()
252 && self.must_stop().not()
253 && cards.clone().all(|c| self.deck().contains(&c))
254 && cards.count() == self.board().street().next().n_revealed()
255 }
256 other => self.legal().contains(other),
257 }
258 }
259}
260
261impl Game {
263 pub fn continuation(mut self) -> Option<Self> {
269 debug_assert!(self.turn() == Turn::Terminal);
270 self.settlements()
271 .iter()
272 .zip(self.seats())
273 .all(|(s, seat)| seat.stack() + s.pnl().reward() >= Game::bblind())
274 .then(|| {
275 self.give_chips();
276 self.wipe_board();
277 self.wipe_seats();
278 self.move_button();
279 self.act(self.posts());
280 self.act(self.posts());
281 self
282 })
283 }
284
285 fn give_chips(&mut self) {
286 for (_, (settlement, seat)) in self
287 .settlements()
288 .iter()
289 .zip(self.seats.iter_mut())
290 .enumerate()
291 .inspect(|(i, (x, s))| log::trace!("{} {} {:>7} {}", i, s.cards(), s.stack(), x.won()))
292 {
293 seat.win(settlement.pnl().reward());
294 }
295 self.pot = 0;
296 }
297
298 fn wipe_board(&mut self) {
299 debug_assert!(self.pot() == 0);
300 self.board.clear();
301 }
302 fn wipe_seats(&mut self) {
303 debug_assert!(self.pot() == 0);
304 debug_assert!(self.street() == Street::Pref);
305 let mut deck = Deck::new();
306 for seat in self.seats.iter_mut() {
307 seat.reset_state(State::Betting);
308 seat.reset_cards(deck.hole());
309 seat.reset_stake();
310 seat.reset_spent();
311 }
312 }
313
314 fn move_button(&mut self) {
315 debug_assert!(self.pot() == 0);
316 debug_assert!(self.seats.len() == self.n());
317 debug_assert!(self.street() == Street::Pref);
318 self.dealer = self.dealer + 1;
319 self.dealer = self.dealer % self.n();
320 self.ticker = 0;
321 }
322}
323
324impl Game {
326 fn act(&mut self, a: Action) {
328 debug_assert!(self.is_allowed(&a));
329 match a {
330 Action::Check => {
331 self.next_player();
332 }
333 Action::Fold => {
334 self.fold();
335 self.next_player();
336 }
337 Action::Call(chips)
338 | Action::Blind(chips)
339 | Action::Raise(chips)
340 | Action::Shove(chips) => {
341 self.bet(chips);
342 self.next_player();
343 }
344 Action::Draw(cards) => {
345 self.show(cards);
346 self.next_player();
347 self.next_street();
348 }
349 }
350 }
351 fn bet(&mut self, bet: Chips) {
352 debug_assert!(self.actor_ref().stack() >= bet);
353 self.pot += bet;
354 self.actor_mut().bet(bet);
355 if self.actor_ref().stack() == 0 {
356 self.allin();
357 }
358 }
359 fn allin(&mut self) {
360 self.actor_mut().reset_state(State::Shoving);
361 }
362 fn fold(&mut self) {
363 self.actor_mut().reset_state(State::Folding);
364 }
365 fn show(&mut self, hand: Hand) {
366 self.ticker = 0;
367 self.board.add(hand);
368 }
369}
370
371impl Game {
373 fn next_street(&mut self) {
375 for seat in self.seats.iter_mut() {
376 seat.reset_stake();
377 }
378 }
379 fn next_player(&mut self) {
381 if !self.is_everyone_alright() {
382 loop {
383 self.ticker += 1;
384 match self.actor_ref().state() {
385 State::Betting => break,
386 State::Folding => continue,
387 State::Shoving => continue,
388 }
389 }
390 }
391 }
392}
393
394impl Game {
396 pub fn must_stop(&self) -> bool {
398 if self.street() == Street::Rive {
399 self.is_everyone_alright()
400 } else {
401 self.is_everyone_folding()
402 }
403 }
404 pub fn must_deal(&self) -> bool {
406 self.street() != Street::Rive && self.is_everyone_alright()
407 }
408 pub fn must_post(&self) -> bool {
410 self.street() == Street::Pref && self.pot() < Self::sblind() + Self::bblind()
411 }
412 fn is_everyone_alright(&self) -> bool {
414 self.is_everyone_calling() || self.is_everyone_folding() || self.is_everyone_shoving()
415 }
416 fn is_everyone_calling(&self) -> bool {
418 self.is_everyone_touched() && self.is_everyone_matched()
419 }
420 fn is_everyone_touched(&self) -> bool {
422 self.ticker > self.n() + if self.street() == Street::Pref { 1 } else { 0 }
423 }
424 fn is_everyone_matched(&self) -> bool {
426 let stake = self.stakes();
427 self.seats
428 .iter()
429 .filter(|s| s.state() == State::Betting)
430 .all(|s| s.stake() == stake)
431 }
432 fn is_everyone_shoving(&self) -> bool {
434 self.seats
435 .iter()
436 .filter(|s| s.state() != State::Folding)
437 .all(|s| s.state() == State::Shoving)
438 }
439 fn is_everyone_folding(&self) -> bool {
441 self.seats
442 .iter()
443 .filter(|s| s.state() != State::Folding)
444 .count()
445 == 1
446 }
447 pub fn may_fold(&self) -> bool {
449 matches!(self.turn(), Turn::Choice(_)) && self.to_call() > 0
450 }
451 pub fn may_call(&self) -> bool {
453 matches!(self.turn(), Turn::Choice(_))
454 && self.may_fold()
455 && self.to_call() < self.to_shove()
456 }
457 pub fn may_check(&self) -> bool {
459 matches!(self.turn(), Turn::Choice(_)) && self.stakes() == self.actor_ref().stake()
460 }
461 pub fn may_raise(&self) -> bool {
463 matches!(self.turn(), Turn::Choice(_)) && self.to_raise() < self.to_shove()
464 }
465 pub fn may_shove(&self) -> bool {
467 matches!(self.turn(), Turn::Choice(_)) && self.to_shove() > 0
468 }
469}
470
471impl Game {
473 pub fn to_call(&self) -> Chips {
475 self.stakes() - self.actor_ref().stake()
476 }
477 pub fn to_post(&self) -> Chips {
479 debug_assert!(self.street() == Street::Pref);
480 if self.actor_idx() == self.dealer {
481 Self::sblind().min(self.actor_ref().stack())
482 } else {
483 Self::bblind().min(self.actor_ref().stack())
484 }
485 }
486 pub fn to_shove(&self) -> Chips {
488 self.actor_ref().stack()
489 }
490 pub fn to_raise(&self) -> Chips {
494 let (most_large_stake, next_large_stake) = self
495 .seats
496 .iter()
497 .filter(|s| s.state() != State::Folding)
498 .map(|s| s.stake())
499 .fold((0, 0), |(most, next), stake| {
500 if stake > most {
501 (stake, most)
502 } else if stake > next {
503 (most, stake)
504 } else {
505 (most, next)
506 }
507 });
508 let relative_raise = most_large_stake - self.actor().stake();
509 let marginal_raise = most_large_stake - next_large_stake;
510 let required_raise = std::cmp::max(marginal_raise, Self::bblind());
511 relative_raise + required_raise
512 }
513 pub fn raise(&self) -> Action {
515 Action::Raise(self.to_raise())
516 }
517 pub fn shove(&self) -> Action {
519 Action::Shove(self.to_shove())
520 }
521 pub fn calls(&self) -> Action {
523 Action::Call(self.to_call())
524 }
525 pub fn posts(&self) -> Action {
527 Action::Blind(self.to_post())
528 }
529 pub fn folds(&self) -> Action {
531 Action::Fold
532 }
533 pub fn check(&self) -> Action {
535 Action::Check
536 }
537 pub fn passive(&self) -> Action {
539 if self.may_check() {
540 Action::Check
541 } else {
542 Action::Fold
543 }
544 }
545 pub fn reveal(&self) -> Action {
547 Action::Draw(self.deck().deal(self.street()))
548 }
549}
550
551impl Game {
553 pub fn settlements(&self) -> Vec<Settlement> {
555 debug_assert!(self.must_stop(), "non terminal game state:\n{}", self);
556 Showdown::from(self.ledger()).settle()
557 }
558 pub fn is_showdown(&self) -> bool {
560 self.seats.iter().filter(|s| s.state().is_active()).count() > 1
561 }
562 fn ledger(&self) -> Vec<Settlement> {
563 self.seats
564 .iter()
565 .enumerate()
566 .map(|(position, _)| self.settlement(position))
567 .collect()
568 }
569 fn settlement(&self, position: usize) -> Settlement {
570 let seat = &self.seats[position];
571 let strength = Strength::from(Hand::add(
572 Hand::from(seat.cards()),
573 Hand::from(self.board()),
574 ));
575 Settlement::from((seat.spent(), seat.state(), strength))
576 }
577}
578
579impl Game {
581 pub fn draw(&self) -> Hand {
583 self.deck().deal(self.street())
584 }
585 pub fn deck(&self) -> Deck {
587 let mut removed = Hand::from(self.board);
588 for seat in self.seats.iter() {
589 removed = Hand::or(removed, Hand::from(seat.cards()));
590 }
591 Deck::from(removed.complement())
592 }
593}
594
595impl Game {
597 fn actor_idx(&self) -> Position {
599 (self.dealer + self.ticker) % self.n()
600 }
601 fn actor_ref(&self) -> &Seat {
602 self.seats
603 .get(self.actor_idx())
604 .expect("index should be in bounds bc modulo")
605 }
606 fn actor_mut(&mut self) -> &mut Seat {
607 let index = self.actor_idx();
608 self.seats
609 .get_mut(index)
610 .expect("index should be in bounds bc modulo")
611 }
612}
613
614impl Game {
616 pub fn total(&self) -> Chips {
618 self.pot() + self.seats().iter().map(|s| s.stack()).sum::<Chips>()
619 }
620 pub fn effective(&self) -> Chips {
625 self.seats.iter().map(|s| s.stack()).min().unwrap_or(0)
626 }
627 pub fn spr(&self) -> f32 {
629 match self.pot() {
630 0 => 0.0,
631 p => self.effective() as f32 / p as f32,
632 }
633 }
634 fn stakes(&self) -> Chips {
636 self.seats
637 .iter()
638 .map(|s| s.stake())
639 .max()
640 .expect("non-empty seats")
641 }
642 #[allow(dead_code)]
645 fn is_opening(&self) -> bool {
646 self.street() == Street::Pref && self.pot() == Self::sblind() + Self::bblind()
647 }
648}
649
650impl Game {
652 pub const fn blinds() -> [Action; 2] {
654 [Action::Blind(Self::sblind()), Action::Blind(Self::bblind())]
655 }
656 pub const fn bblind() -> Chips {
658 rbp_core::B_BLIND
659 }
660 pub const fn sblind() -> Chips {
662 rbp_core::S_BLIND
663 }
664}
665
666impl Game {
668 pub fn choices(&self, depth: usize) -> Path {
671 self.legal()
672 .into_iter()
673 .flat_map(|action| self.unfold(depth, action))
674 .collect()
675 }
676 fn unfold(&self, depth: usize, action: Action) -> Vec<Edge> {
679 match action {
680 Action::Raise(_) => Edge::raises(self.street(), depth),
681 _ => vec![Edge::from(action)],
682 }
683 }
684 pub fn actionize(&self, edge: Edge) -> Action {
687 match edge {
688 Edge::Fold => Action::Fold,
689 Edge::Draw => self.reveal(),
690 Edge::Call => Action::Call(self.to_call()),
691 Edge::Check => Action::Check,
692 Edge::Shove => Action::Shove(self.to_shove()),
693 Edge::Open(n) => Action::Raise(n * rbp_core::B_BLIND),
694 Edge::Raise(_) => Action::Raise(edge.into_chips(self.pot())),
695 }
696 }
697 pub fn edgify(&self, action: Action, depth: usize) -> Edge {
700 match action {
701 Action::Fold => Edge::Fold,
702 Action::Check => Edge::Check,
703 Action::Draw(_) => Edge::Draw,
704 Action::Call(_) => Edge::Call,
705 Action::Blind(_) => Edge::Call,
706 Action::Shove(_) => Edge::Shove,
707 Action::Raise(chips) => self.snap_to_edge(chips, depth),
708 }
709 }
710 fn snap_to_edge(&self, chips: Chips, depth: usize) -> Edge {
712 let edges = Edge::raises(self.street(), depth);
713 edges
714 .into_iter()
715 .min_by_key(|e| (e.into_chips(self.pot()) as i32 - chips as i32).abs())
716 .unwrap_or(Edge::Shove)
717 }
718 pub fn snap(&self, action: Action) -> Action {
735 match action {
736 Action::Raise(x) if x >= self.to_shove() => self.snap(self.shove()), Action::Raise(_) if !self.may_raise() => self.snap(self.shove()), Action::Raise(x) if x < self.to_raise() => self.raise(), Action::Raise(x) => Action::Raise(x), Action::Shove(_) if self.may_shove() => self.shove(), Action::Shove(_) if self.may_call() => self.calls(), Action::Shove(_) => self.passive(), Action::Call(_) if self.may_call() => self.calls(), Action::Call(_) if self.may_shove() => self.shove(), Action::Call(_) => self.passive(), Action::Check if self.may_check() => Action::Check, Action::Check if self.may_call() => self.calls(), Action::Check => self.folds(), Action::Fold if self.may_fold() => Action::Fold, Action::Fold => Action::Check, Action::Draw(_) | Action::Blind(_) => action,
752 }
753 }
754}
755
756
757impl std::fmt::Display for Game {
758 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
759 for seat in self.seats.iter() {
760 writeln!(
761 f,
762 "{:>3} {:>3} {:<6}",
763 seat.state(),
764 seat.cards(),
765 seat.stack()
766 )?;
767 }
768 writeln!(f, "Pot {}", self.pot())?;
769 writeln!(f, "Board {}", self.board())?;
770 Ok(())
771 }
772}
773pub struct Perpetual(Game);
778impl Perpetual {
779 pub fn new(game: Game) -> Self {
780 Self(game)
781 }
782}
783impl Iterator for Perpetual {
784 type Item = Action;
785 fn next(&mut self) -> Option<Self::Item> {
786 loop {
787 let actions = self.0.legal();
788 if !actions.is_empty() {
789 let action = actions[rand::random_range(0..actions.len())];
790 self.0 = self.0.apply(action);
791 return Some(action);
792 }
793 self.0 = self.0.clone().continuation().unwrap_or_else(Game::root);
794 }
795 }
796}
797
798pub struct Hands(Game);
803impl Hands {
804 pub fn new(game: Game) -> Self {
805 Self(game)
806 }
807}
808impl Iterator for Hands {
809 type Item = Game;
810 fn next(&mut self) -> Option<Self::Item> {
811 while !self.0.must_stop() {
812 let actions = self.0.legal();
813 let action = actions[rand::random_range(0..actions.len())];
814 self.0 = self.0.apply(action);
815 }
816 let terminal = self.0.clone();
817 self.0 = self.0.clone().continuation()?;
818 Some(terminal)
819 }
820}
821
822pub struct Session(Game);
827impl Session {
828 pub fn new(game: Game) -> Self {
829 Self(game)
830 }
831}
832impl Iterator for Session {
833 type Item = Action;
834 fn next(&mut self) -> Option<Self::Item> {
835 loop {
836 let actions = self.0.legal();
837 if !actions.is_empty() {
838 let action = actions[rand::random_range(0..actions.len())];
839 self.0 = self.0.apply(action);
840 return Some(action);
841 }
842 self.0 = self.0.clone().continuation()?;
843 }
844 }
845}
846
847impl Game {
848 pub fn perpetual(self) -> Perpetual {
850 Perpetual::new(self)
851 }
852 pub fn hands(self) -> Hands {
854 Hands::new(self)
855 }
856 pub fn session(self) -> Session {
858 Session::new(self)
859 }
860}
861
862#[cfg(test)]
863mod tests {
864 use super::*;
865
866 #[test]
868 fn test_root() {
869 let game = Game::root();
870 assert_eq!(game.board().street(), Street::Pref);
871 assert_eq!(game.actor().state(), State::Betting);
872 assert_eq!(game.pot(), Game::sblind() + Game::bblind());
873 assert_eq!(game.turn(), Turn::Choice(game.dealer)); }
875
876 #[test]
877 fn everyone_folds_pref() {
878 let game = Game::root();
879 let game = game.apply(Action::Fold);
880 assert!(game.is_everyone_folding() == true);
881 assert!(game.is_everyone_alright() == true);
882 assert!(game.is_everyone_calling() == false);
883 assert!(game.must_deal() == true); assert!(game.must_stop() == true);
885 }
886
887 #[test]
888 fn everyone_folds_flop() {
889 let game = Game::root();
890 let flop = game.deck().deal(Street::Pref);
891 let game = game.apply(Action::Call(1));
892 let game = game.apply(Action::Check);
893 let game = game.apply(Action::Draw(flop));
894 let game = game.apply(Action::Raise(10));
895 let game = game.apply(Action::Fold);
896 assert!(game.is_everyone_folding() == true);
897 assert!(game.is_everyone_alright() == true);
898 assert!(game.is_everyone_calling() == false);
899 assert!(game.must_deal() == true); assert!(game.must_stop() == true);
901 }
902
903 #[test]
904 fn history_of_checks() {
905 let game = Game::root();
907 assert!(game.board().street() == Street::Pref);
908 assert!(game.pot() == 3);
909 assert!(game.must_post() == false);
910 assert!(game.must_stop() == false);
911 assert!(game.must_deal() == false);
912 assert!(game.is_everyone_alright() == false);
913 assert!(game.is_everyone_calling() == false);
914 assert!(game.is_everyone_touched() == false);
915 assert!(game.is_everyone_matched() == false);
916
917 let game = game.apply(Action::Call(1));
919 assert!(game.board().street() == Street::Pref);
920 assert!(game.pot() == 4); assert!(game.must_post() == false);
922 assert!(game.must_stop() == false);
923 assert!(game.must_deal() == false);
924 assert!(game.is_everyone_alright() == false);
925 assert!(game.is_everyone_calling() == false);
926 assert!(game.is_everyone_touched() == false);
927 assert!(game.is_everyone_matched() == true); let game = game.apply(Action::Check);
931 assert!(game.board().street() == Street::Pref);
932 assert!(game.pot() == 4);
933 assert!(game.must_post() == false);
934 assert!(game.must_stop() == false);
935 assert!(game.must_deal() == true); assert!(game.is_everyone_alright() == true); assert!(game.is_everyone_calling() == true); assert!(game.is_everyone_touched() == true); assert!(game.is_everyone_matched() == true);
940
941 let flop = game.deck().deal(game.board().street());
943 let game = game.apply(Action::Draw(flop));
944 assert!(game.board().street() == Street::Flop); assert!(game.pot() == 4);
946 assert!(game.must_post() == false);
947 assert!(game.must_stop() == false);
948 assert!(game.must_deal() == false); assert!(game.is_everyone_alright() == false); assert!(game.is_everyone_calling() == false); assert!(game.is_everyone_touched() == false); assert!(game.is_everyone_matched() == true);
953
954 let game = game.apply(Action::Check);
956 assert!(game.board().street() == Street::Flop);
957 assert!(game.pot() == 4);
958 assert!(game.must_post() == false);
959 assert!(game.must_stop() == false);
960 assert!(game.must_deal() == false);
961 assert!(game.is_everyone_alright() == false);
962 assert!(game.is_everyone_calling() == false);
963 assert!(game.is_everyone_touched() == false);
964 assert!(game.is_everyone_matched() == true);
965
966 let game = game.apply(Action::Check);
968 assert!(game.board().street() == Street::Flop);
969 assert!(game.pot() == 4);
970 assert!(game.must_post() == false);
971 assert!(game.must_stop() == false);
972 assert!(game.must_deal() == true); assert!(game.is_everyone_alright() == true); assert!(game.is_everyone_calling() == true); assert!(game.is_everyone_touched() == true); assert!(game.is_everyone_matched() == true);
977
978 let turn = game.deck().deal(game.board().street());
980 let game = game.apply(Action::Draw(turn));
981 assert!(game.board().street() == Street::Turn);
982 assert!(game.pot() == 4);
983 assert!(game.must_post() == false);
984 assert!(game.must_stop() == false);
985 assert!(game.must_deal() == false); assert!(game.is_everyone_alright() == false); assert!(game.is_everyone_calling() == false); assert!(game.is_everyone_touched() == false); assert!(game.is_everyone_matched() == true);
990
991 let game = game.apply(Action::Check);
993 assert!(game.board().street() == Street::Turn);
994 assert!(game.pot() == 4);
995 assert!(game.must_post() == false);
996 assert!(game.must_stop() == false);
997 assert!(game.must_deal() == false);
998 assert!(game.is_everyone_alright() == false);
999 assert!(game.is_everyone_calling() == false);
1000 assert!(game.is_everyone_touched() == false);
1001 assert!(game.is_everyone_matched() == true);
1002
1003 let game = game.apply(Action::Raise(4));
1005 assert!(game.board().street() == Street::Turn);
1006 assert!(game.pot() == 8);
1007 assert!(game.must_post() == false);
1008 assert!(game.must_stop() == false);
1009 assert!(game.must_deal() == false);
1010 assert!(game.is_everyone_alright() == false);
1011 assert!(game.is_everyone_calling() == false);
1012 assert!(game.is_everyone_touched() == true); assert!(game.is_everyone_matched() == false); let game = game.apply(Action::Call(4));
1017 assert!(game.board().street() == Street::Turn);
1018 assert!(game.pot() == 12); assert!(game.must_post() == false);
1020 assert!(game.must_stop() == false);
1021 assert!(game.must_deal() == true); assert!(game.is_everyone_alright() == true); assert!(game.is_everyone_calling() == true); assert!(game.is_everyone_touched() == true);
1025 assert!(game.is_everyone_matched() == true);
1026
1027 let rive = game.deck().deal(game.board().street());
1029 let game = game.apply(Action::Draw(rive));
1030 assert!(game.board().street() == Street::Rive); assert!(game.pot() == 12);
1032 assert!(game.must_post() == false);
1033 assert!(game.must_stop() == false);
1034 assert!(game.must_deal() == false); assert!(game.is_everyone_alright() == false); assert!(game.is_everyone_calling() == false); assert!(game.is_everyone_touched() == false); assert!(game.is_everyone_matched() == true); let game = game.apply(Action::Check);
1042 assert!(game.board().street() == Street::Rive);
1043 assert!(game.pot() == 12);
1044 assert!(game.must_post() == false);
1045 assert!(game.must_stop() == false);
1046 assert!(game.must_deal() == false);
1047 assert!(game.is_everyone_alright() == false);
1048 assert!(game.is_everyone_calling() == false);
1049 assert!(game.is_everyone_touched() == false);
1050 assert!(game.is_everyone_matched() == true);
1051
1052 let game = game.apply(Action::Check);
1054 assert!(game.board().street() == Street::Rive);
1055 assert!(game.pot() == 12);
1056 assert!(game.must_post() == false);
1057 assert!(game.must_stop() == true); assert!(game.must_deal() == false);
1059 assert!(game.is_everyone_alright() == true); assert!(game.is_everyone_calling() == true); assert!(game.is_everyone_touched() == true); assert!(game.is_everyone_matched() == true); }
1064
1065 #[test]
1067 fn next_after_fold() {
1068 let game = Game::root().apply(Action::Fold);
1069 assert!(game.must_stop());
1070 let next = game.continuation().expect("can continue");
1071 assert_eq!(next.street(), Street::Pref);
1072 assert_eq!(next.pot(), Game::sblind() + Game::bblind());
1073 assert_eq!(next.board(), Board::empty());
1074 assert_eq!(next.dealer, 1); assert_eq!(next.turn(), Turn::Choice(1)); assert!(!next.is_everyone_touched());
1077 }
1078
1079 #[test]
1081 fn dealer_rotation() {
1082 let game = Game::root();
1083 assert_eq!(game.dealer, 0);
1084 let game = game.apply(Action::Fold).continuation().unwrap();
1085 assert_eq!(game.dealer, 1);
1086 let game = game.apply(Action::Fold).continuation().unwrap();
1087 assert_eq!(game.dealer, 0); let game = game.apply(Action::Fold).continuation().unwrap();
1089 assert_eq!(game.dealer, 1);
1090 }
1091
1092 #[test]
1094 fn ticker_reset_on_next() {
1095 let g0 = Game::root();
1096 let g1 = g0.apply(Action::Fold).continuation().unwrap();
1097 let g2 = g1.apply(Action::Fold).continuation().unwrap();
1098 assert_eq!(g0.ticker, g1.ticker);
1100 assert_eq!(g1.ticker, g2.ticker);
1101 assert_eq!(g0.ticker, 2); }
1103
1104 #[test]
1106 fn touched_with_rotated_dealer() {
1107 let game = Game::root().apply(Action::Fold).continuation().unwrap();
1108 assert_eq!(game.dealer, 1);
1109 assert!(!game.is_everyone_touched()); let game = game.apply(Action::Call(1));
1111 assert!(!game.is_everyone_touched()); let game = game.apply(Action::Check);
1113 assert!(game.is_everyone_touched()); assert!(game.must_deal());
1115 }
1116
1117 #[test]
1119 fn full_hand_rotated_dealer() {
1120 let game = Game::root().apply(Action::Fold).continuation().unwrap();
1121 assert_eq!(game.dealer, 1);
1122 let game = game.apply(Action::Call(1)).apply(Action::Check);
1124 assert!(game.must_deal());
1125 let flop = game.deck().deal(Street::Pref);
1127 let game = game.apply(Action::Draw(flop));
1128 assert_eq!(game.street(), Street::Flop);
1129 assert_eq!(game.turn(), Turn::Choice(0)); assert!(!game.is_everyone_touched());
1131 let game = game.apply(Action::Check).apply(Action::Check);
1133 assert!(game.is_everyone_touched());
1134 assert!(game.must_deal());
1135 }
1136
1137 #[test]
1139 fn five_hands_sequence() {
1140 let mut game = Game::root();
1141 for i in 0..5 {
1142 assert_eq!(game.dealer, i % 2);
1143 assert_eq!(game.pot(), Game::sblind() + Game::bblind());
1144 assert_eq!(game.street(), Street::Pref);
1145 assert!(!game.is_everyone_touched());
1146 assert_eq!(game.turn(), Turn::Choice(game.dealer));
1147 game = game.apply(Action::Fold).continuation().unwrap();
1148 }
1149 }
1150
1151 #[test]
1153 fn symmetric_preflop_action() {
1154 let g0 = Game::root();
1156 assert_eq!(g0.dealer, 0);
1157 let g0 = g0.apply(Action::Call(1));
1158 assert!(!g0.is_everyone_touched());
1159 let g0 = g0.apply(Action::Check);
1160 assert!(g0.is_everyone_touched());
1161 assert!(g0.must_deal());
1162 let g1 = Game::root().apply(Action::Fold).continuation().unwrap();
1164 assert_eq!(g1.dealer, 1);
1165 let g1 = g1.apply(Action::Call(1));
1166 assert!(!g1.is_everyone_touched());
1167 let g1 = g1.apply(Action::Check);
1168 assert!(g1.is_everyone_touched());
1169 assert!(g1.must_deal());
1170 }
1171
1172 #[test]
1174 fn flop_actor_both_dealers() {
1175 let g0 = Game::root().apply(Action::Call(1)).apply(Action::Check);
1177 let flop = g0.deck().deal(Street::Pref);
1178 let g0 = g0.apply(Action::Draw(flop));
1179 assert_eq!(g0.turn(), Turn::Choice(1)); let g1 = Game::root()
1182 .apply(Action::Fold)
1183 .continuation()
1184 .unwrap()
1185 .apply(Action::Call(1))
1186 .apply(Action::Check);
1187 let flop = g1.deck().deal(Street::Pref);
1188 let g1 = g1.apply(Action::Draw(flop));
1189 assert_eq!(g1.turn(), Turn::Choice(0)); }
1191
1192 #[test]
1194 fn allin_showdown() {
1195 let game = Game::root();
1196 let shove = game.to_shove(); let game = game.apply(Action::Shove(shove));
1198 let shove = game.to_shove();
1200 let game = game.apply(Action::Shove(shove));
1201 assert!(game.is_everyone_shoving());
1202 assert!(game.must_stop() || game.must_deal());
1203 }
1204
1205 #[test]
1207 fn allin_fold() {
1208 let game = Game::root();
1209 let shove = game.to_shove();
1210 let game = game.apply(Action::Shove(shove)).apply(Action::Fold);
1211 assert!(game.must_stop());
1212 assert!(game.is_everyone_folding());
1213 }
1214
1215 #[test]
1217 fn raise_reraise() {
1218 let g0 = Game::root();
1219 let r1 = g0.to_raise();
1220 let g1 = g0.apply(Action::Raise(r1));
1221 let r2 = g1.to_raise();
1222 let g2 = g1.apply(Action::Raise(r2));
1223 assert!(!g2.must_deal()); assert!(!g2.is_everyone_alright()); assert_eq!(g2.turn(), Turn::Choice(0)); assert!(g2.may_raise() || g2.may_call()); }
1228
1229 #[test]
1231 fn stacks_after_fold() {
1232 let game = Game::root().apply(Action::Fold);
1233 assert!(game.must_stop());
1234 let settlements = game.settlements();
1236 assert_eq!(settlements[0].pnl().reward(), 0); assert_eq!(settlements[1].pnl().reward(), 3); assert_eq!(settlements[0].won(), -1); assert_eq!(settlements[1].won(), 1); }
1242
1243 #[test]
1245 fn stacks_after_flop_bet_fold() {
1246 let game = Game::root().apply(Action::Call(1)).apply(Action::Check);
1247 let flop = game.deck().deal(Street::Pref);
1248 let game = game.apply(Action::Draw(flop));
1249 let raise = game.to_raise();
1251 let game = game.apply(Action::Raise(raise));
1252 let game = game.apply(Action::Fold);
1254 assert!(game.must_stop());
1255 let settlements = game.settlements();
1256 assert_eq!(settlements[0].pnl().reward(), 0); assert!(settlements[1].pnl().reward() > 0); assert_eq!(settlements[0].won(), -2); }
1261
1262 #[test]
1264 fn multi_hand_with_betting() {
1265 let g0 = Game::root();
1266 let g0 = g0.apply(Action::Call(1)).apply(Action::Check);
1268 let flop = g0.deck().deal(Street::Pref);
1269 let g0 = g0.apply(Action::Draw(flop));
1270 let raise = g0.to_raise();
1271 let g0 = g0.apply(Action::Raise(raise)).apply(Action::Fold);
1272 let g1 = g0.continuation().unwrap();
1273 assert_eq!(g1.dealer, 1);
1274 let r1 = g1.to_raise();
1276 let g1 = g1.apply(Action::Raise(r1));
1277 let c1 = g1.to_call();
1278 let g1 = g1.apply(Action::Call(c1));
1279 let flop = g1.deck().deal(Street::Pref);
1280 let g1 = g1.apply(Action::Draw(flop));
1281 let raise = g1.to_raise();
1282 let g1 = g1.apply(Action::Raise(raise)).apply(Action::Fold);
1283 let g2 = g1.continuation().unwrap();
1284 assert_eq!(g2.dealer, 0);
1285 assert_eq!(g2.pot(), 3);
1286 }
1287
1288 #[test]
1290 fn legal_preflop_options() {
1291 let game = Game::root();
1292 let legal = game.legal();
1293 assert!(legal.contains(&Action::Fold));
1294 assert!(legal.contains(&Action::Call(1)));
1295 assert!(legal.iter().any(|a| matches!(a, Action::Raise(_))));
1296 assert!(legal.iter().any(|a| matches!(a, Action::Shove(_))));
1297 assert!(!legal.contains(&Action::Check)); }
1299
1300 #[test]
1302 fn legal_bb_can_check() {
1303 let game = Game::root().apply(Action::Call(1));
1304 let legal = game.legal();
1305 assert!(legal.contains(&Action::Check));
1306 assert!(!legal.contains(&Action::Fold)); }
1308
1309 #[test]
1311 fn legal_flop_options() {
1312 let game = Game::root().apply(Action::Call(1)).apply(Action::Check);
1313 let flop = game.deck().deal(Street::Pref);
1314 let game = game.apply(Action::Draw(flop));
1315 let legal = game.legal();
1316 assert!(legal.contains(&Action::Check));
1317 assert!(legal.iter().any(|a| matches!(a, Action::Raise(_))));
1318 assert!(!legal.contains(&Action::Fold)); }
1320
1321 #[test]
1323 fn terminal_river_showdown() {
1324 let mut game = Game::root().apply(Action::Call(1)).apply(Action::Check);
1325 for street in [Street::Pref, Street::Flop, Street::Turn] {
1326 let cards = game.deck().deal(street);
1327 game = game
1328 .apply(Action::Draw(cards))
1329 .apply(Action::Check)
1330 .apply(Action::Check);
1331 }
1332 assert_eq!(game.street(), Street::Rive);
1333 assert!(game.must_stop());
1334 assert!(!game.must_deal());
1335 }
1336
1337 #[test]
1339 fn ten_hands_alternation() {
1340 let mut game = Game::root();
1341 for i in 0..10 {
1342 assert_eq!(game.dealer, i % 2);
1343 assert_eq!(game.turn(), Turn::Choice(game.dealer));
1344 game = game.apply(Action::Fold).continuation().unwrap();
1345 }
1346 }
1347
1348 #[test]
1350 fn min_raise_size() {
1351 let game = Game::root();
1352 assert_eq!(game.to_raise(), 3);
1354 let game = game.apply(Action::Raise(3));
1355 assert_eq!(game.to_raise(), 4);
1357 }
1358
1359 #[test]
1361 fn pot_tracking() {
1362 let game = Game::root();
1363 assert_eq!(game.pot(), 3);
1364 let game = game.apply(Action::Call(1));
1365 assert_eq!(game.pot(), 4);
1366 let game = game.apply(Action::Raise(4));
1367 assert_eq!(game.pot(), 8);
1368 let game = game.apply(Action::Call(4));
1369 assert_eq!(game.pot(), 12);
1370 }
1371
1372 #[test]
1374 fn bust_prevents_next() {
1375 let game = Game::root();
1377 let shove = game.to_shove();
1378 let game = game.apply(Action::Shove(shove));
1379 let shove = game.to_shove();
1381 let game = game.apply(Action::Shove(shove));
1382 let mut game = game;
1384 while !game.must_stop() {
1385 if game.must_deal() {
1386 let cards = game.deck().deal(game.street());
1387 game = game.apply(Action::Draw(cards));
1388 }
1389 }
1390 let rewards: Vec<_> = game
1392 .settlements()
1393 .iter()
1394 .map(|s| s.pnl().reward())
1395 .collect();
1396 assert!(rewards.contains(&0) && rewards.contains(&200));
1397 }
1398
1399 #[test]
1401 fn actor_idx_wrapping() {
1402 let game = Game::root();
1403 assert_eq!(game.actor_idx(), 0); let game = game.apply(Action::Call(1));
1405 assert_eq!(game.actor_idx(), 1); let game = game.apply(Action::Check);
1407 assert_eq!((game.dealer + game.ticker) % game.n(), 0); }
1410
1411 #[test]
1414 fn snap_legal_unchanged() {
1415 let game = Game::root();
1416 game.legal()
1417 .iter()
1418 .inspect(|&&action| assert_eq!(game.snap(action), action))
1419 .count();
1420 }
1421
1422 #[test]
1424 fn snap_raise_to_shove_too_large() {
1425 let game = Game::root();
1426 let shove = game.to_shove();
1427 assert_eq!(game.snap(Action::Raise(Chips::MAX)), game.shove());
1428 assert_eq!(game.snap(Action::Raise(shove)), game.shove());
1429 }
1430
1431 #[test]
1433 fn snap_raise_to_minim_too_small() {
1434 let game = Game::root();
1435 let minraise = game.to_raise();
1436 assert_eq!(game.snap(Action::Raise(1)), Action::Raise(minraise));
1437 assert_eq!(game.snap(Action::Raise(0)), Action::Raise(minraise));
1438 }
1439
1440 #[test]
1442 fn snap_fold_to_check_not_facing_bet() {
1443 let game = Game::root().apply(Action::Call(1));
1444 assert!(!game.may_fold());
1445 assert!(game.may_check());
1446 assert_eq!(game.snap(Action::Fold), Action::Check);
1447 }
1448
1449 #[test]
1451 fn snap_check_to_call_facing_bet() {
1452 let game = Game::root();
1453 assert!(!game.may_check());
1454 assert!(game.may_call());
1455 assert_eq!(game.snap(Action::Check), game.calls());
1456 }
1457}