aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/roulette.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-29 19:48:32 -0400
committerhistoria <[not public]>2026-09-29 19:48:32 -0400
commitffc7b582e9c14fdc2e579b9239b5ff7ad9a0d90a (patch)
treee286210755094b41025f2947e412e05e59ec2ac9 /internal/casino/roulette.go
parent624626b9a10ae47cf7d5f6e91765570ed759bd74 (diff)
downloadthehouseoficarus-ffc7b582e9c14fdc2e579b9239b5ff7ad9a0d90a.tar.gz
feat: roulette history tracker
Diffstat (limited to 'internal/casino/roulette.go')
-rw-r--r--internal/casino/roulette.go30
1 files changed, 25 insertions, 5 deletions
diff --git a/internal/casino/roulette.go b/internal/casino/roulette.go
index 109306a..44c5f30 100644
--- a/internal/casino/roulette.go
+++ b/internal/casino/roulette.go
@@ -467,11 +467,15 @@ type roulettePlayer struct {
func (p *roulettePlayer) participantPtr() *Participant { return &p.Participant }
+// Keep a small, table-local window of completed spins (oldest first).
+const rouletteHistoryLimit = 50
+
type rouletteTable struct {
tableCore[*roulettePlayer]
rng *rand.Rand
spinRemaining int
lastResult *RouletteSnapshot
+ history []string
}
func newRouletteTable(room int, cfg TableConfig, rng *rand.Rand) *rouletteTable {
@@ -479,7 +483,7 @@ func newRouletteTable(room int, cfg TableConfig, rng *rand.Rand) *rouletteTable
return &rouletteTable{tableCore: newTableCore[*roulettePlayer](&tableBase{RoomID: room, Config: cfg}), rng: rng}
}
func (t *rouletteTable) view() *RouletteSnapshot {
- s := &RouletteSnapshot{DoubleZero: t.Config.Roulette.DoubleZero, Racetrack: t.Config.Roulette.Racetrack, Phase: string(t.phase), Wheel: rouletteWheel(t.Config.Roulette.DoubleZero)}
+ s := &RouletteSnapshot{DoubleZero: t.Config.Roulette.DoubleZero, Racetrack: t.Config.Roulette.Racetrack, Phase: string(t.phase), Wheel: rouletteWheel(t.Config.Roulette.DoubleZero), History: append([]string(nil), t.history...)}
for _, p := range t.players.ordered() {
s.Players = append(s.Players, p.Name)
}
@@ -555,12 +559,14 @@ func (t *rouletteTable) bet(name, spot string, amount int, w Wallet) []Event {
}
p.HasBet, p.Wager, p.Wallet, p.lastSpot, p.lastBet, p.SittingOut = true, wager, w, spot, amount, false
events := []Event{t.playerAction(name, fmt.Sprintf("%s bets %d on %s.", name, amount, spot), fmt.Sprintf("You bet %d on %s.", amount, spot))}
- // Always offer a real betting phase, even with only one player.
+ // Always offer a real betting phase, even with only one player. The
+ // board is not attached here: it is sent once per round by the menu event
+ // (join, settlement, or an explicit "table"), so placing a wager never
+ // redraws it.
if t.phase == phaseWaiting {
t.phase = phaseBetting
t.window.open(t.Config.BettingTicks)
e := t.event(fmt.Sprintf("Roulette betting is open for %d ticks.", t.Config.BettingTicks), true)
- e.Snapshot = t.view()
events = append(events, e)
}
return events
@@ -601,9 +607,20 @@ func (t *rouletteTable) settle() []Event {
wheel := rouletteWheel(t.Config.Roulette.DoubleZero)
index := t.rng.Intn(len(wheel))
pocket := wheel[index]
+ t.history = append(t.history, pocket)
+ if len(t.history) > rouletteHistoryLimit {
+ copy(t.history, t.history[len(t.history)-rouletteHistoryLimit:])
+ t.history = t.history[:rouletteHistoryLimit]
+ }
s := t.view()
s.Phase = "result"
- s.Pockets = [3]string{wheel[(index+len(wheel)-1)%len(wheel)], pocket, wheel[(index+1)%len(wheel)]}
+ // Show the winning pocket with two physical neighbours on each side so
+ // the result reads like a slice of the real wheel.
+ n := len(wheel)
+ s.Pockets = [5]string{
+ wheel[(index-2+n)%n], wheel[(index-1+n)%n], pocket,
+ wheel[(index+1)%n], wheel[(index+2)%n],
+ }
t.lastResult = s
e := t.event("The ball lands in "+pocket+"!", true)
e.Snapshot = s
@@ -728,12 +745,15 @@ type RouletteSnapshot struct {
// neighbours bets, so the renderer draws the racetrack panel.
Racetrack bool
Phase string
- Pockets [3]string // physical wheel neighbors, not numerical neighbors
+ Pockets [5]string // winning pocket and two physical wheel neighbours each side
Players []string
// Wheel is the pocket order clockwise from the top; the renderer colors
// and places each pocket. It carries the zero count (one or two) so the
// drawn wheel always matches the configured table.
Wheel []string
+ // History is a detached copy of the last 50 completed spins, oldest first.
+ // It is table-local, survives round resets, and is not persisted on restart.
+ History []string
}
func (*RouletteSnapshot) snapshot() {}