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