From 0ec8f3692960a064616e630c914058298b22897b Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Sat, 3 Oct 2026 01:38:58 -0400 Subject: feat: replaced roulette wheel graphic with line-by-line 'spin' --- internal/casino/roulette_animation_test.go | 103 +++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 internal/casino/roulette_animation_test.go (limited to 'internal/casino/roulette_animation_test.go') diff --git a/internal/casino/roulette_animation_test.go b/internal/casino/roulette_animation_test.go new file mode 100644 index 0000000..33d0e32 --- /dev/null +++ b/internal/casino/roulette_animation_test.go @@ -0,0 +1,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") + } + } + } +} -- cgit v1.2.3