diff options
Diffstat (limited to 'internal/game/cash_hunt_test.go')
| -rw-r--r-- | internal/game/cash_hunt_test.go | 114 |
1 files changed, 96 insertions, 18 deletions
diff --git a/internal/game/cash_hunt_test.go b/internal/game/cash_hunt_test.go index 65ef16f..78d3e38 100644 --- a/internal/game/cash_hunt_test.go +++ b/internal/game/cash_hunt_test.go @@ -25,7 +25,7 @@ func TestCashHuntCommandsAndReceipt(t *testing.T) { g.executeBet(s, []string{"1"}, "bet 1") text := string(conn.data) preview, hidden := strings.Index(text, "PRIZE PREVIEW"), strings.Index(text, "hidden and mixed") - if preview < 0 || hidden <= preview || !strings.Contains(text, " 100 ") || len(s.Player.PendingWagers) != 1 { + if preview < 0 || hidden <= preview || !strings.Contains(text, cashHuntCenter("100", cashHuntTileWidth)) || len(s.Player.PendingWagers) != 1 { t.Fatalf("preview/shuffle sequence missing: %s", text) } if table.Busy(s.Player.Name) { @@ -114,32 +114,47 @@ func TestCashHuntBoardRendering(t *testing.T) { if phase == "result" { s.Selected = 100 } - rendered := renderCashHunt(s, mode, unicode) + rendered := renderCashHunt(s, mode, unicode, "98%") if mode == "none" && strings.Contains(rendered, "\x1b") { t.Fatal("plain board has ANSI escapes") } lines := strings.Split(stripANSI(rendered), "\n") - if len(lines) != 22 { - t.Fatalf("want two headers and 20 tile lines, got %d", len(lines)) + // One subtitle, a header top border + header row, a grid top + // separator, ten rows of (number, prize, separator), and a bottom + // border. + if len(lines) != 34 { + t.Fatalf("want a headed bordered 10x10 grid, got %d lines", len(lines)) } - for _, line := range lines[2:] { - if utf8.RuneCountInString(line) != 70 { - t.Fatalf("tile row is not 70 columns: %q", line) + for _, line := range lines[1:] { + if utf8.RuneCountInString(line) != cashHuntBoardWidth { + t.Fatalf("grid line is not %d columns: %q", cashHuntBoardWidth, line) } } - board := strings.Join(lines[2:], "\n") + board := strings.Join(lines[1:], "\n") if strings.ContainsAny(board, "[]") { t.Fatalf("square numbers must not use brackets: %q", board) } + header := lines[2] + if !strings.Contains(header, "HARD 98%") || !strings.Contains(header, "CASH HUNT") || !strings.Contains(header, "TOP PRIZE: 50000x") { + t.Fatalf("header row wrong: %q", header) + } + if unicode { + // The header is one merged cell, so its bottom border meets the + // grid columns with down-T junctions, not crosses. + if !strings.Contains(lines[3], "┬") || strings.Contains(lines[3], "┼") { + t.Fatalf("grid top border should use down-T junctions: %q", lines[3]) + } + } for row := 0; row < 10; row++ { - numberLine := lines[2+2*row] + numberRunes := []rune(lines[4+3*row]) for col := 0; col < 10; col++ { square := row*10 + col + 1 label := fmt.Sprintf("%d", square) if square == s.Selected { label = fmt.Sprintf(">%d<", square) } - got := numberLine[col*cashHuntTileWidth : (col+1)*cashHuntTileWidth] + start := 1 + col*(cashHuntTileWidth+1) + got := string(numberRunes[start : start+cashHuntTileWidth]) if want := cashHuntCenter(label, cashHuntTileWidth); got != want { t.Fatalf("square %d label: got %q want %q", square, got, want) } @@ -156,23 +171,86 @@ func TestCashHuntBoardRendering(t *testing.T) { } } if mode == "xterm256" { - // Dark rainbow columns replace the old black/blue checker. - if strings.Contains(rendered, "\x1b[48;5;16m") || strings.Contains(rendered, "\x1b[48;5;17m") { - t.Fatal("black/blue tile background survived") + // The whole board is black; the box-drawing grid supplies the + // separation. + if !strings.Contains(rendered, color.BgCode("xterm256", cashHuntTileBlack)) { + t.Fatal("missing black tile background") } - for _, shade := range cashHuntTileColors { - if !strings.Contains(rendered, color.BgCode("xterm256", shade)) { - t.Fatalf("missing dark rainbow shade %d", shade) + if strings.Contains(rendered, color.BgCode("xterm256", 234)) { + t.Fatal("checkerboard gray should be gone") + } + for _, shade := range []int{88, 94, 100, 28, 29, 30, 24, 18, 90, 89} { + if strings.Contains(rendered, color.BgCode("xterm256", shade)) { + t.Fatalf("rainbow tile shade %d should be gone", shade) } } + if !strings.Contains(rendered, color.FgCode("xterm256", 244)) { + t.Fatal("square numbers should be dimmer than the header") + } + if !strings.Contains(rendered, color.FgCode("xterm256", cashHuntBoxFg)) { + t.Fatal("grid characters should be darkened") + } + // 0x is not a prize: it stays dim and is never bold. + if !strings.Contains(board, cashHuntCenter("0x", cashHuntTileWidth)) { + t.Fatal("0x prize missing") + } + if strings.Contains(rendered, "\x1b[1m"+color.FgCode("xterm256", 237)) { + t.Fatal("0x should not render bold") + } + if !strings.Contains(rendered, "\x1b[1m"+color.FgCode("xterm256", 225)) { + t.Fatal("real multipliers should render bold") + } } } - hidden := renderCashHunt(&casino.CashHuntSnapshot{Phase: "hidden"}, mode, unicode) + hidden := renderCashHunt(&casino.CashHuntSnapshot{Phase: "hidden"}, mode, unicode, "") for _, line := range strings.Split(stripANSI(hidden), "\n") { - if utf8.RuneCountInString(line) != 70 { + if utf8.RuneCountInString(line) != cashHuntBoardWidth { t.Fatalf("shuffle banner width changed: %q", line) } } + if mode == "xterm256" { + if !strings.Contains(hidden, color.FgCode("xterm256", 196)) { + t.Fatal("hidden gradient should start on red") + } + if !strings.Contains(hidden, color.FgCode("xterm256", 129)) { + t.Fatal("hidden gradient should end on purple") + } + } } } } + +// TestCashHuntHeader pins the board header contents: difficulty left, title +// centered, top multiplier right, and the RTP readout only when a house-edge +// item was carried (the renderer receives an empty rtp otherwise). +func TestCashHuntHeader(t *testing.T) { + s := &casino.CashHuntSnapshot{Phase: "preview", Risk: "medium"} + s.Squares[0] = 50000 + + withRTP := stripANSI(renderCashHunt(s, "none", true, "98.00%")) + header := strings.Split(withRTP, "\n")[2] + if !strings.Contains(header, "MEDIUM 98.00%") || !strings.Contains(header, "CASH HUNT") || !strings.Contains(header, "TOP PRIZE: 50000x") { + t.Fatalf("header row wrong: %q", header) + } + + withoutRTP := stripANSI(renderCashHunt(s, "none", true, "")) + header = strings.Split(withoutRTP, "\n")[2] + if strings.Contains(header, "98") { + t.Fatalf("header showed RTP without a house-edge item: %q", header) + } +} + +// TestCashHuntHeaderRTPWithHouseEdgeItem verifies the full path: carrying a +// house-edge item makes the board header show the RTP beside the difficulty, +// at the item's precision. +func TestCashHuntHeaderRTPWithHouseEdgeItem(t *testing.T) { + g, s, conn := houseEdgeGame(t, "name: Vault\ncasino_tables:\n - id: cash_hunt\n game: cash_hunt\n") + s.Player.Options = map[string]any{"color": "none", "casino_hints": "off"} + writeHouseEdgeManual(t, g, s, 2) + g.executePlay(s, []string{"cash", "hunt"}, "play cash hunt") + g.executeBet(s, []string{"1"}, "bet 1") + text := stripANSI(string(conn.data)) + if !strings.Contains(text, "EASY 98.00%") { + t.Fatalf("header missing item RTP readout:\n%s", text) + } +} |
