package game import ( "strings" "testing" "thehouseoficarus/internal/item" "thehouseoficarus/internal/player" ) func TestEdgeListAllTableGames(t *testing.T) { for _, game := range []string{"blackjack", "baccarat", "roulette", "craps", "paigow", "video_poker"} { t.Run(game, func(t *testing.T) { g, sess, conn := houseEdgeGame(t, "name: Casino\ncasino_tables:\n - id: test\n game: "+game+"\n") writeHouseEdgeManual(t, g, sess, 2) g.executePlay(sess, []string{game}, "play "+game) if strings.Contains(stripANSI(string(conn.data)), "RTP") { t.Fatal("readout on join") } conn.data = nil g.executeList(sess, nil, "list") text := stripANSI(string(conn.data)) if !strings.Contains(text, "RTP") { t.Fatalf("no RTP column for %s: %s", game, text) } assertRTPColumn(t, text) sess.Player.Inventory = nil conn.data = nil g.executeList(sess, nil, "list") if strings.Contains(stripANSI(string(conn.data)), "RTP") { t.Fatal("readout after reference removed") } }) } } // TestCrapsListEveryBetHasRTP: once a reference item is carried, every // craps wager the list can name must resolve to a real percentage. An // unknown target would render the dash, which is the bug this guards. func TestCrapsListEveryBetHasRTP(t *testing.T) { for _, variant := range []string{"bank", "crapless", "new_york"} { t.Run(variant, func(t *testing.T) { room := "name: CR\ncasino_tables:\n - id: cr\n game: craps\n craps:\n variant: " + variant + "\n" g, sess, conn := houseEdgeGame(t, room) writeHouseEdgeManual(t, g, sess, 2) g.executePlay(sess, []string{"craps"}, "play craps") g.executeBet(sess, []string{"10", "pass"}, "bet 10 pass") conn.data = nil g.executeList(sess, nil, "list") if text := stripANSI(string(conn.data)); strings.Contains(text, "—") { t.Fatalf("%s come-out list left a bet without RTP:\n%s", variant, text) } }) } } func TestEdgeListBlackjackActionsOmitRTP(t *testing.T) { g, sess, conn := houseEdgeGame(t, "name: BJ\ncasino_tables:\n - id: bj\n game: blackjack\n") writeHouseEdgeManual(t, g, sess, 2) g.executePlay(sess, []string{"bj"}, "play bj") table, _ := g.Casino.Participation(sess.Player.Name) for i := 0; i < 10 && len(table.Wagers(sess.Player.Name)) == 0; i++ { g.executeBet(sess, []string{"1"}, "bet 1") } rows := table.Wagers(sess.Player.Name) if len(rows) == 0 { t.Skip("no action rows this deal") } insurance := false for _, r := range rows { if r.Bet == "insurance" { insurance = true } } conn.data = nil g.executeList(sess, nil, "list") text := stripANSI(string(conn.data)) if insurance { // Insurance is a real wager and carries an RTP. if !strings.Contains(text, "RTP") { t.Fatalf("insurance list lost its RTP:\n%s", text) } return } if strings.Contains(text, "RTP") { t.Fatalf("action-only list showed an RTP column:\n%s", text) } } func TestEdgeListRealInstruments(t *testing.T) { g, sess, conn := houseEdgeGame(t, roomRoulette) g.ItemStore = item.NewItemStore("../../data") sess.Player.Inventory = map[int]*player.InventorySlot{ 0: {ItemID: "house_edge_tile", Quantity: 1}, 1: {ItemID: "house_edge_computus", Quantity: 1}, } g.executePlay(sess, []string{"roulette"}, "play roulette") conn.data = nil g.executeList(sess, nil, "list") text := stripANSI(string(conn.data)) if strings.Count(text, "97.30%") != 12 { t.Fatalf("best instrument not used: %s", text) } sess.Player.Inventory[1].Quantity = 0 conn.data = nil g.executeList(sess, nil, "list") text = stripANSI(string(conn.data)) if strings.Count(text, "97%") != 12 { t.Fatalf("tile not used: %s", text) } sess.Player.Inventory[0].Quantity = 0 conn.data = nil g.executeList(sess, nil, "list") if strings.Contains(stripANSI(string(conn.data)), "RTP") { t.Fatal("zero-quantity item activated") } }