aboutsummaryrefslogtreecommitdiff
path: root/internal/game/render_blackjack_felt_test.go
blob: a67251a8bc12637de7b23ca256894cf6a10c8ad8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package game

import (
	"strings"
	"testing"

	"thehouseoficarus/internal/casino"
	"thehouseoficarus/internal/color"
)

func TestBlackjackRulesFeltGeometryAndPhrases(t *testing.T) {
	cfg := casino.TableConfig{ID: "midnight", Game: casino.GameBlackjack, MinBet: 100, MaxBet: 10000, MaxPlayers: 6, BettingTicks: 18,
		Blackjack: casino.BlackjackConfig{ActionTicks: 15, DoubleSplitBlackjack: &[]bool{false}[0]}}
	for _, unicode := range []bool{false, true} {
		art := renderBlackjackRulesFelt(cfg, "none", unicode)
		rows := strings.Split(strings.TrimSuffix(art, "\n"), "\n")
		if len(rows) != 21 {
			t.Fatalf("felt height %d", len(rows))
		}
		for _, row := range rows {
			if color.VisibleLen(row) != 77 {
				t.Fatalf("misaligned (%d): %s", color.VisibleLen(row), row)
			}
		}
		for _, want := range []string{
			"BLACKJACK PAYS 3 TO 2", "DEALER MUST STAND ON 17 AND DRAW TO 16", "INSURANCE PAYS 2 TO 1",
			"THE SHOE", "PAYS", "DOUBLE & SPLIT", "HOUSE",
			"DECKS", "SHUFFLE AT", "25% REMAINING", "RESHUFFLE MID-ROUND", "HOLE CARD",
			"ORDINARY WIN", "SPLIT+DOUBLE 21", "DOUBLE", "ANY TWO, ONE CARD", "MAX HANDS", "ONE CARD, NO HITS",
			"SURRENDER", "NOT OFFERED", "100-10000 CREDITS", "18 TICKS", "15 TICKS",
		} {
			if !strings.Contains(art, want) {
				t.Fatalf("missing %q in unicode=%v felt", want, unicode)
			}
		}
		// The raw dump's phrases and fixed engine rules must not leak onto the felt.
		for _, stale := range []string{"Number of decks", "Dealer hole card / peek:", "FRACTIONS", "BJ CHECK", "HOUSE BLACKJACK"} {
			if strings.Contains(art, stale) {
				t.Fatalf("stale prose %q on felt", stale)
			}
		}
	}
}

func TestBlackjackRulesFeltFollowsConfig(t *testing.T) {
	yes, no := true, false
	cfg := casino.TableConfig{ID: "high", Game: casino.GameBlackjack, MinBet: 5, MaxBet: 500,
		Blackjack: casino.BlackjackConfig{Decks: 1, BlackjackPayout: 1.2, DealerHitSoft17: &yes, Surrender: &yes,
			ShuffleAt: 0.5, MaxSplitHands: 2, DoubleAfterSplit: &no, ResplitAces: &yes, SplitUnlikeTenValues: &no,
			DoubleSplitBlackjack: &no, InsurancePayout: 2}}
	art := renderBlackjackRulesFelt(cfg, "none", true)
	for _, want := range []string{"BLACKJACK PAYS 6 TO 5", "DEALER HITS SOFT 17", "LATE, TWO CARDS", "50% REMAINING",
		"AFTER SPLIT                      NO", "RESPLIT ACES                    YES", "PAIRS               IDENTICAL RANKS",
		"SPLIT+DOUBLE 21                 1:1", "5-500 CREDITS"} {
		if !strings.Contains(art, want) {
			t.Fatalf("missing %q: %s", want, art)
		}
	}
}

func TestBlackjackJoinPrintsFeltNotProse(t *testing.T) {
	g := &Game{Casino: casino.NewManager(1)}
	g.Casino.Join(1, casino.TableConfig{ID: "bj", Game: casino.GameBlackjack, BettingTicks: 2}, "alice")
	events := g.Casino.Join(1, casino.TableConfig{ID: "bj", Game: casino.GameBlackjack, BettingTicks: 2}, "bob")
	found := false
	for _, e := range events {
		if view, ok := e.Snapshot.(*casino.BlackjackRulesView); ok {
			found = true
			art := renderBlackjackRulesFelt(view.Config, "none", true)
			if !strings.Contains(art, "BLACKJACK PAYS 3 TO 2") || !strings.Contains(art, "DECKS") {
				t.Fatal("rules felt missing phrases", art)
			}
			if e.Message != "" {
				t.Fatal("rules event carries prose", e.Message)
			}
		}
		if strings.Contains(e.Message+e.PrivateMessage, "Number of decks") {
			t.Fatal("raw rules prose leaked onto join", e)
		}
	}
	if !found {
		t.Fatal("join did not attach the rules felt")
	}
}