use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method prioritizeLandTerritories.
private List<ProPlaceTerritory> prioritizeLandTerritories(final Map<Territory, ProPurchaseTerritory> purchaseTerritories) {
ProLogger.info("Prioritize land territories to place");
// Get all land place territories
final List<ProPlaceTerritory> prioritizedLandTerritories = new ArrayList<>();
for (final ProPurchaseTerritory ppt : purchaseTerritories.values()) {
for (final ProPlaceTerritory placeTerritory : ppt.getCanPlaceTerritories()) {
final Territory t = placeTerritory.getTerritory();
if (!t.isWater() && placeTerritory.getStrategicValue() >= 1 && placeTerritory.isCanHold()) {
final boolean hasEnemyNeighbors = !data.getMap().getNeighbors(t, ProMatches.territoryIsEnemyLand(player, data)).isEmpty();
final Set<Territory> nearbyLandTerritories = data.getMap().getNeighbors(t, 9, ProMatches.territoryCanPotentiallyMoveLandUnits(player, data));
final int numNearbyEnemyTerritories = CollectionUtils.countMatches(nearbyLandTerritories, Matches.isTerritoryOwnedBy(ProUtils.getPotentialEnemyPlayers(player)));
final boolean hasLocalLandSuperiority = ProBattleUtils.territoryHasLocalLandSuperiority(t, ProBattleUtils.SHORT_RANGE, player);
if (hasEnemyNeighbors || numNearbyEnemyTerritories >= 3 || !hasLocalLandSuperiority) {
prioritizedLandTerritories.add(placeTerritory);
}
}
}
}
// Sort territories by value
prioritizedLandTerritories.sort(Comparator.comparingDouble(ProPlaceTerritory::getStrategicValue));
for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) {
ProLogger.debug(placeTerritory.toString() + " strategicValue=" + placeTerritory.getStrategicValue());
}
return prioritizedLandTerritories;
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method purchaseDefenders.
private void purchaseDefenders(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPlaceTerritory> needToDefendTerritories, final List<ProPurchaseOption> defensePurchaseOptions, final List<ProPurchaseOption> airPurchaseOptions, final boolean isLand) {
if (resourceTracker.isEmpty()) {
return;
}
ProLogger.info("Purchase defenders with resources: " + resourceTracker + ", isLand=" + isLand);
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Loop through prioritized territories and purchase defenders
for (final ProPlaceTerritory placeTerritory : needToDefendTerritories) {
final Territory t = placeTerritory.getTerritory();
ProLogger.debug("Purchasing defenders for " + t.getName() + ", enemyAttackers=" + enemyAttackOptions.getMax(t).getMaxUnits() + ", amphibEnemyAttackers=" + enemyAttackOptions.getMax(t).getMaxAmphibUnits() + ", defenders=" + placeTerritory.getDefendingUnits());
// Find local owned units
final List<Unit> ownedLocalUnits = t.getUnits().getMatches(Matches.unitIsOwnedBy(player));
int unusedCarrierCapacity = Math.min(0, ProTransportUtils.getUnusedCarrierCapacity(player, t, new ArrayList<>()));
int unusedLocalCarrierCapacity = ProTransportUtils.getUnusedLocalCarrierCapacity(player, t, new ArrayList<>());
ProLogger.trace(t + ", unusedCarrierCapacity=" + unusedCarrierCapacity + ", unusedLocalCarrierCapacity=" + unusedLocalCarrierCapacity);
// Determine if need destroyer
boolean needDestroyer = false;
if (enemyAttackOptions.getMax(t).getMaxUnits().stream().anyMatch(Matches.unitIsSub()) && ownedLocalUnits.stream().noneMatch(Matches.unitIsDestroyer())) {
needDestroyer = true;
}
// Find all purchase territories for place territory
final List<Unit> unitsToPlace = new ArrayList<>();
ProBattleResult finalResult = new ProBattleResult();
final List<ProPurchaseTerritory> selectedPurchaseTerritories = getPurchaseTerritories(placeTerritory, purchaseTerritories);
for (final ProPurchaseTerritory purchaseTerritory : selectedPurchaseTerritories) {
// Check remaining production
int remainingUnitProduction = purchaseTerritory.getRemainingUnitProduction();
ProLogger.debug(purchaseTerritory.getTerritory() + ", remainingUnitProduction=" + remainingUnitProduction);
if (remainingUnitProduction <= 0) {
continue;
}
// Find defenders that can be produced in this territory
final List<ProPurchaseOption> purchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, defensePurchaseOptions, t, isBid);
purchaseOptionsForTerritory.addAll(airPurchaseOptions);
// Purchase necessary defenders
while (true) {
// Select purchase option
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, purchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
final Map<ProPurchaseOption, Double> defenseEfficiencies = new HashMap<>();
for (final ProPurchaseOption ppo : purchaseOptionsForTerritory) {
if (isLand) {
defenseEfficiencies.put(ppo, ppo.getDefenseEfficiency2(1, data, ownedLocalUnits, unitsToPlace));
} else {
defenseEfficiencies.put(ppo, ppo.getSeaDefenseEfficiency(data, ownedLocalUnits, unitsToPlace, needDestroyer, unusedCarrierCapacity, unusedLocalCarrierCapacity));
}
}
final Optional<ProPurchaseOption> optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(defenseEfficiencies, "Defense");
if (!optionalSelectedOption.isPresent()) {
break;
}
final ProPurchaseOption selectedOption = optionalSelectedOption.get();
if (selectedOption.isDestroyer()) {
needDestroyer = false;
}
// Create new temp units
resourceTracker.tempPurchase(selectedOption);
remainingUnitProduction -= selectedOption.getQuantity();
unitsToPlace.addAll(selectedOption.getUnitType().create(selectedOption.getQuantity(), player, true));
if (selectedOption.isCarrier() || selectedOption.isAir()) {
unusedCarrierCapacity = ProTransportUtils.getUnusedCarrierCapacity(player, t, unitsToPlace);
unusedLocalCarrierCapacity = ProTransportUtils.getUnusedLocalCarrierCapacity(player, t, unitsToPlace);
}
ProLogger.trace("Selected unit=" + selectedOption.getUnitType().getName() + ", unusedCarrierCapacity=" + unusedCarrierCapacity + ", unusedLocalCarrierCapacity=" + unusedLocalCarrierCapacity);
// Find current battle result
final Set<Unit> enemyAttackingUnits = new HashSet<>(enemyAttackOptions.getMax(t).getMaxUnits());
enemyAttackingUnits.addAll(enemyAttackOptions.getMax(t).getMaxAmphibUnits());
final List<Unit> defenders = new ArrayList<>(placeTerritory.getDefendingUnits());
defenders.addAll(unitsToPlace);
finalResult = calc.calculateBattleResults(t, new ArrayList<>(enemyAttackingUnits), defenders, enemyAttackOptions.getMax(t).getMaxBombardUnits());
// Break if it can be held
if ((!t.equals(ProData.myCapital) && !finalResult.isHasLandUnitRemaining() && finalResult.getTuvSwing() <= 0) || (t.equals(ProData.myCapital) && finalResult.getWinPercentage() < (100 - ProData.winPercentage) && finalResult.getTuvSwing() <= 0)) {
break;
}
}
}
// Check to see if its worth trying to defend the territory
final boolean hasLocalSuperiority = ProBattleUtils.territoryHasLocalLandSuperiority(t, ProBattleUtils.SHORT_RANGE, player, purchaseTerritories);
if (!finalResult.isHasLandUnitRemaining() || (finalResult.getTuvSwing() - resourceTracker.getTempPUs(data) / 2) < placeTerritory.getMinBattleResult().getTuvSwing() || t.equals(ProData.myCapital) || (!t.isWater() && hasLocalSuperiority)) {
resourceTracker.confirmTempPurchases();
ProLogger.trace(t + ", placedUnits=" + unitsToPlace + ", TUVSwing=" + finalResult.getTuvSwing() + ", hasLandUnitRemaining=" + finalResult.isHasLandUnitRemaining() + ", hasLocalSuperiority=" + hasLocalSuperiority);
addUnitsToPlaceTerritory(placeTerritory, unitsToPlace, purchaseTerritories);
} else {
resourceTracker.clearTempPurchases();
setCantHoldPlaceTerritory(placeTerritory, purchaseTerritories);
ProLogger.trace(t + ", unable to defend with placedUnits=" + unitsToPlace + ", TUVSwing=" + finalResult.getTuvSwing() + ", minTUVSwing=" + placeTerritory.getMinBattleResult().getTuvSwing());
}
}
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method purchaseFactory.
private void purchaseFactory(final Map<Territory, ProPurchaseTerritory> factoryPurchaseTerritories, final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPlaceTerritory> prioritizedLandTerritories, final ProPurchaseOptionMap purchaseOptions, final boolean hasExtraPUs) {
if (resourceTracker.isEmpty()) {
return;
}
ProLogger.info("Purchase factory with resources: " + resourceTracker + ", hasExtraPUs=" + hasExtraPUs);
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Only try to purchase a factory if all production was used in prioritized land territories
for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) {
for (final Territory t : purchaseTerritories.keySet()) {
if (placeTerritory.getTerritory().equals(t) && purchaseTerritories.get(t).getRemainingUnitProduction() > 0) {
ProLogger.debug("Not purchasing a factory since remaining land production in " + t);
return;
}
}
}
// Find all owned land territories that weren't conquered and don't already have a factory
final List<Territory> possibleFactoryTerritories = CollectionUtils.getMatches(data.getMap().getTerritories(), ProMatches.territoryHasNoInfraFactoryAndIsNotConqueredOwnedLand(player, data));
possibleFactoryTerritories.removeAll(factoryPurchaseTerritories.keySet());
final Set<Territory> purchaseFactoryTerritories = new HashSet<>();
final List<Territory> territoriesThatCantBeHeld = new ArrayList<>();
for (final Territory t : possibleFactoryTerritories) {
// Only consider territories with production of at least 3 unless there are still remaining PUs
final int production = TerritoryAttachment.get(t).getProduction();
if ((production < 3 && !hasExtraPUs) || production < 2) {
continue;
}
// Check if no enemy attackers and that it wasn't conquered this turn
if (enemyAttackOptions.getMax(t) == null) {
purchaseFactoryTerritories.add(t);
ProLogger.trace("Possible factory since no enemy attackers: " + t.getName());
} else {
// Find current battle result
final List<Unit> defenders = t.getUnits().getMatches(Matches.isUnitAllied(player, data));
final Set<Unit> enemyAttackingUnits = new HashSet<>(enemyAttackOptions.getMax(t).getMaxUnits());
enemyAttackingUnits.addAll(enemyAttackOptions.getMax(t).getMaxAmphibUnits());
final ProBattleResult result = calc.estimateDefendBattleResults(t, new ArrayList<>(enemyAttackingUnits), defenders, enemyAttackOptions.getMax(t).getMaxBombardUnits());
// Check if it can't be held or if it can then that it wasn't conquered this turn
if (result.isHasLandUnitRemaining() || result.getTuvSwing() > 0) {
territoriesThatCantBeHeld.add(t);
ProLogger.trace("Can't hold territory: " + t.getName() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", TUVSwing=" + result.getTuvSwing() + ", enemyAttackers=" + enemyAttackingUnits.size() + ", myDefenders=" + defenders.size());
} else {
purchaseFactoryTerritories.add(t);
ProLogger.trace("Possible factory: " + t.getName() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", TUVSwing=" + result.getTuvSwing() + ", enemyAttackers=" + enemyAttackingUnits.size() + ", myDefenders=" + defenders.size());
}
}
}
ProLogger.debug("Possible factory territories: " + purchaseFactoryTerritories);
// Remove any territories that don't have local land superiority
if (!hasExtraPUs) {
purchaseFactoryTerritories.removeIf(t -> !ProBattleUtils.territoryHasLocalLandSuperiority(t, ProBattleUtils.MEDIUM_RANGE, player, purchaseTerritories));
ProLogger.debug("Possible factory territories that have land superiority: " + purchaseFactoryTerritories);
}
// Find strategic value for each territory
final Map<Territory, Double> territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, territoriesThatCantBeHeld, new ArrayList<>());
double maxValue = 0.0;
Territory maxTerritory = null;
for (final Territory t : purchaseFactoryTerritories) {
final int production = TerritoryAttachment.get(t).getProduction();
final double value = territoryValueMap.get(t) * production + 0.1 * production;
final boolean isAdjacentToSea = Matches.territoryHasNeighborMatching(data, Matches.territoryIsWater()).test(t);
final Set<Territory> nearbyLandTerritories = data.getMap().getNeighbors(t, 9, ProMatches.territoryCanMoveLandUnits(player, data, false));
final int numNearbyEnemyTerritories = CollectionUtils.countMatches(nearbyLandTerritories, Matches.isTerritoryEnemy(player, data));
ProLogger.trace(t + ", strategic value=" + territoryValueMap.get(t) + ", value=" + value + ", numNearbyEnemyTerritories=" + numNearbyEnemyTerritories);
if (value > maxValue && ((numNearbyEnemyTerritories >= 4 && territoryValueMap.get(t) >= 1) || (isAdjacentToSea && hasExtraPUs))) {
maxValue = value;
maxTerritory = t;
}
}
ProLogger.debug("Try to purchase factory for territory: " + maxTerritory);
// Determine whether to purchase factory
if (maxTerritory != null) {
// Find most expensive placed land unit to consider removing for a factory
ProPurchaseOption maxPlacedOption = null;
ProPlaceTerritory maxPlacedTerritory = null;
Unit maxPlacedUnit = null;
for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) {
for (final Unit u : placeTerritory.getPlaceUnits()) {
for (final ProPurchaseOption ppo : purchaseOptions.getLandOptions()) {
if (u.getType().equals(ppo.getUnitType()) && ppo.getQuantity() == 1 && (maxPlacedOption == null || ppo.getCost() >= maxPlacedOption.getCost())) {
maxPlacedOption = ppo;
maxPlacedTerritory = placeTerritory;
maxPlacedUnit = u;
}
}
}
}
// Determine units that can be produced in this territory
final List<ProPurchaseOption> purchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getFactoryOptions(), maxTerritory, isBid);
resourceTracker.removeTempPurchase(maxPlacedOption);
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, purchaseOptionsForTerritory, resourceTracker, 1, new ArrayList<>(), purchaseTerritories);
resourceTracker.clearTempPurchases();
// Determine most expensive factory option (currently doesn't buy mobile factories)
ProPurchaseOption bestFactoryOption = null;
double maxFactoryEfficiency = 0;
for (final ProPurchaseOption ppo : purchaseOptionsForTerritory) {
if (ppo.getMovement() == 0 && ppo.getCost() > maxFactoryEfficiency) {
bestFactoryOption = ppo;
maxFactoryEfficiency = ppo.getCost();
}
}
// Check if there are enough PUs to buy a factory
if (bestFactoryOption != null) {
ProLogger.debug("Best factory unit: " + bestFactoryOption.getUnitType().getName());
final ProPurchaseTerritory factoryPurchaseTerritory = new ProPurchaseTerritory(maxTerritory, data, player, 0);
factoryPurchaseTerritories.put(maxTerritory, factoryPurchaseTerritory);
for (final ProPlaceTerritory ppt : factoryPurchaseTerritory.getCanPlaceTerritories()) {
if (ppt.getTerritory().equals(maxTerritory)) {
final List<Unit> factory = bestFactoryOption.getUnitType().create(bestFactoryOption.getQuantity(), player, true);
ppt.getPlaceUnits().addAll(factory);
if (resourceTracker.hasEnough(bestFactoryOption)) {
resourceTracker.purchase(bestFactoryOption);
ProLogger.debug(maxTerritory + ", placedFactory=" + factory);
} else {
resourceTracker.purchase(bestFactoryOption);
resourceTracker.removePurchase(maxPlacedOption);
maxPlacedTerritory.getPlaceUnits().remove(maxPlacedUnit);
ProLogger.debug(maxTerritory + ", placedFactory=" + factory + ", removedUnit=" + maxPlacedUnit);
}
}
}
}
}
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method prioritizeSeaTerritories.
private List<ProPlaceTerritory> prioritizeSeaTerritories(final Map<Territory, ProPurchaseTerritory> purchaseTerritories) {
ProLogger.info("Prioritize sea territories");
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Determine which sea territories can be placed in
final Set<ProPlaceTerritory> seaPlaceTerritories = new HashSet<>();
for (final ProPurchaseTerritory ppt : purchaseTerritories.values()) {
for (final ProPlaceTerritory placeTerritory : ppt.getCanPlaceTerritories()) {
final Territory t = placeTerritory.getTerritory();
if (t.isWater() && placeTerritory.getStrategicValue() > 0 && placeTerritory.isCanHold()) {
seaPlaceTerritories.add(placeTerritory);
}
}
}
// Calculate value of territory
ProLogger.debug("Determine sea place value:");
for (final ProPlaceTerritory placeTerritory : seaPlaceTerritories) {
final Territory t = placeTerritory.getTerritory();
// Find number of local naval units
final List<Unit> units = new ArrayList<>(placeTerritory.getDefendingUnits());
units.addAll(ProPurchaseUtils.getPlaceUnits(t, purchaseTerritories));
final List<Unit> myUnits = CollectionUtils.getMatches(units, Matches.unitIsOwnedBy(player));
final int numMyTransports = CollectionUtils.countMatches(myUnits, Matches.unitIsTransport());
final int numSeaDefenders = CollectionUtils.countMatches(units, Matches.unitIsNotTransport());
// Determine needed defense strength
int needDefenders = 0;
if (enemyAttackOptions.getMax(t) != null) {
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, enemyAttackOptions.getMax(t).getMaxUnits(), units);
if (strengthDifference > 50) {
needDefenders = 1;
}
}
final boolean hasLocalNavalSuperiority = ProBattleUtils.territoryHasLocalNavalSuperiority(t, player, null, new ArrayList<>());
if (!hasLocalNavalSuperiority) {
needDefenders = 1;
}
// Calculate sea value for prioritization
final double territoryValue = placeTerritory.getStrategicValue() * (1 + numMyTransports + 0.1 * numSeaDefenders) / (1 + 3 * needDefenders);
ProLogger.debug(t + ", value=" + territoryValue + ", strategicValue=" + placeTerritory.getStrategicValue() + ", numMyTransports=" + numMyTransports + ", numSeaDefenders=" + numSeaDefenders + ", needDefenders=" + needDefenders);
placeTerritory.setStrategicValue(territoryValue);
}
// Sort territories by value
final List<ProPlaceTerritory> sortedTerritories = new ArrayList<>(seaPlaceTerritories);
sortedTerritories.sort(Comparator.comparingDouble(ProPlaceTerritory::getStrategicValue));
ProLogger.debug("Sorted sea territories:");
for (final ProPlaceTerritory placeTerritory : sortedTerritories) {
ProLogger.debug(placeTerritory.toString() + " value=" + placeTerritory.getStrategicValue());
}
return sortedTerritories;
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method findDefendersInPlaceTerritories.
private void findDefendersInPlaceTerritories(final Map<Territory, ProPurchaseTerritory> purchaseTerritories) {
ProLogger.info("Find defenders in possible place territories");
for (final ProPurchaseTerritory ppt : purchaseTerritories.values()) {
for (final ProPlaceTerritory placeTerritory : ppt.getCanPlaceTerritories()) {
final Territory t = placeTerritory.getTerritory();
final List<Unit> units = t.getUnits().getMatches(Matches.isUnitAllied(player, data));
placeTerritory.setDefendingUnits(units);
ProLogger.debug(t + " has numDefenders=" + units.size());
}
}
}
Aggregations