1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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: %.6g%% 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)
}
}
|