From bfe22e10b5b9f2c7039d1d67021229659a06a226 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 29 Sep 2026 15:19:40 -0400 Subject: feat: better wheel graphics, better pocket graphics --- internal/game/render_roulette_test.go | 115 ++++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 19 deletions(-) (limited to 'internal/game/render_roulette_test.go') diff --git a/internal/game/render_roulette_test.go b/internal/game/render_roulette_test.go index c1065e5..b1a6005 100644 --- a/internal/game/render_roulette_test.go +++ b/internal/game/render_roulette_test.go @@ -97,28 +97,30 @@ func TestRouletteArtModes(t *testing.T) { wheelArt := renderRouletteWheel(wheelOrder, mode, unicode) plainWheel := plainRoulette(wheelArt) lines := strings.Split(plainWheel, "\n") - if len(lines) != 23 { - t.Fatalf("wheel height = %d, want 23", len(lines)) + if len(lines) != 9 { + t.Fatalf("wheel height = %d, want 9", len(lines)) } - wantDoubleZeroLabel := 0 - if double { - wantDoubleZeroLabel = 1 - } - if got := strings.Count(plainWheel, "00"); got != wantDoubleZeroLabel { - t.Fatalf("double-zero labels = %d, want %d", got, wantDoubleZeroLabel) + if strings.ContainsAny(plainWheel, "0123456789") { + t.Fatalf("wheel should not show numbers:\n%s", plainWheel) } - if mode != "none" { - wantGreen := 1 - if double { - wantGreen = 2 + if mode == "none" || mode == "" { + for _, r := range "RBG" { + if !strings.ContainsRune(plainWheel, r) { + t.Fatalf("colorless wheel missing %q:\n%s", r, plainWheel) + } } - greens := strings.Count(wheelArt, color.BgCode(mode, 2)) - if greens != wantGreen { - t.Fatalf("green pockets = %d, want %d", greens, wantGreen) + // The top and bottom rows must be several cells wide so the + // disc reads as a circle rather than a pointed oval. + for _, idx := range []int{0, 8} { + if got := len(strings.TrimSpace(lines[idx])); got != 5 { + t.Fatalf("wheel row %d = %d wide, want 5:\n%s", idx, got, plainWheel) + } } - total := greens + strings.Count(wheelArt, color.BgCode(mode, 0)) + strings.Count(wheelArt, color.BgCode(mode, 1)) - if total != len(wheelOrder) { - t.Fatalf("drawn pockets = %d, want %d", total, len(wheelOrder)) + } else { + for _, bg := range []int{0, 1, 2} { + if !strings.Contains(wheelArt, color.BgCode(mode, bg)) { + t.Fatalf("wheel missing pocket background %d", bg) + } } } @@ -134,6 +136,21 @@ func TestRouletteArtModes(t *testing.T) { } } +// TestRouletteWheelGreenPockets checks that the single-zero wheel has one green +// pocket and the American wheel adds the diametrically opposite one. +func TestRouletteWheelGreenPockets(t *testing.T) { + single := plainRoulette(renderRouletteWheel(casino.WheelOrder(false), "none", true)) + double := plainRoulette(renderRouletteWheel(casino.WheelOrder(true), "none", true)) + singleGreen := strings.Count(single, "G") + doubleGreen := strings.Count(double, "G") + if singleGreen == 0 { + t.Fatalf("single-zero wheel has no green:\n%s", single) + } + if doubleGreen <= singleGreen { + t.Fatalf("double-zero green = %d, want more than single-zero %d:\n%s", doubleGreen, singleGreen, double) + } +} + // TestRouletteLayoutConnections guards the box-drawing joints: the dozen-row // boxes must connect to the numbered grid above and be closed under, the // row-bet cells must be boxed on the right, and the bottom rule must tee under @@ -197,7 +214,7 @@ func TestRouletteResultSizesAndNeighbors(t *testing.T) { t.Fatalf("unequal pocket widths: %q", line) } } - center := []rune(lines[height/2]) + center := []rune(lines[1]) if !strings.Contains(string(center[:width]), "1") || !strings.Contains(string(center[width+1:2*width+1]), "00") || !strings.Contains(string(center[2*width+2:]), "27") { t.Fatal("wrong pocket order", art) } @@ -212,6 +229,66 @@ func TestRouletteResultSizesAndNeighbors(t *testing.T) { } } +// TestRouletteResultLayout checks the new card shape: number on top, a rule +// under it, the ball one row above centre, and the color spelled out on the +// bottom row only when color is off. cardRenderSize caps non-Unicode cards at +// five rows, so the full nine-row shape is exercised through Unicode. +func TestRouletteResultLayout(t *testing.T) { + pockets := [3]string{"1", "10", "27"} // RED, BLACK, RED + for _, tc := range []struct { + unicode bool + size int + height int + }{ + {true, 9, 9}, + {true, 7, 7}, + {true, 5, 5}, + {false, 9, 5}, + } { + unicode, height := tc.unicode, tc.height + ball := "o" + rule := "-" + if unicode { + ball = "●" + rule = "─" + } + ballRow := height / 2 + colorRow := height - 2 + hasRule := ballRow > 2 + + colored := plainRoulette(renderRouletteResult(pockets, "xterm256", unicode, tc.size)) + lines := strings.Split(colored, "\n") + if len(lines) != height { + t.Fatalf("unicode=%v size=%d: height=%d, want %d", unicode, tc.size, len(lines), height) + } + for i, want := range pockets { + if !strings.Contains(lines[1], want) { + t.Fatalf("unicode=%v size=%d: top row missing pocket %d (%s):\n%s", unicode, tc.size, i, want, colored) + } + } + if hasRule { + if !strings.Contains(lines[2], rule) { + t.Fatalf("unicode=%v size=%d: missing rule under the number:\n%s", unicode, tc.size, colored) + } + } + if !strings.Contains(lines[ballRow], ball) { + t.Fatalf("unicode=%v size=%d: ball should be on row %d:\n%s", unicode, tc.size, ballRow, colored) + } + if strings.Contains(colored, "RED") || strings.Contains(colored, "BLACK") { + t.Fatalf("unicode=%v size=%d: color label shown while color is on:\n%s", unicode, tc.size, colored) + } + + plain := plainRoulette(renderRouletteResult(pockets, "none", unicode, tc.size)) + plainLines := strings.Split(plain, "\n") + if strings.Contains(plainLines[1], "RED") || strings.Contains(plainLines[1], "BLACK") { + t.Fatalf("unicode=%v size=%d: color label should not be on the top row:\n%s", unicode, tc.size, plain) + } + if !strings.Contains(plainLines[colorRow], "RED") || !strings.Contains(plainLines[colorRow], "BLACK") { + t.Fatalf("unicode=%v size=%d: missing color label on row %d:\n%s", unicode, tc.size, colorRow, plain) + } + } +} + func TestRouletteEventColorsDoNotWrapArt(t *testing.T) { for _, public := range []bool{false, true} { for _, mode := range []string{"none", "ansi", "xterm256"} { -- cgit v1.2.3