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); }
public static void PrintTerritories(BotMap map, BotMain BotState) { List <BotTerritory> territories = map.Territories.Values.ToList(); //List<BotTerritory> opponentTerritories = territories.Where(o => o.OwnerPlayerID == BotState.Opponents.First().ID).ToList(); AILog.Log("Debug", "Territories:"); foreach (BotTerritory territory in territories) { string player = "fog"; if (territory.OwnerPlayerID == TerritoryStanding.NeutralPlayerID) { player = "neutral"; } else if (territory.OwnerPlayerID == BotState.Me.ID) { player = "Me"; } else if (territory.OwnerPlayerID == BotState.Opponents.First().ID) { player = "opponent"; } AILog.Log("Debug", territory.Details.Name + ": (" + player + " | " + territory.IsOwnershipHeuristic + ") --> " + territory.Armies.AttackPower); } }
public void DumpToLog() { AILog.Log("MovesCalculator", "Final " + Orders.Count + " orders:"); foreach (var order in Orders) { if (order is BotOrderDeploy) { var dep = (BotOrderDeploy)order; AILog.Log("MovesCalculator", " - " + dep.Armies + " on " + dep.Territory.Details.Name + " " + dep.Territory.ToString()); } else if (order is BotOrderAttackTransfer) { var attack = (BotOrderAttackTransfer)order; AILog.Log("MovesCalculator", " - " + attack.From.Details.Name + " -> " + attack.To.Details.Name + " " + attack.Armies + " Message=" + attack.Message + ", Source=" + attack.Source); } else if (order is BotOrderGeneric) { AILog.Log("MovesCalculator", " - " + order.As <BotOrderGeneric>().Order.ToString()); } else { throw new Exception("Unexpected order type"); } } }
public static List <TerritoryIDType> Go(BotMain bot, HashSet <TerritoryIDType> allAvailable, int maxPicks) { var expansionWeights = allAvailable.ToDictionary(o => o, o => GetExpansionWeight(bot, o)); var ordered = expansionWeights.OrderByDescending(o => o.Value).ToList(); AILog.Log("PickTerritories", "Came up with " + expansionWeights.Count + " expansion weights: "); foreach (var e in ordered.Take(30)) { AILog.Log("PickTerritories", " - " + bot.TerrString(e.Key) + ": " + e.Value); } if (!bot.UseRandomness) { return(ordered.Select(o => o.Key).Take(maxPicks).ToList()); } //Normalize weights var top = ordered.Take(maxPicks * 2); var sub = top.Min(o => o.Value) - 1; var normalized = top.ToDictionary(o => o.Key, o => o.Value - sub); var picks = new List <TerritoryIDType>(); while (picks.Count < maxPicks && normalized.Count > 0) { var pick = RandomUtility.WeightedRandom(normalized.Keys, o => normalized[o]); picks.Add(pick); normalized.Remove(pick); } return(picks); }
public void PrintReport() { var bonusIds = new List <BonusIDType>(Bot.BotMap.Bonuses.Keys); bonusIds.Sort(); AILog.Log("BonusAnalyzer", "Expected troops: " + TroopEstimate); foreach (var i in bonusIds) { var s = Bot.BotMap.GetBonus(i); var msg = s.ToString(); if (MightBeOwned(s)) { msg += "YES:"; } else { msg += "NO:"; } msg += " " + BonusBuckets[s.ID] + " / " + BonusCosts[s.ID]; if (SoonBeOwned(s)) { msg += " SOON"; } AILog.Log("BonusAnalyzer", msg); } }
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"); }
private static float GetExpansionWeight(BotMain bot, TerritoryIDType terrID) { var td = bot.Map.Territories[terrID]; var bonusPaths = td.PartOfBonuses .Where(o => bot.BonusValue(o) > 0) .Select(o => BonusPath.TryCreate(bot, o, ts => ts.ID == terrID)) .Where(o => o != null) .ToDictionary(o => o.BonusID, o => o); var turnsToTake = bonusPaths.Keys.ToDictionary(o => o, o => TurnsToTake(bot, td.ID, o, bonusPaths[o])); foreach (var cannotTake in turnsToTake.Where(o => o.Value == null).ToList()) { turnsToTake.Remove(cannotTake.Key); bonusPaths.Remove(cannotTake.Key); } var bonusWeights = bonusPaths.Keys.ToDictionary(o => o, o => ExpansionHelper.WeighBonus(bot, o, ts => ts.ID == terrID, turnsToTake[o].NumTurns)); var weight = 0.0f; weight += ExpansionHelper.WeighMultipleBonuses(td.PartOfBonuses.Where(o => bonusWeights.ContainsKey(o)).ToDictionary(o => o, o => bonusWeights[o])); AILog.Log("PickTerritories", "Expansion weight for terr " + bot.TerrString(terrID) + " is " + weight + ". " + td.PartOfBonuses.Select(b => "Bonus " + bot.BonusString(b) + " Weight=" + (bonusWeights.ContainsKey(b) ? bonusWeights[b] : 0) + " TurnsToTake=" + (turnsToTake.ContainsKey(b) ? turnsToTake[b].ToString() : "") + " Path=" + (bonusPaths.ContainsKey(b) ? bonusPaths[b].ToString() : "")).JoinStrings(", ")); return(weight); }
private void DoOffense(int armiesToOffense, List <PossibleAttack> orderedAttacks) { AILog.Log("Offense", orderedAttacks.Count + " attack ops: "); foreach (var attack in orderedAttacks.Take(10)) { AILog.Log("Offense", " - " + attack); } var armiesLeft = armiesToOffense; if (!Bot.UseRandomness) { int attackIndex = 0; while (attackIndex < orderedAttacks.Count) { TryDoAttack(orderedAttacks[attackIndex], ref armiesLeft); attackIndex++; } } else { while (orderedAttacks.Count > 0) { if (armiesLeft == 0 && Bot.PastTime(8)) { return; //if we're running slowly and have no armies to deploy, just skip attacks. We just miss out on attacks that we could have done with standing armies. } var i = RandomUtility.WeightedRandomIndex(orderedAttacks, o => o.OffenseImportance); TryDoAttack(orderedAttacks[i], ref armiesLeft); orderedAttacks.RemoveAt(i); } } }
public static void PrintTerritoryValues(BotMap map, BotMain BotState) { AILog.Log("Territory attack values:"); foreach (BotTerritory territory in map.Territories.Values) { if (territory.IsVisible && BotState.IsOpponent(territory.OwnerPlayerID)) { AILog.Log(territory.Details.Name + ": " + territory.AttackTerritoryValue); } } AILog.Log("Territory expansion values:"); foreach (BotTerritory territory in map.Territories.Values) { if (territory.IsVisible && territory.OwnerPlayerID == TerritoryStanding.NeutralPlayerID) { AILog.Log(territory.Details.Name + ": " + territory.ExpansionTerritoryValue); } } AILog.Log("Territory defend values:"); foreach (BotTerritory territory in map.Territories.Values) { if (territory.OwnerPlayerID == BotState.Me.ID && territory.GetOpponentNeighbors().Count > 0) { AILog.Log(territory.Details.Name + ": " + territory.DefenceTerritoryValue); } } }
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); }
/// <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); }
private void TryDoAttack(PossibleAttack attack, ref int armiesToOffense) { bool commanders = true; var toTS = Bot.Standing.Territories[attack.To]; int attackWith = Bot.ArmiesToTake(toTS.NumArmies.Fogged == false ? toTS.NumArmies : ExpansionHelper.GuessNumberOfArmies(Bot, toTS.ID)); //Add a few more to what's required so we're not as predictable. if (Bot.UseRandomness) { attackWith += SharedUtility.Round(attackWith * (RandomUtility.RandomPercentage() * .2)); //Once in a while, be willing to do a stupid attack. Sometimes it will work out, sometimes it will fail catastrophically if (RandomUtility.RandomNumber(20) == 0) { var origAttackWith = attackWith; attackWith = SharedUtility.Round(attackWith * RandomUtility.RandomPercentage()); commanders = false; if (attackWith != origAttackWith) { AILog.Log("Offense", "Willing to do a \"stupid\" attack from " + Bot.TerrString(attack.From) + " to " + Bot.TerrString(attack.To) + ": attacking with " + attackWith + " instead of our planned " + origAttackWith); } } } else { attackWith += SharedUtility.Round(attackWith * 0.1); } int have = Bot.MakeOrders.GetArmiesAvailable(attack.From); int need = Math.Max(0, attackWith - have); if (need > armiesToOffense) { //We can't swing it. Just deploy the rest and quit. Will try again next turn. if (armiesToOffense > 0 && Bot.Orders.TryDeploy(attack.From, armiesToOffense)) { AILog.Log("Offense", "Could not attack from " + Bot.TerrString(attack.From) + " to " + Bot.TerrString(attack.To) + " with " + attackWith + ". Short by " + need + ". Just deploying " + armiesToOffense + " to the source."); armiesToOffense = 0; } } else { //We can attack. First deploy however many we needed if (need > 0) { if (!Bot.Orders.TryDeploy(attack.From, need)) { return; } armiesToOffense -= need; Assert.Fatal(armiesToOffense >= 0); } //Now issue the attack Bot.Orders.AddAttack(attack.From, attack.To, AttackTransferEnum.AttackTransfer, attackWith, false, commanders: commanders); AILog.Log("Offense", "Attacking from " + Bot.TerrString(attack.From) + " to " + Bot.TerrString(attack.To) + " with " + attackWith + " by deploying " + need); } }
private static bool PlayReinforcementCard(BotMain bot, CardInstance card) { var numArmies = card.As <ReinforcementCardInstance>().Armies; AILog.Log("PlayCards", "Playing reinforcement card for " + numArmies); bot.Orders.AddOrder(GameOrderPlayCardReinforcement.Create(card.ID, bot.PlayerID)); bot.EffectiveIncome.FreeArmies += numArmies; return(true); }
public static void LogBeginGame() { var territories = GameState.Map.Territories.Values.ToList(); foreach (var territory in territories) { AILog.Log("Debug", territory.ID + " --> " + territory.Name); } }
private static void PrintDistances(BotMain state) { AILog.Log("Territory distances:"); foreach (var territory in state.VisibleMap.GetOwnedTerritories()) { var message = territory.ID + " --> " + territory.DirectDistanceToOpponentBorder + " | " + territory.DistanceToUnimportantSpot + " | " + territory.DistanceToImportantSpot + " | " + territory.DistanceToHighlyImportantSpot + " | " + territory.DistanceToOpponentBorder + " | " + territory.DistanceToImportantOpponentBorder + " || " + TransferMovesChooser.GetAdjustedDistance(territory); AILog.Log(message); } }
public virtual void Update(PlayerIDType opponentID, int opponentDeployment) { AILog.Log("DeploymentHistory", "VisibleDeployment for " + opponentID + ": " + opponentDeployment); OpponentDeployments[opponentID] = opponentDeployment; if (BotState.NumberOfTurns > 0) { Memory.DeploymentTracker.SetDeploys(opponentID, opponentDeployment, BotState.NumberOfTurns - 1); } }
private void AssignExpansionWeights(Dictionary <TerritoryIDType, int> attackableNeutrals) { AILog.Log("AssignExpansionWeights called with " + attackableNeutrals.Count + " neutrals"); foreach (var attackableNeutral in attackableNeutrals.Keys.ToList()) { int weight = 0; foreach (var bonusID in Map.Territories[attackableNeutral].PartOfBonuses) { int bonusValue = BonusValue(bonusID); if (bonusValue == 0) { continue; //Don't even consider bonuses with no worth } if (bonusValue < 0) { weight -= 50; //Don't want negative bonuses } //Is it part of a bonus? Add ArmiesPerTurn * 3. TODO: We should weight income higher in big FFA games weight += 3 * bonusValue; //How many territories do we need to take to get it? Subtract one weight for each army standing in our way foreach (var terrInBonus in Map.Bonuses[bonusID].Territories) { var ts = Standing.Territories[terrInBonus]; if (ts.OwnerPlayerID == PlayerID) { continue; //Already own it } else if (ts.OwnerPlayerID == TerritoryStanding.FogPlayerID) { weight -= Settings.InitialNonDistributionArmies; //assume neutral on fogged items } else if (IsTeammateOrUs(ts.OwnerPlayerID)) { weight -= ts.NumArmies.NumArmies * 4; //Teammate in it } else if (ts.IsNeutral) { weight -= ts.NumArmies.NumArmies; //Neutral in it } else { weight -= ts.NumArmies.NumArmies * 2; //Opponent in it - expansion less likely } } } attackableNeutrals[attackableNeutral] = weight; } }
public static void Go(BotMain bot) { if (bot.GamePlayerReference.Team != PlayerInvite.NoTeam && bot.Players.Values.Any(o => o.ID != bot.PlayerID && !o.IsAIOrHumanTurnedIntoAI && o.Team == bot.GamePlayerReference.Team && o.State == GamePlayerState.Playing && !o.HasCommittedOrders)) { return; //If there are any humans on our team that have yet to take their turn, do not play cards. } var cardsPlayedByTeammate = bot.TeammatesSubmittedOrders.OfType <GameOrderPlayCard>().Select(o => o.CardInstanceID) .Concat(bot.TeammatesSubmittedOrders.OfType <GameOrderDiscard>().Select(o => o.CardInstanceID)) .ToHashSet(true); int numMustPlay = bot.CardsMustPlay; if (numMustPlay > 0) { AILog.Log("PlayCards", "Must play " + numMustPlay + " cards, have " + bot.Cards.Count + ", teammate played " + cardsPlayedByTeammate.Count); } var availableCards = bot.Cards.ToDictionary(o => o.ID, o => o); foreach (var card in bot.Cards) { if (cardsPlayedByTeammate.Contains(card.ID)) { //Teammate played it availableCards.Remove(card.ID); continue; } Action <CardType, Func <BotMain, CardInstance, bool> > tryPlay = (cardType, playFn) => { if (card.CardID == cardType.CardID && playFn(bot, card)) { availableCards.Remove(card.ID); numMustPlay--; } }; tryPlay(CardType.Reinforcement, PlayReinforcementCard); tryPlay(CardType.Sanctions, PlaySanctionsCard); tryPlay(CardType.Bomb, PlayBombCard); tryPlay(CardType.Blockade, PlayBlockadeCard); tryPlay(CardType.Diplomacy, PlayDiplomacyCard); } while (numMustPlay > 0) { var card = availableCards.First().Value; AILog.Log("PlayCards", "Discarding card " + card + ", type=" + card.CardID); bot.Orders.AddOrder(GameOrderDiscard.Create(bot.PlayerID, card.ID)); numMustPlay--; availableCards.Remove(card.ID); } }
public bool PastTime(double seconds) { var ret = Timer.Elapsed.TotalSeconds >= seconds; if (ret) { AILog.Log("BotMain", "PastTime " + seconds + " seconds, at " + Timer.Elapsed.TotalSeconds + " seconds"); } return(ret); }
public static void printExpandBonusValues(BotMap map, BotMain BotState) { AILog.Log("Bonus expansion values:"); foreach (BotBonus bonus in map.Bonuses.Values) { if (bonus.GetOwnedTerritoriesAndNeighbors().Count > 0 && !bonus.IsOwnedByMyself()) { AILog.Log(bonus.Details.Name + ": " + bonus.GetExpansionValue()); } } }
public static void PrintAllTerritories(BotMain state, BotMap map) { AILog.Log("Debug", "Territories:"); foreach (var territory in map.Territories.Values) { var id = territory.ID; var player = territory.OwnerPlayerID; var armies = territory.Armies; var ownershipHeuristic = territory.IsOwnershipHeuristic; var deployment = territory.GetTotalDeployment(BotTerritory.DeploymentType.Normal); AILog.Log("Debug", " - Territory " + id + " (" + player + " | " + armies + " | " + ownershipHeuristic + " | " + deployment + ")"); } }
public static void Go(BotMain bot) { var terrs = bot.Standing.Territories.Values.Where(o => bot.IsTeammateOrUs(o.OwnerPlayerID) && o.NumArmies.NumArmies == bot.Settings.OneArmyMustStandGuardOneOrZero && o.NumArmies.SpecialUnits.Length == 0).Select(o => o.ID).ToHashSet(true); foreach (var bonus in bot.Map.Bonuses.Values) { if (bonus.Territories.All(o => terrs.Contains(o)) && bonus.ControlsBonus(bot.Standing).HasValue == false) { //bot bonus is entirely controlled by our team with 1s, but not by a single player. The player with the most territories should take it. var owners = bonus.Territories.GroupBy(o => bot.Standing.Territories[o].OwnerPlayerID).ToList(); owners.Sort((f, s) => SharedUtility.CompareInts(s.Count(), f.Count())); Assert.Fatal(owners.Count >= 2); var attacks = bonus.Territories .Where(o => bot.Standing.Territories[o].OwnerPlayerID != bot.PlayerID) //Territories in the bonus by our teammate .Where(o => bot.Map.Territories[o].ConnectedTo.Keys.Any(c => bot.Standing.Territories[c].OwnerPlayerID == bot.PlayerID)) //Where we control an adjacent .Select(o => new PossibleAttack(bot, bot.Map.Territories[o].ConnectedTo.Keys.First(c => bot.Standing.Territories[c].OwnerPlayerID == bot.PlayerID), o)); if (owners[0].Count() == owners[1].Count()) { //The top two players have the same number of terrs. 50% chance we should try taking one. if (attacks.Any() && RandomUtility.RandomNumber(2) == 0) { var doAttack1 = bot.UseRandomness ? attacks.Random() : attacks.First(); var numArmies = bot.ArmiesToTake(bot.Standing.Territories[doAttack1.To].NumArmies); if (bot.Orders.TryDeploy(doAttack1.From, numArmies)) { AILog.Log("ResolveTeamBonuses", "Detected a split bonus " + bot.BonusString(bonus) + ", and we're attempting to break the split by doing a small attack from " + bot.TerrString(doAttack1.From) + " to " + bot.TerrString(doAttack1.To) + " with " + numArmies); bot.Orders.AddAttack(doAttack1.From, doAttack1.To, AttackTransferEnum.Attack, numArmies, true); } } } else if (owners[0].Key == bot.PlayerID) { //We should take the bonus foreach (var doAttack2 in attacks) { var numArmies = bot.ArmiesToTake(bot.Standing.Territories[doAttack2.To].NumArmies); if (bot.Orders.TryDeploy(doAttack2.From, numArmies)) { AILog.Log("ResolveTeamBonuses", "Detected we should take bonus " + bot.BonusString(bonus) + ", so we're attacking from " + bot.TerrString(doAttack2.From) + " to " + bot.TerrString(doAttack2.To) + " with " + numArmies); bot.Orders.AddAttack(doAttack2.From, doAttack2.To, AttackTransferEnum.Attack, 2, true); } } } } } }
public List <TerritoryIDType> GetPicks() { var territoryList = DistributionStanding.Territories.Values.Where(o => o.OwnerPlayerID == TerritoryStanding.AvailableForDistribution).Select(o => BotMap.Territories[o.ID]).ToList(); territoryList.Sort(new StartingTerritoryComparator(this)); AILog.Log("Picking " + territoryList.Count + " territories: "); foreach (var terr in territoryList) { AILog.Log(" - " + terr); } return(territoryList.Select(o => o.ID).ToList()); }
private static void PrintOpponentBonuses(PlayerIDType opponentID, BotMain state) { var message = new StringBuilder(); message.Append("Opponent owns Bonuses: "); foreach (var bonus in state.VisibleMap.Bonuses.Values) { if (bonus.IsOwnedByOpponent(opponentID)) { message.Append(bonus.Details.Name + ", "); } } AILog.Log("Debug", message.ToString()); }
public List <GameOrder> GetOrders() { var deploys = GetPlaceArmiesMoves(); var attacks = GetAttackTransferMoves(); var final = deploys.Cast <BotOrder>().Concat(attacks).ToList(); AILog.Log("Final " + final.Count + " orders: "); foreach (var order in final) { AILog.Log(" - " + order); } return(BotOrder.Convert(final)); }
private static bool PlaySanctionsCard(BotMain bot, CardInstance card) { var canSanction = bot.Players.Values.Where(o => o.State == GamePlayerState.Playing && bot.IsOpponent(o.ID)).Select(o => o.ID).ToList(); if (canSanction.Count == 0) { return(false); } var sanction = bot.UseRandomness ? RandomUtility.WeightedRandom(canSanction, o => bot.WeightedNeighbors[o]) : canSanction.OrderByDescending(o => bot.WeightedNeighbors[o]).First(); AILog.Log("PlayCards", "Sanctioning " + sanction); bot.Orders.AddOrder(GameOrderPlayCardSanctions.Create(card.ID, bot.PlayerID, sanction)); return(true); }
private Dictionary <TerritoryIDType, PossibleExpandTarget> GetExpansionWeights(HashSet <TerritoryIDType> terrs) { var bonusPaths = terrs .SelectMany(o => Bot.Map.Territories[o].PartOfBonuses) .Where(o => Bot.BonusValue(o) > 0) .Distinct() .Select(o => { if (Bot.PastTime(7)) { return(null); //stop trying to expand if we're slow } return(BonusPath.TryCreate(Bot, o, ts => ts.OwnerPlayerID == Bot.PlayerID)); }) .Where(o => o != null) .ToDictionary(o => o.BonusID, o => o); var turnsToTake = bonusPaths.Keys.ToDictionary(o => o, o => TurnsToTake(o, bonusPaths[o])); foreach (var cannotTake in turnsToTake.Where(o => o.Value == null).ToList()) { turnsToTake.Remove(cannotTake.Key); bonusPaths.Remove(cannotTake.Key); } var bonusWeights = bonusPaths.Keys.ToDictionary(o => o, o => ExpansionHelper.WeighBonus(Bot, o, ts => ts.OwnerPlayerID == Bot.PlayerID, turnsToTake[o].NumTurns)); AILog.Log("Expand", "GetExpansionWeights called with " + terrs.Count + " territories. Weighted " + bonusWeights.Count + " bonuses:"); foreach (var bw in bonusWeights.OrderByDescending(o => o.Value).Take(10)) { AILog.Log("Expand", " - " + Bot.BonusString(bw.Key) + " Weight=" + bw.Value + " " + turnsToTake[bw.Key] + " TurnsToTakeByDistance=" + bonusPaths[bw.Key].TurnsToTakeByDistance + " CriticalPath=" + bonusPaths[bw.Key].TerritoriesOnCriticalPath.Select(o => Bot.TerrString(o)).JoinStrings(", ")); } var ret = new Dictionary <TerritoryIDType, PossibleExpandTarget>(); foreach (var terr in terrs) { ret[terr] = new PossibleExpandTarget(Bot, terr, Bot.Map.Territories[terr].PartOfBonuses.Where(b => bonusPaths.ContainsKey(b)).ToDictionary(b => b, b => new PossibleExpandTargetBonus(bonusWeights[b], bonusPaths[b], turnsToTake[b]))); } AILog.Log("Expand", "Finished weighing " + terrs.Count + " territories:"); foreach (var terr in ret.OrderByDescending(o => o.Value.Weight).Take(10)) { AILog.Log("Expand", " - " + Bot.TerrString(terr.Key) + " Weight=" + terr.Value); } return(ret); }
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(); } }
public static void Go(BotMain bot) { var attacks = bot.Orders.Orders.OfType <GameOrderAttackTransfer>(); foreach (var orders in attacks .Where(o => bot.Standing.Territories[o.From].OwnerPlayerID == bot.PlayerID) .Select(o => new UtilizeSpareArmies(o, bot.MakeOrders.GetArmiesAvailable(o.From))) .Where(o => o.Available > 0) .GroupBy(o => o.Order.From)) { var order = bot.UseRandomness ? orders.Random() : orders.First(); AILog.Log("UtilizeSpareArmies", "Adding " + order.Available + " available armies into attack from " + bot.TerrString(order.Order.From) + " to " + bot.TerrString(order.Order.To) + ", originally had " + order.Order.NumArmies.NumArmies); order.Order.NumArmies = order.Order.NumArmies.Add(new Armies(order.Available)); } }
public static void PlayCardsBeginTurn(BotMain state, Moves moves) { //If there are any humans on our team that have yet to take their turn, do not play cards. if (state.Me.Team != PlayerInvite.NoTeam && state.Players.Values.Any(o => state.IsTeammate(o.ID) && !o.IsAIOrHumanTurnedIntoAI && o.State == GamePlayerState.Playing && !o.HasCommittedOrders)) { return; } foreach (var reinforcementCard in state.CardsHandler.GetCards(CardTypes.Reinforcement)) { var numArmies = reinforcementCard.As <ReinforcementCard>().Armies; AILog.Log("PlayCardsTask", "Playing reinforcement card " + reinforcementCard.CardInstanceId + " for " + numArmies + " armies"); moves.AddOrder(new BotOrderGeneric(GameOrderPlayCardReinforcement.Create(reinforcementCard.CardInstanceId, state.Me.ID))); state.MyIncome.FreeArmies += numArmies; } }