diff options
Diffstat (limited to 'internal/casino/settlement.go')
| -rw-r--r-- | internal/casino/settlement.go | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/internal/casino/settlement.go b/internal/casino/settlement.go new file mode 100644 index 0000000..46d3723 --- /dev/null +++ b/internal/casino/settlement.go @@ -0,0 +1,153 @@ +package casino + +import ( + "fmt" + "strings" +) + +// Attach receipts to the recipient's final board/menu where possible, so the +// renderer can place them between the reveal and the next-action prompt. +// Departing recipients still receive their standalone private receipt. +func withSettlementReceipts(events, receipts []Event) []Event { + for _, receipt := range receipts { + attached := false + for i := len(events) - 1; i >= 0; i-- { + if events[i].PrivateTo == receipt.PrivateTo && events[i].Snapshot != nil && !events[i].Public { + events[i].Settlement = receipt.Settlement + events[i].SettlementNote = receipt.SettlementNote + attached = true + break + } + } + if !attached { + events = append(events, receipt) + } + } + return events +} + +// profitOdds reduces an exact profit fraction without rounding currency. +func profitOdds(num, den int) string { + if den <= 0 { + return "Varies" + } + a, b := num, den + if a < 0 { + a = -a + } + for b != 0 { + a, b = b, a%b + } + if a == 0 { + return "0:1" + } + return fmt.Sprintf("%d:%d", num/a, den/a) +} + +func returnResult(stake, returned int) string { + switch { + case returned > stake: + return "win" + case returned < stake: + return "loss" + default: + return "push" + } +} + +func rouletteSettlementOdds(w rouletteWager, pocket string) string { + if s, ok := w.covers(pocket); ok { + return profitOdds(s.num-s.den, s.den) + } + odds := "" + for _, s := range w.shares { + next := profitOdds(s.num-s.den, s.den) + if odds != "" && odds != next { + return "Varies" + } + odds = next + } + if odds == "" { + return "Varies" + } + return odds +} + +func baccaratSettlementOdds(spot string, player, banker []card, rules BaccaratConfig) string { + rules = rules.Normalize() + switch spot { + case baccaratSpotPlayer: + return "1:1" + case baccaratSpotBanker: + if rules.Variant == BaccaratSuper6 && baccaratTotal(banker) > baccaratTotal(player) && baccaratTotal(banker) == 6 { + return "1:2" + } + return payoutRatio(rules.BankerPayout) + case baccaratSpotTie: + return payoutRatio(rules.TiePayout) + case "player_pair", "banker_pair": + return "11:1" + case "dragon_7": + return "40:1" + case "panda_8": + return "25:1" + case "super_6": + return "12:1" + default: + return "Varies" + } +} + +// For losing or active bets, inspect legal winning outcomes. Variable games +// (field, horn and variant pass lines) must not advertise one fixed rate. +func (t *crapsTable) settlementOdds(b *crapsBet) string { + odds := "" + for _, pair := range t.rollPairs() { + done, num, den := t.outcomeFor(b, pair[0], pair[1]) + if !done || num <= 0 { + continue + } + next := profitOdds(num, den) + if odds != "" && odds != next { + return "Varies" + } + odds = next + } + if odds == "" { + odds = "Varies" + } + if b.kind == "buy" || b.kind == "lay" { + odds += " fee" + } + return odds +} + +// Keep the base bet and its free-odds wager separate, including come-out +// refunds where the base loses but the odds push. +func (t *crapsTable) crapsSettlementLines(b *crapsBet, num, den int, refundOdds, active bool) []SettlementLine { + base := *b + base.odds = Wager{} + returned := crapsReturn(&base, num, den, num, false) + odds := t.settlementOdds(b) + if num > 0 && !active { + odds = profitOdds(num, den) + if b.kind == "buy" || b.kind == "lay" { + odds += " fee" + } + } + lines := []SettlementLine{{Label: crapsBetLabel(b), Odds: odds, Stake: b.stake.Total, Returned: returned, Result: returnResult(b.stake.Total, returned), Unresolved: active}} + if b.odds.Total > 0 { + x, y := crapsTrueOdds(b.number) + if strings.HasPrefix(b.kind, "dont") { + x, y = y, x + } + paid := 0 + if refundOdds { + paid = b.odds.Total + } else if num >= 0 { + paid = b.odds.Total + b.odds.Total/y*x + } + lines = append(lines, SettlementLine{Label: crapsBetLabel(b) + " odds", Odds: profitOdds(x, y), Stake: b.odds.Total, Returned: paid, Result: returnResult(b.odds.Total, paid), Unresolved: active}) + } + return lines +} |
