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]
}
|