diff options
Diffstat (limited to 'internal/game/render_craps_test.go')
| -rw-r--r-- | internal/game/render_craps_test.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/internal/game/render_craps_test.go b/internal/game/render_craps_test.go new file mode 100644 index 0000000..9d75630 --- /dev/null +++ b/internal/game/render_craps_test.go @@ -0,0 +1,130 @@ +package game + +import ( + "strings" + "testing" + + "thehouseoficarus/internal/casino" + "thehouseoficarus/internal/color" + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" + "thehouseoficarus/internal/world" +) + +func TestCrapsHalfTableGeometryAndPuck(t *testing.T) { + for _, unicode := range []bool{false, true} { + for _, point := range []int{0, 4, 5, 6, 8, 9, 10} { + s := &casino.CrapsSnapshot{Point: point, Field12: 3} + art := renderCrapsFelt(s, "none", unicode) + rows := strings.Split(strings.TrimSuffix(art, "\n"), "\n") + if len(rows) != 26 { + t.Fatal(len(rows)) + } + for _, row := range rows { + if color.VisibleLen(row) != 77 { + t.Fatalf("misaligned (%d): %s", color.VisibleLen(row), row) + } + } + // Check connected box edges at the main rail and centre-action partition. + if unicode { + for _, r := range []rune{'┌', '┬', '┼', '├', '┤', '┴', '┘'} { + if !strings.ContainsRune(art, r) { + t.Fatalf("missing joint %c", r) + } + } + } + v := "|" + if unicode { + v = "│" + } + want := v + "OFF" + v + if point != 0 { + want = v + "ON " + v + } + if strings.Count(art, want) != 1 { + t.Fatalf("missing/duplicate puck %d: %s", point, art) + } + if !strings.Contains(art, "12 PAYS 3:1") { + t.Fatal("field variant invisible") + } + for _, bet := range []string{"DON'T COME", "C O M E", "FIELD", "DON'T PASS", "PASS LINE", "HARD 4", "HARD 6", "HARD 8", "HARD 10", "SEVEN", "CRAPS", "ELEVEN", "ACES", "ACE 3", "BOXCARS", "HORN", "HOP"} { + if strings.Count(art, bet) != 1 { + t.Fatalf("missing or duplicate %q", bet) + } + } + } + } + t.Log("\n" + renderCrapsSnapshot(&casino.CrapsSnapshot{Point: 6, Field12: 3, Dice: [2]int{3, 3}, Queue: []string{"Alice", "Bob"}, Made: []int{4, 5}, Seen: []int{2, 4, 5, 6, 9}, Phase: "betting", ShootIn: 10, DealerIn: 70}, "none", true)) +} +func TestCrapsTrackersAndDiceStyles(t *testing.T) { + s := &casino.CrapsSnapshot{Made: []int{4, 6}, Seen: []int{2, 12}} + art := renderCrapsTrackers(s, "xterm256", true) + plain := plainRoulette(art) + for _, token := range []string{"[ 4*]", "[ 5 ]", "[ 6*]", " 2*", "12*"} { + if !strings.Contains(plain, token) { + t.Fatal("tracker missing", token) + } + } + if strings.Count(art, color.BgCode("xterm256", 220)) != 4 { + t.Fatal("wrong number of filled tracker tokens") + } + if !strings.Contains(renderCrapsFelt(s, "xterm256", true), color.BgCode("xterm256", 22)) { + t.Fatal("felt not dark green") + } + g := &Game{} + p := player.New("Alice") + p.Options = map[string]any{"card_style": "light", "unicode": true} + sess := &net.Session{Player: p} + s.Dice = [2]int{2, 5} + light := g.renderCasinoSnapshot(sess, s) + p.Options["card_style"] = "dark" + dark := g.renderCasinoSnapshot(sess, s) + if light == dark { + t.Fatal("card_style not wired to craps") + } + for a := 1; a <= 6; a++ { + for b := 1; b <= 6; b++ { + for _, unicode := range []bool{false, true} { + lit := renderCrapsDice([2]int{a, b}, "xterm256", unicode, "light") + dim := renderCrapsDice([2]int{a, b}, "xterm256", unicode, "dark") + if !strings.Contains(lit, color.BgCode("xterm256", 15)) || !strings.Contains(dim, color.BgCode("xterm256", 0)) { + t.Fatal("incorrect dice background") + } + pip := "o" + if unicode { + pip = "●" + } + if strings.Count(strings.ReplaceAll(plainRoulette(lit), "Total:", ""), pip) != a+b { + t.Fatal("wrong pip count", a, b) + } + if plainRoulette(lit) != plainRoulette(dim) { + t.Fatal("style changed dice outcome") + } + } + } + } +} +func TestCrapsRemindersFollowArt(t *testing.T) { + g := &Game{Casino: casino.NewManager(1), Combat: combat.NewTracker(), Deps: Deps{World: world.New(t.TempDir())}} + g.Casino.Join(1, casino.TableConfig{ID: "c", Game: casino.GameCraps}, "alice") + conn := &casinoTestConn{} + p := player.New("alice") + sess := &net.Session{Player: p, Conn: conn} + g.loggedInChars = map[string]*net.Session{"alice": sess} + for _, display := range []string{"full", "compact"} { + p.Options = map[string]any{"casino_display": display} + conn.data = nil + g.emitCasinoEvents(g.Casino.Table(1, "c").Status("alice")) + text := plainRoulette(string(conn.data)) + felt, commands := strings.Index(text, "PASS LINE"), strings.Index(text, "bet <amount> on <target>") + if felt < 0 || commands < felt { + t.Fatal("reminder above graphic", text) + } + for _, old := range []string{"Next in order:", "Fire points made:", "ATS numbers:", "Phase:", "Timer: 0"} { + if strings.Contains(text, old) { + t.Fatal("raw status leaked", old) + } + } + } +} |
