aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/roulette_geometry_test.go
blob: 37fec745d713a37eed5811ea05e1b20d74c91913 (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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package casino

import (
	"fmt"
	"testing"
)

func TestRouletteRejectsNonTouchingCombinations(t *testing.T) {
	for _, tc := range []struct {
		target string
		double bool
	}{
		{"corner 1 3 4 6", false}, {"corner 1 2 7 8", false},
		{"corner 1 3 34 36", true}, {"trio 0 1 3", false},
		{"trio 0 1 3", true}, {"trio 0 2 3", true},
		{"trio 00 1 2", true}, {"trio 0 00 1", true},
		{"trio 0 00 3", true}, {"split 0 3", true},
		{"split 00 1", true},
	} {
		if _, mult := rouletteBet(tc.target, tc.double); mult != 0 {
			t.Errorf("accepted %q (double=%v)", tc.target, tc.double)
		}
	}
	for _, double := range []bool{false, true} {
		for c := 0; c < 11; c++ {
			for r := 1; r <= 2; r++ {
				n := 3*c + r
				target := fmt.Sprintf("corner %d %d %d %d", n, n+1, n+3, n+4)
				if _, mult := rouletteBet(target, double); mult != 9 {
					t.Errorf("rejected %s", target)
				}
			}
		}
		for _, target := range []string{"split 0 1", "split 0 2", "trio 0 1 2"} {
			if _, mult := rouletteBet(target, double); mult == 0 {
				t.Errorf("rejected %s", target)
			}
		}
	}
	for _, target := range []string{"split 00 2", "split 00 3", "trio 00 2 3", "trio 0 00 2"} {
		if _, mult := rouletteBet(target, true); mult == 0 {
			t.Errorf("rejected %s", target)
		}
	}
}

// Sum the return over every equally likely outcome. Ordinary bets return
// 36 stakes per wheel; the American five-number basket returns only 35.
func TestRouletteWheelAndExpectedReturns(t *testing.T) {
	for _, double := range []bool{false, true} {
		wheel := WheelOrder(double)
		want := 37
		if double {
			want = 38
		}
		seen := map[string]bool{}
		for _, p := range wheel {
			if _, valid := roulettePocketToken(p, double); !valid || seen[p] {
				t.Fatalf("invalid wheel pocket %s", p)
			}
			seen[p] = true
		}
		if len(seen) != want {
			t.Fatalf("wheel has %d pockets, want %d", len(seen), want)
		}
		targets := append(WheelOrder(double), "red", "black", "odd", "even", "low", "high", "1to12", "13to24", "25to36", "row1", "row2", "row3", "split 1 2", "street 1 2 3", "corner 1 2 4 5", "line 1 2 3 4 5 6", "trio 0 1 2", "basket")
		for _, target := range targets {
			wager, ok := rouletteWagerFor(target, double, false)
			if !ok {
				t.Fatalf("invalid target %s", target)
			}
			sum := 0
			for _, p := range wheel {
				share, _ := wager.covers(p)
				payout, err := share.payout(1)
				if err != nil {
					t.Fatal(err)
				}
				sum += payout
			}
			wantReturn := 36
			if double && target == "basket" {
				wantReturn = 35
			}
			if sum != wantReturn {
				t.Errorf("%s: total return %d, want %d", target, sum, wantReturn)
			}
		}
	}
}

func TestRouletteSharePayoutCap(t *testing.T) {
	shares := []rouletteShare{{36, 1}, {7, 1}, {36, 9}}
	for _, bet := range rouletteCallBets {
		for _, share := range bet.wager().shares {
			shares = append(shares, share)
		}
	}
	for _, share := range shares {
		limit := ((MaxCredits+1)*share.den - 1) / share.num
		got, err := share.payout(limit)
		if err != nil || got > MaxCredits {
			t.Fatalf("%+v at limit: %d, %v", share, got, err)
		}
		if _, err := share.payout(limit + 1); err == nil {
			t.Fatalf("%+v accepted overflow", share)
		}
	}
}