# Games and the play audit ## Implemented | Game | Status | Notes | | --- | --- | --- | | Slots | Done | 5 reels x 3 rows, 5 paylines, 98.6% RTP | | Roulette | Done | European wheel, split bets, 97.3% RTP | | Blackjack | Done | Six-deck shoe per hand, S17, 3:2, hit/stand/double | ## Planned | Game | Shape | Main open decisions | | --- | --- | --- | | Crash | Real-time round | Crash-point distribution; cashout latency; provable fairness | Crash needs a timed round loop and a cashout action, so it should be its own protocol/loop change. ## Blackjack - Six-deck shoe, shuffled fresh for every hand and discarded afterwards. - Dealer stands on all 17s (including soft 17). - Blackjack pays 3:2, rounded down to whole PLN. - Hit, stand, and double; no split, insurance, or surrender. - The bet is reserved when the hand starts. Leaving an active hand with Q, or disconnecting mid-hand, forfeits the reserved bet; it is not refunded. A settled hand is unaffected. - A natural or dealer blackjack settles immediately. Client controls: ``` H hit S stand D double (on the first two cards) SPACE deal the next hand + or = / - change the next hand's bet Q forfeit an active hand (bet is lost), or leave when no hand is active ``` ## Roulette - European wheel: 0-36, one green zero. - Bets: red, black, even, odd, and straight numbers. - Bets can be split across all of those; every winning bet is added together. - Straight pays 35:1 (36x returned), outside bets pay 1:1 (2x returned). - 0 loses all outside bets. RTP is 36/37 = 97.30%. - Numbers are color-coded in the TUI: red numbers are red, 0 is green, and black numbers stay at the default terminal color. Bet amounts and balances are not colored. Client controls inside roulette: ``` R / B / E / O add the current chip to red/black/even/odd digits + Enter add the current chip to that number C clear all bets + or = / - change the chip size SPACE spin Q leave the table ``` The result is shown as a CS:GO-style horizontal strip: the ball marker stays fixed and the wheel numbers scroll beneath it, ending on the winning number. ## Audit schema Every settled play is one row in `plays`: ``` plays ( session_id TEXT PRIMARY KEY, username TEXT NOT NULL, game_type TEXT NOT NULL, bet_amount INTEGER NOT NULL, winnings INTEGER NOT NULL, balance_after INTEGER NOT NULL, details TEXT NOT NULL DEFAULT '{}', created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ``` `details` is game-specific JSON: ```json // slots {"reels":"CCCCLLCLODGSDGS","win_type":"win","win_lines":"1","win_cells":"0,3,6"} // roulette {"number":"17","color":"black","bets":"{\"red\":10,\"black\":10,\"even\":10,\"odd\":10,\"numbers\":[{\"number\":17,\"amount\":5}]}"} // blackjack {"player":["10S","6H","5D"],"dealer":["9D","8C"],"player_total":21,"dealer_total":17,"bet":10,"result":"win","winnings":20} ``` The balance update and the `plays` insert happen in one transaction (`database::apply_play`). ## Wire protocol Slots keeps its original exchange: ``` PLAY_START slots GAME_RESULT ``` Roulette adds a compact bets payload and a roulette-specific result: ``` PLAY_START roulette ROULETTE_RESULT ``` Blackjack is a multi-step session: ``` PLAY_START blackjack BLACKJACK_STATE BLACKJACK_ACTION hit|stand|double|cancel BLACKJACK_STATE ``` `BLACKJACK_STATE` carries the player/dealer cards, totals, actions, balance, result and winnings. The dealer's hole card is `?` until the hand is done.