diff options
| author | historia <[not public]> | 2026-10-05 20:00:02 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-10-05 20:00:02 -0400 |
| commit | 4bc1daaf259e0c19c5fe4a12ec8bc7f6e5a735c1 (patch) | |
| tree | f7ea1da2f88f37c44b937aaaf1fd12c722811147 /internal/casino/pai_gow.go | |
| parent | a5447965e7808d656a5e5d9326a9ca0231148f85 (diff) | |
| download | thehouseoficarus-4bc1daaf259e0c19c5fe4a12ec8bc7f6e5a735c1.tar.gz | |
feat: terminal talk action, typed pai gow poker phase
Diffstat (limited to 'internal/casino/pai_gow.go')
| -rw-r--r-- | internal/casino/pai_gow.go | 66 |
1 files changed, 33 insertions, 33 deletions
diff --git a/internal/casino/pai_gow.go b/internal/casino/pai_gow.go index 8f581db..55dc601 100644 --- a/internal/casino/pai_gow.go +++ b/internal/casino/pai_gow.go @@ -83,7 +83,7 @@ type paiGowTable struct { mu sync.Mutex rng *rand.Rand players []*pgPlayer // stable seat/deal/settlement order - phase string + phase tablePhase ticks int dealer []card dealerSplit pgSplit @@ -91,7 +91,7 @@ type paiGowTable struct { } func newPaiGowTable(room int, c TableConfig, rng *rand.Rand) tableGame { - return &paiGowTable{tableBase: &tableBase{RoomID: room, Config: c}, rng: rng, phase: "waiting"} + return &paiGowTable{tableBase: &tableBase{RoomID: room, Config: c}, rng: rng, phase: phaseWaiting} } func (t *paiGowTable) base() *tableBase { return t.tableBase } func (t *paiGowTable) player(name string) *pgPlayer { @@ -133,7 +133,7 @@ func (t *paiGowTable) seats() []string { func (t *paiGowTable) state() string { t.mu.Lock() defer t.mu.Unlock() - return t.phase + return string(t.phase) } func (t *paiGowTable) hintsLocked(name string) []MenuCommand { p := t.player(name) @@ -143,7 +143,7 @@ func (t *paiGowTable) hintsLocked(name string) []MenuCommand { commands := []MenuCommand{} faceUp := t.Config.PaiGow.Variant == PaiGowFaceUp switch t.phase { - case "waiting", "betting": + case phaseWaiting, phaseBetting: if p.main.Total == 0 { // Side bets are placed before the main wager: the main bet is what // deals, so there is no later chance to add them. @@ -158,7 +158,7 @@ func (t *paiGowTable) hintsLocked(name string) []MenuCommand { if p.main.Total > 0 || p.fortune.Total > 0 || p.pushace.Total > 0 { commands = append(commands, MenuCommand{Command: "unbet", Desc: "Take back all your wagers before the deal"}) } - case "setting": + case phaseSetting: if p.main.Total > 0 && !p.ready { if p.pending.high != nil { commands = append(commands, MenuCommand{Command: "set", Desc: "Lock this arrangement and reveal the dealer"}) @@ -173,7 +173,7 @@ func (t *paiGowTable) hintsLocked(name string) []MenuCommand { commands = append(commands, MenuCommand{Command: "autoset on", Desc: "Set a legal arrangement immediately"}) } } - case "settling": + case phaseSettling: commands = append(commands, MenuCommand{Command: "settle", Desc: "Retry the same pending payment"}) } return append(commands, MenuCommand{Command: "table", Desc: "View the felt"}, MenuCommand{Command: "rules", Desc: "Learn Pai Gow"}, MenuCommand{Command: "stop", Desc: "Leave after finishing your wager"}) @@ -187,7 +187,7 @@ func (t *paiGowTable) wagers(name string) []WagerRow { t.mu.Lock() defer t.mu.Unlock() p := t.player(name) - if p == nil || t.phase == "setting" || t.phase == "settling" { + if p == nil || t.phase == phaseSetting || t.phase == phaseSettling { return nil } rows := []WagerRow{{Bet: "main", Payout: "See the felt", Win: "Beat both dealer hands"}, {Bet: "fortune", Payout: "See Fortune felt", Win: "Best seven-card bonus; independent of main result"}} @@ -241,7 +241,7 @@ func pgCardNums(hand, all []card) []int { } func (t *paiGowTable) statusLocked(name string, showFelt bool) []Event { - s := &PaiGowSnapshot{Config: t.Config, Phase: t.phase, ShowFelt: showFelt} + s := &PaiGowSnapshot{Config: t.Config, Phase: string(t.phase), ShowFelt: showFelt} if p := t.player(name); p != nil { // The dealt hand only appears before the player has arranged anything; // afterwards the board shows the arrangement or the waiting message. @@ -266,14 +266,14 @@ func (t *paiGowTable) statusLocked(name string, showFelt bool) []Event { s.PreviewLowNums = pgCardNums(split.low, p.cards) } s.Result = p.result - if p.ready && t.phase == "setting" && p.showdown == nil { + if p.ready && t.phase == phaseSetting && p.showdown == nil { s.Result = "Hand set — waiting for the other players." } - if t.phase == "settling" && !p.paid && p.main.Total > 0 { + if t.phase == phaseSettling && !p.paid && p.main.Total > 0 { s.Result += "; PAYMENT PENDING (not yet credited)" } } - if t.phase == "settling" || t.phase == "waiting" || t.phase == "setting" && t.Config.PaiGow.Variant == PaiGowFaceUp { + if t.phase == phaseSettling || t.phase == phaseWaiting || t.phase == phaseSetting && t.Config.PaiGow.Variant == PaiGowFaceUp { s.DealerHigh = pgViews(t.dealerSplit.high) s.DealerLow = pgViews(t.dealerSplit.low) if len(t.dealerSplit.high) > 0 { @@ -323,7 +323,7 @@ func (t *paiGowTable) leave(name string) []Event { return nil } // Cards in flight must finish; before the deal the wagers are returned. - if t.phase == "setting" || t.phase == "settling" { + if t.phase == phaseSetting || t.phase == phaseSettling { return []Event{t.private(name, "You're in the middle of a Pai Gow round!")} } if p.wallet != nil && (p.main.Total > 0 || p.fortune.Total > 0 || p.pushace.Total > 0) { @@ -353,7 +353,7 @@ func (t *paiGowTable) bet(name, spot string, amount int, w Wallet) []Event { return nil } fail := func(s string) []Event { return []Event{t.private(name, s)} } - if t.phase != "waiting" && t.phase != "betting" { + if t.phase != phaseWaiting && t.phase != phaseBetting { return fail("Betting is closed.") } if spot == "" { @@ -406,8 +406,8 @@ func (t *paiGowTable) bet(name, spot string, amount int, w Wallet) []Event { } else { p.fortune = stake } - if spot == "main" && t.phase == "waiting" { - t.phase = "betting" + if spot == "main" && t.phase == phaseWaiting { + t.phase = phaseBetting t.ticks = t.Config.BettingTicks t.dealer = nil t.dealerSplit = pgSplit{} @@ -475,7 +475,7 @@ func (t *paiGowTable) dealLocked() []Event { t.dealer = packets[6] t.dealerSplit = pgHouseRules(t.dealer, t.a2345High()) t.tie = [2]card{deck.draw(), deck.draw()} - t.phase = "setting" + t.phase = phaseSetting t.ticks = t.Config.PaiGow.ActionTicks // Face Up ace-high settles immediately: there is no decision to make. // Still assign every player's seven cards for independent Fortune/Envy. @@ -511,11 +511,11 @@ func (t *paiGowTable) action(name, action string) []Event { if action == "paytable" || action == "status" { return t.statusLocked(name, false) } - if t.phase == "settling" && action == "settle" { + if t.phase == phaseSettling && action == "settle" { return t.payLocked() } if action == "leave_after" { - if t.phase == "setting" || t.phase == "settling" { + if t.phase == phaseSetting || t.phase == phaseSettling { p.leaveAfter = true return []Event{t.private(name, "You'll leave after this round. Your current hand still needs your actions.")} } @@ -525,7 +525,7 @@ func (t *paiGowTable) action(name, action string) []Event { return []Event{t.private(name, "Pai Gow has no sit-out; use stop to leave after the round.")} } if action == "autoset" || strings.HasPrefix(action, "autoset ") { - if t.phase != "waiting" && t.phase != "betting" && t.phase != "setting" { + if t.phase != phaseWaiting && t.phase != phaseBetting && t.phase != phaseSetting { return []Event{t.private(name, "Autoset can only change before the showdown.")} } rest := strings.TrimSpace(strings.TrimPrefix(action, "autoset")) @@ -548,13 +548,13 @@ func (t *paiGowTable) action(name, action string) []Event { if strings.HasPrefix(action, "unbet") { return t.unbetLocked(p) } - if action == "deal" && (t.phase == "waiting" || t.phase == "betting") && p.main.Total > 0 { + if action == "deal" && (t.phase == phaseWaiting || t.phase == phaseBetting) && p.main.Total > 0 { if t.allBetLocked() { return t.dealLocked() } return []Event{t.private(name, "Waiting for the other bettors; the window closes on the timer.")} } - if t.phase != "setting" || p.main.Total == 0 { + if t.phase != phaseSetting || p.main.Total == 0 { return []Event{t.private(name, "Place your bets, then deal; set cards only after they are dealt.")} } if p.ready { @@ -600,7 +600,7 @@ func (t *paiGowTable) action(name, action string) []Event { return t.statusLocked(name, false) } func (t *paiGowTable) prepareSettlementLocked() []Event { - t.phase = "settling" + t.phase = phaseSettling for _, p := range t.players { if p.main.Total == 0 { continue @@ -720,7 +720,7 @@ func (t *paiGowTable) payLocked() []Event { } return withSettlementReceipts(events, receipts) } - t.phase = "waiting" + t.phase = phaseWaiting kept := t.players[:0] for _, p := range t.players { p.main = Wager{} @@ -741,9 +741,9 @@ func (t *paiGowTable) tick() []Event { t.mu.Lock() defer t.mu.Unlock() switch t.phase { - case "settling": + case phaseSettling: return t.payLocked() - case "betting": + case phaseBetting: if t.allBetLocked() { return t.dealLocked() } @@ -759,7 +759,7 @@ func (t *paiGowTable) tick() []Event { return nil } return t.finishBettingLocked() - case "setting": + case phaseSetting: // A lone player has no time limit; wait for them to set. if t.activePlayersLocked() <= 1 { return nil @@ -791,7 +791,7 @@ func (t *paiGowTable) markDisconnected(name string) []Event { } // Before the deal nothing is revealed, so a disconnect returns the // wagers and frees the seat; the remaining bettors may then be dealt. - if t.phase == "waiting" || t.phase == "betting" { + if t.phase == phaseWaiting || t.phase == phaseBetting { if p.wallet != nil { // Nothing has been dealt, so the stake is refunded; a failed refund // leaves it pending for startup recovery, but the seat is still freed. @@ -803,7 +803,7 @@ func (t *paiGowTable) markDisconnected(name string) []Event { } p.disconnected = true p.ready = true - if t.phase == "setting" { + if t.phase == phaseSetting { if p.split.high == nil { p.split = pgHouseRules(p.cards, t.a2345High()) } @@ -818,7 +818,7 @@ func (t *paiGowTable) markDisconnected(name string) []Event { // or disconnects: the cards deal when every remaining active player has bet, // and a table with no main wager returns to waiting. func (t *paiGowTable) afterSeatChangeLocked() []Event { - if t.phase != "betting" { + if t.phase != phaseBetting { return nil } if t.allBetLocked() { @@ -879,7 +879,7 @@ func (t *paiGowTable) refundSideBetsLocked(p *pgPlayer) []Event { // resetTableLocked clears a round that closed without a main wager and // returns the table to waiting. Callers have already refunded any side bets. func (t *paiGowTable) resetTableLocked() { - t.phase = "waiting" + t.phase = phaseWaiting t.ticks = 0 t.dealer = nil t.dealerSplit = pgSplit{} @@ -920,7 +920,7 @@ func (t *paiGowTable) seatedPlayersLocked() int { // PayCredits with the original stake handles so the ledger entries resolve in // the same save; wagers are only cleared on success. func (t *paiGowTable) unbetLocked(p *pgPlayer) []Event { - if t.phase != "waiting" && t.phase != "betting" { + if t.phase != phaseWaiting && t.phase != phaseBetting { return []Event{t.private(p.name, "You can only take back bets before the cards are dealt.")} } total, ids := 0, []string{} @@ -943,8 +943,8 @@ func (t *paiGowTable) unbetLocked(p *pgPlayer) []Event { } } p.main, p.fortune, p.pushace = Wager{}, Wager{}, Wager{} - if !t.anyMainLocked() && t.phase == "betting" { - t.phase = "waiting" + if !t.anyMainLocked() && t.phase == phaseBetting { + t.phase = phaseWaiting t.ticks = 0 } return append([]Event{t.private(p.name, fmt.Sprintf("You take back %d credits.", total))}, t.statusLocked(p.name, false)...) |
