aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/blackjack_rules.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-24 19:31:05 -0400
committerhistoria <[not public]>2026-09-24 19:31:05 -0400
commitd114c747a7672c7e4daab3a5b5f1b2f066ebc912 (patch)
tree81cc03354561f2f631d68f0de28bc742b1f49114 /internal/casino/blackjack_rules.go
parentf606db40c3290fd9ce40b53ef9bbe135b1e6f6e2 (diff)
downloadthehouseoficarus-d114c747a7672c7e4daab3a5b5f1b2f066ebc912.tar.gz
feat: additional baca and bj rules variants
Diffstat (limited to 'internal/casino/blackjack_rules.go')
-rw-r--r--internal/casino/blackjack_rules.go66
1 files changed, 66 insertions, 0 deletions
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)
+ }
+}