// TODO endless recursion for some reason, so max depth. Probably when multiple choices available private List <MultiMoves> GetFollowupMoves(MultiMoves currentMoves, int currentDepth) { int maxDepth = 1; BreakBonusMultiTask breakBonusMultiTask = new BreakBonusMultiTask(); List <MultiMoves> breakFollowupupMoves = breakBonusMultiTask.CalculateBreakBonusMultiTask(currentMoves); TakeBonusMultiTask takeBonusMultiTask = new TakeBonusMultiTask(); List <MultiMoves> takeBonusFollowupMoves = takeBonusMultiTask.CalculateTakeBonusMultiTask(currentMoves); List <MultiMoves> followupMoves = new List <MultiMoves>(); followupMoves.AddRange(breakFollowupupMoves); followupMoves.AddRange(takeBonusFollowupMoves); if (currentDepth == maxDepth) { return(followupMoves); } List <MultiMoves> deeperMoves = new List <MultiMoves>(); foreach (MultiMoves followupMove in followupMoves) { deeperMoves.AddRange(GetFollowupMoves(followupMove, currentDepth + 1)); } followupMoves.AddRange(deeperMoves); return(followupMoves); }
private MultiMoves GetBreakBonusMoves(BonusIDType opponentBonus, MultiMoves presentMoves) { var bonusTerritories = GameState.Map.Bonuses[opponentBonus].Territories; var distances = MapInformer.GetDistancesFromTerritories(bonusTerritories); var ownedBorderTerritories = MapInformer.GetOwnedBorderTerritories(presentMoves.GetTerritoryStandingsAfterAllMoves(), GameState.MyPlayerId); int minDistance = ownedBorderTerritories.Min(o => distances[o.ID]); var bestStartTerritory = ownedBorderTerritories.Where(o => distances[o.ID] == minDistance).First(); int currentDistance = minDistance; var currentTerritoryInAttackPath = bestStartTerritory.ID; List <TerritoryIDType> territoriesToTake = new List <TerritoryIDType>(); while (currentDistance != 0) { var neighbors = MapInformer.GetNeighborTerritories(currentTerritoryInAttackPath); var possibleAttackNeighbors = neighbors.Where(n => distances[n] == currentDistance - 1).ToList(); var bestNeighborToAttack = GetBestNeighborToAttack(possibleAttackNeighbors); territoriesToTake.Add(bestNeighborToAttack); currentTerritoryInAttackPath = bestNeighborToAttack; currentDistance--; } TakeTerritoriesTask takeTerritoriesTask = new TakeTerritoriesTask(REASON); MultiMoves resultMoves = takeTerritoriesTask.CalculateTakeTerritoriesMoves(territoriesToTake, presentMoves); return(resultMoves); }
public MultiMoves CalculateTakeTerritoriesMoves(List <TerritoryIDType> territoriesToTake, MultiMoves precondition) { MultiMoves resultMoves = precondition.Clone(); List <TerritoryIDType> territoriesToTakeCopy = new List <TerritoryIDType>(territoriesToTake); while (territoriesToTakeCopy.Count > 0) { var reachableTerritories = FilterNonBorderingTerritories(territoriesToTakeCopy, resultMoves); if (reachableTerritories.Count == 0) { return(null); } var bestStartTerritory = GetBestAttackingTerritory(reachableTerritories, resultMoves); var bestAttackTerritory = GetBestAttackTerritory(reachableTerritories, territoriesToTakeCopy, bestStartTerritory, resultMoves); int neededAttackArmies = AttackInformer.GetNeededBreakArmies (resultMoves.GetTerritoryStandingsAfterAllMoves()[bestAttackTerritory].NumArmies.ArmiesOrZero); GameOrderAttackTransfer attackOrder = GameOrderAttackTransfer.Create (GameState.MyPlayerId, bestStartTerritory, bestAttackTerritory, AttackTransferEnum.AttackTransfer, new Armies(neededAttackArmies), REASON); var standing = resultMoves.GetTerritoryStandingsAfterAllMoves().Where(o => o.Key == attackOrder.From).First().Value; int leftoverArmies = standing.NumArmies.ArmiesOrZero - standing.ArmiesMarkedAsUsed.ArmiesOrZero - 1; int armiesToPump = Math.Max(0, attackOrder.NumArmies.ArmiesOrZero - leftoverArmies); bool successfull = resultMoves.PumpArmies(attackOrder.From, armiesToPump, REASON); if (!successfull) { return(null); } resultMoves.AddAttackOrder(attackOrder); territoriesToTakeCopy.Remove(bestAttackTerritory); } return(resultMoves); }
public MultiMoves GetMoves() { List <MultiMoves> allChoices = GetAllMoves(); MultiMoves bestChoice = GetBestMoves(allChoices); return(bestChoice); }
private List <MultiMoves> GetAllMoves() { MultiMoves bestMove = new MultiMoves(); List <MultiMoves> allMoves = new List <MultiMoves>(); int currentCount = 0; for (int i = 0; i < 4; i++) { allMoves.AddRange(GetFollowupMoves(bestMove, 0)); if (allMoves.Count == currentCount) { break; } currentCount = allMoves.Count; bestMove = GetBestMoves(allMoves); } if (allMoves.Count == 0) { allMoves.Add(new MultiMoves()); } var completedMoves = new List <MultiMoves>(); foreach (MultiMoves multiMove in allMoves) { var completedMove = new NoPlanAddAddRemainingTask().CalculateNoPlanMoves(multiMove); completedMove = new MoveArmiesToBorderTask().CalculateMoveArmiesToBorderMoves(completedMove); completedMoves.Add(completedMove); } return(completedMoves); }
public MultiMoves CalculateMoveArmiesToBorderMoves(MultiMoves presentMoves) { MultiMoves result = presentMoves.Clone(); var nonOwnedTerritories = MapInformer.GetNonOwnedTerritories(result.GetTerritoryStandingsAfterAllMoves().Values.ToList(), GameState.MyPlayerId); var keys = new List <TerritoryIDType>(); nonOwnedTerritories.ForEach(k => keys.Add(k.ID)); var distances = MapInformer.GetDistancesFromTerritories(keys); foreach (TerritoryIDType territoryId in distances.Keys) { int distance = distances[territoryId]; if (distance <= 1) { continue; } var neighbors = MapInformer.GetNeighborTerritories(territoryId); var lowestDistanceNeighborValue = neighbors.Min(c => distances[c]); var lowestDistanceNeighbor = neighbors.Where(n => distances[n] == lowestDistanceNeighborValue).First(); TerritoryStanding theTerritory = result.GetTerritoryStandingsAfterAllMoves()[territoryId]; int armiesAvailable = theTerritory.NumArmies.ArmiesOrZero - theTerritory.ArmiesMarkedAsUsed.ArmiesOrZero - 1; if (armiesAvailable == 0) { continue; } GameOrderAttackTransfer attackMove = GameOrderAttackTransfer.Create (GameState.MyPlayerId, territoryId, lowestDistanceNeighbor, AttackTransferEnum.AttackTransfer, new Armies(armiesAvailable), REASON); result.AddAttackOrder(attackMove); } return(result); }
// TODO returns no results private Dictionary <BonusIDType, BonusDetails> GetApplicableBonuses(MultiMoves presentMoves) { var territoryStandings = presentMoves.GetTerritoryStandingsAfterAllMoves(); Dictionary <BonusIDType, BonusDetails> allBonuses = GameState.Map.Bonuses; Dictionary <BonusIDType, BonusDetails> applicableBonuses = new Dictionary <BonusIDType, BonusDetails>(); Dictionary <BonusIDType, BonusDetails> ownedBonuses = MapInformer.GetOwnedBonuses(territoryStandings, GameState.MyPlayerId); foreach (BonusDetails bonus in allBonuses.Values) { if (ownedBonuses.Keys.Contains(bonus.ID)) { continue; } List <TerritoryIDType> bonusTerritoriesAndNeighbors = MapInformer.GetBonusTerritoriesAndNeighbors(bonus); foreach (var territoryId in bonusTerritoriesAndNeighbors) { if (territoryStandings[territoryId].OwnerPlayerID == GameState.MyPlayerId) { applicableBonuses.Add(bonus.ID, bonus); break; } } } return(applicableBonuses); }
public MultiMoves CalculateScheduledMoves(MultiMoves precondition) { MultiMoves resultMoves = precondition.Clone(); ScheduleDeployMoves(resultMoves); ScheduleAttackMoves(resultMoves); return(resultMoves); }
private void AddBorderTerritoryDeployment(MultiMoves movesSoFar, int availableDeployment) { TerritoryStanding territoryToDeployTo = MapInformer.GetOwnedBorderTerritories(movesSoFar.GetTerritoryStandingsAfterAllMoves(), GameState.MyPlayerId).FirstOrDefault(); if (territoryToDeployTo == null) { territoryToDeployTo = MapInformer.GetOwnedTerritories(GameState.CurrentTurn().LatestTurnStanding.Territories.Values.ToList(), GameState.MyPlayerId).First(); } movesSoFar.AddDeployOrder(GameOrderDeploy.Create(GameState.MyPlayerId, availableDeployment, territoryToDeployTo.ID, REASON)); }
public List <MultiMoves> CalculateBreakBonusMultiTask(MultiMoves presentMoves) { List <MultiMoves> resultMoves = new List <MultiMoves>(); var opponentBonuses = MapInformer.GetOwnedBonuses(presentMoves.GetTerritoryStandingsAfterAllMoves(), GameState.OpponentPlayerId); foreach (var opponentBonus in opponentBonuses) { MultiMoves breakBonusMoves = GetBreakBonusMoves(opponentBonus.Key, presentMoves); if (breakBonusMoves != null) { resultMoves.Add(breakBonusMoves); } } return(resultMoves); }
private GameOrderAttackTransfer GetBiggestAttackMove(MultiMoves movesSoFar) { if (movesSoFar.AttackMoves.Count() == 0) { return(null); } GameOrderAttackTransfer biggestAttack = movesSoFar.AttackMoves.First(); foreach (GameOrderAttackTransfer attackMove in movesSoFar.AttackMoves) { if (attackMove.NumArmies.ArmiesOrZero > biggestAttack.NumArmies.ArmiesOrZero) { biggestAttack = attackMove; } } return(biggestAttack); }
public MultiMoves CalculateNoPlanMoves(MultiMoves presentMoves) { MultiMoves resultMoves = presentMoves.Clone(); // we currently assume the biggest attack has to start from an owned territory GameOrderAttackTransfer biggestAttack = GetBiggestAttackMove(resultMoves); int stillAvailableDeployment = GameState.CurrentTurn().GetMyIncome() - resultMoves.GetCurrentDeployment(); if (biggestAttack != null) { PumpBiggestAttack(resultMoves, biggestAttack, stillAvailableDeployment); } else { AddBorderTerritoryDeployment(resultMoves, stillAvailableDeployment); } return(resultMoves); }
private void ScheduleDeployMoves(MultiMoves multiMoves) { var deployMoves = multiMoves.DeployMoves; deployMoves = deployMoves.OrderBy(d => d.DeployOn.GetValue()).ToList(); var enemyTerritories = MapInformer.GetOwnedTerritories(GameState.CurrentTurn().LatestTurnStanding.Territories.Values.ToList(), GameState.OpponentPlayerId); var enemyTerritoryIds = new List <TerritoryIDType>(); enemyTerritories.ForEach(t => enemyTerritoryIds.Add(t.ID)); var distances = MapInformer.GetDistancesFromTerritories(enemyTerritoryIds); var opponentNeighboringDeployMoves = deployMoves.Where(d => distances[d.DeployOn] == 1); var nonOpponentNeighboringDeployMoves = deployMoves.Where(d => distances[d.DeployOn] > 1); multiMoves.DeployMoves.Clear(); multiMoves.DeployMoves.AddRange(opponentNeighboringDeployMoves); multiMoves.DeployMoves.AddRange(nonOpponentNeighboringDeployMoves); }
// Calculates for each bonus on the map the steps necessary to take it // Currently only neighboring bonuses are seen as applicable public List <MultiMoves> CalculateTakeBonusMultiTask(MultiMoves presentMoves) { List <MultiMoves> resultMoves = new List <MultiMoves>(); Dictionary <BonusIDType, BonusDetails> applicableBonuses = GetApplicableBonuses(presentMoves); foreach (var bonus in applicableBonuses.Values) { var territoriesToTake = GetMissingBonusTerritories(bonus, presentMoves); TakeTerritoriesTask takeTerritoriesTask = new TakeTerritoriesTask(REASON); MultiMoves calculatedMoves = takeTerritoriesTask.CalculateTakeTerritoriesMoves(territoriesToTake, presentMoves); if (calculatedMoves != null) { resultMoves.Add(calculatedMoves); } } return(resultMoves); }
private MultiMoves GetBestMoves(List <MultiMoves> choices) { MultiMoves bestMoves = choices.FirstOrDefault(); foreach (MultiMoves multimoves in choices) { MapEvaluation testEvaluation = new MapEvaluation(multimoves); MapEvaluation bestMovesEvaluation = new MapEvaluation(bestMoves); int testEvaluationValue = testEvaluation.GetValue(); int bestMovesEvaluationValue = bestMovesEvaluation.GetValue(); if (testEvaluationValue > bestMovesEvaluationValue) { bestMoves = multimoves; } } bestMoves = new MovesScheduler().CalculateScheduledMoves(bestMoves); return(bestMoves); }
private List <TerritoryIDType> GetNonOwnedBonusTerritoriesToTake(MultiMoves multiMoves) { // Choose an arbitrary territory with a non owned neighbor TerritoryIDType nonOwnedTerritory = new TerritoryIDType(); foreach (var territory in multiMoves.GetTerritoryStandingsAfterAllMoves().Values.Where(t => t.OwnerPlayerID == GameState.MyPlayerId)) { var nonOwnedNeighbors = MapInformer.GetNonOwnedNeighborTerritories(territory.ID, multiMoves.GetTerritoryStandingsAfterAllMoves()); if (nonOwnedNeighbors.Count > 0) { nonOwnedTerritory = nonOwnedNeighbors.First().Key; break; } } var bonus = MapInformer.GetBonus(nonOwnedTerritory); AILog.Log("Debug", "Attempting to take bonus: " + bonus.Name); var nonOwnedBonusTerritories = MapInformer.GetNonOwnedBonusTerritories(bonus, multiMoves.GetTerritoryStandingsAfterAllMoves()); return(nonOwnedBonusTerritories); }
private TerritoryIDType GetBestOwnTerritoryToMakeAttack(Dictionary <TerritoryIDType, TerritoryStanding> ownedNeighbors, TerritoryIDType territoryToTake, MultiMoves currentMoves) { TerritoryIDType bestNeighbor = ownedNeighbors.First().Key; foreach (TerritoryIDType territoryId in ownedNeighbors.Keys) { var attackMoves = currentMoves.AttackMoves.Where(o => o.From == bestNeighbor && o.To == territoryId).ToList(); if (attackMoves.Count > 0) { bestNeighbor = attackMoves.First().To; } } // if we have all neighbors already choose the one with the max armies var ownedTerritories = MapInformer.GetOwnedTerritories(GameState.CurrentTurn().LatestTurnStanding.Territories.Values.ToList(), GameState.MyPlayerId); bool allNeighborsOwnedAtStart = true; foreach (TerritoryIDType ownedNeighbor in ownedNeighbors.Keys) { if (ownedTerritories.Where(o => o.ID == ownedNeighbor).Count() == 0) { allNeighborsOwnedAtStart = false; break; } } if (allNeighborsOwnedAtStart) { var territoryStandings = currentMoves.GetTerritoryStandingsAfterAllMoves(); foreach (TerritoryIDType ownedNeighbor in ownedNeighbors.Keys) { if (territoryStandings[ownedNeighbor].NumArmies.ArmiesOrZero > territoryStandings[bestNeighbor].NumArmies.ArmiesOrZero) { bestNeighbor = ownedNeighbor; } } } return(bestNeighbor); }
private void ScheduleAttackMoves(MultiMoves multiMoves) { var attackMoves = multiMoves.AttackMoves; /* * Algorithm * Step 1: Calculate the moves which belong together. The order of moves belonging together can't get changed. * Step 3: Schedule the moves */ List <List <GameOrderAttackTransfer> > movesBelongingTogether = GetMovesBelongingTogether(attackMoves); List <GameOrderAttackTransfer> resultMoves = new List <GameOrderAttackTransfer>(); while (movesBelongingTogether.Count() != 0) { var bestNextMove = movesBelongingTogether[0][0]; int bestNextMoveListIndex = 0; for (int i = 0; i < movesBelongingTogether.Count(); i++) { var testMove = movesBelongingTogether[i][0]; if (GetClassification(testMove) < GetClassification(bestNextMove)) { bestNextMove = testMove; bestNextMoveListIndex = i; } else if (GetClassification(testMove) == GetClassification(bestNextMove) && testMove.NumArmies.ArmiesOrZero > bestNextMove.NumArmies.ArmiesOrZero) { bestNextMove = testMove; bestNextMoveListIndex = i; } } resultMoves.Add(bestNextMove); movesBelongingTogether[bestNextMoveListIndex].Remove(bestNextMove); // Remove empty lists movesBelongingTogether.RemoveWhere(list => list.Count() == 0); } multiMoves.AttackMoves = resultMoves; }
private void PumpBiggestAttack(MultiMoves movesSoFar, GameOrderAttackTransfer biggestAttack, int availableDeployment) { if (availableDeployment == 0) { return; } movesSoFar.AddDeployOrder(GameOrderDeploy.Create(GameState.MyPlayerId, availableDeployment, biggestAttack.From, REASON)); var endAttack = biggestAttack; bool foundStep = true; while (foundStep) { foundStep = false; // probably endless loop possible as soon as we add transfer moves back to attacking territory var nextAttack = movesSoFar.AttackMoves.Where(a => a.From == endAttack.To).FirstOrDefault(); if (nextAttack != null) { endAttack = nextAttack; foundStep = true; } } movesSoFar.PumpArmies(endAttack.To, availableDeployment, REASON); }
public static void LogAllMoves(MultiMoves multiMoves) { var deployMoves = multiMoves.DeployMoves; var attackMoves = multiMoves.AttackMoves; MapDetails map = GameState.Map; foreach (GameOrderDeploy deployMove in deployMoves) { var territoryName = map.Territories[deployMove.DeployOn].Name; int armies = deployMove.NumArmies; String message = "Deployment on " + territoryName + " - Armies: " + armies + " - Reason: " + deployMove.Reason; AILog.Log("Debug", message); } foreach (GameOrderAttackTransfer attackMove in attackMoves) { var fromName = map.Territories[attackMove.From].Name; var toName = map.Territories[attackMove.To].Name; int armies = attackMove.NumArmies.ArmiesOrZero; String reason = attackMove.Reason; String message = "Attacking: " + fromName + " -[" + armies + "]-> " + toName + " - Reason: " + attackMove.Reason; AILog.Log("Debug", message); } }
private List <TerritoryIDType> GetMissingBonusTerritories(BonusDetails bonus, MultiMoves presentMoves) { var bonusTerritories = bonus.Territories; var currentStatus = presentMoves.GetTerritoryStandingsAfterAllMoves(); List <TerritoryIDType> territories = new List <TerritoryIDType>(); foreach (var bonusTerritory in bonusTerritories) { if (currentStatus[bonusTerritory].OwnerPlayerID != GameState.MyPlayerId) { territories.Add(bonusTerritory); } } return(territories); }
public static void LogEndMove(MultiMoves moves) { watch.Stop(); AILog.Log("Debug", "Round execution time: " + watch.ElapsedMilliseconds); LogAllMoves(moves); }
private TerritoryIDType GetBestAttackingTerritory(List <TerritoryIDType> takeTargets, MultiMoves presentMoves) { var currentGameStandings = presentMoves.GetTerritoryStandingsAfterAllMoves(); var ownedTerritories = MapInformer.GetOwnedTerritories(currentGameStandings.Values.ToList(), GameState.MyPlayerId); var possibleStartTerritories = new List <TerritoryStanding>(); foreach (var ownedTerritory in ownedTerritories) { List <TerritoryIDType> neighbors = MapInformer.GetNeighborTerritories(ownedTerritory.ID); var matchingNeighbors = neighbors.Where(n => takeTargets.Contains(n)).ToList(); if (matchingNeighbors.Count > 0) { possibleStartTerritories.Add(ownedTerritory); } } var bestStartTerritory = possibleStartTerritories.First(); var beginTurnStandings = GameState.CurrentTurn().LatestTurnStanding.Territories; foreach (var testTerritory in possibleStartTerritories) { bool bestTerritoryOwnedByMyself = beginTurnStandings[bestStartTerritory.ID].OwnerPlayerID == GameState.MyPlayerId; bool testTerritoryOwnedByMyself = beginTurnStandings[testTerritory.ID].OwnerPlayerID == GameState.MyPlayerId; // if one of them has no neighbors to take prefer the other one bool bestTerritoryCanContinue = MapInformer.GetNeighborTerritories(bestStartTerritory.ID).Where(n => takeTargets.Contains(n)).Count() > 0; bool testTerritoryCanContinue = MapInformer.GetNeighborTerritories(testTerritory.ID).Where(n => takeTargets.Contains(n)).Count() > 0; if (testTerritoryCanContinue && !bestTerritoryCanContinue) { bestStartTerritory = testTerritory; } // if both are already owned by myself at the beginning of the round prefer the one with more armies on it else if (bestTerritoryOwnedByMyself && testTerritoryOwnedByMyself) { if (testTerritory.NumArmies.ArmiesOrZero > bestStartTerritory.NumArmies.ArmiesOrZero) { bestStartTerritory = testTerritory; } } // if only one of them is owned by myself at the beginning of the round prefer the one not owned else if (bestTerritoryOwnedByMyself && !testTerritoryOwnedByMyself) { bestStartTerritory = testTerritory; } // if both aren't owned by myself at the beginning of the round prefer the one with the longer attack path else if (!bestTerritoryOwnedByMyself && !testTerritoryOwnedByMyself) { var bestPathCount = presentMoves.GetMovePath(bestStartTerritory.ID).Count(); var testPathCount = presentMoves.GetMovePath(testTerritory.ID).Count(); if (testPathCount > bestPathCount) { bestStartTerritory = testTerritory; } } } return(bestStartTerritory.ID); }
private TerritoryIDType GetBestAttackTerritory(List <TerritoryIDType> immediateTakeTargets, List <TerritoryIDType> allTakeTargets, TerritoryIDType attackingTerritory, MultiMoves presentMoves) { List <TerritoryIDType> borderingTargets = immediateTakeTargets.Where(t => MapInformer.GetNeighborTerritories(t).Contains(attackingTerritory)).ToList(); // We prefer territories with a as little neighboring territories in the takeTargets as possible var bestAttackTerritory = borderingTargets.First(); foreach (var testAttackTerritory in borderingTargets) { var bestAttackTerritoryNeighborCount = MapInformer.GetNeighborTerritories(bestAttackTerritory).Where(t => allTakeTargets.Contains(t)).Count(); var testAttackTerritoryNeighborCount = MapInformer.GetNeighborTerritories(testAttackTerritory).Where(t => allTakeTargets.Contains(t)).Count(); if (testAttackTerritoryNeighborCount < bestAttackTerritoryNeighborCount) { bestAttackTerritory = testAttackTerritory; } else if (testAttackTerritoryNeighborCount == bestAttackTerritoryNeighborCount) { // If both have the same amount we prefer territories with as little unowned neighbors as possible var bestUnownedNeighborCount = MapInformer.GetNonOwnedNeighborTerritories(bestAttackTerritory, presentMoves.GetTerritoryStandingsAfterAllMoves()).Count(); var testUnownedNeighborCount = MapInformer.GetNonOwnedNeighborTerritories(testAttackTerritory, presentMoves.GetTerritoryStandingsAfterAllMoves()).Count(); if (testUnownedNeighborCount < bestUnownedNeighborCount) { bestAttackTerritory = testAttackTerritory; } } } return(bestAttackTerritory); }
private List <TerritoryIDType> FilterNonBorderingTerritories(List <TerritoryIDType> territoriesToTake, MultiMoves presentMoves) { var standings = presentMoves.GetTerritoryStandingsAfterAllMoves(); return(territoriesToTake.Where(t => MapInformer.GetOwnedNeighborTerritories(t, standings).Count > 0).ToList()); }