Esempio n. 1
0
 public void Init(GameIDType gameID, PlayerIDType myPlayerID, Dictionary <PlayerIDType, GamePlayer> players, MapDetails map, GameStanding distributionStanding, GameSettings gameSettings, int numberOfTurns, Dictionary <PlayerIDType, PlayerIncome> incomes, GameOrder[] prevTurn, GameStanding latestTurnStanding, GameStanding previousTurnStanding, Dictionary <PlayerIDType, TeammateOrders> teammatesOrders, List <CardInstance> cards, int cardsMustPlay, Stopwatch timer, List <string> directives)
 {
     this.DistributionStandingOpt = distributionStanding;
     this.Standing          = latestTurnStanding;
     this.PlayerID          = myPlayerID;
     this.Players           = players;
     this.Map               = map;
     this.Settings          = gameSettings;
     this.TeammatesOrders   = teammatesOrders;
     this.Cards             = cards;
     this.CardsMustPlay     = cardsMustPlay;
     this.Incomes           = incomes;
     this.BaseIncome        = Incomes[PlayerID];
     this.EffectiveIncome   = BaseIncome.Clone();
     this.Neighbors         = players.Keys.ExceptOne(PlayerID).ConcatOne(TerritoryStanding.NeutralPlayerID).ToDictionary(o => o, o => new Neighbor(this, o));
     this.Opponents         = players.Values.Where(o => o.State == GamePlayerState.Playing && !IsTeammateOrUs(o.ID)).ToList();
     this.IsFFA             = Opponents.Count > 1 && (Opponents.Any(o => o.Team == PlayerInvite.NoTeam) || Opponents.GroupBy(o => o.Team).Count() > 1);
     this.WeightedNeighbors = WeightNeighbors();
     this.Timer             = timer;
     this.Directives        = directives;
     if (tracker.isInit())
     {
         tracker.update(this);
     }
     else
     {
         tracker.init(this);
     }
     AILog.Log("BotMain", "PyBot initialized.  Starting at " + timer.Elapsed.TotalSeconds + " seconds");
 }
Esempio n. 2
0
        public bool IsBorderTerritory(GameStanding standing, TerritoryIDType terrID)
        {
            var ts = standing.Territories[terrID];

            if (ts.OwnerPlayerID != PlayerID)
            {
                return(false);
            }
            return(this.Map.Territories[terrID].ConnectedTo.Keys.Any(c => standing.Territories[c].OwnerPlayerID != this.PlayerID));
        }
Esempio n. 3
0
        public static BotMap FromStanding(BotMain state, GameStanding stand)
        {
            var map = state.VisibleMap.GetMapCopy();

            foreach (var terr in stand.Territories.Values)
            {
                var territory = map.Territories[terr.ID];
                territory.OwnerPlayerID = terr.OwnerPlayerID;
                territory.Armies        = terr.NumArmies;
            }
            return(map);
        }
Esempio n. 4
0
 public void Init(PlayerIDType myPlayerID, Dictionary<PlayerIDType, GamePlayer> players, MapDetails map, GameStanding distributionStanding, GameSettings gameSettings, int numberOfTurns, Dictionary<PlayerIDType, PlayerIncome> incomes, GameOrder[] prevTurn, GameStanding latestTurnStanding, GameStanding previousTurnStanding, Dictionary<PlayerIDType, TeammateOrders> teammatesOrders, List<CardInstance> cards, int cardsMustPlay)
 {
     this.DistributionStanding = distributionStanding;
     this.LatestTurnStanding = latestTurnStanding;
     this.MyPlayerID = myPlayerID;
     this.Players = players;
     this.Map = map;
     this.Settings = gameSettings;
     this.TeammatesOrders = teammatesOrders;
     this.Cards = cards;
     this.CardsMustPlay = cardsMustPlay;
     this.Incomes = incomes;
 }
Esempio n. 5
0
 public TurnState(int numberOfTurns,
                  Dictionary <PlayerIDType, PlayerIncome> incomes,
                  GameOrder[] prevTurn,
                  GameStanding latestTurnStanding,
                  GameStanding previousTurnStanding
                  )
 {
     NumberOfTurns        = numberOfTurns;
     Incomes              = incomes;
     PrevTurn             = prevTurn;
     LatestTurnStanding   = latestTurnStanding;
     PreviousTurnStanding = previousTurnStanding;
 }
Esempio n. 6
0
 public static void PushMoveState(PlayerIDType myPlayerId, Dictionary <PlayerIDType, GamePlayer> players,
                                  MapDetails map, GameStanding distributionStanding, GameSettings gameSettings, int numberOfTurns,
                                  Dictionary <PlayerIDType, PlayerIncome> incomes, GameOrder[] prevTurn, GameStanding latestTurnStanding,
                                  GameStanding previousTurnStanding)
 {
     MyPlayerId           = myPlayerId;
     OpponentPlayerId     = players.Keys.Where(o => o != MyPlayerId).First();
     Players              = players;
     DistributionStanding = distributionStanding;
     GameSettings         = gameSettings;
     Map = map;
     TurnStates.Add(new TurnState(numberOfTurns, incomes, prevTurn, latestTurnStanding, previousTurnStanding));
 }
Esempio n. 7
0
        public TakePlayingTurnContainer(MapDetails map, GameStanding noFogStanding, Dictionary <PlayerIDType, GamePlayer> players, GameSettings settings, PlayerIDType player, PlayerIncome income, List <CardInstance> cards, int cardsMustPlay, Dictionary <PlayerIDType, TeammateOrders> activeOrders, Stopwatch aiTimer)
        {
            this.Map             = map;
            this.Standing        = noFogStanding;
            this.Players         = players;
            this.Settings        = settings;
            this.PlayerID        = player;
            this.Income          = income;
            this.Cards           = cards;
            this.CardsMustPlay   = cardsMustPlay;
            this.TeammatesOrders = activeOrders;
            this._aiTimer        = aiTimer;

            Orders    = new List <GameOrder>();
            Neighbors = players.Keys.ExceptOne(player).ConcatOne(TerritoryStanding.NeutralPlayerID).ToDictionary(o => o, o => new Neighbor(this, o));

            BuildOrders();
        }
Esempio n. 8
0
        public void Init(GameIDType gameID, PlayerIDType myPlayerID, Dictionary <PlayerIDType, GamePlayer> players, MapDetails map, GameStanding distributionStanding, GameSettings gameSettings, int numberOfTurns, Dictionary <PlayerIDType, PlayerIncome> incomes, GameOrder[] prevTurn, GameStanding latestTurnStanding, GameStanding previousTurnStanding, Dictionary <PlayerIDType, TeammateOrders> teammatesOrders, List <CardInstance> cards, int cardsMustPlay, Stopwatch timer, List <string> directives)
        {
            this.Me                   = players[myPlayerID];
            this.Players              = players;
            this.NumberOfTurns        = numberOfTurns;
            this.Settings             = gameSettings;
            this.Map                  = map;
            this.DistributionStanding = distributionStanding;
            this.LatestStanding       = latestTurnStanding;
            this.PreviousTurnStanding = previousTurnStanding;
            this.MyIncome             = incomes[myPlayerID];
            this.PreviousTurn         = prevTurn;

            //teammatesOrders
            //cards
            //cardsMustPlay

            this.BotMap = new BotMap(this, Map, LatestStanding ?? DistributionStanding);
        }
Esempio n. 9
0
        private static bool TryTraverseBonus(BotMain bot, GameStanding standing, HashSet <TerritoryIDType> allUnownedTerrsInBonus, TerritoryIDType terrID, HashSet <TerritoryIDType> visited, Stack <MultiAttackPlan> stack, int depth)
        {
            if (depth > 20)
            {
                return(false); //prevent stack overflows. If the bonus is too deep, we'll just skip it
            }
            if (bot.PastTime(10))
            {
                return(false); //don't look for too long. This algorithm can take forever on large maps, so abort if we're slow.
            }
            visited.Add(terrID);
            stack.Push(new MultiAttackPlan(bot, terrID, MultiAttackPlanType.MainStack));

            if (allUnownedTerrsInBonus.All(o => visited.Contains(o)))
            {
                return(true); //we did it, we traversed the bonus
            }
            var nextSteps = bot.Map.Territories[terrID].ConnectedTo.Keys.Where(o => !visited.Contains(o) && allUnownedTerrsInBonus.Contains(o)).ToList();

            //Disable offshoots.  Their plan calculates correctly, however the code that calculates the number of armies we need doesn't take into account offshoots, so it ends up using remainders when we don't really get those remainders.  This makes them not able to complete the bonus.
            //if (nextSteps.Count == 0)
            //{
            //    //We're an offshoot.
            //    stack.Peek().Type = MultiAttackPlanType.OneTerritoryOffshoot;
            //    return false;
            //}

            //Traverse from big to small.  We want to take bigger territories first so that more remainders are left for taking smaller ones
            foreach (var next in nextSteps.OrderByDescending(o => ExpansionHelper.GuessNumberOfArmies(bot, o, standing).DefensePower))
            {
                if (TryTraverseBonus(bot, standing, allUnownedTerrsInBonus, next, visited, stack, depth + 1))
                {
                    return(true);
                }
            }

            //Could not find a solution through here. Back up and keep searching.
            visited.Remove(terrID);
            stack.Pop();
            return(false);
        }
Esempio n. 10
0
        public void Init(GameIDType gameID, PlayerIDType myPlayerID, Dictionary <PlayerIDType, GamePlayer> players, MapDetails map, GameStanding distributionStanding, GameSettings settings, int numTurns, Dictionary <PlayerIDType, PlayerIncome> playerIncomes, GameOrder[] prevTurn, GameStanding latestTurnStanding, GameStanding previousTurnStanding, Dictionary <PlayerIDType, TeammateOrders> teammatesOrders, List <CardInstance> cards, int cardsMustPlay, Stopwatch timer, List <string> directives)
        {
            this.Players  = players;
            this.Me       = players[myPlayerID];
            this.Settings = settings;

            this.Map        = map;
            this.VisibleMap = new BotMap(this);
            foreach (var bonus in this.Map.Bonuses.Values)
            {
                VisibleMap.Bonuses.Add(bonus.ID, new BotBonus(VisibleMap, bonus.ID));
            }

            foreach (var terr in this.Map.Territories.Values)
            {
                VisibleMap.Territories.Add(terr.ID, new BotTerritory(VisibleMap, terr.ID, TerritoryStanding.FogPlayerID, new Armies(0)));
            }

            VisibleMap = BotMap.FromStanding(this, latestTurnStanding);
            if (numTurns > 0)
            {
                LastVisibleMapX = BotMap.FromStanding(this, previousTurnStanding);
            }

            this.DistributionStanding = distributionStanding;

            this.NumberOfTurns = numTurns;
            this.PlayerIncomes = playerIncomes;

            this.PrevTurn        = prevTurn;
            this.TeammatesOrders = teammatesOrders ?? new Dictionary <PlayerIDType, TeammateOrders>();

            var allTeammatesOrders = TeammatesOrders.Values.Where(o => o.Orders != null).SelectMany(o => o.Orders).ToList();

            this.CardsPlayedByTeammates = allTeammatesOrders.OfType <GameOrderPlayCard>().Select(o => o.CardInstanceID).Concat(allTeammatesOrders.OfType <GameOrderDiscard>().Select(o => o.CardInstanceID)).ToHashSet(true);

            this.Cards         = cards;
            this.CardsMustPlay = cardsMustPlay;
            this.CardsHandler.initCards();
        }
Esempio n. 11
0
        // Returns an already calculated attack path from an owned territory to a territory in the path to which we want to pump extra deployment.
        private List <GameOrderAttackTransfer> GetPumpPath(TerritoryIDType territoryToPumpTo)
        {
            // we can't pump from transfer moves
            GameStanding           gameStanding     = GameState.CurrentTurn().LatestTurnStanding;
            List <TerritoryIDType> ownedTerritories = gameStanding.Territories.Values.Where(o => o.OwnerPlayerID == GameState.MyPlayerId).Select(o => o.ID).ToList();
            var attackMoves = AttackMoves.Where(o => !ownedTerritories.Contains(o.To)).ToList();

            List <GameOrderAttackTransfer> pumpPath = new List <GameOrderAttackTransfer>();
            TerritoryIDType currentPumpToTerritory  = territoryToPumpTo;

            while (true)
            {
                if (ownedTerritories.Contains(currentPumpToTerritory))
                {
                    break;
                }
                GameOrderAttackTransfer pumpOrder = attackMoves.Find(o => o.To == currentPumpToTerritory);
                pumpPath.Insert(0, pumpOrder);
                currentPumpToTerritory = pumpOrder.From;
            }
            return(pumpPath);
        }
Esempio n. 12
0
        public BotMap(CowzowBot bot, MapDetails map, GameStanding latest)
        {
            this.Bot    = bot;
            Territories = new Dictionary <TerritoryIDType, BotTerritory>();
            Bonuses     = new Dictionary <BonusIDType, BotBonus>();

            foreach (var terr in map.Territories.Values)
            {
                var t = new BotTerritory(bot, terr.ID);
                this.Territories.Add(terr.ID, t);

                var ts = latest.Territories[terr.ID];
                t.OwnerPlayerID = ts.OwnerPlayerID;
                if (!ts.NumArmies.Fogged)
                {
                    t.Armies = ts.NumArmies.NumArmies;
                }
            }

            foreach (var bonus in map.Bonuses.Values)
            {
                this.Bonuses.Add(bonus.ID, new BotBonus(bot, bonus.ID));
            }
        }
Esempio n. 13
0
        public static List <MultiAttackPlan> TryCreate(BotMain bot, MultiAttackPathToBonus pathToBonus, GameStanding standing, TerritoryIDType terr)
        {
            var ret = new List <MultiAttackPlan>();

            //First get us to the bonus via our pre-defined path.  Skip the last one, as we don't want to actually enter the bonus yet
            for (int i = 0; i < pathToBonus.PathToGetThere.Count - 1; i++)
            {
                ret.Add(new MultiAttackPlan(bot, pathToBonus.PathToGetThere[i], MultiAttackPlanType.MainStack));
            }

            var stackOn = ret.Count > 0 ? ret.Last().To : terr;

            var bonus = bot.Map.Bonuses[pathToBonus.BonusID];
            var allUnownedTerrsInBonus = bonus.Territories.Where(o => standing.Territories[o].OwnerPlayerID != bot.PlayerID).ToHashSet(true);

            var visited = new HashSet <TerritoryIDType>();
            var stack   = new Stack <MultiAttackPlan>();

            if (!TryTraverseBonus(bot, standing, allUnownedTerrsInBonus.ToHashSet(true), stackOn, visited, stack, 0))
            {
                return(null);
            }

            return(ret.Concat(Enumerable.Reverse(stack).Skip(1)).ToList()); //skip the first one, as that's the one we're already on.  Our plan just contains the movements we want to make
        }
        private static int DistanceToTerrs(BotMain bot, TerritoryIDType startFrom, HashSet <TerritoryIDType> terrs, GameStanding standing, int maxDistance, out HashSet <TerritoryIDType> terrsWeEntered)
        {
            Assert.Fatal(terrs.Count > 0, "No terrs");
            var visited = new HashSet <TerritoryIDType>();

            visited.Add(startFrom);

            var contains = visited.Where(o => terrs.Contains(o)).ToHashSet(true);

            if (contains.Count > 0)
            {
                //We're already there
                terrsWeEntered = new HashSet <TerritoryIDType>();
                return(0);
            }

            int distance = 1;

            while (true)
            {
                var expand = visited.SelectMany(o => bot.Map.Territories[o].ConnectedTo.Keys).Where(o => visited.Contains(o) == false && standing.Territories[o].OwnerPlayerID != bot.PlayerID).ToHashSet(false);

                if (expand.Count == 0)
                {
                    terrsWeEntered = null;
                    return(int.MaxValue);
                }

                contains = expand.Where(o => terrs.Contains(o)).ToHashSet(true);
                if (contains.Count > 0)
                {
                    //Found it
                    terrsWeEntered = contains;
                    return(distance);
                }

                distance++;
                if (distance > maxDistance)
                {
                    terrsWeEntered = null;
                    return(int.MaxValue);
                }
                visited.AddRange(expand);
            }

#if CS2HX || CSSCALA
            throw new Exception("Never");
#endif
        }
        /// <summary>
        /// Returns null if we can't find a way to take the bonus or if we already own it
        /// </summary>
        /// <param name="bot"></param>
        /// <param name="bonusID"></param>
        /// <returns></returns>
        public static MultiAttackPathToBonus TryCreate(BotMain bot, TerritoryIDType startFrom, BonusIDType bonusID, GameStanding standing, int maxDistance)
        {
            var bonus = bot.Map.Bonuses[bonusID];
            var allUnownedTerrsInBonus = bonus.Territories.Where(o => standing.Territories[o].OwnerPlayerID != bot.PlayerID).ToHashSet(true);

            if (allUnownedTerrsInBonus.Count == 0)
            {
                return(null); //already own it
            }
            HashSet <TerritoryIDType> terrsWeEnterBonus;

            int jumpsToGetToBonus = DistanceToTerrs(bot, startFrom, bonus.Territories.ToHashSet(true), standing, maxDistance, out terrsWeEnterBonus);

            if (jumpsToGetToBonus == int.MaxValue)
            {
                return(null); //can't take it within a reasonable searching distance
            }
            if (jumpsToGetToBonus == 0)
            {
                //We're already in it
                var armiesNeededToCapture = bot.ArmiesToTakeMultiAttack(allUnownedTerrsInBonus.Select(o => ExpansionHelper.GuessNumberOfArmies(bot, o, standing, MultiAttackExpand.GuessOpponentNumberOfArmiesInFog)));
                return(new MultiAttackPathToBonus(bot, startFrom, bonusID, 0, armiesNeededToCapture, 0, new List <TerritoryIDType>()));
            }
            else
            {
                var pathToGetThere = FindPath.TryFindShortestPath(bot, startFrom, t => terrsWeEnterBonus.Contains(t), visit => visit == startFrom || bot.IsTeammateOrUs(standing.Territories[visit].OwnerPlayerID) == false);
                if (pathToGetThere == null)
                {
                    return(null);
                }

                var getThere = pathToGetThere.ExceptOne(pathToGetThere.Last());
                var armiesNeededToCapture = bot.ArmiesToTakeMultiAttack(getThere.Concat(allUnownedTerrsInBonus).Select(o => ExpansionHelper.GuessNumberOfArmies(bot, o, standing, MultiAttackExpand.GuessOpponentNumberOfArmiesInFog)));

                return(new MultiAttackPathToBonus(bot, startFrom, bonusID, jumpsToGetToBonus, armiesNeededToCapture, getThere.Sum(o => ExpansionHelper.GuessNumberOfArmies(bot, o, standing).DefensePower), pathToGetThere));
            }
        }
Esempio n. 16
0
        public void Init(PlayerIDType myPlayerID, Dictionary <PlayerIDType, GamePlayer> players, MapDetails map, GameStanding distributionStanding, GameSettings settings, int numTurns, Dictionary <PlayerIDType, PlayerIncome> playerIncomes, GameOrder[] prevTurn, GameStanding latestTurnStanding, GameStanding previousTurnStanding, Dictionary <PlayerIDType, TeammateOrders> teammatesOrders, List <CardInstance> cards, int cardsMustPlay)
        {
            this.Players  = players;
            this.Me       = players[myPlayerID];
            this.Settings = settings;

            this.Map        = map;
            this.VisibleMap = new BotMap(this);
            foreach (var bonus in this.Map.Bonuses.Values)
            {
                VisibleMap.Bonuses.Add(bonus.ID, new BotBonus(VisibleMap, bonus.ID));
            }

            foreach (var terr in this.Map.Territories.Values)
            {
                VisibleMap.Territories.Add(terr.ID, new BotTerritory(VisibleMap, terr.ID, TerritoryStanding.FogPlayerID, new Armies(0)));
            }

            VisibleMap = BotMap.FromStanding(this, latestTurnStanding);

            this.DistributionStanding = distributionStanding;

            this.NumberOfTurns = numTurns;
            this.PlayerIncomes = playerIncomes;

            this.PrevTurn        = prevTurn;
            this.TeammatesOrders = teammatesOrders ?? new Dictionary <PlayerIDType, TeammateOrders>();
            this.Cards           = cards;
            this.CardsMustPlay   = cardsMustPlay;
        }
Esempio n. 17
0
 public MultiAttackExpand(BotMain bot)
 {
     this.Bot    = bot;
     this.Normal = new ExpandNormal(bot);
     this.MultiAttackStanding = (GameStanding)bot.Standing.Clone();
 }
Esempio n. 18
0
        private static IEnumerable <TerritoryIDType> ClusterOut(HashSet <TerritoryIDType> usedSpots, TerritoryIDType startingSpot, GameStanding standing, HashSet <TerritoryIDType> traversedSpots, MapDetails map, int maxPicks, int depth)
        {
            var ret = new List <TerritoryIDType>();

            if (usedSpots.Count >= maxPicks) //just for perf, we don't need to keep clustering if we've reached the max.  Our caller does the authoritive limit check.
            {
                return(ret);
            }

            traversedSpots.Add(startingSpot);
            foreach (var connected1 in map.Territories[startingSpot].ConnectedTo.Keys)
            {
                if (!usedSpots.Contains(connected1) && standing.Territories[connected1].OwnerPlayerID == TerritoryStanding.AvailableForDistribution)
                {
                    usedSpots.Add(connected1);
                    ret.Add(connected1);

                    if (usedSpots.Count >= maxPicks) //same comment as above
                    {
                        return(ret);
                    }
                }
            }

            if (depth >= 30) //prevent stack overflows
            {
                return(ret);
            }

            foreach (var connected2 in map.Territories[startingSpot].ConnectedTo.Keys)
            {
                if (!traversedSpots.Contains(connected2))
                {
                    foreach (var o in ClusterOut(usedSpots, connected2, standing, traversedSpots, map, maxPicks, depth + 1))
                    {
                        ret.Add(o);
                    }
                }
            }

            return(ret);
        }
Esempio n. 19
0
        public static Armies GuessNumberOfArmies(BotMain bot, TerritoryIDType terrID, GameStanding standing, Func <BotMain, TerritoryStanding, Armies> opponentFoggedTerritoryOpt = null)
        {
            var ts = standing.Territories[terrID];

            if (!ts.NumArmies.Fogged)
            {
                return(ts.NumArmies);
            }

            if (bot.IsOpponent(ts.OwnerPlayerID))
            {
                //We can see it's an opponent, but the armies are fogged.  This can happen in light, dense, or heavy fog. We have no way of knowing what's there, so just assume the minimum
                if (opponentFoggedTerritoryOpt != null)
                {
                    return(opponentFoggedTerritoryOpt(bot, ts));
                }
                else
                {
                    return(new Armies(bot.Settings.OneArmyMustStandGuardOneOrZero));
                }
            }

            if (bot.DistributionStandingOpt != null)
            {
                var dist = bot.DistributionStandingOpt.Territories[terrID];
                if (dist.IsNeutral)
                {
                    return(dist.NumArmies);
                }
                Assert.Fatal(dist.OwnerPlayerID == TerritoryStanding.AvailableForDistribution);

                return(new Armies(Math.Max(bot.Settings.InitialNeutralsInDistribution, bot.Settings.InitialPlayerArmiesPerTerritory))); //TODO: If it's not a random distribution, we could check if this territory is in the distribution and be more accurate on whether a player started with it or not.
            }

            return(new Armies(bot.Settings.InitialNonDistributionArmies));
        }
Esempio n. 20
0
        public static TerritoryIDType[] MakePicks(Dictionary <PlayerIDType, GamePlayer> players, GameStanding standing, GameSettings settings, MapDetails map, ushort scenarioID)
        {
            //Assert.Fatal(game.State == GameState.DistributingTerritories, "Called MakeClusterPicks in " + game.State);

            if (map.IsScenarioDistribution(settings.DistributionModeID))
            {
                var us = map.GetTerritoriesForScenario(settings.DistributionModeID, scenarioID);

                us.RandomizeOrder();
                return(us.ToArray());
            }
            else
            {
                int maxPicks = settings.LimitDistributionTerritories == 0 ? map.Territories.Count : (settings.LimitDistributionTerritories * players.Values.Count(o => o.State == GamePlayerState.Playing));

                var picks = new List <TerritoryIDType>();

                picks.Add(standing.Territories.Values.RandomWhere(o => o.OwnerPlayerID == TerritoryStanding.AvailableForDistribution).ID);

                var usedSpots = new HashSet <TerritoryIDType>();
                usedSpots.Add(picks[0]);

                foreach (var pick1 in ClusterOut(usedSpots, picks[0], standing, new HashSet <TerritoryIDType>(), map, maxPicks, 1))
                {
                    if (picks.Count >= maxPicks)
                    {
                        break;
                    }
                    picks.Add(pick1);
                    if (picks.Count >= maxPicks)
                    {
                        break;
                    }
                }

                if (picks.Count < maxPicks)
                {
                    //Due to stack depth, we may not traverse everything.  Finish it out.
                    foreach (var terr in map.Territories.Keys)
                    {
                        if (!usedSpots.Contains(terr) && standing.Territories[terr].OwnerPlayerID == TerritoryStanding.AvailableForDistribution)
                        {
                            picks.Add(terr);
                            if (picks.Count >= maxPicks)
                            {
                                break;
                            }
                        }
                    }
                }

                return(picks.ToArray());
            }
        }