aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/baccarat_variants.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/casino/baccarat_variants.go')
-rw-r--r--internal/casino/baccarat_variants.go98
1 files changed, 98 insertions, 0 deletions
diff --git a/internal/casino/baccarat_variants.go b/internal/casino/baccarat_variants.go
new file mode 100644
index 0000000..95b5041
--- /dev/null
+++ b/internal/casino/baccarat_variants.go
@@ -0,0 +1,98 @@
+package casino
+
+import "strings"
+
+const (
+ BaccaratCommission = "commission"
+ BaccaratSuper6 = "super_6"
+ BaccaratEZ = "ez_baccarat"
+)
+
+// Optional wagers use fixed, conventional profit odds. They are evaluated
+// independently of the main Banker wager (notably the EZ Dragon 7 push).
+func (c BaccaratConfig) spots() []string {
+ spots := []string{baccaratSpotPlayer, baccaratSpotBanker, baccaratSpotTie}
+ if c.PairBets {
+ spots = append(spots, "player_pair", "banker_pair")
+ }
+ if c.Dragon7 {
+ spots = append(spots, "dragon_7")
+ }
+ if c.Panda8 {
+ spots = append(spots, "panda_8")
+ }
+ if c.Super6Bet {
+ spots = append(spots, "super_6")
+ }
+ return spots
+}
+
+func (c BaccaratConfig) allowsSpot(spot string) bool {
+ for _, allowed := range c.spots() {
+ if spot == allowed {
+ return true
+ }
+ }
+ return false
+}
+
+func (c BaccaratConfig) betChoices() string { return strings.Join(c.spots(), "|") }
+
+func baccaratPair(hand []card) bool {
+ return len(hand) >= 2 && hand[0].rank == hand[1].rank
+}
+
+// settleBaccaratHand needs the complete hands: totals alone cannot identify
+// a three-card seven/eight or an initial pair.
+func settleBaccaratHand(spot string, bet int, player, banker []card, rules BaccaratConfig) (string, int, error) {
+ rules = rules.Normalize()
+ if !rules.allowsSpot(spot) {
+ return "loss", 0, nil
+ }
+ pt, bt := baccaratTotal(player), baccaratTotal(banker)
+ win, odds := false, 0.0
+ switch spot {
+ case "player_pair":
+ win, odds = baccaratPair(player), 11
+ case "banker_pair":
+ win, odds = baccaratPair(banker), 11
+ case "dragon_7":
+ win, odds = bt > pt && bt == 7 && len(banker) == 3, 40
+ case "panda_8":
+ win, odds = pt > bt && pt == 8 && len(player) == 3, 25
+ case "super_6":
+ win, odds = bt > pt && bt == 6, 12
+ default:
+ if spot == baccaratSpotBanker && bt > pt {
+ if rules.Variant == BaccaratEZ && bt == 7 && len(banker) == 3 {
+ return "push", bet, nil
+ }
+ if rules.Variant == BaccaratSuper6 && bt == 6 {
+ // Floor the total return, not a positive-profit minimum: a one-credit
+ // stake returns one credit, not two, on this half-pay outcome.
+ payout, err := MulPayout(bet, 1.5)
+ return "win", payout, err
+ }
+ }
+ return settleBaccaratBet(spot, bet, pt, bt, rules)
+ }
+ if !win {
+ return "loss", 0, nil
+ }
+ payout, err := MulPayout(bet, 1+odds)
+ return "win", payout, err
+}
+
+func baccaratVariantOutcome(player, banker []card, rules BaccaratConfig) string {
+ pt, bt := baccaratTotal(player), baccaratTotal(banker)
+ if bt <= pt {
+ return ""
+ }
+ if rules.Variant == BaccaratEZ && bt == 7 && len(banker) == 3 {
+ return "EZ Baccarat: Banker wins with a three-card 7. Banker bets push; Player bets lose."
+ }
+ if rules.Variant == BaccaratSuper6 && bt == 6 {
+ return "Super 6: Banker wins with 6. Banker bets pay 1:2."
+ }
+ return ""
+}