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")
}
}
|