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
        }
Пример #2
0
        private void TryExpand(ref int armiesLeft, int maxDistanceArg, float armyMult, Dictionary <BonusIDType, float> bonusWeights)
        {
            var maxDistance = maxDistanceArg;

            foreach (var borderTerritory in MultiAttackStanding.Territories.Values.Where(o => Bot.IsBorderTerritory(MultiAttackStanding, o.ID)).OrderByDescending(o => o.NumArmies.NumArmies).ToList())
            {
                if (Bot.PastTime(10))
                {
                    return;
                }

                var stackSize = Math.Max(0, MultiAttackStanding.Territories[borderTerritory.ID].NumArmies.NumArmies - Bot.Settings.OneArmyMustStandGuardOneOrZero);
                var canDeployOnBorderTerritory = Bot.Standing.Territories[borderTerritory.ID].OwnerPlayerID == Bot.PlayerID;

                if (stackSize == 0 && !canDeployOnBorderTerritory)
                {
                    continue;
                }

                var bonusPaths = Bot.Map.Bonuses.Keys
                                 .Where(o => Bot.BonusValue(o) > 0)
                                 .Select(o =>
                {
                    if (maxDistance > 1 && Bot.PastTime(7))
                    {
                        AILog.Log("MultiAttackExpand", "Due to slow speed, reducing bonus search distance from " + maxDistance + " to 1");
                        maxDistance = 1;     //if we're taking too long, give up on far away bonuses.  Otherwise this algorithm can take forever on large maps
                    }
                    if (Bot.PastTime(10))
                    {
                        return(null);
                    }

                    return(MultiAttackPathToBonus.TryCreate(Bot, borderTerritory.ID, o, MultiAttackStanding, maxDistance));
                })
                                 .Where(o => o != null)
                                 .ToDictionary(o => o.BonusID, o => o);

                var adjustedWeights = bonusPaths.Values.ToDictionary(o => o.BonusID, o => bonusWeights[o.BonusID] - o.ArmiesNeedToKillToGetThere * armyMult);

                //AILog.Log("ExpandMultiAttack", "Found " + bonusPaths.Count + " bonuses in range of " + Bot.TerrString(borderTerritory.ID) + ": " + bonusPaths.Values.OrderByDescending(o => adjustedWeights[o.BonusID]).Select(o => Bot.BonusString(o.BonusID)).JoinStrings(", "));


                foreach (var bonus in bonusPaths.Values.OrderByDescending(o => adjustedWeights[o.BonusID]))
                {
                    var estimatedArmiesNeedToDeploy = Math.Max(0, bonus.EstArmiesNeededToCapture - stackSize);
                    if (estimatedArmiesNeedToDeploy > armiesLeft)
                    {
                        continue;
                    }
                    if (estimatedArmiesNeedToDeploy > 0 && !canDeployOnBorderTerritory)
                    {
                        continue;
                    }

                    AILog.Log("ExpandMultiAttack", "Considering expansion to bonus " + Bot.BonusString(bonus.BonusID) + " from " + Bot.TerrString(borderTerritory.ID) + ".  stackSize=" + stackSize + " estimatedArmiesNeedToDeploy=" + estimatedArmiesNeedToDeploy + " weight=" + adjustedWeights[bonus.BonusID] + " ArmiesNeedToKillToGetThere=" + bonus.ArmiesNeedToKillToGetThere + " EstArmiesNeededToCapture=" + bonus.EstArmiesNeededToCapture + " armiesLeft=" + armiesLeft + " PathToGetThere=" + bonus.PathToGetThere.Select(o => Bot.TerrString(o)).JoinStrings(" -> "));

                    var plan = MultiAttackPlan.TryCreate(Bot, bonus, MultiAttackStanding, borderTerritory.ID);

                    if (plan == null)
                    {
                        AILog.Log("ExpandMultiAttack", " - Could not find a plan");
                        continue;
                    }

                    var actualArmiesNeedToCapture = Bot.ArmiesToTakeMultiAttack(plan.Select(o => ExpansionHelper.GuessNumberOfArmies(Bot, o.To, MultiAttackStanding, GuessOpponentNumberOfArmiesInFog)));
                    var actualArmiesNeedToDeploy  = Math.Max(0, actualArmiesNeedToCapture - stackSize);
                    if (actualArmiesNeedToDeploy > armiesLeft)
                    {
                        AILog.Log("ExpandMultiAttack", " - actualArmiesNeedToDeploy=" + actualArmiesNeedToDeploy + " is not enough, have " + armiesLeft);
                        continue;
                    }

                    var stackStartedFrom = this.StackStartedFrom.ContainsKey(borderTerritory.ID) ? this.StackStartedFrom[borderTerritory.ID] : borderTerritory.ID;
                    if (!Bot.Orders.TryDeploy(stackStartedFrom, actualArmiesNeedToDeploy))
                    {
                        AILog.Log("ExpandMultiAttack", " - Could not deploy armies");
                        continue;
                    }
                    armiesLeft -= actualArmiesNeedToDeploy;


                    AILog.Log("ExpandMultiAttack", " - Attempting to capture. actualArmiesNeedToDeploy=" + actualArmiesNeedToDeploy + " plan=" + plan.Select(o => o.ToString()).JoinStrings(" -> "));

                    var terr = borderTerritory.ID;
                    foreach (var planStep in plan)
                    {
                        Assert.Fatal(Bot.Map.Territories[terr].ConnectedTo.ContainsKey(planStep.To), terr + " does not connect to " + planStep.To);

                        var defendersKill = SharedUtility.Round(ExpansionHelper.GuessNumberOfArmies(Bot, planStep.To).DefensePower *Bot.Settings.DefenseKillRate);
                        if (planStep.Type == MultiAttackPlanType.MainStack)
                        {
                            Bot.Orders.AddAttack(terr, planStep.To, AttackTransferEnum.AttackTransfer, 100, false, true);
                            MultiAttackStanding.Territories[planStep.To]    = TerritoryStanding.Create(planStep.To, Bot.PlayerID, MultiAttackStanding.Territories[terr].NumArmies.Subtract(new Armies(defendersKill)));
                            MultiAttackStanding.Territories[terr].NumArmies = new Armies(Bot.Settings.OneArmyMustStandGuardOneOrZero);

                            terr = planStep.To;
                        }
                        else if (planStep.Type == MultiAttackPlanType.OneTerritoryOffshoot)
                        {
                            var attackWith = Bot.ArmiesToTake(ExpansionHelper.GuessNumberOfArmies(Bot, planStep.To));
                            Bot.Orders.AddAttack(terr, planStep.To, AttackTransferEnum.AttackTransfer, attackWith, false, false);

                            MultiAttackStanding.Territories[planStep.To]    = TerritoryStanding.Create(planStep.To, Bot.PlayerID, new Armies(attackWith - defendersKill));
                            MultiAttackStanding.Territories[terr].NumArmies = MultiAttackStanding.Territories[terr].NumArmies.Subtract(new Armies(attackWith));
                        }

                        this.StackStartedFrom.Add(planStep.To, stackStartedFrom);
                    }

                    //After taking a bonus, we changed MultiAttackStanding. Therefore, we need to re-calc everything.
                    TryExpand(ref armiesLeft, maxDistance, armyMult, bonusWeights);
                    return;
                }
            }
        }