diff options
Diffstat (limited to 'internal/casino/baccarat.go')
| -rw-r--r-- | internal/casino/baccarat.go | 106 |
1 files changed, 20 insertions, 86 deletions
diff --git a/internal/casino/baccarat.go b/internal/casino/baccarat.go index 164d0ff..b762b6f 100644 --- a/internal/casino/baccarat.go +++ b/internal/casino/baccarat.go @@ -3,14 +3,13 @@ package casino import ( "fmt" "math/rand" - "sync" ) -type baccaratPhase string - +// Baccarat uses the shared table phases; these aliases keep the call sites +// readable. const ( - baccaratWaiting baccaratPhase = "waiting" - baccaratBetting baccaratPhase = "betting" + baccaratWaiting = phaseWaiting + baccaratBetting = phaseBetting ) // baccaratSpots are the outcomes a participant may wager on. @@ -36,38 +35,27 @@ type baccaratPlayer struct { func (p *baccaratPlayer) participantPtr() *Participant { return &p.Participant } type baccaratTable struct { - mu sync.Mutex - tableBase - Rules BaccaratConfig - players seatSet[*baccaratPlayer] - phase baccaratPhase - window bettingWindow - shoe *shoe + tableCore[*baccaratPlayer] + Rules BaccaratConfig + shoe *shoe } func newBaccaratTable(roomID int, cfg TableConfig, rng *rand.Rand) *baccaratTable { cfg = cfg.Normalize() rules := cfg.Baccarat.Normalize() return &baccaratTable{ - tableBase: tableBase{RoomID: roomID, Config: cfg}, Rules: rules, - players: newSeatSet[*baccaratPlayer](), phase: baccaratWaiting, - shoe: newShoe(rules.Decks, rules.ShuffleAt, rng), + tableCore: newTableCore[*baccaratPlayer](&tableBase{RoomID: roomID, Config: cfg}), + Rules: rules, + shoe: newShoe(rules.Decks, rules.ShuffleAt, rng), } } func (t *baccaratTable) menuEvent(name string) Event { - e := t.private(name, t.menu()) - e.Color = "casino_menu" - e.Menu = &MenuView{Kind: MenuBaccaratBet, Commands: []MenuCommand{ + return t.betMenuEvent(name, MenuBaccaratBet, []MenuCommand{ {Command: "bet <amount>", Desc: "Place a wager (min/max accepted)"}, {Command: "bet <amount> on player|banker|tie", Desc: "Wager on a specific outcome"}, {Command: "stop", Desc: "Leave the table"}, - }} - return e -} - -func (t *baccaratTable) menu() string { - return "New baccarat hand! Place your bet." + }) } func (t *baccaratTable) join(name string) []Event { @@ -79,8 +67,7 @@ func (t *baccaratTable) join(name string) []Event { if t.players.count() >= t.Config.MaxPlayers { return []Event{t.private(name, "That baccarat table is full.")} } - t.players.add(name, &baccaratPlayer{Participant: Participant{Name: name, Connected: true}}) - events := []Event{t.playerAction(name, fmt.Sprintf("%s sits down.", name), "You sit down.")} + events := []Event{t.addSeatLocked(name, &baccaratPlayer{Participant: Participant{Name: name, Connected: true}})} events = append(events, t.menuEvent(name)) return events } @@ -97,12 +84,9 @@ func (t *baccaratTable) leave(name string) []Event { if p.HasBet { return []Event{t.private(name, "You're in the middle of a baccarat round!")} } - t.players.remove(name) + t.removeSeatLocked(name) events := []Event{t.playerAction(name, fmt.Sprintf("%s stands up.", name), "You stand up.")} - if t.players.count() == 0 { - events = append(events, t.event("The baccarat table closes.", true)) - } - return events + return t.closeIfEmptyLocked(events) } func (t *baccaratTable) bet(name, spot string, amount int, wallet Wallet) []Event { @@ -135,11 +119,7 @@ func (t *baccaratTable) bet(name, spot string, amount int, wallet Wallet) []Even events := []Event{t.playerAction(name, fmt.Sprintf("%s bets %d credits on %s.", name, amount, spot), fmt.Sprintf("You bet %d credits on %s.", amount, spot))} - if t.players.count() > 1 && t.phase == baccaratWaiting { - t.phase = baccaratBetting - t.window.open(t.Config.BettingTicks) - events = append(events, t.event(fmt.Sprintf("Baccarat betting is open for %d ticks.", t.Config.BettingTicks), true)) - } + events = t.openBettingLocked(events) if allBet(t.players.participants()) { events = append(events, t.deal()...) } @@ -152,20 +132,7 @@ func (t *baccaratTable) tick() []Event { if t.phase != baccaratBetting { return nil } - sitOuts, resolve, pending := t.window.advance(t.players.participants()) - if pending { - return nil - } - var events []Event - for _, name := range sitOuts { - events = append(events, t.event(fmt.Sprintf("%s sits out this baccarat round.", name), true)) - } - if resolve { - events = append(events, t.deal()...) - } else { - t.resetRound() - } - return events + return t.advanceBettingLocked(t.deal, t.resetRound) } func (t *baccaratTable) action(name, action string) []Event { @@ -291,18 +258,9 @@ func (t *baccaratTable) markDisconnected(name string) []Event { if p := t.players.get(name); p != nil && p.HasBet && p.Wallet != nil { p.Wallet.RefundOutstanding() } - t.players.remove(name) + t.removeSeatLocked(name) events := []Event{t.event(fmt.Sprintf("%s stands up.", name), true)} - if t.players.count() == 0 { - events = append(events, t.event("The baccarat table closes.", true)) - } - return events -} - -func (t *baccaratTable) hasParticipant(name string) bool { - t.mu.Lock() - defer t.mu.Unlock() - return t.players.has(name) + return t.closeIfEmptyLocked(events) } // baccaratTotal scores a hand modulo 10. @@ -431,31 +389,7 @@ func baccaratResultMessages(name, result string, payout int) (string, string) { func (t *baccaratTable) refundAll() []Event { t.mu.Lock() defer t.mu.Unlock() - var events []Event - for _, p := range t.players.ordered() { - if !p.HasBet || p.Wallet == nil { - continue - } - name := p.Name - chips, credits, err := p.Wallet.RefundOutstanding() - refund := chips + credits - if err != nil || refund <= 0 { - if err != nil { - events = append(events, t.private(name, "Shutdown refund could not be persisted; the stake is recorded for recovery.")) - } - continue - } - events = append(events, t.playerAction(name, - fmt.Sprintf("%s is refunded %d as the casino closes.", name, refund), - fmt.Sprintf("The house refunds your %d stake for the shutdown.", refund))) - } + events := t.refundAllLocked() t.resetRound() return events } - -// setRoom updates the event-routing room after a room-ID rekey. Locked. -func (t *baccaratTable) setRoom(roomID int) { - t.mu.Lock() - defer t.mu.Unlock() - t.tableBase.setRoom(roomID) -} |
