aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/pai_gow_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/casino/pai_gow_test.go')
-rw-r--r--internal/casino/pai_gow_test.go151
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}