# 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 | ## Planned | Game | Shape | Main open decisions | | --- | --- | --- | | Blackjack | Multi-step hand | Dealer hits/stands soft 17; double/split/insurance; blackjack payout; shoe persistence | | Crash | Real-time round | Crash-point distribution; cashout latency; provable fairness | Blackjack needs server-side hand state and player actions. Crash needs a timed round loop and a cashout action, so it should come after blackjack unless we redesign the loop first. ## 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}]}"} ``` 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 and crash still need a generic state/action exchange, for example: ``` GAME_START GAME_ACTION [json] GAME_STATE # cards, bets, multiplier, legal actions, result ``` That will be its own protocol change.