Пример #1
0
        /// <summary>
        /// Runs the commander away from opponents
        /// </summary>
        private static void DoCommander(BotMain bot, TerritoryStanding cmdrTerritory, Commander cmdr)
        {
            var directive = CommanderDirective(bot, cmdrTerritory.ID);

            if (directive.HasValue)
            {
                AILog.Log("SpecialUnits", "Directive directs us to move the commander from " + bot.TerrString(cmdrTerritory.ID) + " to " + bot.TerrString(directive.Value));

                if (directive.Value != cmdrTerritory.ID)
                {
                    bot.Orders.AddAttack(cmdrTerritory.ID, directive.Value, AttackTransferEnum.AttackTransfer, cmdrTerritory.NumArmies.NumArmies, false, commanders: true);
                }
                bot.AvoidTerritories.Add(cmdrTerritory.ID); //add this so we don't deploy there, we want the commander to stay alone
                return;
            }

            var powerDiff = bot.Map.Territories[cmdrTerritory.ID].ConnectedTo.Keys
                            .Select(o => bot.Standing.Territories[o])
                            .Where(o => bot.IsOpponent(o.OwnerPlayerID) && o.NumArmies.Fogged == false)
                            .Sum(o => o.NumArmies.AttackPower)
                            - cmdrTerritory.NumArmies.DefensePower;
            var toDeploy = Math.Max(0, powerDiff);

            if (powerDiff > 0)
            {
                if (bot.UseRandomness)
                {
                    toDeploy = SharedUtility.Round(toDeploy * RandomUtility.BellRandom(0.5, 1.5));
                }
                if (toDeploy > bot.MakeOrders.IncomeTracker.RemainingUndeployed)
                {
                    toDeploy = bot.MakeOrders.IncomeTracker.RemainingUndeployed;
                }

                if (toDeploy > 0 && bot.Orders.TryDeploy(cmdrTerritory.ID, toDeploy))
                {
                    AILog.Log("SpecialUnits", "Deployed " + toDeploy + " to defend commander");
                }
            }

            //Consider this territory and all adjacent territories.  Which is the furthest from any enemy?
            var terrDistances = bot.Map.Territories[cmdrTerritory.ID].ConnectedTo.Keys.ConcatOne(cmdrTerritory.ID)
                                .Where(o => bot.Standing.Territories[o].OwnerPlayerID == bot.PlayerID || bot.Standing.Territories[o].NumArmies.DefensePower <= 4) //don't go somewhere that's defended heavily
                                .ToDictionary(o => o, o => bot.DistanceFromEnemy(o));

            AILog.Log("SpecialUnits", "Commander run options: " + terrDistances.Select(o => bot.TerrString(o.Key) + " dist=" + o.Value).JoinStrings(", "));

            var sorted = terrDistances.OrderByDescending(o => o.Value).ToList();

            sorted.RemoveWhere(o => o.Value < sorted[0].Value);

            var runTo = bot.UseRandomness ? sorted.Random().Key : sorted[0].Key;

            if (runTo == cmdrTerritory.ID)
            {
                return; //already there
            }
            AILog.Log("SpecialUnits", "Moving commander from " + bot.TerrString(cmdrTerritory.ID) + " to " + bot.TerrString(runTo));
            bot.Orders.AddAttack(cmdrTerritory.ID, runTo, AttackTransferEnum.AttackTransfer, cmdrTerritory.NumArmies.NumArmies + toDeploy, false, commanders: true);
        }
Пример #2
0
        public int ArmiesToTake(Armies defenseArmies)
        {
            Assert.Fatal(!defenseArmies.Fogged, "ArmiesToTake called on fog");

            var ret = SharedUtility.Round((defenseArmies.DefensePower / Settings.OffenseKillRate) - 0.5);

            if (ret == SharedUtility.Round(defenseArmies.DefensePower * Settings.DefenseKillRate))
            {
                ret++;
            }

            if (Settings.RoundingMode == RoundingModeEnum.WeightedRandom && (!UseRandomness || RandomUtility.RandomNumber(3) != 0))
            {
                ret++;
            }

            if (Settings.LuckModifier > 0)
            {
                //Add up some armies to account for luck
                var factor = UseRandomness ? RandomUtility.BellRandom(2.5, 17.5) : 10.0;
                ret += SharedUtility.Round(Settings.LuckModifier / factor * ret);
            }

            return(ret);
        }
Пример #3
0
        public void Go(int incomeToUse)
        {
            if (WeightedMoves.None())
            {
                AILog.Log("DefendAttack", "No attacks or defenses to do, skipping DefendAttack");
                return; //No attacks possible
            }

            //Divide between offense and defense.  Defense armies could still be used for offense if we happen to attack there
            var baseOffenseRatio = (Bot.IsFFA ? 0.3 : 0.6);

            if (Bot.Settings.MultiAttack)
            {
                baseOffenseRatio = 0; //in MA, our expansion routine is actually our primary attack weapon.  Therefore, set offense ratio to 0 so that we skip the routine that tries to attack one territory at a time.
            }
            var offenseRatio    = baseOffenseRatio + (Bot.UseRandomness ? RandomUtility.BellRandom(-.15, .15) : 0);
            int armiesToOffense = SharedUtility.Round(incomeToUse * offenseRatio);
            int armiesToDefense = incomeToUse - armiesToOffense;

            AILog.Log("DefendAttack", "offenseRatio=" + offenseRatio + ": " + armiesToOffense + " armies go to offense, " + armiesToDefense + " armies go to defense");

            //Find defensive opportunities.
            var orderedDefenses = WeightedMoves.OrderByDescending(o => o.DefenseImportance).ToList();
            var orderedAttacks  = WeightedMoves.OrderByDescending(o => o.OffenseImportance).ToList();


            DoDefense(armiesToDefense, orderedDefenses);
            DoOffense(armiesToOffense, orderedAttacks);
        }
Пример #4
0
        private void BuildCities()
        {
            if (Bot.Settings.CommerceGame == false || Bot.Settings.CommerceCityBaseCost.HasValue == false)
            {
                return; //can't build cities
            }
            var totalGold  = Bot.Standing.NumResources(Bot.PlayerID, ResourceType.Gold);
            var spentGold  = Bot.Settings.CostOfBuyingArmies(IncomeTracker.TotalArmiesDeployed);
            var maxPercent = !Bot.UseRandomness ? 0.5 : RandomUtility.BellRandom(0, 0.9);
            int goldLeftToSpendOnCities = Math.Min(totalGold - spentGold, SharedUtility.Round(totalGold * maxPercent)); //limit our cities to about half our gold to ensure we don't over-build

            AILog.Log("BuildCities", "totalGold=" + totalGold + " spentGold=" + spentGold + " goldToSpendOnCities=" + goldLeftToSpendOnCities + " maxPercent=" + maxPercent);

            if (goldLeftToSpendOnCities < Bot.Settings.CommerceCityBaseCost.Value)
            {
                return; //can't even afford one city
            }
            //randomize the safe range.  This makes it
            int acceptableRangeFromOpponent = !Bot.UseRandomness ? 4 : SharedUtility.Round(RandomUtility.BellRandom(2, 6));

            var eligibleTerritories = Bot.TerritoriesNotNearOpponent(acceptableRangeFromOpponent);

            eligibleTerritories.RemoveAll(Bot.AvoidTerritories);

            var numCitiesOn = eligibleTerritories.ToDictionary(o => o, o => Bot.Standing.Territories[o].NumStructures(StructureType.City));

            //while we might be able to afford a city...
            while (goldLeftToSpendOnCities > Bot.Settings.CommerceCityBaseCost.Value)
            {
                var fewestCities     = numCitiesOn.Values.Min();
                var cheapestCityCost = fewestCities + Bot.Settings.CommerceCityBaseCost.Value;
                if (goldLeftToSpendOnCities < cheapestCityCost)
                {
                    return; //can't afford any more, we must have one on every spot which increases the cost.
                }
                //We can afford it, let's build a city
                var buildCityOn = Bot.UseRandomness ? numCitiesOn.Where(o => o.Value == fewestCities).Random().Key : numCitiesOn.Where(o => o.Value == fewestCities).OrderBy(o => (int)o.Key).First().Key;
                goldLeftToSpendOnCities -= cheapestCityCost; //remember that we spent it for the loop above.

                AILog.Log("BuildCities", "Building a city on " + Bot.TerrString(buildCityOn) + " for " + cheapestCityCost + " unspentGold=" + goldLeftToSpendOnCities);

                Orders.PurchaseOrder.BuildCities.AddTo(buildCityOn, 1);
                numCitiesOn.AddTo(buildCityOn, 1);

                //Since we spent gold, adjust the remaining deployable armies so we don't overdeploy later
                this.UpdateEffectiveIncome();
            }
        }
Пример #5
0
        public float BonusFuzz(BonusIDType bonusID)
        {
            if (!UseRandomness)
            {
                return(0);
            }

            if (_bonusFuzz == null)
            {
                _bonusFuzz = new Dictionary <BonusIDType, float>();
            }

            if (!_bonusFuzz.ContainsKey(bonusID))
            {
                _bonusFuzz.Add(bonusID, (float)RandomUtility.BellRandom(-2, 2));
            }

            return(_bonusFuzz[bonusID]);
        }
Пример #6
0
        public override void Go(int useArmies, bool highlyValuedOnly)
        {
            //In FFA, focus on expansion even moreso than in headsup
            float minWeight = !highlyValuedOnly ? float.MinValue : ExpansionHelper.BaseBonusWeight + (Bot.IsFFA ? -10 : 0) + (Bot.UseRandomness ? (float)RandomUtility.BellRandom(-9, 9) : 0);

            AILog.Log("Expand", "Expand called with useArmies=" + useArmies + ", minWeight=" + minWeight);
            Assert.Fatal(useArmies >= 0, "useArmies negative");

            var meetsFilter = AttackableNeutrals.Where(o => o.Value.Weight > minWeight).ToDictionary(o => o.Key, o => o.Value);  //Don't bother with anything less than the min weight

            AILog.Log("Expand", meetsFilter.Count + " items over weight " + minWeight + " (" + AttackableNeutrals.Count + " total), top:");
            foreach (var spot in meetsFilter.OrderByDescending(o => o.Value.Weight).Take(10))
            {
                AILog.Log("Expand", " - " + spot.Value);
            }

            int armiesToExpandWithRemaining = useArmies;

            while (meetsFilter.Count > 0)
            {
                var expandTo = meetsFilter.OrderByDescending(o => o.Value.Weight).First().Key;
                meetsFilter.Remove(expandTo);

                if (Bot.Orders.Orders.OfType <GameOrderAttackTransfer>().Any(o => o.To == expandTo))
                {
                    continue; //we've already attacked it
                }
                int attackWith = Bot.ArmiesToTake(Bot.Standing.Territories[expandTo].NumArmies.Fogged ? ExpansionHelper.GuessNumberOfArmies(Bot, expandTo) : Bot.Standing.Territories[expandTo].NumArmies);

                var attackFromList = Bot.Map.Territories[expandTo].ConnectedTo.Keys
                                     .Select(o => Bot.Standing.Territories[o])
                                     .Where(o => o.OwnerPlayerID == Bot.PlayerID && !Bot.AvoidTerritories.Contains(o.ID))
                                     .ToDictionary(o => o.ID, o => Bot.MakeOrders.GetArmiesAvailable(o.ID))
                                     .OrderByDescending(o => o.Value).ToList();

                if (attackFromList.Count == 0)
                {
                    continue; //nowhere to attack from
                }
                var attackFrom = attackFromList[0];

                int armiesNeedToDeploy = Math.Max(0, attackWith - attackFrom.Value);

                if (armiesToExpandWithRemaining >= armiesNeedToDeploy)
                {
                    //Deploy if needed
                    if (armiesNeedToDeploy > 0)
                    {
                        armiesToExpandWithRemaining -= armiesNeedToDeploy;
                        if (!Bot.Orders.TryDeploy(attackFrom.Key, armiesNeedToDeploy))
                        {
                            continue;
                        }
                        else
                        {
                            //Remember that we deployed armies towards the capture of this bonus
                            foreach (var bonusID in AttackableNeutrals[expandTo].Bonuses.Keys)
                            {
                                foreach (var an in AttackableNeutrals.Values)
                                {
                                    if (an.Bonuses.ContainsKey(bonusID))
                                    {
                                        an.Bonuses[bonusID].DeployedTowardsCapturing += armiesNeedToDeploy;
                                    }
                                }
                            }
                        }
                    }

                    AILog.Log("Expand", "Expanding into " + Bot.TerrString(expandTo) + " from " + Bot.TerrString(attackFrom.Key) + " with " + attackWith + " by deploying " + armiesNeedToDeploy + ", already had " + attackFrom.Value + " available");

                    //Attack
                    Bot.Orders.AddAttack(attackFrom.Key, expandTo, AttackTransferEnum.AttackTransfer, attackWith, false);
                }
            }
        }
Пример #7
0
        private static bool PlayBlockadeCard(BotMain bot, CardInstance card)
        {
            //Look for bonuses that we can't hold and should blockade
            foreach (var bonus in bot.Map.Bonuses.Values)
            {
                var grouped = bonus.Territories.GroupBy(o => bot.Standing.Territories[o].OwnerPlayerID).ToDictionary(o => o.Key, o => o);
                if (!grouped.ContainsKey(bot.PlayerID))
                {
                    continue; //we're not in it
                }
                if (grouped.ContainsKey(TerritoryStanding.NeutralPlayerID))
                {
                    continue; //only complete bonuses -- if it's never been taken, don't blockade
                }
                var opps = grouped.Keys.Where(o => bot.IsOpponent(o)).ToList();
                if (opps.Count == 0)
                {
                    continue; //no opponents in it
                }
                if (bonus.Territories.Any(t => bot.AvoidTerritories.Contains(t)))
                {
                    continue; //already doing something here, perhaps already blockading it.
                }
                var oppTerrs       = opps.SelectMany(o => grouped[o].ToList()).ToHashSet(false);
                var friendlyTerrs  = grouped.Where(o => bot.IsTeammateOrUs(o.Key)).SelectMany(o => o.Value.ToList()).ToList();
                var friendlyArmies = friendlyTerrs.Sum(o => bot.Standing.Territories[o].NumArmies.DefensePower);
                var enemyArmies    = oppTerrs.Sum(o => ExpansionHelper.GuessNumberOfArmies(bot, o).AttackPower);
                var ratio          = bot.UseRandomness ? RandomUtility.BellRandom(1, 3) : 2;
                if (friendlyArmies * ratio > enemyArmies)
                {
                    continue;
                }

                var armies = SharedUtility.Round(bot.EffectiveIncome.FreeArmies * (bot.UseRandomness ? RandomUtility.BellRandom(.1, .4) : .25));
                if (armies < 5)
                {
                    armies = 5;
                }

                var canBlockade = friendlyTerrs.Where(o =>
                                                      bot.Standing.Territories[o].OwnerPlayerID == bot.PlayerID &&
                                                      bot.Map.Territories[o].ConnectedTo.Keys.None(t => oppTerrs.Contains(t)) &&
                                                      bot.Standing.Territories[o].NumArmies.SpecialUnits.Length == 0 &&
                                                      bot.Standing.Territories[o].NumArmies.NumArmies < armies * 2
                                                      ).ToList();
                if (canBlockade.Count == 0)
                {
                    continue;
                }
                var blockade = bot.UseRandomness ? canBlockade.Random() : canBlockade.First();
                var deploy   = Math.Max(0, armies - bot.Standing.Territories[blockade].NumArmies.NumArmies);

                if (!bot.Orders.TryDeploy(blockade, deploy))
                {
                    continue;
                }

                AILog.Log("PlayCards", "Blockading " + bot.TerrString(blockade) + " with " + armies + " (had to deploy " + deploy + ")");

                bot.Orders.AddOrder(GameOrderPlayCardBlockade.Create(card.ID, bot.PlayerID, blockade));
                bot.AvoidTerritories.Add(blockade);
                return(true);
            }

            return(false);
        }
Пример #8
0
        private static bool PlayBombCard(BotMain bot, CardInstance card)
        {
            var allBombableEnemyTerritories = bot.Standing.Territories.Values
                                              .Where(o => o.OwnerPlayerID == bot.PlayerID)
                                              .SelectMany(o => bot.Map.Territories[o.ID].ConnectedTo.Keys)
                                              .Distinct()
                                              .Select(o => bot.Standing.Territories[o])
                                              .Where(o => bot.IsOpponent(o.OwnerPlayerID) && o.NumArmies.Fogged == false)
                                              .ToList();

            var minArmies = !bot.UseRandomness ? bot.BaseIncome.Total * 2 : SharedUtility.Round(bot.BaseIncome.Total * RandomUtility.BellRandom(1, 3));

            var weights = allBombableEnemyTerritories.Where(o => o.NumArmies.NumArmies > minArmies).ToDictionary(o => o.ID, o => o.NumArmies.NumArmies - minArmies);

            if (weights.Count == 0)
            {
                return(false);
            }

            var bomb = bot.UseRandomness ? RandomUtility.WeightedRandom(weights.Keys, o => weights[o]) : weights.OrderByDescending(o => o.Value).First().Key;

            AILog.Log("PlayCards", "Bombing " + bot.TerrString(bomb));
            bot.Orders.AddOrder(GameOrderPlayCardBomb.Create(card.ID, bot.PlayerID, bomb));
            return(true);
        }