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_test.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_test.go')
| -rw-r--r-- | internal/casino/pai_gow_test.go | 151 |
1 files changed, 146 insertions, 5 deletions
diff --git a/internal/casino/pai_gow_test.go b/internal/casino/pai_gow_test.go index 02ea187..3936704 100644 --- a/internal/casino/pai_gow_test.go +++ b/internal/casino/pai_gow_test.go @@ -278,14 +278,17 @@ func TestPaiGowAtomicRetryAndEnvy(t *testing.T) { // collects b's fixed quad Envy, even though b didn't bet Fortune. tab.player("a").cards = pgCards("2s 4h 6c 8d Js Qh Ac") tab.player("b").cards = pgCards("Ks Kh Kc Kd 2h 3c 7h") + // Autoset is off by default, so each player previews then confirms. tab.action("a", "house") tab.action("b", "house") + tab.action("a", "set") + tab.action("b", "set") if tab.phase != "settling" || len(a.open) != 2 || len(b.open) != 0 || b.calls != 1 { t.Fatal("failed settlement wasn't held atomically") } p := tab.player("a") - if !strings.Contains(p.result, "Envy: 5") { - t.Fatal(p.result) + if p.showdown == nil || !p.showdown.ShowEnvy || p.showdown.Envy != 5 { + t.Fatalf("envy not reported: %+v", p.showdown) } cards := append([]card(nil), p.cards...) amount := p.payout @@ -312,14 +315,18 @@ func TestPaiGowRejectedFoulDoesNotLock(t *testing.T) { p := tab.player("a") p.cards = pgCards("As Ah 2c 3d 4s 7h 9c") events := tab.action("a", "12") - if p.ready || p.split.high != nil || !strings.Contains(events[0].Message, "FOUL HAND") { + if p.ready || p.split.high != nil || p.pending.high != nil || !strings.Contains(events[0].Message, "FOUL HAND") { t.Fatal(events) } tab.action("a", "34567") - if p.ready { + if p.ready || p.pending.high != nil { t.Fatal("complement foul should fail") } tab.action("a", "67") + if p.ready || p.pending.high == nil { + t.Fatal("a legal arrangement should preview, not lock") + } + tab.action("a", "set") if tab.phase != "waiting" { t.Fatal("legal set did not settle") } @@ -351,10 +358,15 @@ func TestPaiGowEnvyEligibilityAndMultipleAwards(t *testing.T) { tab.dealerSplit = pgHouse(tab.dealer) for _, name := range []string{"a", "b", "c"} { tab.action(name, "house") + tab.action(name, "set") } p := tab.player("a") main := pgMainPay(20, pgMainResult(p.split, tab.dealerSplit, tab.dealer, PaiGowClassic, tab.tie), PaiGowClassic) - if want := main + tt.stake*151 + tt.envy; p.payout != want { + wantEnvy := 0 + if tt.enabled && tt.stake >= 5 { + wantEnvy = tt.envy + } + if want := main + tt.stake*151 + wantEnvy; p.payout != want { t.Fatalf("%+v payout=%d want=%d", tt, p.payout, want) } } @@ -429,6 +441,7 @@ func TestPaiGowFaceUpAndPushAceHigh(t *testing.T) { t.Fatal("round resolved before player set") } tab.action("a", "house") + tab.action("a", "set") if tab.phase != "waiting" || len(w.open) != 0 { t.Fatal("Face Up settlement did not finish", tab.phase, w.open) } @@ -491,6 +504,134 @@ func TestPaiGowA2345Option(t *testing.T) { } } +func TestPaiGowRankNames(t *testing.T) { + cases := []struct { + cards string + name string + }{ + {"As Ah", "PAIR OF ACES"}, + {"Ks Qh", "HIGH CARD KING"}, + {"As Ah Kc Kd 2s", "TWO PAIR ACES AND KINGS"}, + {"As Kh Qc Jd 10s", "STRAIGHT ACE-HIGH"}, + {"2s 3h 4c 5d 6s", "STRAIGHT SIX-HIGH"}, + {"As 2h 3c 4d 5s", "STRAIGHT FIVE-HIGH"}, + {"10s Js Qs Ks As", "ROYAL FLUSH"}, + {"Ks Kh Kd Kc 2s", "FOUR OF A KIND KINGS"}, + {"Ks Kh Kd Qc Qs", "FULL HOUSE KINGS FULL OF QUEENS"}, + } + for _, tt := range cases { + if got := pgRankName(pgEvaluate(pgCards(tt.cards))); got != tt.name { + t.Errorf("%s = %q want %q", tt.cards, got, tt.name) + } + } +} + +func TestPaiGowManualSetConfirmsBeforeReveal(t *testing.T) { + tab := pgTestTable(false) + wa, wb := &testWallet{chips: 100}, &testWallet{chips: 100} + tab.join("a") + tab.join("b") + tab.bet("a", "main", 10, wa) + tab.bet("b", "main", 10, wb) + p := tab.player("a") + p.cards = pgCards("As Ah 2c 3d 4s 7h 9c") + events := tab.action("a", "house") + if p.ready || p.pending.high == nil { + t.Fatalf("house should preview, not lock: ready=%v pending=%+v", p.ready, p.pending) + } + snap := events[len(events)-1].Snapshot.(*PaiGowSnapshot) + if !snap.Preview || len(snap.PreviewHigh) != 5 || len(snap.PreviewLow) != 2 { + t.Fatalf("arranged preview missing: %+v", snap) + } + if len(snap.DealerHigh) != 0 { + t.Fatal("dealer revealed before set") + } + // "set" locks the arrangement but the round stays open for b. + events = tab.action("a", "set") + if !p.ready || tab.phase != "setting" { + t.Fatalf("set did not lock: ready=%v phase=%s", p.ready, tab.phase) + } + snap = events[len(events)-1].Snapshot.(*PaiGowSnapshot) + if snap.Showdown != nil { + t.Fatal("showdown before every seat set") + } + // b finishing the house way settles both. + tab.action("b", "house") + tab.action("b", "set") + if tab.phase != "waiting" || p.showdown == nil || len(p.showdown.Hands) != 4 { + t.Fatalf("round did not settle: phase=%s showdown=%+v", tab.phase, p.showdown) + } + // The showdown compares high hands first, then low hands. + labels := []string{p.showdown.Hands[0].Label, p.showdown.Hands[1].Label, p.showdown.Hands[2].Label, p.showdown.Hands[3].Label} + want := []string{"Your high", "Dealer high", "Your low", "Dealer low"} + if !reflect.DeepEqual(labels, want) { + t.Fatalf("showdown order %v want %v", labels, want) + } +} + +func TestPaiGowPreviewKeepsOriginalPositions(t *testing.T) { + tab := pgTestTable(false) + w := &testWallet{chips: 100} + tab.join("a") + tab.bet("a", "", 10, w) + p := tab.player("a") + p.cards = pgCards("As Ah 2c 3d 4s 7h 9c") + events := tab.action("a", "24") + snap := events[len(events)-1].Snapshot.(*PaiGowSnapshot) + if !snap.Preview { + t.Fatal("a legal arrangement should preview") + } + if !reflect.DeepEqual(snap.PreviewLowNums, []int{2, 4}) { + t.Fatalf("low numbers %v", snap.PreviewLowNums) + } + if !reflect.DeepEqual(snap.PreviewHighNums, []int{1, 3, 5, 6, 7}) { + t.Fatalf("high numbers %v", snap.PreviewHighNums) + } +} + +func TestPaiGowAutosetLocksWithoutPreview(t *testing.T) { + cfg := TableConfig{ID: "pg", Game: GamePaiGow, BettingTicks: 2, PaiGow: PaiGowConfig{Autoset: true, ActionTicks: 60}}.Normalize() + tab := newPaiGowTable(1, cfg, rand.New(rand.NewSource(3))).(*paiGowTable) + wa, wb := &testWallet{chips: 100}, &testWallet{chips: 100} + tab.join("a") + tab.join("b") + if !tab.player("a").autoset { + t.Fatal("table config did not seed the seat's autoset") + } + tab.bet("a", "main", 10, wa) + tab.bet("b", "main", 10, wb) + p := tab.player("a") + p.cards = pgCards("As Ah 2c 3d 4s 7h 9c") + events := tab.action("a", "house") + if !p.ready || p.pending.high != nil { + t.Fatalf("autoset did not lock: ready=%v pending=%+v", p.ready, p.pending) + } + snap := events[len(events)-1].Snapshot.(*PaiGowSnapshot) + if snap.Preview || len(snap.Cards) != 0 { + t.Fatalf("autoset re-showed the hand: preview=%v cards=%d", snap.Preview, len(snap.Cards)) + } + if !strings.Contains(snap.Result, "waiting") { + t.Fatalf("waiting note missing: %q", snap.Result) + } +} + +func TestPaiGowAutosetToggle(t *testing.T) { + tab := pgTestTable(false) + w := &testWallet{chips: 100} + tab.join("a") + if events := tab.action("a", "autoset on"); !hasMessage(events, "Autoset is on.") { + t.Fatalf("autoset on failed: %+v", events) + } + tab.bet("a", "", 10, w) + p := tab.player("a") + p.cards = pgCards("As Ah 2c 3d 4s 7h 9c") + tab.action("a", "24") + // A lone bettor settles at once, so a locked hand shows as a showdown. + if p.showdown == nil && (!p.ready || p.pending.high != nil) { + t.Fatalf("toggled autoset did not lock: ready=%v pending=%+v", p.ready, p.pending) + } +} + func TestPaiGowSoloMainDealsAfterSideBets(t *testing.T) { tab := pgTestTable(false) w := &testWallet{chips: 100} |
