summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-29 20:43:09 +0100
committersalmonik <salmonik@tuta.io>2026-10-29 20:43:09 +0100
commit6e2787d792de64c003eff03b62a2df798ef851c0 (patch)
tree0e9bf97b2f71df5fb9eb00d5195d32b8326886ff /docs
parentv2.2.1: forfeit blackjack bets when leaving or disconnecting (diff)
downloadzagan-bet-6e2787d792de64c003eff03b62a2df798ef851c0.tar.gz
zagan-bet-6e2787d792de64c003eff03b62a2df798ef851c0.zip
v2.3.0: add crash with local multiplier and pushed crash event
Diffstat (limited to 'docs')
-rw-r--r--docs/GAMES.md65
-rw-r--r--docs/TESTING.md18
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
18Crash rounds are private to one player and use the same request/response socket
19plus one server-initiated line. A shared multiplayer round would need a lobby
20and 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
17Crash needs a timed round loop and a cashout action, so it should be its own 48Client controls:
18protocol/loop change. 49
50```
51C cash out at the server's current multiplier
52SPACE start the next round
53+ or = / - change the next round's bet
54Q 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
97The balance update and the `plays` insert happen in one transaction 137The 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,
126result and winnings. The dealer's hole card is `?` until the hand is done. 166result and winnings. The dealer's hole card is `?` until the hand is done.
167
168Crash sends one line when the round starts, one line when it crashes (without a
169request), and answers the cashout:
170
171```
172PLAY_START crash <bet>
173CRASH_START <json>
174
175CRASH_CASHOUT <session>
176CRASH_STATE <json>
177
178CRASH_BUSTED <json> # pushed when the crash time passes
179CRASH_FORFEIT <session>
180CRASH_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
991. `play crash` shows the ready board with a 1.00x multiplier; Space starts and
100 reserves the bet.
1012. 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.
1043. 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.
1064. 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.
1085. Q during a live round forfeits the bet; Q when idle just leaves.
1096. Check the audit rows: one per round, `game_type = crash`, the reserved bet,
110 the payout, and `crash_point`/`multiplier`/`result` in `details`.
1117. 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).