diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/GAMES.md | 65 | ||||
| -rw-r--r-- | docs/TESTING.md | 18 |
2 files changed, 80 insertions, 3 deletions
diff --git a/docs/GAMES.md b/docs/GAMES.md index ae15d50..844d1b0 100644 --- a/docs/GAMES.md +++ b/docs/GAMES.md | |||
| @@ -7,15 +7,52 @@ | |||
| 7 | | Slots | Done | 5 reels x 3 rows, 5 paylines, 98.6% RTP | | 7 | | Slots | Done | 5 reels x 3 rows, 5 paylines, 98.6% RTP | |
| 8 | | Roulette | Done | European wheel, split bets, 97.3% RTP | | 8 | | Roulette | Done | European wheel, split bets, 97.3% RTP | |
| 9 | | Blackjack | Done | Six-deck shoe per hand, S17, 3:2, hit/stand/double | | 9 | | Blackjack | Done | Six-deck shoe per hand, S17, 3:2, hit/stand/double | |
| 10 | | Crash | Done | Local multiplier, server-owned clock and crash event, 99% RTP | | ||
| 10 | 11 | ||
| 11 | ## Planned | 12 | ## Planned |
| 12 | 13 | ||
| 13 | | Game | Shape | Main open decisions | | 14 | | Game | Shape | Main open decisions | |
| 14 | | --- | --- | --- | | 15 | | --- | --- | --- | |
| 15 | | Crash | Real-time round | Crash-point distribution; cashout latency; provable fairness | | 16 | | — | — | Provable fairness for the crash point (`hash` commit/reveal) | |
| 17 | |||
| 18 | Crash rounds are private to one player and use the same request/response socket | ||
| 19 | plus one server-initiated line. A shared multiplayer round would need a lobby | ||
| 20 | and broadcast, which is a different product. | ||
| 21 | |||
| 22 | ## Crash | ||
| 23 | |||
| 24 | - The multiplier is `exp(0.1386294 * t)`: 1.00x at the start, 2.00x at 5s, | ||
| 25 | 10x at ~16.6s, capped at 1000x. | ||
| 26 | - The crash point is drawn when the round starts: | ||
| 27 | `max(1.0, (1 - 0.01) / (1 - u))` for a uniform `u`. That gives | ||
| 28 | `P(crash >= m) = 0.99 / m`, so a fixed-target cashout returns 99% of the | ||
| 29 | stake. The cap trims the RTP by a hair. | ||
| 30 | - The crash point is **not** sent to the client until the round ends. Knowing it | ||
| 31 | early would let a patched client cash out at `crash - epsilon` every round. | ||
| 32 | - The client draws the multiplier from its own monotonic clock, anchored when | ||
| 33 | `CRASH_START` arrives. That number is display only. | ||
| 34 | - The server computes the cashout multiplier from its own clock when the | ||
| 35 | request arrives. The client never sends a multiplier. A cashout that arrives | ||
| 36 | after the crash time loses the bet. | ||
| 37 | - Because `P(crash = 1.00x) = 1%`, an instant cashout returns the stake 99% of | ||
| 38 | the time and nothing 1% of the time. There is no risk-free window, which is | ||
| 39 | why there is no cashout lockout. | ||
| 40 | - Payouts are `floor(bet * multiplier)` in whole PLN, so anything under 1.10x | ||
| 41 | on a 10 PLN bet returns 10. | ||
| 42 | - When the crash time passes, the server pushes `CRASH_BUSTED` on the same | ||
| 43 | connection without being asked. The client's event loop polls for keys and | ||
| 44 | drains the socket every 25ms. | ||
| 45 | - Leaving with Q or disconnecting during a round forfeits the reserved bet and | ||
| 46 | writes a `result = forfeit` audit row. | ||
| 16 | 47 | ||
| 17 | Crash needs a timed round loop and a cashout action, so it should be its own | 48 | Client controls: |
| 18 | protocol/loop change. | 49 | |
| 50 | ``` | ||
| 51 | C cash out at the server's current multiplier | ||
| 52 | SPACE start the next round | ||
| 53 | + or = / - change the next round's bet | ||
| 54 | Q forfeit an active round (bet is lost), or leave when idle | ||
| 55 | ``` | ||
| 19 | 56 | ||
| 20 | ## Blackjack | 57 | ## Blackjack |
| 21 | 58 | ||
| @@ -92,6 +129,9 @@ plays ( | |||
| 92 | 129 | ||
| 93 | // blackjack | 130 | // blackjack |
| 94 | {"player":["10S","6H","5D"],"dealer":["9D","8C"],"player_total":21,"dealer_total":17,"bet":10,"result":"win","winnings":20} | 131 | {"player":["10S","6H","5D"],"dealer":["9D","8C"],"player_total":21,"dealer_total":17,"bet":10,"result":"win","winnings":20} |
| 132 | |||
| 133 | // crash | ||
| 134 | {"bet":10,"crash_point":3.0,"started_at":12.44,"phase":"cashed","result":"cashed","multiplier":2.0,"payout":20} | ||
| 95 | ``` | 135 | ``` |
| 96 | 136 | ||
| 97 | The balance update and the `plays` insert happen in one transaction | 137 | The balance update and the `plays` insert happen in one transaction |
| @@ -124,3 +164,22 @@ BLACKJACK_STATE <json> | |||
| 124 | 164 | ||
| 125 | `BLACKJACK_STATE` carries the player/dealer cards, totals, actions, balance, | 165 | `BLACKJACK_STATE` carries the player/dealer cards, totals, actions, balance, |
| 126 | result and winnings. The dealer's hole card is `?` until the hand is done. | 166 | result and winnings. The dealer's hole card is `?` until the hand is done. |
| 167 | |||
| 168 | Crash sends one line when the round starts, one line when it crashes (without a | ||
| 169 | request), and answers the cashout: | ||
| 170 | |||
| 171 | ``` | ||
| 172 | PLAY_START crash <bet> | ||
| 173 | CRASH_START <json> | ||
| 174 | |||
| 175 | CRASH_CASHOUT <session> | ||
| 176 | CRASH_STATE <json> | ||
| 177 | |||
| 178 | CRASH_BUSTED <json> # pushed when the crash time passes | ||
| 179 | CRASH_FORFEIT <session> | ||
| 180 | CRASH_STATE <json> | ||
| 181 | ``` | ||
| 182 | |||
| 183 | `CRASH_STATE` carries `session_id`, `phase` (`running`, `cashed`, `crashed`, | ||
| 184 | `forfeit`), `bet`, `balance`, the current/final `multiplier`, `potential`, | ||
| 185 | `crash_point` (null while running), `payout` and `result`. | ||
diff --git a/docs/TESTING.md b/docs/TESTING.md index ec5c681..3c7fa61 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md | |||
| @@ -14,6 +14,7 @@ shared global database. Each test owns its state. | |||
| 14 | | `tests/client_core.rs` | Client command/game flows via a headless screen applying logical effects. | | 14 | | `tests/client_core.rs` | Client command/game flows via a headless screen applying logical effects. | |
| 15 | | `tests/client_ui.rs` | Help, history, completion, bet parsing, display width, cursor math. | | 15 | | `tests/client_ui.rs` | Help, history, completion, bet parsing, display width, cursor math. | |
| 16 | | `tests/blackjack.rs` | Card totals, naturals, hit/stand/double, dealer bust, S17, state parsing. | | 16 | | `tests/blackjack.rs` | Card totals, naturals, hit/stand/double, dealer bust, S17, state parsing. | |
| 17 | | `tests/crash.rs` | Multiplier curve, payout floor, crash-point distribution, house edge, cap. | | ||
| 17 | | `tests/protocol.rs` | Newline buffering and timeout/error classification. | | 18 | | `tests/protocol.rs` | Newline buffering and timeout/error classification. | |
| 18 | | `tests/roulette.rs` | European wheel, split-bet payouts, zero handling, result parser. | | 19 | | `tests/roulette.rs` | European wheel, split-bet payouts, zero handling, result parser. | |
| 19 | | `tests/server_core.rs` | Handler, bcrypt migration, SQL injection, transaction rollback, `plays` audit, sessions. | | 20 | | `tests/server_core.rs` | Handler, bcrypt migration, SQL injection, transaction rollback, `plays` audit, sessions. | |
| @@ -93,6 +94,23 @@ Use an 80-column terminal because several output lines are width-sensitive. | |||
| 93 | double), winnings, and the final cards/result in `details`. A forfeit has | 94 | double), winnings, and the final cards/result in `details`. A forfeit has |
| 94 | `result = forfeit`, `winnings = 0`. | 95 | `result = forfeit`, `winnings = 0`. |
| 95 | 96 | ||
| 97 | ## Manual crash checklist | ||
| 98 | |||
| 99 | 1. `play crash` shows the ready board with a 1.00x multiplier; Space starts and | ||
| 100 | reserves the bet. | ||
| 101 | 2. The multiplier rises smoothly with no network traffic. Cash out with C and | ||
| 102 | confirm the board shows the cashout multiplier, the payout and the new | ||
| 103 | balance. | ||
| 104 | 3. On another round, press nothing. The board must switch to `CRASHED at Xx` | ||
| 105 | by itself when the crash point is reached, and the bet must be lost. | ||
| 106 | 4. Press C just as a round crashes. Either it pays or the crashed result wins; | ||
| 107 | a late cashout must never show an error over a finished round. | ||
| 108 | 5. Q during a live round forfeits the bet; Q when idle just leaves. | ||
| 109 | 6. Check the audit rows: one per round, `game_type = crash`, the reserved bet, | ||
| 110 | the payout, and `crash_point`/`multiplier`/`result` in `details`. | ||
| 111 | 7. Confirm the crash point is absent from the `CRASH_START` line (it must only | ||
| 112 | appear once the round is over). | ||
| 113 | |||
| 96 | ## Manual server checks | 114 | ## Manual server checks |
| 97 | 115 | ||
| 98 | - Register, log out, log in again (bcrypt path). | 116 | - Register, log out, log in again (bcrypt path). |
