aboutsummaryrefslogtreecommitdiff
path: root/dev_guide/pai_gow.md
blob: 3e0bc887c43a7e1574c1a49fc00c870d0959a37b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# Pai Gow Poker internals

Builder-facing table configuration and the published Fortune pay table
live in [../building_guide/pai_gow.md](../building_guide/pai_gow.md).
This page covers the engine side: hand evaluation, the house way,
settlement and the Joker art.

## Hand evaluation

The Joker is partially wild: an ace, or any missing card completing a
straight, flush or straight flush. Five aces beats a royal flush. A2345 is
the second-highest straight (and straight flush), below TJQKA but above
9TJQK, by default. `PaiGowConfig.A2345High()` reads the optional
`a2345_second_highest` field (default true); the evaluator is threaded
through the `...Rules` variants (`pgEvaluateRules`, `pgHouseRules`,
`pgFortuneRules`, `pgBestRules`, `pgDealerPushRules`,
`pgMainResultRules`, `pgPushAceClassRules`) so a table can demote the wheel
to the lowest straight without changing the default wrappers the tests use.
Low hands recognize only pairs and high cards. Suits do not break ties.
Copies lose to the dealer. The high hand must strictly outrank the low hand.

## Betting flow

Side bets (`fortune`, and `pushace` on Face Up) are placed first; the main
wager commits the round. The main bet deals immediately when every active
(connected) player has one, and a lone bettor is dealt at once, so a single
seat never waits on a timer. With two or more active players the shared
betting window (`betting_ticks`) opens and `finishBettingLocked` deals when
it expires if any main wager is live, refunding side bets on seats that
never placed one. `unbet main|fortune|pushace|all` returns an undealt stake
through `PayCredits`, and `leave` before the deal refunds the departing
seat and re-checks `allBetLocked` so the remaining bettors can be dealt.
The Push Ace High cap (half the main wager) is enforced when the main wager
lands, because side bets are already down by then.

## Player setting and showdown

An arrangement made with `24`/`13456`/`house` is stored on the player as
`pending`; it does not lock the hand or reveal the dealer. `set` moves
`pending` into `split` and marks the seat ready. When `autoset` is on (the
table default or a per-seat `autoset on`) a legal arrangement is committed
straight to `split`. A seat's `autoset` is seeded from
`PaiGowConfig.Autoset` at join.

When every active seat is ready, `prepareSettlementLocked` evaluates both
sides, builds a `PaiGowShowdown`, and hands it to `payLocked`. The showdown
always orders `Hands` player-high, dealer-high, player-low, dealer-low.
Each `PaiGowHandView` carries the label, the `pgRankName` strength, the
cards, and whether that hand won its comparison. The presentation layer
derives the colours (bold yellow for a winning strength, bold white for a
losing one) from those flags, so the casino package stays colour-free. The
`PaiGowShowdown` also carries the main result word, Fortune and Push Ace
outcomes, the Envy amount (only when another active player is seated), the
total stake, the payout, and the paid/pending state.

The dealt seven cards are only put on the snapshot before a seat has
arranged anything. A manual seat shows its `pending`/committed split as the
`Preview` (high then low, gap between, position numbers); an autoset seat
skips the preview and shows only the set/waiting note. `pgCardNums` maps
each hand card back to its 1-7 dealt position.

## House way

This is a **local, deterministic house way**, not a claim to reproduce a
particular casino's proprietary chart or optimal player strategy:

1. Enumerate the 21 possible splits and discard fouls.
2. Preserve the strongest available high-hand category.
3. With two pair or a full house available, also allow splits leaving at
   least a pair high and a pair low.
4. Maximize the low hand among these options, then the high hand.

The dealer and automatic player setting use precisely the same algorithm.
Published main-game house-edge estimates using other house ways do not
necessarily apply to this implementation.

## Fortune / Envy mathematics

Of the eight published fixed tables compared on the Wizard of Odds page,
table 8 (the one configured here) has the lowest house edge: 4.4292%
before Envy, about 0.08% with six players each betting five. With Envy
disabled, quads improve from 25:1 to 30:1, a custom local schedule
lowering the published no-Envy edge by about 0.9974 percentage points to
3.4318%. These are published theoretical side-bet figures, not a
simulation of this server; Envy value depends on occupancy and wager size.

## Face Up mechanics

The dealer sets and reveals before players act; the automatic ace-high
push is checked against the dealer's best five-card hand (`pgDealerPush`),
so ace pairs and ace-headed flushes do not trigger it. Push Ace High
classes are resolved by `pgPushAceClass`: a Joker in the dealer's seven
cards pays the Joker rate (a natural ace plus the Joker makes a pair of
aces, which is NOT ace-high); otherwise 40:1 when the player is also
ace-high, else the plain rate.

## Settlement

Main, Fortune, Envy and Push Ace High settle in a single wallet
transaction per player. Failed settlements freeze the result and block
the next deal; `settle` or the table tick retries payment, never redraws.
Successful recipients are not paid twice. Shutdown uses the existing
durable stake-refund mechanism.

## Joker art

The shared Joker is rank `JK`, suit `joker`. `data/cards.yaml` supplies
`JK` artwork at sizes 1/5/7/9; `internal/game/render_joker.go` also has
ASCII and no-store fallbacks, including dark/light styles. Existing Joker
Poker video poker uses the same art.