Esempio n. 1
0
        private static TerritoryIDType?CommanderDirective(BotMain bot, TerritoryIDType commanderOn)
        {
            var directive = bot.Directives.SingleOrDefault(o => o.StartsWith("CommanderRunTo "));

            if (directive == null)
            {
                return(null);
            }

            var runTo = (TerritoryIDType)int.Parse(directive.RemoveFromStartOfString("CommanderRunTo "));

            return(FindPath.TryFindShortestPath(bot, commanderOn, t => t == runTo)[0]);
        }
        /// <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. 3
0
        private static void DoBoss(BotMain bot, TerritoryStanding terr, SpecialUnit su)
        {
            AILog.Log("SpecialUnits", "Considering boss " + su.ID + " on " + bot.TerrString(terr.ID));

            var routes = bot.Directives.Where(o => o.StartsWith("BossRoute ")).Select(o => new BossRoute(o, bot)).ToList();

            var routeNexts = routes.Select(o => new { Route = o, Terr = o.NextTerr(terr.ID) }).Where(o => o.Terr.HasValue).ToList();

            if (routeNexts.Count > 0)
            {
                var routeNext = routeNexts.WeightedRandom(o => o.Route.Weight);
                AILog.Log("SpecialUnits", routeNexts.Count + " matching routes: " + routeNexts.Select(o => o.Route.Name).JoinStrings(", ") + ", selected " + routeNext.Route);

                if (RandomUtility.RandomPercentage() > routeNext.Route.Chance)
                {
                    AILog.Log("SpecialUnits", "Skipping boss route to " + routeNext.Terr.Value + " due to failed random chance. ");
                }
                else
                {
                    AILog.Log("SpecialUnits", "Moving boss along route to " + bot.TerrString(routeNext.Terr.Value) + ". ");
                    bot.Orders.AddAttack(terr.ID, routeNext.Terr.Value, AttackTransferEnum.AttackTransfer, 0, true, bosses: true);
                    bot.AvoidTerritories.Add(routeNext.Terr.Value);
                    return;
                }
            }
            else if (routes.Count > 0)
            {
                //Move towards the nearest route territory. If there's a tie, take the one that's furthest along in that route
                var terrRoutes = routes.SelectMany(r => r.Route.Select((t, i) => new { Route = r, Terr = t, Index = i }))
                                 .GroupBy(o => o.Terr)
                                 .Select(o => o.MaxSelectorOrDefault(r => r.Index))
                                 .ToDictionary(o => o.Terr, o => o);

                var visited = new HashSet <TerritoryIDType>();
                visited.Add(terr.ID);

                while (true)
                {
                    var visit = visited.SelectMany(o => bot.Map.Territories[o].ConnectedTo.Keys).ToHashSet(false);
                    if (visit.Count == 0)
                    {
                        throw new Exception("Never found route territory");
                    }

                    var visitOnRoute = visit.Where(o => terrRoutes.ContainsKey(o)).ToList();
                    if (visitOnRoute.Count > 0)
                    {
                        var final = visitOnRoute.Select(o => terrRoutes[o]).MaxSelectorOrDefault(o => o.Index);
                        if (RandomUtility.RandomPercentage() > final.Route.Chance)
                        {
                            AILog.Log("SpecialUnits", "Skipping moving boss to route due to failed random check: " + final.Route);
                            break;
                        }
                        else
                        {
                            var move = FindPath.TryFindShortestPath(bot, terr.ID, t => t == final.Terr);
                            AILog.Log("SpecialUnits", "Moving boss to get back to route. Moving to " + bot.TerrString(move[0]) + " to get to " + bot.TerrString(final.Terr) + " index=" + final.Index + " " + final.Route);
                            bot.Orders.AddAttack(terr.ID, move[0], AttackTransferEnum.AttackTransfer, 0, true, bosses: true);
                            bot.AvoidTerritories.Add(final.Terr);
                            return;
                        }
                    }

                    visited.AddRange(visit);
                }
            }

            var attackCandidates = bot.Map.Territories[terr.ID].ConnectedTo.Keys.Select(o => bot.Standing.Territories[o])
                                   .Where(o => !bot.IsTeammateOrUs(o.OwnerPlayerID) && o.NumArmies.DefensePower < 300 && !bot.AvoidTerritories.Contains(o.ID))
                                   .ToList();

            if (attackCandidates.Count > 0)
            {
                var ranks = attackCandidates.ToDictionary(o => o.ID, ts =>
                {
                    if (bot.IsOpponent(ts.OwnerPlayerID))
                    {
                        return(bot.Players[ts.OwnerPlayerID].IsAI ? 3 : 2); //prefer human player
                    }
                    else if (ts.OwnerPlayerID == TerritoryStanding.NeutralPlayerID)
                    {
                        return(1);
                    }
                    else
                    {
                        throw new Exception("Unexpected owner " + ts.OwnerPlayerID);
                    }
                });

                var max = ranks.Values.Max();
                var to  = ranks.Where(o => o.Value == max).Random().Key;
                AILog.Log("SpecialUnits", "Normal boss move to " + bot.TerrString(to));
                bot.Orders.AddAttack(terr.ID, to, AttackTransferEnum.AttackTransfer, 0, false, bosses: true);
                bot.AvoidTerritories.Add(to);
            }
            else
            {
                //Surrounded by ourself or teammates. Move towards enemy
                var move = bot.MoveTowardsNearestBorderNonNeutralThenNeutral(terr.ID);
                if (move.HasValue)
                {
                    AILog.Log("SpecialUnits", "Landlocked boss move to " + bot.TerrString(move.Value));
                    bot.Orders.AddAttack(terr.ID, move.Value, AttackTransferEnum.AttackTransfer, 0, false, bosses: true);
                }
            }
        }