diff options
| author | historia <[not public]> | 2026-10-01 17:24:54 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-10-01 17:24:54 -0400 |
| commit | 4e2a95503e4ea4c830510f5aea23fac7948ddc41 (patch) | |
| tree | 690b06df9094480febfaaaf7d9fc71ef7b81848d /internal/casino/pai_gow_rules.go | |
| parent | d762f8e1360cf38b8e11e69083c2dad59ec7130e (diff) | |
| download | thehouseoficarus-4e2a95503e4ea4c830510f5aea23fac7948ddc41.tar.gz | |
feat: set and autoset in pai gow, better showdown arrangement, better formatting
Diffstat (limited to 'internal/casino/pai_gow_rules.go')
| -rw-r--r-- | internal/casino/pai_gow_rules.go | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/internal/casino/pai_gow_rules.go b/internal/casino/pai_gow_rules.go index ced7c47..3a1f4b5 100644 --- a/internal/casino/pai_gow_rules.go +++ b/internal/casino/pai_gow_rules.go @@ -21,7 +21,11 @@ type PaiGowConfig struct { Variant string `yaml:"variant,omitempty"` Envy bool `yaml:"envy,omitempty"` PushAceHigh string `yaml:"push_ace_high,omitempty"` // Face Up only: 5_15_40 or 5_12_40 - ActionTicks int `yaml:"action_ticks,omitempty"` + // Autoset makes a legal arrangement lock immediately instead of waiting + // for the player's "set" confirmation. Players may toggle it per seat with + // "autoset on|off"; this field only seeds the default at join. + Autoset bool `yaml:"autoset,omitempty"` + ActionTicks int `yaml:"action_ticks,omitempty"` // A2345SecondHighest makes the wheel the second-highest straight, below // Broadway and above a six-high straight. It defaults to true; only an // explicit false demotes A2345 to the lowest straight. @@ -95,7 +99,7 @@ func paiGowRules(c TableConfig) string { if !r.A2345High() { wheel = "A2345 is the lowest straight." } - s := r.Label() + "\nSeven cards from a fresh 53-card deck. Joker is an ace unless completing a straight, flush or straight flush. " + wheel + "\nSet two cards low and five high: 24 chooses low cards 2/4; 13456 chooses the high hand. High must strictly outrank low. Copies go to the dealer.\nBoth hands win: win; both lose: loss; one wins: push." + s := r.Label() + "\nSeven cards from a fresh 53-card deck. Joker is an ace unless completing a straight, flush or straight flush. " + wheel + "\nArrange two cards low and five high: 24 chooses low cards 2/4; 13456 chooses the high hand. Your five-card hand must strictly outrank your two-card hand. The board then shows the five high cards and the two low cards, and set locks the hand and reveals the dealer; copies go to the dealer.\nBoth hands win: win; both lose: loss; one wins: push." switch r.Variant { case PaiGowClassic: s += " Wins pay 0.95:1 (profit rounded down, minimum one credit)." @@ -106,7 +110,7 @@ func paiGowRules(c TableConfig) string { case PaiGowNoPush: s += " No commission; split results use two extra cards: player must beat dealer, ties lose; Joker is ace." } - s += "\nHouse way: preserve the best high-hand category, maximize low within it; split two pair, full houses and trips-pairs when this improves low to a pair. Never foul. Use house or set <digits>; set locks your hand. Timeout/disconnect uses house way.\nBet main first, optionally bet <amount> fortune before dealing. Fortune uses all seven cards regardless of split; highest listed prize only, profit odds plus stake returned." + s += "\nHouse way: preserve the best high-hand category, maximize low within it; split two pair, full houses and trips-pairs when this improves low to a pair. Never foul. house arranges the house way and still needs set; autoset on locks any legal arrangement immediately (autoset off restores the confirmation). Timeout/disconnect uses house way.\nBet main first, optionally bet <amount> fortune before dealing. Fortune uses all seven cards regardless of split; highest listed prize only, profit odds plus stake returned." if r.Envy { s += "\nEnvy: Fortune stake of at least 5 qualifies for fixed bonuses on OTHER active players' hands, never your own or dealer; multiple bonuses add." } else { @@ -148,6 +152,7 @@ func pgCompare(a, b pgRank) int { } return 0 } + // pgNatural keeps the default-rules entry point used by tests and callers that // do not thread a table configuration. Production evaluation goes through // pgNaturalRules. @@ -258,6 +263,73 @@ func pgEvaluateRules(cards []card, a2345High bool) pgRank { return best } +// pgRankWords names card ranks for the hand-strength labels shown at the +// showdown. Index 14 is ACE so a pair of aces reads "PAIR OF ACES". +var pgRankWords = [...]string{"", "", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "TEN", "JACK", "QUEEN", "KING", "ACE"} + +func pgRankWord(v int) string { + if v >= 2 && v <= 14 { + return pgRankWords[v] + } + return "?" +} + +func pgRankPlural(v int) string { + word := pgRankWord(v) + switch word { + case "SIX": + return "SIXES" + case "ACE": + return "ACES" + default: + return word + "S" + } +} + +func pgStraightName(v int) string { + switch v { + case 16: + return "ACE-HIGH" + case 15: + return "FIVE-HIGH" + default: + return pgRankWord(v) + "-HIGH" + } +} + +// pgRankName renders a hand strength for the showdown, for example +// "PAIR OF ACES", "TWO PAIR ACES AND KINGS" or "STRAIGHT ACE-HIGH". +func pgRankName(r pgRank) string { + switch r[0] { + case 9: + return "FIVE OF A KIND " + pgRankPlural(r[1]) + case 8: + if r[1] == 16 { + return "ROYAL FLUSH" + } + return "STRAIGHT FLUSH " + pgStraightName(r[1]) + case 7: + return "FOUR OF A KIND " + pgRankPlural(r[1]) + case 6: + return "FULL HOUSE " + pgRankPlural(r[1]) + " FULL OF " + pgRankPlural(r[2]) + case 5: + return "FLUSH " + pgRankWord(r[1]) + "-HIGH" + case 4: + return "STRAIGHT " + pgStraightName(r[1]) + case 3: + return "THREE OF A KIND " + pgRankPlural(r[1]) + case 2: + return "TWO PAIR " + pgRankPlural(r[1]) + " AND " + pgRankPlural(r[2]) + case 1: + return "PAIR OF " + pgRankPlural(r[1]) + default: + if r[1] > 0 { + return "HIGH CARD " + pgRankWord(r[1]) + } + return "HIGH CARD" + } +} + type pgSplit struct{ high, low []card } func pgSet(cards []card, digits []int) pgSplit { @@ -437,6 +509,7 @@ func pgFortuneRules(cards []card, envy, a2345High bool) (FortuneRow, bool) { } return rows[bestIndex], true } + // pgBest keeps the default-rules entry point used by tests and callers that do // not thread a table configuration. Production evaluation goes through // pgBestRules. |
