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 casino
// countdown tracks tick-based deadlines for table phases (betting windows,
// insurance offers, and player action timeouts).
type countdown struct {
clock int
deadline int
}
func (c *countdown) start(ticks int) { c.clock, c.deadline = 0, ticks }
func (c *countdown) stop() { c.clock, c.deadline = 0, 0 }
func (c *countdown) tick() { c.clock++ }
func (c *countdown) expired() bool { return c.deadline > 0 && c.clock >= c.deadline }
// bettingWindow is the timed betting phase shared by multiplayer table games.
// The owning table opens it when the first wager lands with multiple seated
// players and decides the outcome (deal/resolve vs reset) from advance.
type bettingWindow struct {
timer countdown
}
func (w *bettingWindow) open(ticks int) { w.timer.start(ticks) }
func (w *bettingWindow) close() { w.timer.stop() }
// advance moves the window one tick. pending means the window is still open;
// otherwise resolve reports whether wagers are down and the round should play
// out, and sitOuts names the seated players who never bet.
func (w *bettingWindow) advance(seats []*Participant) (sitOuts []string, resolve, pending bool) {
w.timer.tick()
if allBet(seats) {
return nil, true, false
}
if !w.timer.expired() {
return nil, false, true
}
return sitOutNames(seats), anyBet(seats), false
}
// allBet reports whether at least one connected participant exists and every
// connected participant has placed a bet. Disconnected participants never
// hold a round open.
func allBet(seats []*Participant) bool {
connected := false
for _, p := range seats {
if !p.Connected {
continue
}
connected = true
if !p.HasBet {
return false
}
}
return connected
}
// anyBet reports whether any participant, connected or not, has a wager
// committed to the current round.
func anyBet(seats []*Participant) bool {
for _, p := range seats {
if p.HasBet {
return true
}
}
return false
}
// sitOutNames lists participants without a bet, in seat order.
func sitOutNames(seats []*Participant) []string {
var names []string
for _, p := range seats {
if !p.HasBet {
names = append(names, p.Name)
}
}
return names
}
// clearBets resets per-round betting state on every participant.
func clearBets(seats []*Participant) {
for _, p := range seats {
p.HasBet = false
p.Wager = Wager{}
}
}
|