aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/roulette_animation_test.go
blob: 33d0e32cf25fa430cbe8bc3c1407772c5f804a11 (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
package casino

import (
	"strconv"
	"testing"
)

func TestRouletteAnimationTiming(t *testing.T) {
	for _, multiplayer := range []bool{false, true} {
		table := rouletteFixture()
		table.Config.Roulette.SpinTicks = 8
		table.join("a")
		if multiplayer {
			table.join("b")
		}
		events := table.bet("a", "red", 10, &testWallet{chips: 100})
		if multiplayer {
			table.tick()
			events = table.tick()
		}
		for _, e := range events {
			if e.Snapshot != nil {
				t.Fatal("spin announcement contains old wheel")
			}
		}
		var final *RouletteSnapshot
		for tick := 1; tick <= 8; tick++ {
			events = table.tick()
			switch {
			case tick <= 5:
				if len(events) != 1 {
					t.Fatalf("tick %d: missing frame", tick)
				}
				s := events[0].Snapshot.(*RouletteSnapshot)
				if s.SpinFrame != tick || s.BallPosition < -1 || s.BallPosition >= 10 {
					t.Fatalf("bad frame: %+v", s)
				}
				final = s
			case tick < 8:
				if len(events) != 0 {
					t.Fatalf("tick %d: pause interrupted", tick)
				}
			default:
				if len(events) == 0 || events[0].Snapshot.(*RouletteSnapshot).Phase != "result" {
					t.Fatal("missing result at tick 8")
				}
				result := events[0].Snapshot.(*RouletteSnapshot)
				if final.BallPosition < 0 || final.SpinPockets[final.BallPosition] != result.Pockets[2] {
					t.Fatal("final ball disagrees with result")
				}
			}
		}
	}
}

func TestRouletteSpinFramePockets(t *testing.T) {
	table := rouletteFixture()
	for frame := 1; frame <= 4; frame++ {
		for green := 1; green <= 36; green++ {
			for _, showBall := range []bool{false, true} {
				s := table.spinFrame(frame, showBall, 3, green)
				if (s.BallPosition == 3) != showBall || (!showBall && s.BallPosition != -1) {
					t.Fatal("ball visibility ignored")
				}
				want := "1"
				if frame%2 == 0 {
					want = "2"
				}
				if s.SpinPockets[0] != want {
					t.Fatal("starting color did not alternate")
				}
				for i, pocket := range s.SpinPockets {
					if pocket == "0" && (i == 0 || i == 9 || s.SpinPockets[i-1] == s.SpinPockets[i+1]) {
						t.Fatalf("green not between red and black: %v", s.SpinPockets)
					}
				}
			}
		}
	}
	for _, double := range []bool{false, true} {
		table.Config.Roulette.DoubleZero = double
		wheel := rouletteWheel(double)
		for index, winner := range wheel {
			table.winningIndex = index
			s := table.spinFrame(5, false, 0, 0)
			start, _ := strconv.Atoi(s.SpinPockets[0])
			if !rouletteRed(start) {
				t.Fatal("final strip must start red after the black-starting fourth strip")
			}
			if s.BallPosition < 1 || s.BallPosition >= 9 || s.SpinPockets[s.BallPosition] != winner {
				t.Fatalf("missing winning ball for %s", winner)
			}
			for i, pocket := range s.SpinPockets {
				if pocket != wheel[(index+i-s.BallPosition+len(wheel))%len(wheel)] {
					t.Fatalf("wrong physical neighbors for %s", winner)
				}
			}
			if !double && winner == "26" && s.SpinPockets[s.BallPosition+1] != "0" {
				t.Fatal("26 must have green to its right")
			}
		}
	}
}