use of games.strategy.triplea.ai.pro.data.ProBattleResult in project triplea by triplea-game.
the class ProNonCombatMoveAi method prioritizeDefendOptions.
private List<ProTerritory> prioritizeDefendOptions(final Map<Territory, ProTerritory> factoryMoveMap, final Map<Territory, Double> territoryValueMap) {
ProLogger.info("Prioritizing territories to try to defend");
final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Calculate value of defending territory
for (final Territory t : moveMap.keySet()) {
// Determine if it is my capital or adjacent to my capital
int isMyCapital = 0;
if (t.equals(ProData.myCapital)) {
isMyCapital = 1;
}
// Determine if it has a factory
int isFactory = 0;
if (ProMatches.territoryHasInfraFactoryAndIsLand().test(t) || (factoryMoveMap != null && factoryMoveMap.containsKey(t))) {
isFactory = 1;
}
// Determine production value and if it is an enemy capital
int production = 0;
int isEnemyOrAlliedCapital = 0;
final TerritoryAttachment ta = TerritoryAttachment.get(t);
if (ta != null) {
production = ta.getProduction();
if (ta.isCapital() && !t.equals(ProData.myCapital)) {
isEnemyOrAlliedCapital = 1;
}
}
// Determine neighbor value
double neighborValue = 0;
if (!t.isWater()) {
final Set<Territory> landNeighbors = data.getMap().getNeighbors(t, Matches.territoryIsLand());
for (final Territory neighbor : landNeighbors) {
double neighborProduction = TerritoryAttachment.getProduction(neighbor);
if (Matches.isTerritoryAllied(player, data).test(neighbor)) {
neighborProduction = 0.1 * neighborProduction;
}
neighborValue += neighborProduction;
}
}
// Determine defending unit value
final int cantMoveUnitValue = TuvUtils.getTuv(moveMap.get(t).getCantMoveUnits(), ProData.unitValueMap);
double unitOwnerMultiplier = 1;
if (moveMap.get(t).getCantMoveUnits().stream().noneMatch(Matches.unitIsOwnedBy(player))) {
if (t.isWater() && moveMap.get(t).getCantMoveUnits().stream().noneMatch(Matches.unitIsTransportButNotCombatTransport())) {
unitOwnerMultiplier = 0;
} else {
unitOwnerMultiplier = 0.5;
}
}
// Calculate defense value for prioritization
final double territoryValue = unitOwnerMultiplier * (2 * production + 10 * isFactory + 0.5 * cantMoveUnitValue + 0.5 * neighborValue) * (1 + 10 * isMyCapital) * (1 + 4 * isEnemyOrAlliedCapital);
moveMap.get(t).setValue(territoryValue);
}
// Sort attack territories by value
final List<ProTerritory> prioritizedTerritories = new ArrayList<>(moveMap.values());
prioritizedTerritories.sort(Comparator.comparingDouble(ProTerritory::getValue));
// Remove territories that I'm not going to try to defend
for (final Iterator<ProTerritory> it = prioritizedTerritories.iterator(); it.hasNext(); ) {
final ProTerritory patd = it.next();
final Territory t = patd.getTerritory();
final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
final ProBattleResult minResult = patd.getMinBattleResult();
final int cantMoveUnitValue = TuvUtils.getTuv(moveMap.get(t).getCantMoveUnits(), ProData.unitValueMap);
final List<Unit> maxEnemyUnits = patd.getMaxEnemyUnits();
final boolean isLandAndCanOnlyBeAttackedByAir = !t.isWater() && !maxEnemyUnits.isEmpty() && maxEnemyUnits.stream().allMatch(Matches.unitIsAir());
final boolean isNotFactoryAndShouldHold = !hasFactory && (minResult.getTuvSwing() <= 0 || !minResult.isHasLandUnitRemaining());
final boolean canAlreadyBeHeld = minResult.getTuvSwing() <= 0 && minResult.getWinPercentage() < (100 - ProData.winPercentage);
final boolean isNotFactoryAndHasNoEnemyNeighbors = !t.isWater() && !hasFactory && !ProMatches.territoryHasNeighborOwnedByAndHasLandUnit(data, ProUtils.getPotentialEnemyPlayers(player)).test(t);
final boolean isNotFactoryAndOnlyAmphib = !t.isWater() && !hasFactory && moveMap.get(t).getMaxUnits().stream().noneMatch(Matches.unitIsLand()) && cantMoveUnitValue < 5;
if (!patd.isCanHold() || patd.getValue() <= 0 || isLandAndCanOnlyBeAttackedByAir || isNotFactoryAndShouldHold || canAlreadyBeHeld || isNotFactoryAndHasNoEnemyNeighbors || isNotFactoryAndOnlyAmphib) {
final double tuvSwing = minResult.getTuvSwing();
final boolean hasRemainingLandUnit = minResult.isHasLandUnitRemaining();
ProLogger.debug("Removing territory=" + t.getName() + ", value=" + patd.getValue() + ", CanHold=" + patd.isCanHold() + ", isLandAndCanOnlyBeAttackedByAir=" + isLandAndCanOnlyBeAttackedByAir + ", isNotFactoryAndShouldHold=" + isNotFactoryAndShouldHold + ", canAlreadyBeHeld=" + canAlreadyBeHeld + ", isNotFactoryAndHasNoEnemyNeighbors=" + isNotFactoryAndHasNoEnemyNeighbors + ", isNotFactoryAndOnlyAmphib=" + isNotFactoryAndOnlyAmphib + ", tuvSwing=" + tuvSwing + ", hasRemainingLandUnit=" + hasRemainingLandUnit + ", maxEnemyUnits=" + patd.getMaxEnemyUnits().size());
it.remove();
}
}
// Add best sea production territory for sea factories
List<Territory> seaFactories = CollectionUtils.getMatches(data.getMap().getTerritories(), ProMatches.territoryHasInfraFactoryAndIsNotConqueredOwnedLand(player, data));
seaFactories = CollectionUtils.getMatches(seaFactories, ProMatches.territoryHasInfraFactoryAndIsOwnedLandAdjacentToSea(player, data));
for (final Territory t : seaFactories) {
if (territoryValueMap.get(t) >= 1) {
continue;
}
final Set<Territory> neighbors = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, true));
double maxValue = 0;
Territory maxTerritory = null;
for (final Territory neighbor : neighbors) {
if (moveMap.get(neighbor) != null && moveMap.get(neighbor).isCanHold() && territoryValueMap.get(neighbor) > maxValue) {
maxTerritory = neighbor;
maxValue = territoryValueMap.get(neighbor);
}
}
if (maxTerritory != null && enemyAttackOptions.getMax(maxTerritory) != null) {
boolean alreadyAdded = false;
for (final ProTerritory patd : prioritizedTerritories) {
if (patd.getTerritory().equals(maxTerritory)) {
alreadyAdded = true;
}
}
if (!alreadyAdded) {
prioritizedTerritories.add(moveMap.get(maxTerritory));
}
}
}
// Log prioritized territories
for (final ProTerritory attackTerritoryData : prioritizedTerritories) {
ProLogger.debug("Value=" + attackTerritoryData.getValue() + ", " + attackTerritoryData.getTerritory().getName());
}
return prioritizedTerritories;
}
use of games.strategy.triplea.ai.pro.data.ProBattleResult in project triplea by triplea-game.
the class ProSimulateTurnUtils method simulateBattles.
public static void simulateBattles(final GameData data, final PlayerID player, final IDelegateBridge delegateBridge, final ProOddsCalculator calc) {
ProLogger.info("Starting battle simulation phase");
final BattleDelegate battleDelegate = DelegateFinder.battleDelegate(data);
final Map<BattleType, Collection<Territory>> battleTerritories = battleDelegate.getBattles().getBattles();
for (final Entry<BattleType, Collection<Territory>> entry : battleTerritories.entrySet()) {
for (final Territory t : entry.getValue()) {
final IBattle battle = battleDelegate.getBattleTracker().getPendingBattle(t, entry.getKey().isBombingRun(), entry.getKey());
final List<Unit> attackers = (List<Unit>) battle.getAttackingUnits();
attackers.retainAll(t.getUnits().getUnits());
final List<Unit> defenders = (List<Unit>) battle.getDefendingUnits();
defenders.retainAll(t.getUnits().getUnits());
final Set<Unit> bombardingUnits = new HashSet<>(battle.getBombardingUnits());
ProLogger.debug("---" + t);
ProLogger.debug("attackers=" + attackers);
ProLogger.debug("defenders=" + defenders);
ProLogger.debug("bombardingUnits=" + bombardingUnits);
final ProBattleResult result = calc.callBattleCalculator(t, attackers, defenders, bombardingUnits);
final List<Unit> remainingUnits = result.getAverageAttackersRemaining();
ProLogger.debug("remainingUnits=" + remainingUnits);
// Make updates to data
final List<Unit> attackersToRemove = new ArrayList<>(attackers);
attackersToRemove.removeAll(remainingUnits);
final List<Unit> defendersToRemove = CollectionUtils.getMatches(defenders, Matches.unitIsInfrastructure().negate());
final List<Unit> infrastructureToChangeOwner = CollectionUtils.getMatches(defenders, Matches.unitIsInfrastructure());
ProLogger.debug("attackersToRemove=" + attackersToRemove);
ProLogger.debug("defendersToRemove=" + defendersToRemove);
ProLogger.debug("infrastructureToChangeOwner=" + infrastructureToChangeOwner);
final Change attackerskilledChange = ChangeFactory.removeUnits(t, attackersToRemove);
delegateBridge.addChange(attackerskilledChange);
final Change defenderskilledChange = ChangeFactory.removeUnits(t, defendersToRemove);
delegateBridge.addChange(defenderskilledChange);
BattleTracker.captureOrDestroyUnits(t, player, player, delegateBridge, null);
if (!checkIfCapturedTerritoryIsAlliedCapital(t, data, player, delegateBridge)) {
delegateBridge.addChange(ChangeFactory.changeOwner(t, player));
}
battleDelegate.getBattleTracker().getConquered().add(t);
battleDelegate.getBattleTracker().removeBattle(battle);
final Territory updatedTerritory = data.getMap().getTerritory(t.getName());
ProLogger.debug("after changes owner=" + updatedTerritory.getOwner() + ", units=" + updatedTerritory.getUnits().getUnits());
}
}
}
use of games.strategy.triplea.ai.pro.data.ProBattleResult in project triplea by triplea-game.
the class ProOddsCalculator method estimateDefendBattleResults.
public ProBattleResult estimateDefendBattleResults(final Territory t, final List<Unit> attackingUnits, final List<Unit> defendingUnits, final Set<Unit> bombardingUnits) {
final ProBattleResult result = checkIfNoAttackersOrDefenders(t, attackingUnits, defendingUnits);
if (result != null) {
return result;
}
// Determine if defenders have no chance
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackingUnits, defendingUnits);
if (strengthDifference > 55) {
final boolean isLandAndCanOnlyBeAttackedByAir = !t.isWater() && !attackingUnits.isEmpty() && attackingUnits.stream().allMatch(Matches.unitIsAir());
return new ProBattleResult(100 + strengthDifference, 999 + strengthDifference, !isLandAndCanOnlyBeAttackedByAir, attackingUnits, new ArrayList<>(), 1);
}
return callBattleCalculator(t, attackingUnits, defendingUnits, bombardingUnits);
}
use of games.strategy.triplea.ai.pro.data.ProBattleResult in project triplea by triplea-game.
the class ProOddsCalculator method callBattleCalculator.
public ProBattleResult callBattleCalculator(final Territory t, final List<Unit> attackingUnits, final List<Unit> defendingUnits, final Set<Unit> bombardingUnits, final boolean retreatWhenOnlyAirLeft) {
final GameData data = ProData.getData();
if (isCanceled || attackingUnits.isEmpty() || defendingUnits.isEmpty()) {
return new ProBattleResult();
}
final int minArmySize = Math.min(attackingUnits.size(), defendingUnits.size());
final int runCount = Math.max(16, 100 - minArmySize);
final PlayerID attacker = attackingUnits.get(0).getOwner();
final PlayerID defender = defendingUnits.get(0).getOwner();
if (retreatWhenOnlyAirLeft) {
calc.setRetreatWhenOnlyAirLeft(true);
}
final AggregateResults results = calc.setCalculateDataAndCalculate(attacker, defender, t, attackingUnits, defendingUnits, new ArrayList<>(bombardingUnits), TerritoryEffectHelper.getEffects(t), runCount);
if (retreatWhenOnlyAirLeft) {
calc.setRetreatWhenOnlyAirLeft(false);
}
// Find battle result statistics
final double winPercentage = results.getAttackerWinPercent() * 100;
final List<Unit> averageAttackersRemaining = results.getAverageAttackingUnitsRemaining();
final List<Unit> averageDefendersRemaining = results.getAverageDefendingUnitsRemaining();
final List<Unit> mainCombatAttackers = CollectionUtils.getMatches(attackingUnits, Matches.unitCanBeInBattle(true, !t.isWater(), 1, false, true, true));
final List<Unit> mainCombatDefenders = CollectionUtils.getMatches(defendingUnits, Matches.unitCanBeInBattle(false, !t.isWater(), 1, false, true, true));
double tuvSwing = results.getAverageTuvSwing(attacker, mainCombatAttackers, defender, mainCombatDefenders, data);
if (Matches.territoryIsNeutralButNotWater().test(t)) {
// Set TUV swing for neutrals
final double attackingUnitValue = TuvUtils.getTuv(mainCombatAttackers, ProData.unitValueMap);
final double remainingUnitValue = results.getAverageTuvOfUnitsLeftOver(ProData.unitValueMap, ProData.unitValueMap).getFirst();
tuvSwing = remainingUnitValue - attackingUnitValue;
}
final List<Unit> defendingTransportedUnits = CollectionUtils.getMatches(defendingUnits, Matches.unitIsBeingTransported());
if (t.isWater() && !defendingTransportedUnits.isEmpty()) {
// Add TUV swing for transported units
final double transportedUnitValue = TuvUtils.getTuv(defendingTransportedUnits, ProData.unitValueMap);
tuvSwing += transportedUnitValue * winPercentage / 100;
}
// Create battle result object
final List<Territory> territoryList = new ArrayList<>();
territoryList.add(t);
return (!territoryList.isEmpty() && territoryList.stream().allMatch(Matches.territoryIsLand())) ? new ProBattleResult(winPercentage, tuvSwing, averageAttackersRemaining.stream().anyMatch(Matches.unitIsLand()), averageAttackersRemaining, averageDefendersRemaining, results.getAverageBattleRoundsFought()) : new ProBattleResult(winPercentage, tuvSwing, !averageAttackersRemaining.isEmpty(), averageAttackersRemaining, averageDefendersRemaining, results.getAverageBattleRoundsFought());
}
use of games.strategy.triplea.ai.pro.data.ProBattleResult in project triplea by triplea-game.
the class ProOddsCalculator method checkIfNoAttackersOrDefenders.
private static ProBattleResult checkIfNoAttackersOrDefenders(final Territory t, final List<Unit> attackingUnits, final List<Unit> defendingUnits) {
final GameData data = ProData.getData();
final boolean hasNoDefenders = defendingUnits.stream().noneMatch(Matches.unitIsNotInfrastructure());
final boolean isLandAndCanOnlyBeAttackedByAir = !t.isWater() && !attackingUnits.isEmpty() && attackingUnits.stream().allMatch(Matches.unitIsAir());
if (attackingUnits.size() == 0 || hasNoDefenders && isLandAndCanOnlyBeAttackedByAir) {
return new ProBattleResult();
} else if (hasNoDefenders) {
return new ProBattleResult(100, 0.1, true, attackingUnits, new ArrayList<>(), 0);
} else if (Properties.getSubRetreatBeforeBattle(data) && !defendingUnits.isEmpty() && defendingUnits.stream().allMatch(Matches.unitIsSub()) && attackingUnits.stream().noneMatch(Matches.unitIsDestroyer())) {
return new ProBattleResult();
}
return null;
}
Aggregations