use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method purchaseUnitsWithRemainingProduction.
private void purchaseUnitsWithRemainingProduction(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPurchaseOption> landPurchaseOptions, final List<ProPurchaseOption> airPurchaseOptions) {
if (resourceTracker.isEmpty()) {
return;
}
ProLogger.info("Purchase units in territories with remaining production with resources: " + resourceTracker);
// Get all safe/unsafe land place territories with remaining production
final List<ProPlaceTerritory> prioritizedLandTerritories = new ArrayList<>();
final List<ProPlaceTerritory> prioritizedCantHoldLandTerritories = new ArrayList<>();
for (final ProPurchaseTerritory ppt : purchaseTerritories.values()) {
for (final ProPlaceTerritory placeTerritory : ppt.getCanPlaceTerritories()) {
final Territory t = placeTerritory.getTerritory();
if (!t.isWater() && placeTerritory.isCanHold() && purchaseTerritories.get(t).getRemainingUnitProduction() > 0) {
prioritizedLandTerritories.add(placeTerritory);
} else if (!t.isWater() && purchaseTerritories.get(t).getRemainingUnitProduction() > 0) {
prioritizedCantHoldLandTerritories.add(placeTerritory);
}
}
}
// Sort territories by value
prioritizedLandTerritories.sort(Comparator.comparingDouble(ProPlaceTerritory::getStrategicValue));
ProLogger.debug("Sorted land territories with remaining production: " + prioritizedLandTerritories);
// Loop through territories and purchase long range attack units
for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) {
final Territory t = placeTerritory.getTerritory();
ProLogger.debug("Checking territory: " + t);
// Determine units that can be produced in this territory
final List<ProPurchaseOption> airAndLandPurchaseOptions = new ArrayList<>(airPurchaseOptions);
airAndLandPurchaseOptions.addAll(landPurchaseOptions);
final List<ProPurchaseOption> purchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, airAndLandPurchaseOptions, t, isBid);
// Purchase long range attack units for any remaining production
int remainingUnitProduction = purchaseTerritories.get(t).getRemainingUnitProduction();
while (true) {
// Remove options that cost too much PUs or production
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, purchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, new ArrayList<>(), purchaseTerritories);
if (purchaseOptionsForTerritory.isEmpty()) {
break;
}
// Determine best long range attack option (prefer air units)
ProPurchaseOption bestAttackOption = null;
double maxAttackEfficiency = 0;
for (final ProPurchaseOption ppo : purchaseOptionsForTerritory) {
double attackEfficiency = ppo.getAttackEfficiency() * ppo.getMovement() / ppo.getQuantity();
if (ppo.isAir()) {
attackEfficiency *= 10;
}
if (attackEfficiency > maxAttackEfficiency) {
bestAttackOption = ppo;
maxAttackEfficiency = attackEfficiency;
}
}
if (bestAttackOption == null) {
break;
}
// Purchase unit
resourceTracker.purchase(bestAttackOption);
remainingUnitProduction -= bestAttackOption.getQuantity();
final List<Unit> newUnit = bestAttackOption.getUnitType().create(bestAttackOption.getQuantity(), player, true);
placeTerritory.getPlaceUnits().addAll(newUnit);
ProLogger.trace(t + ", addedUnit=" + newUnit);
}
}
// Sort territories by value
prioritizedCantHoldLandTerritories.sort(Comparator.comparingDouble(ProPlaceTerritory::getDefenseValue));
ProLogger.debug("Sorted can't hold land territories with remaining production: " + prioritizedCantHoldLandTerritories);
// Loop through territories and purchase defense units
for (final ProPlaceTerritory placeTerritory : prioritizedCantHoldLandTerritories) {
final Territory t = placeTerritory.getTerritory();
ProLogger.debug("Checking territory: " + t);
// Find local owned units
final List<Unit> ownedLocalUnits = t.getUnits().getMatches(Matches.unitIsOwnedBy(player));
// Determine units that can be produced in this territory
final List<ProPurchaseOption> airAndLandPurchaseOptions = new ArrayList<>(airPurchaseOptions);
airAndLandPurchaseOptions.addAll(landPurchaseOptions);
final List<ProPurchaseOption> purchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, airAndLandPurchaseOptions, t, isBid);
// Purchase defense units for any remaining production
int remainingUnitProduction = purchaseTerritories.get(t).getRemainingUnitProduction();
while (true) {
// Select purchase option
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, purchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, new ArrayList<>(), purchaseTerritories);
final Map<ProPurchaseOption, Double> defenseEfficiencies = new HashMap<>();
for (final ProPurchaseOption ppo : purchaseOptionsForTerritory) {
defenseEfficiencies.put(ppo, Math.pow(ppo.getCost(), 2) * ppo.getDefenseEfficiency2(1, data, ownedLocalUnits, placeTerritory.getPlaceUnits()));
}
final Optional<ProPurchaseOption> optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(defenseEfficiencies, "Defense");
if (!optionalSelectedOption.isPresent()) {
break;
}
final ProPurchaseOption selectedOption = optionalSelectedOption.get();
// Purchase unit
resourceTracker.purchase(selectedOption);
remainingUnitProduction -= selectedOption.getQuantity();
final List<Unit> newUnit = selectedOption.getUnitType().create(selectedOption.getQuantity(), player, true);
placeTerritory.getPlaceUnits().addAll(newUnit);
ProLogger.trace(t + ", addedUnit=" + newUnit);
}
}
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method populateProductionRuleMap.
private IntegerMap<ProductionRule> populateProductionRuleMap(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final ProPurchaseOptionMap purchaseOptions) {
ProLogger.info("Populate production rule map");
final List<Unit> unplacedUnits = player.getUnits().getMatches(Matches.unitIsNotSea());
final IntegerMap<ProductionRule> purchaseMap = new IntegerMap<>();
for (final ProPurchaseOption ppo : purchaseOptions.getAllOptions()) {
final int numUnits = (int) purchaseTerritories.values().stream().map(ProPurchaseTerritory::getCanPlaceTerritories).flatMap(Collection::stream).map(ProPlaceTerritory::getPlaceUnits).flatMap(Collection::stream).filter(u -> u.getType().equals(ppo.getUnitType())).filter(u -> !unplacedUnits.contains(u)).count();
if (numUnits > 0) {
final int numProductionRule = numUnits / ppo.getQuantity();
purchaseMap.put(ppo.getProductionRule(), numProductionRule);
ProLogger.info(numProductionRule + " " + ppo.getProductionRule());
}
}
return purchaseMap;
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method purchaseAaUnits.
private void purchaseAaUnits(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPlaceTerritory> prioritizedLandTerritories, final List<ProPurchaseOption> specialPurchaseOptions) {
if (resourceTracker.isEmpty()) {
return;
}
ProLogger.info("Purchase AA units with resources: " + resourceTracker);
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Loop through prioritized territories and purchase AA units
for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) {
final Territory t = placeTerritory.getTerritory();
ProLogger.debug("Checking AA place for " + t);
// Check if any enemy attackers
if (enemyAttackOptions.getMax(t) == null) {
continue;
}
// Check remaining production
final int remainingUnitProduction = purchaseTerritories.get(t).getRemainingUnitProduction();
ProLogger.debug(t + ", remainingUnitProduction=" + remainingUnitProduction);
if (remainingUnitProduction <= 0) {
continue;
}
// Check if territory needs AA
final boolean enemyCanBomb = enemyAttackOptions.getMax(t).getMaxUnits().stream().anyMatch(Matches.unitIsStrategicBomber());
final boolean territoryCanBeBombed = t.getUnits().anyMatch(Matches.unitCanProduceUnitsAndCanBeDamaged());
final boolean hasAaBombingDefense = t.getUnits().anyMatch(Matches.unitIsAaForBombingThisUnitOnly());
ProLogger.debug(t + ", enemyCanBomb=" + enemyCanBomb + ", territoryCanBeBombed=" + territoryCanBeBombed + ", hasAABombingDefense=" + hasAaBombingDefense);
if (!enemyCanBomb || !territoryCanBeBombed || hasAaBombingDefense) {
continue;
}
// Remove options that cost too much PUs or production
final List<ProPurchaseOption> purchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, specialPurchaseOptions, t, isBid);
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, purchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, new ArrayList<>(), purchaseTerritories);
if (purchaseOptionsForTerritory.isEmpty()) {
continue;
}
// Determine most cost efficient units that can be produced in this territory
ProPurchaseOption bestAaOption = null;
int minCost = Integer.MAX_VALUE;
for (final ProPurchaseOption ppo : purchaseOptionsForTerritory) {
final boolean isAaForBombing = Matches.unitTypeIsAaForBombingThisUnitOnly().test(ppo.getUnitType());
if (isAaForBombing && ppo.getCost() < minCost && !Matches.unitTypeConsumesUnitsOnCreation().test(ppo.getUnitType())) {
bestAaOption = ppo;
minCost = ppo.getCost();
}
}
// Check if there aren't any available units
if (bestAaOption == null) {
continue;
}
ProLogger.trace("Best AA unit: " + bestAaOption.getUnitType().getName());
// Create new temp units
resourceTracker.purchase(bestAaOption);
final List<Unit> unitsToPlace = bestAaOption.getUnitType().create(bestAaOption.getQuantity(), player, true);
placeTerritory.getPlaceUnits().addAll(unitsToPlace);
ProLogger.trace(t + ", placedUnits=" + unitsToPlace);
}
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method purchase.
Map<Territory, ProPurchaseTerritory> purchase(final IPurchaseDelegate purchaseDelegate, final GameData startOfTurnData) {
// Current data fields
data = ProData.getData();
this.startOfTurnData = startOfTurnData;
player = ProData.getPlayer();
resourceTracker = new ProResourceTracker(player);
territoryManager = new ProTerritoryManager(calc);
isBid = false;
final ProPurchaseOptionMap purchaseOptions = ProData.purchaseOptions;
ProLogger.info("Starting purchase phase with resources: " + resourceTracker);
if (!player.getUnits().getUnits().isEmpty()) {
ProLogger.info("Starting purchase phase with unplaced units=" + player.getUnits().getUnits());
}
// Find all purchase/place territories
final Map<Territory, ProPurchaseTerritory> purchaseTerritories = ProPurchaseUtils.findPurchaseTerritories(player);
final Set<Territory> placeTerritories = new HashSet<>(CollectionUtils.getMatches(data.getMap().getTerritoriesOwnedBy(player), Matches.territoryIsLand()));
for (final Territory t : purchaseTerritories.keySet()) {
for (final ProPlaceTerritory ppt : purchaseTerritories.get(t).getCanPlaceTerritories()) {
placeTerritories.add(ppt.getTerritory());
}
}
// Determine max enemy attack units and current allied defenders
territoryManager.populateEnemyAttackOptions(new ArrayList<>(), new ArrayList<>(placeTerritories));
findDefendersInPlaceTerritories(purchaseTerritories);
// Prioritize land territories that need defended and purchase additional defenders
final List<ProPlaceTerritory> needToDefendLandTerritories = prioritizeTerritoriesToDefend(purchaseTerritories, true);
purchaseDefenders(purchaseTerritories, needToDefendLandTerritories, purchaseOptions.getLandFodderOptions(), purchaseOptions.getAirOptions(), true);
// Find strategic value for each territory
ProLogger.info("Find strategic value for place territories");
final Map<Territory, Double> territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, new ArrayList<>(), new ArrayList<>());
for (final Territory t : purchaseTerritories.keySet()) {
for (final ProPlaceTerritory ppt : purchaseTerritories.get(t).getCanPlaceTerritories()) {
ppt.setStrategicValue(territoryValueMap.get(ppt.getTerritory()));
ProLogger.debug(ppt.getTerritory() + ", strategicValue=" + territoryValueMap.get(ppt.getTerritory()));
}
}
// Prioritize land place options purchase AA then land units
final List<ProPlaceTerritory> prioritizedLandTerritories = prioritizeLandTerritories(purchaseTerritories);
purchaseAaUnits(purchaseTerritories, prioritizedLandTerritories, purchaseOptions.getAaOptions());
purchaseLandUnits(purchaseTerritories, prioritizedLandTerritories, purchaseOptions, territoryValueMap);
// Prioritize sea territories that need defended and purchase additional defenders
final List<ProPlaceTerritory> needToDefendSeaTerritories = prioritizeTerritoriesToDefend(purchaseTerritories, false);
purchaseDefenders(purchaseTerritories, needToDefendSeaTerritories, purchaseOptions.getSeaDefenseOptions(), purchaseOptions.getAirOptions(), false);
// Determine whether to purchase new land factory
final Map<Territory, ProPurchaseTerritory> factoryPurchaseTerritories = new HashMap<>();
purchaseFactory(factoryPurchaseTerritories, purchaseTerritories, prioritizedLandTerritories, purchaseOptions, false);
// Prioritize sea place options and purchase units
final List<ProPlaceTerritory> prioritizedSeaTerritories = prioritizeSeaTerritories(purchaseTerritories);
purchaseSeaAndAmphibUnits(purchaseTerritories, prioritizedSeaTerritories, territoryValueMap, purchaseOptions);
// Try to use any remaining PUs on high value units
purchaseUnitsWithRemainingProduction(purchaseTerritories, purchaseOptions.getLandOptions(), purchaseOptions.getAirOptions());
upgradeUnitsWithRemainingPUs(purchaseTerritories, purchaseOptions);
// Try to purchase land/sea factory with extra PUs
purchaseFactory(factoryPurchaseTerritories, purchaseTerritories, prioritizedLandTerritories, purchaseOptions, true);
// Add factory purchase territory to list if not empty
if (!factoryPurchaseTerritories.isEmpty()) {
purchaseTerritories.putAll(factoryPurchaseTerritories);
}
// Determine final count of each production rule
final IntegerMap<ProductionRule> purchaseMap = populateProductionRuleMap(purchaseTerritories, purchaseOptions);
// Purchase units
ProMetricUtils.collectPurchaseStats(purchaseMap);
final String error = purchaseDelegate.purchase(purchaseMap);
if (error != null) {
ProLogger.warn("Purchase error: " + error);
}
return purchaseTerritories;
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method placeDefenders.
private void placeDefenders(final Map<Territory, ProPurchaseTerritory> placeNonConstructionTerritories, final List<ProPlaceTerritory> needToDefendTerritories, final IAbstractPlaceDelegate placeDelegate) {
ProLogger.info("Place defenders with units=" + player.getUnits().getUnits());
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Loop through prioritized territories and purchase defenders
for (final ProPlaceTerritory placeTerritory : needToDefendTerritories) {
final Territory t = placeTerritory.getTerritory();
ProLogger.debug("Placing defenders for " + t.getName() + ", enemyAttackers=" + enemyAttackOptions.getMax(t).getMaxUnits() + ", amphibEnemyAttackers=" + enemyAttackOptions.getMax(t).getMaxAmphibUnits() + ", defenders=" + placeTerritory.getDefendingUnits());
// Check if any units can be placed
final PlaceableUnits placeableUnits = placeDelegate.getPlaceableUnits(player.getUnits().getMatches(Matches.unitIsNotConstruction()), t);
if (placeableUnits.isError()) {
ProLogger.trace(t + " can't place units with error: " + placeableUnits.getErrorMessage());
continue;
}
// Find remaining unit production
int remainingUnitProduction = placeableUnits.getMaxUnits();
if (remainingUnitProduction == -1) {
remainingUnitProduction = Integer.MAX_VALUE;
}
ProLogger.trace(t + ", remainingUnitProduction=" + remainingUnitProduction);
// Place defenders and check battle results
final List<Unit> unitsThatCanBePlaced = new ArrayList<>(placeableUnits.getUnits());
final int landPlaceCount = Math.min(remainingUnitProduction, unitsThatCanBePlaced.size());
final List<Unit> unitsToPlace = new ArrayList<>();
ProBattleResult finalResult = new ProBattleResult();
for (int i = 0; i < landPlaceCount; i++) {
// Add defender
unitsToPlace.add(unitsThatCanBePlaced.get(i));
// 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
if (!finalResult.isHasLandUnitRemaining() || finalResult.getTuvSwing() < placeTerritory.getMinBattleResult().getTuvSwing() || t.equals(ProData.myCapital)) {
ProLogger.trace(t + ", placedUnits=" + unitsToPlace + ", TUVSwing=" + finalResult.getTuvSwing());
doPlace(t, unitsToPlace, placeDelegate);
} else {
setCantHoldPlaceTerritory(placeTerritory, placeNonConstructionTerritories);
ProLogger.trace(t + ", unable to defend with placedUnits=" + unitsToPlace + ", TUVSwing=" + finalResult.getTuvSwing() + ", minTUVSwing=" + placeTerritory.getMinBattleResult().getTuvSwing());
}
}
}
Aggregations