diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-29 20:43:09 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-29 20:43:09 +0100 |
| commit | 6e2787d792de64c003eff03b62a2df798ef851c0 (patch) | |
| tree | 0e9bf97b2f71df5fb9eb00d5195d32b8326886ff /docs/GAMES.md | |
| parent | v2.2.1: forfeit blackjack bets when leaving or disconnecting (diff) | |
| download | zagan-bet-6e2787d792de64c003eff03b62a2df798ef851c0.tar.gz zagan-bet-6e2787d792de64c003eff03b62a2df798ef851c0.zip | |
v2.3.0: add crash with local multiplier and pushed crash event
Diffstat (limited to '')
| -rw-r--r-- | docs/GAMES.md | 65 |
1 files changed, 62 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`. | ||
