From d114c747a7672c7e4daab3a5b5f1b2f066ebc912 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Thu, 24 Sep 2026 19:31:05 -0400 Subject: feat: additional baca and bj rules variants --- internal/casino/blackjack_rules.go | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 internal/casino/blackjack_rules.go (limited to 'internal/casino/blackjack_rules.go') diff --git a/internal/casino/blackjack_rules.go b/internal/casino/blackjack_rules.go new file mode 100644 index 0000000..8bf63a8 --- /dev/null +++ b/internal/casino/blackjack_rules.go @@ -0,0 +1,66 @@ +package casino + +import ( + "fmt" + "strings" +) + +// BlackjackRulesText is the table's rule card, built from effective defaults. +// Keep fixed engine rules here too: players should not have to guess them. +func (c TableConfig) BlackjackRulesText() string { + c = c.Normalize() + b := c.Blackjack + yesNo := func(v bool) string { + if v { + return "Yes" + } + return "No" + } + dealer := "stands on" + if b.DealerHitsSoft17() { + dealer = "hits" + } + surrender := "Not offered" + if b.AllowsSurrender() { + surrender = "Late (original two-card hand only)" + } + split := "Identical ranks only" + if b.AllowsUnlikeTenSplit() { + split = "Identical ranks or any two ten-valued cards" + } + return strings.Join([]string{ + fmt.Sprintf("Blackjack table %s — rules", c.ID), + fmt.Sprintf("Number of decks: %d", b.Decks), + "Blackjack pays " + payoutRatio(b.BlackjackPayout), + "Dealer " + dealer + " soft 17", + "Dealer hole card / peek: Yes; blackjack checked before player actions (after insurance)", + "Ordinary wins pay 1:1; ties push; player and dealer blackjack push", + "Double down: Any initial two cards; one additional card only", + "Double after split: " + yesNo(b.AllowsDoubleAfterSplit()), + fmt.Sprintf("Maximum split hands: %d (including original hand)", b.MaxSplitHands), + "Re-splitting: " + yesNo(b.MaxSplitHands > 2) + " (within maximum hands)", + "Re-splitting aces: " + yesNo(b.AllowsResplitAces()) + " (within maximum hands)", + "Split pairs: " + split, + "Split aces: One card per ace; no hitting or doubling", + "Split-hand 21 pays 1:1, except the optional bonus below", + "Split-and-doubled 21 receives blackjack payout: " + yesNo(b.CountsDoubleSplitBlackjack()), + "Surrender: " + surrender, + "Insurance: Offered against an ace; costs half the original bet; pays " + payoutRatio(b.InsurancePayout), + "Fractional credits: Rounded down (including insurance stake and surrender return)", + fmt.Sprintf("Shuffle threshold: %g%% of shoe remaining; may shuffle earlier for round coverage", b.ShuffleAt*100), + "Shoe exhaustion: Reshuffle mid-round if necessary", + "Bet limits: " + betRangeText(c.MinBet, c.MaxBet) + " credits", + fmt.Sprintf("Seats: %d; betting window: %d ticks; action window: %d ticks", c.MaxPlayers, c.BettingTicks, b.ActionTicks), + }, "\n") +} + +func payoutRatio(p float64) string { + switch p { + case 1.5: + return "3:2" + case 1.2: + return "6:5" + default: + return fmt.Sprintf("%g:1", p) + } +} -- cgit v1.2.3