package casino import ( "strings" "testing" ) func hintHas(commands []MenuCommand, command string) bool { for _, c := range commands { if c.Command == command { return true } } return false } func hintBet(commands []MenuCommand) bool { for _, c := range commands { if strings.HasPrefix(c.Command, "bet") { return true } } return false } func TestCrapsHintsFollowPlayerState(t *testing.T) { for _, v := range crapsVariants { tb := variantFixture(v) tb.join("a") w := &testWallet{chips: 1000} commands := tb.commands("a") if !hintBet(commands) || !hintHas(commands, "stop") { t.Fatal(v, "missing idle actions", commands) } for _, c := range []string{"roll", "autoroll", "unbet"} { if hintHas(commands, c) { t.Fatal(v, "idle", c) } } if watch := tb.commands("watcher"); len(watch) != 1 || watch[0].Command != "table" { t.Fatal(v, "spectator actions", watch) } tb.bet("a", "pass", 10, w) commands = tb.commands("a") if v == "simplified" { // Simplified craps rolls by itself: no manual shooting actions // while the pass contract is live. if hintHas(commands, "roll") || hintHas(commands, "autoroll") || hintHas(commands, "unbet") || hintBet(commands) { t.Fatal(v, "manual actions", commands) } if !hintHas(commands, "stop") { t.Fatal(v, "missing stop", commands) } continue } if !hintHas(commands, "roll") || !hintHas(commands, "autoroll") || hintHas(commands, "unbet") { t.Fatal(v, "contract actions", commands) } if !tb.Config.Craps.allows("buy") && hintBet(commands) { t.Fatal(v, "duplicate pass advertised") } tb.action("a", "autoroll") if hintHas(tb.commands("a"), "autoroll") { t.Fatal(v, "already enabled") } tb.join("b") if hintHas(tb.commands("a"), "roll") { t.Fatal(v, "roll before betting window ends") } tb.players.get("a").autoRoll = false tb.bet("b", "pass", 10, &testWallet{chips: 1000}) tb.advance(10) if !hintHas(tb.commands("a"), "roll") || hintHas(tb.commands("b"), "roll") { t.Fatal(v, "wrong shooter hints") } } } func TestCrapsHintsOnlyOfferRemovableWagers(t *testing.T) { tb := crapsFixture() tb.join("a") w := &testWallet{chips: 1000} tb.bet("a", "pass", 10, w) tb.resolveRoll(2, 2) if hintHas(tb.commands("a"), "unbet") { t.Fatal("contract removable") } tb.bet("a", "odds pass", 10, w) if !hintHas(tb.commands("a"), "unbet") { t.Fatal("odds not removable") } tb.action("a", "unbet") if hintHas(tb.commands("a"), "unbet") { t.Fatal("removed odds still advertised") } tb.bet("a", "place 6", 12, w) if !hintHas(tb.commands("a"), "unbet") { t.Fatal("place removal missing") } } func TestOtherCasinoHintsRespectCommitment(t *testing.T) { bj := newBlackjackTable(1, TableConfig{ID: "bj", Game: GameBlackjack, BettingTicks: 10}, newTestRand()) bj.join("a") bj.join("b") bj.bet("a", "", 10, &testWallet{chips: 1000}) if hintBet(bj.menuEvent("a").Menu.Commands) { t.Fatal("blackjack duplicate bet advertised") } if !hintBet(bj.menuEvent("b").Menu.Commands) { t.Fatal("blackjack missing eligible bet") } bac := newBaccaratTable(1, TableConfig{ID: "bac", Game: GameBaccarat, BettingTicks: 10}, newTestRand()) bac.join("a") bac.join("b") bac.bet("a", "banker", 10, &testWallet{chips: 1000}) if hintBet(bac.menuEvent("a").Menu.Commands) { t.Fatal("baccarat duplicate bet advertised") } if !hintBet(bac.menuEvent("b").Menu.Commands) { t.Fatal("baccarat missing eligible bet") } r := newRouletteTable(1, TableConfig{ID: "r", Game: GameRoulette, BettingTicks: 10}, newTestRand()) r.join("a") r.join("b") if hintHas(r.menuEvent("a", true).Menu.Commands, "bet / rebet") { t.Fatal("roulette no wager to repeat") } r.bet("a", "red", 10, &testWallet{chips: 1000}) if hintBet(r.menuEvent("a", true).Menu.Commands) { t.Fatal("roulette duplicate bet advertised") } if !hintBet(r.menuEvent("b", true).Menu.Commands) { t.Fatal("roulette missing eligible bet") } r.phase = phasePlaying if hintBet(r.menuEvent("b", true).Menu.Commands) { t.Fatal("roulette spinning bets advertised") } r.phase = phaseWaiting r.resetRound() if !hintHas(r.menuEvent("a", true).Menu.Commands, "bet / rebet") { t.Fatal("roulette repeat missing") } } func TestSlotHintsRequirePriorWager(t *testing.T) { m := newMachine(1, MachineConfig{ID: "slots", Game: GameSlots}, newTestRand()) m.join("a") for _, c := range []string{"spin", "autospin"} { if hintHas(m.commands(), c) { t.Fatal("fresh slots", c) } } m.bet = 10 for _, c := range []string{"spin", "autospin"} { if !hintHas(m.commands(), c) { t.Fatal("configured slots", c) } } m.autoBet = true if commands := m.commands(); len(commands) != 1 || commands[0].Command != "stop" { t.Fatal("autospin hints", commands) } m.phase = machineSpinning if events := m.privateMenu(""); events[0].Menu != nil { t.Fatal("manual commands during spin") } }