package game // SimulateBattle resolves a hypothetical battle between the given arranged // decks (top of deck first) and returns the result. deckA sits at seat 0 and // deckB at seat 1; firstSeat (0 or 1) is the one holding priority. It runs on // a scratch game and awards nothing, so it never touches real state — callers // (notably the AI player) can roll out as many what-if battles as they like. // Dice rolls are random unless rollDie is non-nil. func SimulateBattle(round, firstSeat int, deckA, deckB []Card, rollDie func() int) *BattleResult { g := &Game{ Round: round, RollDie: rollDie, // Cards minted during the simulation (apples, bees) get IDs far away // from real ones, purely to avoid confusion when reading results. NextCardID: 1_000_000, Players: []*Player{ {Name: "A", Seat: 0, Deck: append([]Card(nil), deckA...)}, {Name: "B", Seat: 1, Deck: append([]Card(nil), deckB...)}, }, } if firstSeat == 1 { return g.runBattle(1, 0) } return g.runBattle(0, 1) } // TierContents returns the full printed contents of a tier's shop deck for the // default pack. Cards carry placeholder IDs; they are reference data, not live // instances. func TierContents(tier int) []Card { return TierContentsForPacks([]string{DefaultPack}, tier) } // TierContentsForPacks returns the printed tier contents of a pack selection, // combined the way the shop decks combine them — public information from the // boxes. Used by the AI, which decides from a View that names its packs. func TierContentsForPacks(packs []string, tier int) []Card { scratch := &Game{Packs: packs} scratch.buildShopDecks() if tier < 1 || tier > len(scratch.ShopDecks) { return nil } return scratch.ShopDecks[tier-1] }