aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/house_edge_fire.go
blob: 3bb16972fd6d2542bdc4807afe4695f82bc3c9ad (plain)
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
package casino

import "math/bits"

// crapsFireReturn is the fire bet's exact expected return (profit plus stake
// where the bet wins; nothing where it loses) per unit staked. The bet
// resolves only on a point-phase seven-out — a come-out seven keeps the
// shooter's hand and the bet alive — paying 24/249/999:1 for 4/5/6 distinct
// made points. The state is the six-bit mask of distinct points made in the
// hand; come-out rolls and rerolls of an already-made point are self loops.
// Solved by fixed-point iteration over the 64 masks (the chain is absorbing
// and monotone, so iteration converges to the exact solution).
func crapsFireReturn() float64 {
	numbers := []int{4, 5, 6, 8, 9, 10}
	ways := make([]int, len(numbers))
	for i, n := range numbers {
		ways[i] = diceWays(n)
	}
	pay := func(made int) float64 {
		switch made {
		case 4:
			return 25 // 24:1 profit plus the returned stake
		case 5:
			return 250
		case 6:
			return 1000
		}
		return 0
	}
	vCome := make([]float64, 64)
	for it := 0; it < 2000; it++ {
		next := make([]float64, 64)
		for mask := 0; mask < 64; mask++ {
			sum := 0.0
			for i := range numbers {
				w := ways[i]
				nm := mask | 1<<i
				// Point-phase value of an established point n: making it
				// moves to the come-out with the grown mask; a seven (6/36)
				// resolves the bet at the CURRENT mask (not the grown one —
				// the point has not been made).
				made := bits.OnesCount(uint(mask))
				pointValue := (float64(w)/36*vCome[nm] + 6.0/36*pay(made)) / (1 - float64(36-w-6)/36)
				sum += float64(w) / 36 * pointValue
			}
			next[mask] = sum / (24.0 / 36.0)
		}
		done := true
		for i := range next {
			if diff := next[i] - vCome[i]; diff > 1e-12 || diff < -1e-12 {
				done = false
				break
			}
		}
		vCome = next
		if done {
			break
		}
	}
	return vCome[0]
}