diff options
Diffstat (limited to 'internal/game/pai_gow_test.go')
| -rw-r--r-- | internal/game/pai_gow_test.go | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/internal/game/pai_gow_test.go b/internal/game/pai_gow_test.go new file mode 100644 index 0000000..614d0dd --- /dev/null +++ b/internal/game/pai_gow_test.go @@ -0,0 +1,141 @@ +package game + +import ( + "strings" + "testing" + "unicode/utf8" + + "thehouseoficarus/internal/cardart" + "thehouseoficarus/internal/casino" + "thehouseoficarus/internal/world" +) + +func TestPaiGowCommandsLookAndSettlement(t *testing.T) { + g, sess, conn := casinoCrapsGame(t, "name: Pai Gow\ncasino_tables:\n - id: fortune\n game: pai_gow\n pai_gow:\n envy: true\n") + g.executePlay(sess, []string{"pai"}, "play pai") + table, playing := g.Casino.Participation(sess.Player.Name) + if !playing || table.Config.Game != casino.GamePaiGow { + t.Fatal("alias failed") + } + conn.data = nil + g.executeTableStatus(sess, []string{"rules"}, "table rules") + text := stripANSI(string(conn.data)) + for _, want := range []string{"FORTUNE", "ENVY (FIXED)", "750:1", "Three pair"} { + if !strings.Contains(text, want) { + t.Fatalf("missing %s: %s", want, text) + } + } + g.executeBet(sess, []string{"20"}, "bet 20") + g.executeBet(sess, []string{"5", "fortune"}, "bet 5 fortune") + g.executeTableAction(sess, "deal") + snap := table.Status(sess.Player.Name)[0].Snapshot.(*casino.PaiGowSnapshot) + if len(snap.Cards) != 7 || len(snap.DealerHigh) != 0 || len(sess.Player.PendingWagers) != 2 { + t.Fatal("deal/side bet") + } + conn.data = nil + g.executeCommand(sess, "22", nil, "22") + if text = string(conn.data); !strings.Contains(text, "different numbers") { + t.Fatal(text) + } + if classifyCommand("67") != ClassInstant || classifyCommand("13456") != ClassInstant { + t.Fatal("numeric classification") + } + // A numeric selection either locks a valid split or gives a clear foul; + // either way it must reach Pai Gow rather than the generic unknown verb. + conn.data = nil + g.executeCommand(sess, "67", nil, "67") + text = string(conn.data) + if table.Status(sess.Player.Name)[0].Snapshot.(*casino.PaiGowSnapshot).Phase == "setting" && !strings.Contains(text, "FOUL HAND") { + t.Fatal(text) + } + g.executeCommand(sess, "house", nil, "house") + if table.Status(sess.Player.Name)[0].Snapshot.(*casino.PaiGowSnapshot).Phase != "waiting" || len(sess.Player.PendingWagers) != 0 { + t.Fatal("settlement did not finish") + } +} +func TestPaiGowFeltAndJokerAllModes(t *testing.T) { + store := cardart.Load("../../data/cards.yaml") + for _, size := range []int{1, 5, 7, 9} { + if len(store.Art("JK", size)) != size { + t.Fatalf("missing JK art at %d", size) + } + for _, unicode := range []bool{false, true} { + for _, style := range []string{"dark", "light"} { + for _, art := range []*cardart.Store{nil, store} { + lines := jokerCardArt(size, unicode, style, art) + if len(lines) != size { + t.Fatal(size, lines) + } + for _, line := range lines { + if size > 1 && utf8.RuneCountInString(line) != size { + t.Fatalf("%d width: %q", size, line) + } + if !unicode { + for _, r := range line { + if r > 127 { + t.Fatalf("ASCII Joker has Unicode: %q", line) + } + } + } + } + for _, mode := range []string{"none", "xterm256", "truecolor"} { + out := cardsLine(mode, []casino.CardView{{Rank: "JK", Suit: "joker"}}, cardRenderSize(unicode, size), unicode, style, art) + if !strings.Contains(strings.Join(out, "\n"), "J") { + t.Fatal(out) + } + } + } + } + } + } + for _, envy := range []bool{false, true} { + for _, unicode := range []bool{false, true} { + cfg := casino.TableConfig{Game: casino.GamePaiGow, PaiGow: casino.PaiGowConfig{Envy: envy}} + felt := renderPaiGowFelt(cfg, "none", unicode) + lines := strings.Split(strings.TrimRight(felt, "\n"), "\n") + width := utf8.RuneCountInString(lines[0]) + for _, line := range lines { + if utf8.RuneCountInString(line) != width { + t.Fatal("jagged felt", line) + } + } + if !strings.Contains(felt, "Three pair") || !strings.Contains(felt, "1000:1") { + t.Fatal(felt) + } + if !envy && (!strings.Contains(felt, "ENVY OFF") || !strings.Contains(felt, "30:1")) { + t.Fatal(felt) + } + if cfg.PaiGow.Envy && (strings.Contains(felt, "ENVY OFF") || !strings.Contains(felt, "ENVY (FIXED)")) { + t.Fatal(felt) + } + } + } + cfg := casino.TableConfig{MinBet: 5, MaxBet: 1000, Game: casino.GamePaiGow, PaiGow: casino.PaiGowConfig{Variant: casino.PaiGowFaceUp, PushAceHigh: "5_15_40"}} + felt := renderPaiGowFelt(cfg, "none", true) + if !strings.Contains(felt, "DEALER FACE UP") || !strings.Contains(felt, "PUSH ACE HIGH 5/15/40:1") { + t.Fatal(felt) + } +} +func TestVestaPaiGowRooms(t *testing.T) { + _, rooms, _ := loadVesta(t) + for id, variant := range map[int]string{6195: casino.PaiGowClassic, 6196: casino.PaiGowEZ, 6197: casino.PaiGowNoPush, 6198: casino.PaiGowFaceUp} { + r, ok := rooms[id] + if !ok || len(r.CasinoTables) != 1 { + t.Fatalf("missing Pai Gow room %d", id) + } + cfg := r.CasinoTables[0] + if cfg.Validate() != nil || cfg.Game != casino.GamePaiGow || cfg.PaiGow.Variant != variant || cfg.PaiGow.Envy != (id != 6197) { + t.Fatalf("bad Pai Gow configuration: %+v", cfg) + } + } + if rooms[6192].Exits[world.East].Room != 6195 || rooms[6195].Exits[world.West].Room != 6192 || rooms[6195].Exits[world.North].Room != 6196 || rooms[6196].Exits[world.South].Room != 6195 || rooms[6195].Exits[world.South].Room != 6197 || rooms[6197].Exits[world.North].Room != 6195 || rooms[6196].Exits[world.North].Room != 6198 || rooms[6198].Exits[world.South].Room != 6196 { + t.Fatal("broken Pai Gow navigation") + } +} +func TestJokerEmptySuitDoesNotPanic(t *testing.T) { + for _, size := range []int{5, 7, 9} { + if len(cardArtLines(casino.CardView{Rank: "JK"}, size, true, "dark", nil)) != size { + t.Fatal(size) + } + } +} |
