diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-29 18:43:09 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-29 18:43:09 +0100 |
| commit | 08269639606c0481037cbde7ebaf2e0455460883 (patch) | |
| tree | 57c1f967e8836a1a7da84b1887d932e0067d538f | |
| parent | v2.2.0: add blackjack with reserved bets and hit/stand/double (diff) | |
| download | zagan-bet-08269639606c0481037cbde7ebaf2e0455460883.tar.gz zagan-bet-08269639606c0481037cbde7ebaf2e0455460883.zip | |
v2.2.1: forfeit blackjack bets when leaving or disconnecting
| -rw-r--r-- | AGENTS.md | 3 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | docs/GAMES.md | 6 | ||||
| -rw-r--r-- | docs/TESTING.md | 7 | ||||
| -rw-r--r-- | src/client/core.rs | 18 | ||||
| -rw-r--r-- | src/client/games/blackjack.rs | 9 | ||||
| -rw-r--r-- | src/server/core.rs | 50 | ||||
| -rw-r--r-- | src/server/games/blackjack.rs | 4 | ||||
| -rw-r--r-- | tests/blackjack.rs | 11 | ||||
| -rw-r--r-- | tests/client_core.rs | 19 | ||||
| -rw-r--r-- | tests/server_core.rs | 20 |
11 files changed, 107 insertions, 42 deletions
| @@ -21,7 +21,8 @@ | |||
| 21 | touched. The session is the audit trail for the deduction; without it the | 21 | touched. The session is the audit trail for the deduction; without it the |
| 22 | deduction is orphaned. | 22 | deduction is orphaned. |
| 23 | - Clean up sessions on client disconnect. If a game is in progress when the | 23 | - Clean up sessions on client disconnect. If a game is in progress when the |
| 24 | connection drops, the server must roll back the bet. | 24 | connection drops, settle it as a forfeit (the reserved bet is lost) and |
| 25 | record the play; never refund an active hand. | ||
| 25 | 26 | ||
| 26 | ## Server Handler | 27 | ## Server Handler |
| 27 | - Never hold a lock, drop it, then re-acquire it in the same function to | 28 | - Never hold a lock, drop it, then re-acquire it in the same function to |
| @@ -1,6 +1,6 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "zagan-bet" | 2 | name = "zagan-bet" |
| 3 | version = "2.2.0" | 3 | version = "2.2.1" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | 5 | ||
| 6 | [dependencies] | 6 | [dependencies] |
diff --git a/docs/GAMES.md b/docs/GAMES.md index 4c42369..ae15d50 100644 --- a/docs/GAMES.md +++ b/docs/GAMES.md | |||
| @@ -23,7 +23,9 @@ protocol/loop change. | |||
| 23 | - Dealer stands on all 17s (including soft 17). | 23 | - Dealer stands on all 17s (including soft 17). |
| 24 | - Blackjack pays 3:2, rounded down to whole PLN. | 24 | - Blackjack pays 3:2, rounded down to whole PLN. |
| 25 | - Hit, stand, and double; no split, insurance, or surrender. | 25 | - Hit, stand, and double; no split, insurance, or surrender. |
| 26 | - The bet is reserved when the hand starts. Cancel or disconnect refunds it. | 26 | - The bet is reserved when the hand starts. Leaving an active hand with Q, or |
| 27 | disconnecting mid-hand, forfeits the reserved bet; it is not refunded. A | ||
| 28 | settled hand is unaffected. | ||
| 27 | - A natural or dealer blackjack settles immediately. | 29 | - A natural or dealer blackjack settles immediately. |
| 28 | 30 | ||
| 29 | Client controls: | 31 | Client controls: |
| @@ -34,7 +36,7 @@ S stand | |||
| 34 | D double (on the first two cards) | 36 | D double (on the first two cards) |
| 35 | SPACE deal the next hand | 37 | SPACE deal the next hand |
| 36 | + or = / - change the next hand's bet | 38 | + or = / - change the next hand's bet |
| 37 | Q leave the table (active hand is cancelled and refunded) | 39 | Q forfeit an active hand (bet is lost), or leave when no hand is active |
| 38 | ``` | 40 | ``` |
| 39 | 41 | ||
| 40 | ## Roulette | 42 | ## Roulette |
diff --git a/docs/TESTING.md b/docs/TESTING.md index ed2f746..ec5c681 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md | |||
| @@ -87,10 +87,11 @@ Use an 80-column terminal because several output lines are width-sensitive. | |||
| 87 | D is only offered on the first two cards and reserves the extra bet. | 87 | D is only offered on the first two cards and reserves the extra bet. |
| 88 | 3. Stand and check the dealer stands on all 17s. Check a dealer bust pays the | 88 | 3. Stand and check the dealer stands on all 17s. Check a dealer bust pays the |
| 89 | player, and a natural blackjack pays 3:2. | 89 | player, and a natural blackjack pays 3:2. |
| 90 | 4. Q during a hand sends cancel and refunds the reserved bet; Q after a hand | 90 | 4. Q during a hand forfeits the reserved bet (it is **not** refunded); Q after |
| 91 | just leaves. Disconnecting mid-hand also refunds it. | 91 | a hand just leaves. Disconnecting mid-hand also forfeits it. |
| 92 | 5. Check the audit row: `game_type = blackjack`, the total bet (including a | 92 | 5. Check the audit row: `game_type = blackjack`, the total bet (including a |
| 93 | double), winnings, and the final cards/result in `details`. | 93 | double), winnings, and the final cards/result in `details`. A forfeit has |
| 94 | `result = forfeit`, `winnings = 0`. | ||
| 94 | 95 | ||
| 95 | ## Manual server checks | 96 | ## Manual server checks |
| 96 | 97 | ||
diff --git a/src/client/core.rs b/src/client/core.rs index 6e9c28b..77761b4 100644 --- a/src/client/core.rs +++ b/src/client/core.rs | |||
| @@ -65,7 +65,7 @@ enum Pending { | |||
| 65 | RouletteSpin, | 65 | RouletteSpin, |
| 66 | BlackjackStart, | 66 | BlackjackStart, |
| 67 | BlackjackAction, | 67 | BlackjackAction, |
| 68 | BlackjackCancel, | 68 | BlackjackForfeit, |
| 69 | Ping, | 69 | Ping, |
| 70 | Echo, | 70 | Echo, |
| 71 | Info, | 71 | Info, |
| @@ -209,12 +209,16 @@ impl ClientCore { | |||
| 209 | } | 209 | } |
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | Some(Pending::BlackjackCancel) => match parse_blackjack_response(reply) { | 212 | Some(Pending::BlackjackForfeit) => match parse_blackjack_response(reply) { |
| 213 | Ok(_) => { | 213 | Ok(state) => { |
| 214 | self.game.end_game(); | 214 | self.game.end_game(); |
| 215 | let message = format!( | ||
| 216 | "Game exited. Active hand forfeited ({} PLN lost).", | ||
| 217 | state.bet | ||
| 218 | ); | ||
| 215 | vec![ | 219 | vec![ |
| 216 | Effect::ClearRegion, | 220 | Effect::ClearRegion, |
| 217 | Effect::Print(vec!["Game exited.".to_string()]), | 221 | Effect::Print(vec![message]), |
| 218 | ] | 222 | ] |
| 219 | } | 223 | } |
| 220 | Err(message) => { | 224 | Err(message) => { |
| @@ -457,10 +461,10 @@ impl ClientCore { | |||
| 457 | Key::CtrlC => vec![Effect::Quit], | 461 | Key::CtrlC => vec![Effect::Quit], |
| 458 | Key::Char('q') => { | 462 | Key::Char('q') => { |
| 459 | if let Some(hand) = hand.filter(|hand| hand.phase == "player") { | 463 | if let Some(hand) = hand.filter(|hand| hand.phase == "player") { |
| 460 | self.game.set_blackjack_status("cancelling"); | 464 | self.game.set_blackjack_status("forfeiting"); |
| 461 | self.pending = Some(Pending::BlackjackCancel); | 465 | self.pending = Some(Pending::BlackjackForfeit); |
| 462 | vec![Effect::SendLine(format!( | 466 | vec![Effect::SendLine(format!( |
| 463 | "BLACKJACK_ACTION {} cancel", | 467 | "BLACKJACK_ACTION {} forfeit", |
| 464 | hand.session_id | 468 | hand.session_id |
| 465 | ))] | 469 | ))] |
| 466 | } else { | 470 | } else { |
diff --git a/src/client/games/blackjack.rs b/src/client/games/blackjack.rs index a34eb63..bad1781 100644 --- a/src/client/games/blackjack.rs +++ b/src/client/games/blackjack.rs | |||
| @@ -38,6 +38,7 @@ impl BlackjackGame { | |||
| 38 | "push" => "Push. Bet returned.".to_string(), | 38 | "push" => "Push. Bet returned.".to_string(), |
| 39 | "lose" => "Dealer wins.".to_string(), | 39 | "lose" => "Dealer wins.".to_string(), |
| 40 | "bust" => "Bust.".to_string(), | 40 | "bust" => "Bust.".to_string(), |
| 41 | "forfeit" => "Forfeited. Bet lost.".to_string(), | ||
| 41 | "cancelled" => "Cancelled.".to_string(), | 42 | "cancelled" => "Cancelled.".to_string(), |
| 42 | _ => "Hand complete.".to_string(), | 43 | _ => "Hand complete.".to_string(), |
| 43 | } | 44 | } |
| @@ -85,15 +86,15 @@ impl Game for BlackjackGame { | |||
| 85 | } | 86 | } |
| 86 | } | 87 | } |
| 87 | "dealing" => "Dealing...".to_string(), | 88 | "dealing" => "Dealing...".to_string(), |
| 88 | "cancelling" => "Cancelling...".to_string(), | 89 | "forfeiting" => "Forfeiting...".to_string(), |
| 89 | "done" => Self::result_text(&hand.result, hand.winnings), | 90 | "done" => Self::result_text(&hand.result, hand.winnings), |
| 90 | _ => "Press [SPACE] to deal.".to_string(), | 91 | _ => "Press [SPACE] to deal.".to_string(), |
| 91 | }; | 92 | }; |
| 92 | let controls = if status == "player" { | 93 | let controls = if status == "player" { |
| 93 | if hand.actions.iter().any(|action| action == "double") { | 94 | if hand.actions.iter().any(|action| action == "double") { |
| 94 | "[H]it [S]tand [D]ouble [Q]uit".to_string() | 95 | "[H]it [S]tand [D]ouble [Q] Forfeit".to_string() |
| 95 | } else { | 96 | } else { |
| 96 | "[H]it [S]tand [Q]uit".to_string() | 97 | "[H]it [S]tand [Q] Forfeit".to_string() |
| 97 | } | 98 | } |
| 98 | } else { | 99 | } else { |
| 99 | "[SPACE] New hand [+/-] Bet [Q] Quit".to_string() | 100 | "[SPACE] New hand [+/-] Bet [Q] Quit".to_string() |
| @@ -142,7 +143,7 @@ impl Game for BlackjackGame { | |||
| 142 | D - double (when available)\n\ | 143 | D - double (when available)\n\ |
| 143 | SPACE - deal a new hand\n\ | 144 | SPACE - deal a new hand\n\ |
| 144 | +/- - change the next hand's bet\n\ | 145 | +/- - change the next hand's bet\n\ |
| 145 | Q - leave the table" | 146 | Q - forfeit an active hand (bet is lost), or leave when no hand is active" |
| 146 | .to_string() | 147 | .to_string() |
| 147 | } | 148 | } |
| 148 | } | 149 | } |
diff --git a/src/server/core.rs b/src/server/core.rs index cf8c4b9..259f936 100644 --- a/src/server/core.rs +++ b/src/server/core.rs | |||
| @@ -297,11 +297,27 @@ impl ServerCore { | |||
| 297 | return format!("ERROR {error}"); | 297 | return format!("ERROR {error}"); |
| 298 | } | 298 | } |
| 299 | } | 299 | } |
| 300 | "cancel" => { | 300 | "forfeit" | "cancel" => { |
| 301 | let refund = session.bet_amount as i64; | 301 | hand.forfeit(); |
| 302 | let balance = database::credit(&mut self.conn, user, refund).unwrap_or(balance); | 302 | let state = hand.state(session_id, balance); |
| 303 | let details = serde_json::to_string(&state).unwrap_or_else(|_| "{}".to_string()); | ||
| 304 | let balance = match database::settle_play( | ||
| 305 | &mut self.conn, | ||
| 306 | session_id, | ||
| 307 | user, | ||
| 308 | "blackjack", | ||
| 309 | hand.bet as i64, | ||
| 310 | 0, | ||
| 311 | &details, | ||
| 312 | ) { | ||
| 313 | Ok(balance) => balance, | ||
| 314 | Err(error) => { | ||
| 315 | eprintln!("Blackjack forfeit settlement failed for {user}: {error}"); | ||
| 316 | let _ = self.sessions.remove_session(session_id); | ||
| 317 | return "ERROR Failed to update balance".to_string(); | ||
| 318 | } | ||
| 319 | }; | ||
| 303 | let _ = self.sessions.remove_session(session_id); | 320 | let _ = self.sessions.remove_session(session_id); |
| 304 | hand.cancel(); | ||
| 305 | let state = hand.state(session_id, balance); | 321 | let state = hand.state(session_id, balance); |
| 306 | return blackjack_wire(&state); | 322 | return blackjack_wire(&state); |
| 307 | } | 323 | } |
| @@ -485,7 +501,31 @@ impl ServerCore { | |||
| 485 | if let Some(user) = state.user.as_deref() { | 501 | if let Some(user) = state.user.as_deref() { |
| 486 | for session in self.sessions.get_user_sessions(user) { | 502 | for session in self.sessions.get_user_sessions(user) { |
| 487 | if session.game_type == "blackjack" { | 503 | if session.game_type == "blackjack" { |
| 488 | let _ = database::credit(&mut self.conn, user, session.bet_amount as i64); | 504 | if let Some(raw) = session.state.data.get("hand") { |
| 505 | if let Ok(mut hand) = BlackjackHand::from_json(raw) { | ||
| 506 | if !hand.is_done() { | ||
| 507 | hand.forfeit(); | ||
| 508 | let balance = | ||
| 509 | database::get_balance(&self.conn, user).unwrap_or(0); | ||
| 510 | let final_state = hand.state(&session.session_id, balance); | ||
| 511 | let details = serde_json::to_string(&final_state) | ||
| 512 | .unwrap_or_else(|_| "{}".to_string()); | ||
| 513 | if let Err(error) = database::settle_play( | ||
| 514 | &mut self.conn, | ||
| 515 | &session.session_id, | ||
| 516 | user, | ||
| 517 | "blackjack", | ||
| 518 | hand.bet as i64, | ||
| 519 | 0, | ||
| 520 | &details, | ||
| 521 | ) { | ||
| 522 | eprintln!( | ||
| 523 | "Blackjack disconnect forfeit failed for {user}: {error}" | ||
| 524 | ); | ||
| 525 | } | ||
| 526 | } | ||
| 527 | } | ||
| 528 | } | ||
| 489 | } | 529 | } |
| 490 | let _ = self.sessions.remove_session(&session.session_id); | 530 | let _ = self.sessions.remove_session(&session.session_id); |
| 491 | } | 531 | } |
diff --git a/src/server/games/blackjack.rs b/src/server/games/blackjack.rs index 9505fed..df5a6ac 100644 --- a/src/server/games/blackjack.rs +++ b/src/server/games/blackjack.rs | |||
| @@ -133,9 +133,9 @@ impl BlackjackHand { | |||
| 133 | Ok(()) | 133 | Ok(()) |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | pub fn cancel(&mut self) { | 136 | pub fn forfeit(&mut self) { |
| 137 | self.phase = "done".to_string(); | 137 | self.phase = "done".to_string(); |
| 138 | self.result = "cancelled".to_string(); | 138 | self.result = "forfeit".to_string(); |
| 139 | self.winnings = 0; | 139 | self.winnings = 0; |
| 140 | } | 140 | } |
| 141 | 141 | ||
diff --git a/tests/blackjack.rs b/tests/blackjack.rs index 79721d3..f90ca8d 100644 --- a/tests/blackjack.rs +++ b/tests/blackjack.rs | |||
| @@ -80,6 +80,17 @@ fn doubling_adds_the_base_bet_and_draws_one_card() { | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | #[test] | 82 | #[test] |
| 83 | fn forfeiting_loses_the_bet() { | ||
| 84 | let mut hand = hand(&["10S", "9D", "6H", "8C"], 10); | ||
| 85 | hand.forfeit(); | ||
| 86 | |||
| 87 | assert!(hand.is_done()); | ||
| 88 | assert_eq!(hand.result, "forfeit"); | ||
| 89 | assert_eq!(hand.winnings, 0); | ||
| 90 | assert_eq!(hand.bet, 10); | ||
| 91 | } | ||
| 92 | |||
| 93 | #[test] | ||
| 83 | fn the_dealer_busts_and_the_player_wins() { | 94 | fn the_dealer_busts_and_the_player_wins() { |
| 84 | let mut hand = hand(&["10S", "7H", "8H", "9C", "10H"], 10); | 95 | let mut hand = hand(&["10S", "7H", "8H", "9C", "10H"], 10); |
| 85 | assert_eq!(hand.player_total(), 18); | 96 | assert_eq!(hand.player_total(), 18); |
diff --git a/tests/client_core.rs b/tests/client_core.rs index cfcf608..ec444bd 100644 --- a/tests/client_core.rs +++ b/tests/client_core.rs | |||
| @@ -722,6 +722,7 @@ fn blackjack_deals_hits_and_settles() { | |||
| 722 | assert!(h.board()[3].contains("You: [10♠] [6♥] 16")); | 722 | assert!(h.board()[3].contains("You: [10♠] [6♥] 16")); |
| 723 | assert!(h.board()[4].contains("Hit, stand or double.")); | 723 | assert!(h.board()[4].contains("Hit, stand or double.")); |
| 724 | assert!(h.board()[5].contains("[D]ouble")); | 724 | assert!(h.board()[5].contains("[D]ouble")); |
| 725 | assert!(h.board()[5].contains("[Q] Forfeit")); | ||
| 725 | 726 | ||
| 726 | h.key(Key::Char('h')); | 727 | h.key(Key::Char('h')); |
| 727 | assert_eq!( | 728 | assert_eq!( |
| @@ -757,7 +758,7 @@ fn blackjack_deals_hits_and_settles() { | |||
| 757 | } | 758 | } |
| 758 | 759 | ||
| 759 | #[test] | 760 | #[test] |
| 760 | fn blackjack_cancel_sends_a_cancel_action() { | 761 | fn blackjack_forfeit_is_sent_when_leaving_an_active_hand() { |
| 761 | let mut h = Harness::new(); | 762 | let mut h = Harness::new(); |
| 762 | h.enter_blackjack(); | 763 | h.enter_blackjack(); |
| 763 | h.key(Key::Char(' ')); | 764 | h.key(Key::Char(' ')); |
| @@ -784,10 +785,10 @@ fn blackjack_cancel_sends_a_cancel_action() { | |||
| 784 | h.key(Key::Char('q')); | 785 | h.key(Key::Char('q')); |
| 785 | assert_eq!( | 786 | assert_eq!( |
| 786 | h.sent.last().map(String::as_str), | 787 | h.sent.last().map(String::as_str), |
| 787 | Some("BLACKJACK_ACTION bj1 cancel") | 788 | Some("BLACKJACK_ACTION bj1 forfeit") |
| 788 | ); | 789 | ); |
| 789 | 790 | ||
| 790 | let cancelled = bj_state( | 791 | let forfeited = bj_state( |
| 791 | "bj1", | 792 | "bj1", |
| 792 | "done", | 793 | "done", |
| 793 | &["10S", "6H"], | 794 | &["10S", "6H"], |
| @@ -796,18 +797,22 @@ fn blackjack_cancel_sends_a_cancel_action() { | |||
| 796 | 9, | 797 | 9, |
| 797 | 10, | 798 | 10, |
| 798 | 10, | 799 | 10, |
| 799 | 1000, | 800 | 990, |
| 800 | &[], | 801 | &[], |
| 801 | "cancelled", | 802 | "forfeit", |
| 802 | 0, | 803 | 0, |
| 803 | ); | 804 | ); |
| 804 | h.reply(&format!( | 805 | h.reply(&format!( |
| 805 | "BLACKJACK_STATE {}", | 806 | "BLACKJACK_STATE {}", |
| 806 | serde_json::to_string(&cancelled).unwrap() | 807 | serde_json::to_string(&forfeited).unwrap() |
| 807 | )); | 808 | )); |
| 808 | 809 | ||
| 809 | assert!(h.board().is_empty()); | 810 | assert!(h.board().is_empty()); |
| 810 | assert!(h.screen.lines.iter().any(|line| line == "Game exited.")); | 811 | assert!(h |
| 812 | .screen | ||
| 813 | .lines | ||
| 814 | .iter() | ||
| 815 | .any(|line| line.contains("forfeited (10 PLN lost)"))); | ||
| 811 | } | 816 | } |
| 812 | 817 | ||
| 813 | #[test] | 818 | #[test] |
diff --git a/tests/server_core.rs b/tests/server_core.rs index 3ad277a..08a2bf2 100644 --- a/tests/server_core.rs +++ b/tests/server_core.rs | |||
| @@ -457,7 +457,7 @@ fn blackjack_natural_settles_immediately() { | |||
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | #[test] | 459 | #[test] |
| 460 | fn blackjack_cancel_refunds_the_reserved_bet() { | 460 | fn blackjack_forfeit_keeps_the_reserved_bet() { |
| 461 | let (mut core, _path) = | 461 | let (mut core, _path) = |
| 462 | setup_blackjack("blackjack-cancel", &["10S", "9D", "6H", "8C"]); | 462 | setup_blackjack("blackjack-cancel", &["10S", "9D", "6H", "8C"]); |
| 463 | let mut state = ConnectionState::default(); | 463 | let mut state = ConnectionState::default(); |
| @@ -467,20 +467,20 @@ fn blackjack_cancel_refunds_the_reserved_bet() { | |||
| 467 | let current = blackjack_state(&core.handle_message(&mut state, "PLAY_START blackjack 10")); | 467 | let current = blackjack_state(&core.handle_message(&mut state, "PLAY_START blackjack 10")); |
| 468 | assert_eq!(current.balance, 990); | 468 | assert_eq!(current.balance, 990); |
| 469 | 469 | ||
| 470 | let cancelled = blackjack_state(&core.handle_message( | 470 | let forfeited = blackjack_state(&core.handle_message( |
| 471 | &mut state, | 471 | &mut state, |
| 472 | &format!("BLACKJACK_ACTION {} cancel", current.session_id), | 472 | &format!("BLACKJACK_ACTION {} forfeit", current.session_id), |
| 473 | )); | 473 | )); |
| 474 | 474 | ||
| 475 | assert_eq!(cancelled.result, "cancelled"); | 475 | assert_eq!(forfeited.result, "forfeit"); |
| 476 | assert_eq!(cancelled.balance, 1000); | 476 | assert_eq!(forfeited.balance, 990); |
| 477 | assert_eq!(core.balance("alice"), Some(1000)); | 477 | assert_eq!(core.balance("alice"), Some(990)); |
| 478 | assert_eq!(core.play_count("alice"), 0); | 478 | assert_eq!(core.play_count("alice"), 1); |
| 479 | assert_eq!(core.session_count(), 0); | 479 | assert_eq!(core.session_count(), 0); |
| 480 | } | 480 | } |
| 481 | 481 | ||
| 482 | #[test] | 482 | #[test] |
| 483 | fn blackjack_disconnect_refunds_the_reserved_bet() { | 483 | fn blackjack_disconnect_forfeits_the_reserved_bet() { |
| 484 | let (mut core, _path) = | 484 | let (mut core, _path) = |
| 485 | setup_blackjack("blackjack-disconnect", &["10S", "9D", "6H", "8C"]); | 485 | setup_blackjack("blackjack-disconnect", &["10S", "9D", "6H", "8C"]); |
| 486 | let mut state = ConnectionState::default(); | 486 | let mut state = ConnectionState::default(); |
| @@ -492,7 +492,7 @@ fn blackjack_disconnect_refunds_the_reserved_bet() { | |||
| 492 | 492 | ||
| 493 | core.disconnect(&state); | 493 | core.disconnect(&state); |
| 494 | 494 | ||
| 495 | assert_eq!(core.balance("alice"), Some(1000)); | 495 | assert_eq!(core.balance("alice"), Some(990)); |
| 496 | assert_eq!(core.play_count("alice"), 0); | 496 | assert_eq!(core.play_count("alice"), 1); |
| 497 | assert_eq!(core.session_count(), 0); | 497 | assert_eq!(core.session_count(), 0); |
| 498 | } | 498 | } |
