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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
package casino
import "testing"
// TestBaccaratSideBetsRideWithMain pins the multi-wager contract: a side bet
// is committed before the main wager, both settle in the same round, and only
// the main wager deals the cards.
func TestBaccaratSideBetsRideWithMain(t *testing.T) {
cfg := TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}}
table := newBaccaratTestTable(cfg)
table.join("alice")
forceShoe(table, baccaratCards("5 5 5 5 5 5")...)
w := &testWallet{credits: 1000}
if events := table.bet("alice", "player_pair", 10, w); hasMessage(events, "New baccarat hand!") {
t.Fatal("side bet alone dealt a round")
}
if table.players.get("alice").HasBet {
t.Fatal("side bet counted as the round's main wager")
}
events := table.bet("alice", "player", 10, w)
if !hasMessage(events, "New baccarat hand!") {
t.Fatalf("main wager did not deal: %+v", events)
}
// Player and banker tie at 5; the player main pushes and the player pair wins 11:1.
if w.paid != 130 {
t.Fatalf("paid=%d, want 130", w.paid)
}
var labels []string
for _, e := range events {
for _, line := range e.Settlement {
labels = append(labels, line.Label)
}
}
if len(labels) != 2 || labels[0] != "player" || labels[1] != "player_pair" {
t.Fatalf("settlement labels=%v, want [player player_pair]", labels)
}
// The snapshot carries both bets for the table view.
var snapshot *BaccaratSnapshot
for _, e := range events {
if s, ok := e.Snapshot.(*BaccaratSnapshot); ok && len(s.Bets) > 0 {
snapshot = s
}
}
if snapshot == nil || len(snapshot.Bets) != 2 ||
snapshot.Bets[0].Spot != "player" || snapshot.Bets[0].Amount != 10 ||
snapshot.Bets[1].Spot != "player_pair" || snapshot.Bets[1].Amount != 10 {
t.Fatalf("snapshot bets=%+v", snapshot)
}
}
// A side wager may not follow the main wager: the main is the deal trigger.
func TestBaccaratSideBetAfterMainRefused(t *testing.T) {
table := newBaccaratTestTable(TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}, MaxPlayers: 2})
table.join("alice")
table.join("bob")
w := &testWallet{credits: 1000}
table.bet("alice", "player", 10, w)
if events := table.bet("alice", "player_pair", 10, w); !hasMessage(events, "before your main wager") {
t.Fatalf("side bet after main accepted: %+v", events)
}
}
// A bare "bet" repeats the remembered side bets and the main wager together.
func TestBaccaratRebetAll(t *testing.T) {
cfg := TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}}
table := newBaccaratTestTable(cfg)
table.join("alice")
forceShoe(table, baccaratCards("5 5 5 5 5 5")...)
table.bet("alice", "player_pair", 10, &testWallet{credits: 1000})
table.bet("alice", "player", 10, &testWallet{credits: 1000})
forceShoe(table, baccaratCards("5 5 5 5 5 5")...)
w := &testWallet{credits: 1000}
events := table.rebetAll("alice", w)
if !hasMessage(events, "New baccarat hand!") || w.paid != 130 {
t.Fatalf("rebet all did not replay both wagers: paid=%d events=%+v", w.paid, events)
}
}
// unbet returns the main wager and every side bet in one step.
func TestBaccaratUnbetReturnsAllWagers(t *testing.T) {
table := newBaccaratTestTable(TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}})
table.join("alice")
w := &testWallet{credits: 1000}
table.bet("alice", "player_pair", 10, w)
table.bet("alice", "banker_pair", 15, w)
if events := table.unbetAllLocked("alice"); !hasMessage(events, "take back 25") {
t.Fatalf("unbet did not return both side stakes: %+v", events)
}
if w.paid != 25 || len(w.open) != 0 {
t.Fatalf("paid=%d open=%d, want 25/0", w.paid, len(w.open))
}
}
// A side-only seat is not part of the round: the timer returns the side stake
// and the other seat's main wager still deals.
func TestBaccaratSideOnlySeatRefundedOnTimeout(t *testing.T) {
cfg := TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}, MaxPlayers: 2, BettingTicks: 2}
table := newBaccaratTestTable(cfg)
table.join("alice")
table.join("bob")
wa, wb := &testWallet{credits: 1000}, &testWallet{credits: 1000}
table.bet("alice", "player_pair", 10, wa)
table.bet("bob", "player", 10, wb)
forceShoe(table, baccaratCards("5 5 5 5 5 5")...)
var events []Event
for i := 0; i < 4 && !hasMessage(events, "New baccarat hand!"); i++ {
events = append(events, table.tick()...)
}
if !hasMessage(events, "New baccarat hand!") {
t.Fatalf("side-only seat held the round open: %+v", events)
}
if wa.paid != 10 {
t.Fatalf("alice side stake not returned: paid=%d", wa.paid)
}
if !hasMessage(events, "side bets is returned") {
t.Fatalf("missing side-bet refund notice: %+v", events)
}
}
|