Search in sources :

Example 6 with ProPurchaseOption

use of games.strategy.triplea.ai.pro.data.ProPurchaseOption in project triplea by triplea-game.

the class ProPurchaseUtils method findMaxPurchaseDefenders.

public static List<Unit> findMaxPurchaseDefenders(final PlayerID player, final Territory t, final List<ProPurchaseOption> landPurchaseOptions) {
    ProLogger.info("Find max purchase defenders for " + t.getName());
    final GameData data = ProData.getData();
    // Determine most cost efficient defender that can be produced in this territory
    final Resource pus = data.getResourceList().getResource(Constants.PUS);
    final int pusRemaining = player.getResources().getQuantity(pus);
    final List<ProPurchaseOption> purchaseOptionsForTerritory = findPurchaseOptionsForTerritory(player, landPurchaseOptions, t, false);
    ProPurchaseOption bestDefenseOption = null;
    double maxDefenseEfficiency = 0;
    for (final ProPurchaseOption ppo : purchaseOptionsForTerritory) {
        if (ppo.getDefenseEfficiency() > maxDefenseEfficiency && ppo.getCost() <= pusRemaining) {
            bestDefenseOption = ppo;
            maxDefenseEfficiency = ppo.getDefenseEfficiency();
        }
    }
    // Determine number of defenders I can purchase
    final List<Unit> placeUnits = new ArrayList<>();
    if (bestDefenseOption != null) {
        ProLogger.debug("Best defense option: " + bestDefenseOption.getUnitType().getName());
        int remainingUnitProduction = getUnitProduction(t, data, player);
        int pusSpent = 0;
        while (bestDefenseOption.getCost() <= (pusRemaining - pusSpent) && remainingUnitProduction >= bestDefenseOption.getQuantity()) {
            // If out of PUs or production then break
            // Create new temp defenders
            pusSpent += bestDefenseOption.getCost();
            remainingUnitProduction -= bestDefenseOption.getQuantity();
            placeUnits.addAll(bestDefenseOption.getUnitType().create(bestDefenseOption.getQuantity(), player, true));
        }
        ProLogger.debug("Potential purchased defenders: " + placeUnits);
    }
    return placeUnits;
}
Also used : GameData(games.strategy.engine.data.GameData) Resource(games.strategy.engine.data.Resource) ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 7 with ProPurchaseOption

use of games.strategy.triplea.ai.pro.data.ProPurchaseOption in project triplea by triplea-game.

the class ProPurchaseUtils method removeInvalidPurchaseOptions.

public static List<ProPurchaseOption> removeInvalidPurchaseOptions(final PlayerID player, final GameData data, final List<ProPurchaseOption> purchaseOptions, final ProResourceTracker resourceTracker, final int remainingUnitProduction, final List<Unit> unitsToPlace, final Map<Territory, ProPurchaseTerritory> purchaseTerritories) {
    for (final Iterator<ProPurchaseOption> it = purchaseOptions.iterator(); it.hasNext(); ) {
        final ProPurchaseOption purchaseOption = it.next();
        // Check PU cost and production
        if (!resourceTracker.hasEnough(purchaseOption) || purchaseOption.getQuantity() > remainingUnitProduction) {
            it.remove();
            continue;
        }
        // Check max unit limits (-1 is unlimited)
        final int maxBuilt = purchaseOption.getMaxBuiltPerPlayer();
        final UnitType type = purchaseOption.getUnitType();
        if (maxBuilt == 0) {
            it.remove();
        } else if (maxBuilt > 0) {
            // Find number of unit type that are already built and about to be placed
            int currentlyBuilt = 0;
            final Predicate<Unit> unitTypeOwnedBy = Matches.unitIsOfType(type).and(Matches.unitIsOwnedBy(player));
            final List<Territory> allTerritories = data.getMap().getTerritories();
            for (final Territory t : allTerritories) {
                currentlyBuilt += t.getUnits().countMatches(unitTypeOwnedBy);
            }
            currentlyBuilt += CollectionUtils.countMatches(unitsToPlace, unitTypeOwnedBy);
            for (final ProPurchaseTerritory t : purchaseTerritories.values()) {
                for (final ProPlaceTerritory placeTerritory : t.getCanPlaceTerritories()) {
                    currentlyBuilt += CollectionUtils.countMatches(placeTerritory.getPlaceUnits(), unitTypeOwnedBy);
                }
            }
            final int allowedBuild = maxBuilt - currentlyBuilt;
            if (allowedBuild - purchaseOption.getQuantity() < 0) {
                it.remove();
            }
        }
    }
    return purchaseOptions;
}
Also used : ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) Territory(games.strategy.engine.data.Territory) ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) UnitType(games.strategy.engine.data.UnitType) ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) ArrayList(java.util.ArrayList) List(java.util.List) Predicate(java.util.function.Predicate)

Example 8 with ProPurchaseOption

use of games.strategy.triplea.ai.pro.data.ProPurchaseOption 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());
        }
    }
}
Also used : ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) Territory(games.strategy.engine.data.Territory) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) ProBattleResult(games.strategy.triplea.ai.pro.data.ProBattleResult) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption) ProOtherMoveOptions(games.strategy.triplea.ai.pro.data.ProOtherMoveOptions) HashSet(java.util.HashSet)

Example 9 with ProPurchaseOption

use of games.strategy.triplea.ai.pro.data.ProPurchaseOption 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);
                    }
                }
            }
        }
    }
}
Also used : ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) Territory(games.strategy.engine.data.Territory) ArrayList(java.util.ArrayList) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) ProBattleResult(games.strategy.triplea.ai.pro.data.ProBattleResult) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption) ProOtherMoveOptions(games.strategy.triplea.ai.pro.data.ProOtherMoveOptions) HashSet(java.util.HashSet)

Example 10 with ProPurchaseOption

use of games.strategy.triplea.ai.pro.data.ProPurchaseOption 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);
        }
    }
}
Also used : ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) Territory(games.strategy.engine.data.Territory) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption)

Aggregations

ProPurchaseOption (games.strategy.triplea.ai.pro.data.ProPurchaseOption)12 Territory (games.strategy.engine.data.Territory)9 Unit (games.strategy.engine.data.Unit)9 TripleAUnit (games.strategy.triplea.TripleAUnit)9 ProPlaceTerritory (games.strategy.triplea.ai.pro.data.ProPlaceTerritory)9 ProPurchaseTerritory (games.strategy.triplea.ai.pro.data.ProPurchaseTerritory)9 ArrayList (java.util.ArrayList)9 ProOtherMoveOptions (games.strategy.triplea.ai.pro.data.ProOtherMoveOptions)5 HashMap (java.util.HashMap)5 ProBattleResult (games.strategy.triplea.ai.pro.data.ProBattleResult)4 HashSet (java.util.HashSet)4 GameData (games.strategy.engine.data.GameData)2 Route (games.strategy.engine.data.Route)2 ProPurchaseOptionMap (games.strategy.triplea.ai.pro.data.ProPurchaseOptionMap)2 List (java.util.List)2 Predicate (java.util.function.Predicate)2 PlayerID (games.strategy.engine.data.PlayerID)1 ProductionRule (games.strategy.engine.data.ProductionRule)1 RepairRule (games.strategy.engine.data.RepairRule)1 Resource (games.strategy.engine.data.Resource)1