package casino import "fmt" // maxBetUnlimited is the MaxBet sentinel meaning "no wager cap". const maxBetUnlimited = int(^uint(0) >> 1) // betRangeText describes the accepted wager range; the unlimited sentinel is // rendered as "no maximum" instead of a machine-sized integer. func betRangeText(minBet, maxBet int) string { if maxBet == maxBetUnlimited { return fmt.Sprintf("%d or more (no maximum)", minBet) } return fmt.Sprintf("between %d and %d", minBet, maxBet) } type GameName string const ( GameSlots GameName = "slots" GameBlackjack GameName = "blackjack" GameBaccarat GameName = "baccarat" ) type BlackjackConfig struct { Decks int `yaml:"decks,omitempty"` ShuffleAt float64 `yaml:"shuffle_at,omitempty"` BlackjackPayout float64 `yaml:"blackjack_payout,omitempty"` DealerHitSoft17 *bool `yaml:"dealer_hit_soft_17,omitempty"` MaxSplitHands int `yaml:"max_split_hands,omitempty"` ResplitAces *bool `yaml:"resplit_aces,omitempty"` DoubleAfterSplit *bool `yaml:"double_after_split,omitempty"` DoubleSplitBlackjack *bool `yaml:"double_split_blackjack,omitempty"` InsurancePayout float64 `yaml:"insurance_payout,omitempty"` Surrender *bool `yaml:"surrender,omitempty"` ActionTicks int `yaml:"action_ticks,omitempty"` SplitUnlikeTenValues *bool `yaml:"split_unlike_ten_values,omitempty"` } func ruleBool(value *bool, defaultValue bool) bool { if value == nil { return defaultValue } return *value } func (c BlackjackConfig) DealerHitsSoft17() bool { return ruleBool(c.DealerHitSoft17, false) } func (c BlackjackConfig) AllowsResplitAces() bool { return ruleBool(c.ResplitAces, false) } func (c BlackjackConfig) AllowsDoubleAfterSplit() bool { return ruleBool(c.DoubleAfterSplit, true) } func (c BlackjackConfig) CountsDoubleSplitBlackjack() bool { return ruleBool(c.DoubleSplitBlackjack, true) } func (c BlackjackConfig) AllowsSurrender() bool { return ruleBool(c.Surrender, false) } func (c BlackjackConfig) AllowsUnlikeTenSplit() bool { return ruleBool(c.SplitUnlikeTenValues, true) } func (c BlackjackConfig) Normalize() BlackjackConfig { if c.Decks <= 0 { c.Decks = 8 } if c.ShuffleAt <= 0 || c.ShuffleAt >= 1 { c.ShuffleAt = 0.25 } if c.BlackjackPayout <= 0 { c.BlackjackPayout = 1.5 } if c.MaxSplitHands <= 0 { c.MaxSplitHands = 4 } if c.InsurancePayout <= 0 { c.InsurancePayout = 2 } if c.ActionTicks <= 0 { c.ActionTicks = 20 } return c } // BaccaratConfig holds punto banco house rules: shoe composition and payout // multipliers. Banker wins pay BankerPayout:1 (a 5% commission game is 0.95); // tie wins pay TiePayout:1. type BaccaratConfig struct { Decks int `yaml:"decks,omitempty"` ShuffleAt float64 `yaml:"shuffle_at,omitempty"` TiePayout float64 `yaml:"tie_payout,omitempty"` BankerPayout float64 `yaml:"banker_payout,omitempty"` } func (c BaccaratConfig) Normalize() BaccaratConfig { if c.Decks <= 0 { c.Decks = 8 } if c.ShuffleAt <= 0 || c.ShuffleAt >= 1 { c.ShuffleAt = 0.25 } if c.TiePayout <= 0 { c.TiePayout = 8 } if c.BankerPayout <= 0 { c.BankerPayout = 0.95 } return c } type TableConfig struct { ID string `yaml:"id"` Game GameName `yaml:"game"` MaxPlayers int `yaml:"max_players,omitempty"` BettingTicks int `yaml:"betting_ticks,omitempty"` MinBet int `yaml:"min_bet,omitempty"` MaxBet int `yaml:"max_bet,omitempty"` Blackjack BlackjackConfig `yaml:"blackjack,omitempty"` Baccarat BaccaratConfig `yaml:"baccarat,omitempty"` } type MachineConfig struct { ID string `yaml:"id"` Game GameName `yaml:"game"` Variant string `yaml:"variant,omitempty"` MinBet int `yaml:"min_bet,omitempty"` MaxBet int `yaml:"max_bet,omitempty"` SpinTicks int `yaml:"spin_ticks,omitempty"` Payout float64 `yaml:"payout,omitempty"` } func (c MachineConfig) Normalize() MachineConfig { if c.MinBet <= 0 { c.MinBet = 1 } if c.MaxBet <= 0 { c.MaxBet = maxBetUnlimited } if c.SpinTicks <= 0 { c.SpinTicks = 2 } if c.Variant == "" { c.Variant = "huff_and_even_more_puff" } if c.Payout <= 0 { c.Payout = 0.97 } return c } func (c TableConfig) Normalize() TableConfig { if c.MaxPlayers <= 0 { c.MaxPlayers = 8 } if c.BettingTicks <= 0 { c.BettingTicks = 20 } if c.MinBet <= 0 { c.MinBet = 1 } if c.MaxBet <= 0 { c.MaxBet = maxBetUnlimited } return c } type Wager struct { Total int Chips int Credits int } type Wallet interface { Wager(amount int) (Wager, bool) PayCredits(amount int) } type EventType string const ( EventJoined EventType = "joined" EventBetting EventType = "betting" EventBetPlaced EventType = "bet_placed" EventRoundStarted EventType = "round_started" EventResult EventType = "result" EventPayout EventType = "payout" EventTimedOut EventType = "timed_out" EventLeft EventType = "left" EventClosed EventType = "closed" ) type MenuKind string const ( MenuSlotCommands MenuKind = "slot_commands" MenuBlackjackBet MenuKind = "blackjack_bet" MenuBlackjackTurn MenuKind = "blackjack_turn" MenuBaccaratBet MenuKind = "baccarat_bet" ) // MenuView carries a structured menu alongside its plain-text Message so the // presentation layer can enrich it (balances, command colors) without parsing // message prefixes. type MenuView struct { Kind MenuKind Body string // command list (MenuSlotCommands) Title string // prompt heading (MenuBlackjackTurn) Actions []string // available commands (MenuBlackjackTurn) Commands []MenuCommand // unified command list for all casino menus } // MenuCommand is one selectable command shown in a casino menu: the typed // command text plus a short human-readable description. type MenuCommand struct { Command string Desc string } type Event struct { RoomID int TableID string Type EventType Player string Message string PrivateMessage string PrivateTo string Color string Public bool Slot *SlotSnapshot Blackjack *BlackjackSnapshot Baccarat *BaccaratSnapshot Menu *MenuView } type SlotSnapshot struct { Grid [3][5]string StoppedReels int } // CardView renders one card for any card-based table game. type CardView struct { Rank string Suit string Hidden bool } type BlackjackPlayerView struct { Name string Cards []CardView Score string } type BlackjackSnapshot struct { Dealer []CardView DealerShownScore string DealerScore string DealerRevealed bool Players []BlackjackPlayerView } // BaccaratBetView lists one participant's wager on a baccarat outcome. type BaccaratBetView struct { Name string Spot string Amount int } type BaccaratSnapshot struct { Player []CardView Banker []CardView PlayerScore string BankerScore string Bets []BaccaratBetView } type Participant struct { Name string Connected bool HasBet bool Wager Wager Wallet Wallet }