diff options
| author | historia <[not public]> | 2026-10-04 17:44:27 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-10-04 17:44:27 -0400 |
| commit | 93dcb67ffee05ebf1de0c9a78a8b906eaf161007 (patch) | |
| tree | 88cdd3d732f11eee616698a9ca32f699d2b41d77 /internal/game/plinko_test.go | |
| parent | 3a39a020e4449bc4d6f728ef837cffb9f7bd0c56 (diff) | |
| download | thehouseoficarus-93dcb67ffee05ebf1de0c9a78a8b906eaf161007.tar.gz | |
feat: new casino game: cash hunt, fixed verb issue with pai gow
Diffstat (limited to 'internal/game/plinko_test.go')
| -rw-r--r-- | internal/game/plinko_test.go | 130 |
1 files changed, 85 insertions, 45 deletions
diff --git a/internal/game/plinko_test.go b/internal/game/plinko_test.go index 711525f..dd3e205 100644 --- a/internal/game/plinko_test.go +++ b/internal/game/plinko_test.go @@ -24,6 +24,11 @@ func TestPlinkoCommands(t *testing.T) { t.Fatalf("commands failed: %+v", snap) } g.executeBet(s, []string{"1"}, "bet 1") + for _, removed := range []string{"Welcome to PLINKO", "*** PLINKO", "=== P L I N K O", "White = one ball", "Matching letters share", "(base "} { + if strings.Contains(string(conn.data), removed) { + t.Fatalf("obsolete prose still printed: %q", removed) + } + } if !table.Busy(s.Player.Name) || len(s.Player.PendingWagers) != 1 { t.Fatal("drop did not start") } @@ -35,12 +40,15 @@ func TestPlinkoCommands(t *testing.T) { t.Fatal("drop did not settle") } text := stripANSI(string(conn.data)) - if !strings.Contains(text, "Ball 10 ->") || strings.Count(text, "Returned:") != 1 || strings.Contains(text, "credits returned") || strings.Contains(text, "net +") { + if strings.Contains(text, "->") || strings.Count(text, "Returned:") != 1 || strings.Contains(text, "credits returned") || strings.Contains(text, "net +") { t.Fatal(text) } + if !strings.Contains(text, "Wager") || !strings.Contains(text, "Staked") { + t.Fatalf("settlement receipt missing: %s", text) + } conn.data = nil g.doLookTarget(s, "plinko") - if !strings.Contains(stripANSI(string(conn.data)), "P L I N K O") { + if !strings.Contains(stripANSI(string(conn.data)), "% RTP:") { t.Fatal("look missing paytable") } } @@ -75,16 +83,27 @@ func TestPlinkoRenderRows(t *testing.T) { } } wantLines := 1 - if row == plinkoRows/2 || row == plinkoRows { - wantLines = 2 // midpoint hint ruler, base rail + if row == plinkoRows { + wantLines = 2 // base rail } if got := len(strings.Split(out, "\n")); got != wantLines { t.Fatalf("row %d printed %d lines, want %d", row, got, wantLines) } - if strings.Contains(out, "\x1b[48;") { - t.Fatal("the board must not paint a background") + switch mode { + case "none": + if strings.Contains(out, "\x1b") { + t.Fatal("plain board must not contain escapes") + } + case "ansi", "xterm256": + // The board is background-free: the player's terminal theme + // shows through instead of a fixed gradient. + for bg := 0; bg < 256; bg++ { + if strings.Contains(out, color.BgCode(mode, bg)) { + t.Fatalf("%s board must not paint a background", mode) + } + } } - if mode == "none" && (!strings.Contains(out, "*") || strings.Contains(out, "\x1b")) { + if mode == "none" && !strings.Contains(out, "*") { t.Fatal("plain overlap fallback missing") } } @@ -102,7 +121,7 @@ func TestPlinkoUsesSharedHints(t *testing.T) { if strings.Contains(text, "difficulty easy|medium|hard|expert") != (mode != "off") { t.Fatalf("join hints (%s): %s", mode, text) } - if mode != "off" && strings.Index(text, "P L I N K O") > strings.Index(text, "bet N") { + if mode != "off" && strings.Index(text, "% RTP:") > strings.Index(text, "bet N") { t.Fatal("hints must follow the paytable") } conn.data = nil @@ -134,15 +153,17 @@ func plinkoTestBoardRow(s *casino.PlinkoSnapshot) []rune { } func TestPlinkoPegsNeverMove(t *testing.T) { + pockets := [17]float64{16, 7.8, 5.9, 4.4, 3.1, 2, 1.1, 0.5, 0.2, 0.5, 1.1, 2, 3.1, 4.4, 5.9, 7.8, 16} for row := 0; row <= 16; row++ { - s := &casino.PlinkoSnapshot{Row: row, Total: 1} + s := &casino.PlinkoSnapshot{Row: row, Total: 1, Pockets: pockets} empty := plinkoTestBoardRow(s) left, right := 32-2*row, 36+2*row pegs := map[int]bool{} for k := 1; k <= row; k++ { - pegs[left+4*k] = true - if empty[left+4*k] != '·' { - t.Fatalf("row %d: peg missing at its true position %d", row, left+4*k) + x := left + 4*k + pegs[x] = true + if empty[x] != '·' { + t.Fatalf("row %d: peg missing at its true position %d", row, x) } } if right < plinkoWidth && empty[right] != '\\' || empty[left] != '/' { @@ -165,35 +186,28 @@ func TestPlinkoPegsNeverMove(t *testing.T) { } } -func TestPlinkoHintsPrintOnceAtMidpoint(t *testing.T) { +func TestPlinkoHintsOverlayReminderRow(t *testing.T) { pockets := [17]float64{16, 7.8, 5.9, 4.4, 3.1, 2, 1.1, 0.5, 0.2, 0.5, 1.1, 2, 3.1, 4.4, 5.9, 7.8, 16} labels := casino.PlinkoPocketLabels(pockets) - isRuler := func(line string) bool { - r := []rune(line) - if len(r) != plinkoWidth || r[1] != ' ' { - return false - } - for k, label := range labels { - if r[2+4*k] != label { - return false - } - } - return true - } for row := 0; row <= 16; row++ { s := &casino.PlinkoSnapshot{Row: row, Total: 1, Pockets: pockets} - hasRuler := false - for _, line := range strings.Split(stripANSI(renderPlinko(s, "none", true)), "\n") { - hasRuler = hasRuler || isRuler(line) + lines := strings.Split(stripANSI(renderPlinko(s, "none", true)), "\n") + wantLines := 1 + if row == plinkoRows { + wantLines = 2 } - if hasRuler != (row == plinkoRows/2) { - t.Fatalf("row %d: hint ruler present=%v", row, hasRuler) + if len(lines) != wantLines { + t.Fatalf("row %d printed %d lines, want %d", row, len(lines), wantLines) } - // The pyramid row itself never carries pocket letters any more. - board := plinkoTestBoardRow(s) + board := []rune(lines[0]) for k, label := range labels { - if board[2+4*k] == label { - t.Fatalf("row %d: pocket hint leaked into the board", row) + x := 2 + 4*k + if row == plinkoHintRow { + if board[x] != label { + t.Fatalf("row %d: reminder %c missing at pocket column %d (got %q)", row, label, x, board[x]) + } + } else if board[x] == label { + t.Fatalf("row %d: reminder %c leaked into the board at %d", row, label, x) } } } @@ -225,11 +239,11 @@ func TestPlinkoLegendDownTheLeft(t *testing.T) { if left := 32 - 2*s.Row; left <= 10 { t.Fatalf("legend would collide with the pyramid: left border %d", left) } - // The paytable prints the same entries, one per line, not a wide block. + // The standalone paytable prints the same entries on one line. s.Row = 0 paytable := stripANSI(renderPlinko(&casino.PlinkoSnapshot{Pockets: s.Pockets, Risk: "easy", Paytable: true}, "none", true)) for _, e := range entries { - if strings.Count(paytable, fmt.Sprintf("%c %s", e.label, e.text)) != 1 { + if strings.Count(paytable, fmt.Sprintf("%c%s", e.label, e.text)) != 1 { t.Fatalf("paytable legend missing or duplicated %c", e.label) } } @@ -246,16 +260,42 @@ func TestPlinkoLegendDownTheLeft(t *testing.T) { } } -func TestPlinkoHintsAreDimWhite(t *testing.T) { - r, g, b := color.Xterm256ToRGB(plinkoHintColor()) - if r != g || g != b { - t.Fatalf("hint is not white: %d,%d,%d", r, g, b) +func TestPlinkoPaytableIsCompact(t *testing.T) { + s := &casino.PlinkoSnapshot{ + Paytable: true, Risk: "easy", Total: 1, RTP: 97.9998779296875, + Pockets: [17]float64{16, 7.8, 5.8, 4.3, 3, 2, 1.1, 0.4, 0.2, 0.4, 1.1, 2, 3, 4.3, 5.8, 7.8, 16}, } - if r > 95 { - t.Fatalf("hint is too bright: %d", r) + want := "easy 1 ball 98.00% RTP: A16x B7.8x C5.8x D4.3x E3x F2x G1.1x H0.4x I0.2x" + for _, mode := range []string{"none", "ansi", "xterm256"} { + out := renderPlinko(s, mode, true) + if plain := stripANSI(out); plain != want { + t.Fatalf("%s paytable: %q", mode, plain) + } + if mode != "none" { + for bg := 0; bg < 256; bg++ { + if strings.Contains(out, color.BgCode(mode, bg)) { + t.Fatalf("%s paytable must not paint a background", mode) + } + } + } } - br, bg, bb := color.Xterm256ToRGB(plinkoBallColor(1, 1)) - if r >= br || g >= bg || b >= bb { - t.Fatal("hint must be dimmer than a ball") +} + +func TestPlinkoLandingPockets(t *testing.T) { + s := &casino.PlinkoSnapshot{Row: plinkoRows, Total: 3} + s.Pockets[0], s.Pockets[16] = 16, 16 + s.Counts[0], s.Counts[8] = 1, 2 + for _, mode := range []string{"none", "ansi", "xterm256"} { + rail := strings.Split(renderPlinko(s, mode, true), "\n")[1] + plain := []rune(stripANSI(rail)) + for k := range s.Counts { + left, right := '[', ']' + if s.Counts[k] > 0 { + left, right = '>', '<' + } + if plain[1+4*k] != left || plain[3+4*k] != right { + t.Fatalf("%s: incorrect landing marker at pocket %d: %s", mode, k, string(plain)) + } + } } } |
