Search in sources :

Example 1 with ProPurchaseOption

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

the class ProTransportUtils method findMaxMovementForTransports.

public static int findMaxMovementForTransports(final List<ProPurchaseOption> seaTransportPurchaseOptions) {
    int maxMovement = 2;
    final int maxTransportEfficiency = 0;
    for (final ProPurchaseOption ppo : seaTransportPurchaseOptions) {
        if (ppo.getTransportEfficiency() > maxTransportEfficiency) {
            maxMovement = ppo.getMovement();
        }
    }
    return maxMovement;
}
Also used : ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption)

Example 2 with ProPurchaseOption

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

the class ProPurchaseAi method upgradeUnitsWithRemainingPUs.

private void upgradeUnitsWithRemainingPUs(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final ProPurchaseOptionMap purchaseOptions) {
    if (resourceTracker.isEmpty()) {
        return;
    }
    ProLogger.info("Upgrade units with resources: " + resourceTracker);
    // Get all safe 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.isCanHold()) {
                prioritizedLandTerritories.add(placeTerritory);
            }
        }
    }
    // Sort territories by ascending value (try upgrading units in far away territories first)
    prioritizedLandTerritories.sort(Comparator.comparingDouble(ProPlaceTerritory::getStrategicValue));
    ProLogger.debug("Sorted land territories: " + prioritizedLandTerritories);
    // Loop through territories and upgrade units to 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<>(purchaseOptions.getAirOptions());
        airAndLandPurchaseOptions.addAll(purchaseOptions.getLandOptions());
        final List<ProPurchaseOption> purchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, airAndLandPurchaseOptions, t, isBid);
        // Purchase long range attack units for any remaining production
        int remainingUpgradeUnits = purchaseTerritories.get(t).getUnitProduction() / 3;
        while (true) {
            if (remainingUpgradeUnits <= 0) {
                break;
            }
            // Find cheapest placed purchase option
            ProPurchaseOption minPurchaseOption = null;
            for (final Unit u : placeTerritory.getPlaceUnits()) {
                for (final ProPurchaseOption ppo : airAndLandPurchaseOptions) {
                    if (u.getType().equals(ppo.getUnitType()) && (minPurchaseOption == null || ppo.getCost() < minPurchaseOption.getCost())) {
                        minPurchaseOption = ppo;
                    }
                }
            }
            if (minPurchaseOption == null) {
                break;
            }
            // Remove options that cost too much PUs or production
            resourceTracker.removeTempPurchase(minPurchaseOption);
            ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, purchaseOptionsForTerritory, resourceTracker, 1, new ArrayList<>(), purchaseTerritories);
            resourceTracker.clearTempPurchases();
            if (purchaseOptionsForTerritory.isEmpty()) {
                break;
            }
            // Determine best long range attack option (prefer air units)
            ProPurchaseOption bestAttackOption = null;
            double maxAttackEfficiency = minPurchaseOption.getAttackEfficiency() * minPurchaseOption.getMovement() * minPurchaseOption.getCost() / minPurchaseOption.getQuantity();
            for (final ProPurchaseOption ppo : purchaseOptionsForTerritory) {
                if (ppo.getCost() > minPurchaseOption.getCost() && (ppo.isAir() || placeTerritory.getStrategicValue() >= 0.25 || ppo.getTransportCost() <= minPurchaseOption.getTransportCost())) {
                    double attackEfficiency = ppo.getAttackEfficiency() * ppo.getMovement() * ppo.getCost() / ppo.getQuantity();
                    if (ppo.isAir()) {
                        attackEfficiency *= 10;
                    }
                    if (ppo.getCarrierCost() > 0) {
                        final int unusedLocalCarrierCapacity = ProTransportUtils.getUnusedLocalCarrierCapacity(player, t, placeTerritory.getPlaceUnits());
                        final int neededFighters = unusedLocalCarrierCapacity / ppo.getCarrierCost();
                        attackEfficiency *= (1 + neededFighters);
                    }
                    if (attackEfficiency > maxAttackEfficiency) {
                        bestAttackOption = ppo;
                        maxAttackEfficiency = attackEfficiency;
                    }
                }
            }
            if (bestAttackOption == null) {
                airAndLandPurchaseOptions.remove(minPurchaseOption);
                continue;
            }
            // Find units to remove
            final List<Unit> unitsToRemove = new ArrayList<>();
            int numUnitsToRemove = minPurchaseOption.getQuantity();
            for (final Unit u : placeTerritory.getPlaceUnits()) {
                if (numUnitsToRemove <= 0) {
                    break;
                }
                if (u.getType().equals(minPurchaseOption.getUnitType())) {
                    unitsToRemove.add(u);
                    numUnitsToRemove--;
                }
            }
            if (numUnitsToRemove > 0) {
                airAndLandPurchaseOptions.remove(minPurchaseOption);
                continue;
            }
            // Replace units
            resourceTracker.removePurchase(minPurchaseOption);
            remainingUpgradeUnits -= minPurchaseOption.getQuantity();
            placeTerritory.getPlaceUnits().removeAll(unitsToRemove);
            ProLogger.trace(t + ", removedUnits=" + unitsToRemove);
            for (int i = 0; i < unitsToRemove.size(); i++) {
                if (resourceTracker.hasEnough(bestAttackOption)) {
                    resourceTracker.purchase(bestAttackOption);
                    final List<Unit> newUnit = bestAttackOption.getUnitType().create(bestAttackOption.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) ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ArrayList(java.util.ArrayList) ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 3 with ProPurchaseOption

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

the class ProPurchaseAi method purchaseSeaAndAmphibUnits.

private void purchaseSeaAndAmphibUnits(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPlaceTerritory> prioritizedSeaTerritories, final Map<Territory, Double> territoryValueMap, final ProPurchaseOptionMap purchaseOptions) {
    if (resourceTracker.isEmpty()) {
        return;
    }
    ProLogger.info("Purchase sea and amphib units with resources: " + resourceTracker);
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    // Loop through prioritized territories and purchase sea units
    for (final ProPlaceTerritory placeTerritory : prioritizedSeaTerritories) {
        final Territory t = placeTerritory.getTerritory();
        ProLogger.debug("Checking sea place for " + t.getName());
        // Find all purchase territories for place territory
        final List<ProPurchaseTerritory> selectedPurchaseTerritories = getPurchaseTerritories(placeTerritory, purchaseTerritories);
        // Find local owned units
        final Set<Territory> neighbors = data.getMap().getNeighbors(t, 2, ProMatches.territoryCanMoveSeaUnits(player, data, false));
        neighbors.add(t);
        final List<Unit> ownedLocalUnits = new ArrayList<>();
        for (final Territory neighbor : neighbors) {
            ownedLocalUnits.addAll(neighbor.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);
        // If any enemy attackers then purchase sea defenders until it can be held
        boolean needDestroyer = false;
        if (enemyAttackOptions.getMax(t) != null) {
            // Determine if need destroyer
            if (enemyAttackOptions.getMax(t).getMaxUnits().stream().anyMatch(Matches.unitIsSub()) && t.getUnits().getMatches(Matches.unitIsOwnedBy(player)).stream().noneMatch(Matches.unitIsDestroyer())) {
                needDestroyer = true;
            }
            ProLogger.trace(t + ", needDestroyer=" + needDestroyer + ", checking defense since has enemy attackers: " + enemyAttackOptions.getMax(t).getMaxUnits());
            final List<Unit> initialDefendingUnits = new ArrayList<>(placeTerritory.getDefendingUnits());
            initialDefendingUnits.addAll(ProPurchaseUtils.getPlaceUnits(t, purchaseTerritories));
            ProBattleResult result = calc.calculateBattleResults(t, enemyAttackOptions.getMax(t).getMaxUnits(), initialDefendingUnits, enemyAttackOptions.getMax(t).getMaxBombardUnits());
            boolean hasOnlyRetreatingSubs = Properties.getSubRetreatBeforeBattle(data) && !initialDefendingUnits.isEmpty() && initialDefendingUnits.stream().allMatch(Matches.unitIsSub()) && enemyAttackOptions.getMax(t).getMaxUnits().stream().noneMatch(Matches.unitIsDestroyer());
            final List<Unit> unitsToPlace = new ArrayList<>();
            for (final ProPurchaseTerritory purchaseTerritory : selectedPurchaseTerritories) {
                // Check remaining production
                int remainingUnitProduction = purchaseTerritory.getRemainingUnitProduction();
                ProLogger.trace(t + ", purchaseTerritory=" + purchaseTerritory.getTerritory() + ", remainingUnitProduction=" + remainingUnitProduction);
                if (remainingUnitProduction <= 0) {
                    continue;
                }
                // Determine sea and transport units that can be produced in this territory
                final List<ProPurchaseOption> seaPurchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getSeaDefenseOptions(), t, isBid);
                seaPurchaseOptionsForTerritory.addAll(purchaseOptions.getAirOptions());
                // Purchase enough sea defenders to hold territory
                while (true) {
                    // If it can be held then break
                    if (!hasOnlyRetreatingSubs && (result.getTuvSwing() < -1 || result.getWinPercentage() < ProData.winPercentage)) {
                        break;
                    }
                    // Select purchase option
                    ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, seaPurchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
                    final Map<ProPurchaseOption, Double> defenseEfficiencies = new HashMap<>();
                    for (final ProPurchaseOption ppo : seaPurchaseOptionsForTerritory) {
                        defenseEfficiencies.put(ppo, ppo.getSeaDefenseEfficiency(data, ownedLocalUnits, unitsToPlace, needDestroyer, unusedCarrierCapacity, unusedLocalCarrierCapacity));
                    }
                    final Optional<ProPurchaseOption> optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(defenseEfficiencies, "Sea Defense");
                    if (!optionalSelectedOption.isPresent()) {
                        break;
                    }
                    final ProPurchaseOption selectedOption = optionalSelectedOption.get();
                    if (selectedOption.isDestroyer()) {
                        needDestroyer = false;
                    }
                    // Create new temp defenders
                    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(t + ", added sea defender for defense: " + selectedOption.getUnitType().getName() + ", TUVSwing=" + result.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", unusedCarrierCapacity=" + unusedCarrierCapacity + ", unusedLocalCarrierCapacity=" + unusedLocalCarrierCapacity);
                    // Find current battle result
                    final List<Unit> defendingUnits = new ArrayList<>(placeTerritory.getDefendingUnits());
                    defendingUnits.addAll(ProPurchaseUtils.getPlaceUnits(t, purchaseTerritories));
                    defendingUnits.addAll(unitsToPlace);
                    result = calc.estimateDefendBattleResults(t, enemyAttackOptions.getMax(t).getMaxUnits(), defendingUnits, enemyAttackOptions.getMax(t).getMaxBombardUnits());
                    hasOnlyRetreatingSubs = Properties.getSubRetreatBeforeBattle(data) && !defendingUnits.isEmpty() && defendingUnits.stream().allMatch(Matches.unitIsSub()) && enemyAttackOptions.getMax(t).getMaxUnits().stream().noneMatch(Matches.unitIsDestroyer());
                }
            }
            // Check to see if its worth trying to defend the territory
            if (result.getTuvSwing() < 0 || result.getWinPercentage() < ProData.winPercentage) {
                resourceTracker.confirmTempPurchases();
                ProLogger.trace(t + ", placedUnits=" + unitsToPlace + ", TUVSwing=" + result.getTuvSwing() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining());
                addUnitsToPlaceTerritory(placeTerritory, unitsToPlace, purchaseTerritories);
            } else {
                resourceTracker.clearTempPurchases();
                setCantHoldPlaceTerritory(placeTerritory, purchaseTerritories);
                ProLogger.trace(t + ", can't defend TUVSwing=" + result.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", tried to placeDefenders=" + unitsToPlace + ", enemyAttackers=" + enemyAttackOptions.getMax(t).getMaxUnits());
                continue;
            }
        }
        // TODO: update to use ProBattleUtils method
        // Check to see if local naval superiority
        int landDistance = ProUtils.getClosestEnemyLandTerritoryDistanceOverWater(data, player, t);
        if (landDistance <= 0) {
            landDistance = 10;
        }
        final int enemyDistance = Math.max(3, (landDistance + 1));
        final Set<Territory> nearbyTerritories = data.getMap().getNeighbors(t, enemyDistance, ProMatches.territoryCanMoveAirUnits(player, data, false));
        final List<Territory> nearbyLandTerritories = CollectionUtils.getMatches(nearbyTerritories, Matches.territoryIsLand());
        final Set<Territory> nearbyEnemySeaTerritories = data.getMap().getNeighbors(t, enemyDistance, Matches.territoryIsWater());
        nearbyEnemySeaTerritories.add(t);
        final int alliedDistance = (enemyDistance + 1) / 2;
        final Set<Territory> nearbyAlliedSeaTerritories = data.getMap().getNeighbors(t, alliedDistance, Matches.territoryIsWater());
        nearbyAlliedSeaTerritories.add(t);
        final List<Unit> enemyUnitsInLandTerritories = new ArrayList<>();
        for (final Territory nearbyLandTerritory : nearbyLandTerritories) {
            enemyUnitsInLandTerritories.addAll(nearbyLandTerritory.getUnits().getMatches(ProMatches.unitIsEnemyAir(player, data)));
        }
        final List<Unit> enemyUnitsInSeaTerritories = new ArrayList<>();
        for (final Territory nearbySeaTerritory : nearbyEnemySeaTerritories) {
            final List<Unit> enemySeaUnits = nearbySeaTerritory.getUnits().getMatches(ProMatches.unitIsEnemyNotLand(player, data));
            if (enemySeaUnits.isEmpty()) {
                continue;
            }
            final Route route = data.getMap().getRoute_IgnoreEnd(t, nearbySeaTerritory, Matches.territoryIsWater());
            if (route == null) {
                continue;
            }
            if (MoveValidator.validateCanal(route, enemySeaUnits, enemySeaUnits.get(0).getOwner(), data) != null) {
                continue;
            }
            final int routeLength = route.numberOfSteps();
            if (routeLength <= enemyDistance) {
                enemyUnitsInSeaTerritories.addAll(enemySeaUnits);
            }
        }
        final List<Unit> myUnitsInSeaTerritories = new ArrayList<>();
        for (final Territory nearbySeaTerritory : nearbyAlliedSeaTerritories) {
            myUnitsInSeaTerritories.addAll(nearbySeaTerritory.getUnits().getMatches(ProMatches.unitIsOwnedNotLand(player)));
            myUnitsInSeaTerritories.addAll(ProPurchaseUtils.getPlaceUnits(nearbySeaTerritory, purchaseTerritories));
        }
        // Check if destroyer is needed
        final int numEnemySubs = CollectionUtils.countMatches(enemyUnitsInSeaTerritories, Matches.unitIsSub());
        final int numMyDestroyers = CollectionUtils.countMatches(myUnitsInSeaTerritories, Matches.unitIsDestroyer());
        if (numEnemySubs > 2 * numMyDestroyers) {
            needDestroyer = true;
        }
        ProLogger.trace(t + ", enemyDistance=" + enemyDistance + ", alliedDistance=" + alliedDistance + ", enemyAirUnits=" + enemyUnitsInLandTerritories + ", enemySeaUnits=" + enemyUnitsInSeaTerritories + ", mySeaUnits=" + myUnitsInSeaTerritories + ", needDestroyer=" + needDestroyer);
        // Purchase naval defenders until I have local naval superiority
        final List<Unit> unitsToPlace = new ArrayList<>();
        for (final ProPurchaseTerritory purchaseTerritory : selectedPurchaseTerritories) {
            // Check remaining production
            int remainingUnitProduction = purchaseTerritory.getRemainingUnitProduction();
            ProLogger.trace(t + ", purchaseTerritory=" + purchaseTerritory.getTerritory() + ", remainingUnitProduction=" + remainingUnitProduction);
            if (remainingUnitProduction <= 0) {
                continue;
            }
            // Determine sea and transport units that can be produced in this territory
            final List<ProPurchaseOption> seaPurchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getSeaDefenseOptions(), t, isBid);
            seaPurchaseOptionsForTerritory.addAll(purchaseOptions.getAirOptions());
            while (true) {
                // If I have naval attack/defense superiority then break
                if (ProBattleUtils.territoryHasLocalNavalSuperiority(t, player, purchaseTerritories, unitsToPlace)) {
                    break;
                }
                // Select purchase option
                ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, seaPurchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
                final Map<ProPurchaseOption, Double> defenseEfficiencies = new HashMap<>();
                for (final ProPurchaseOption ppo : seaPurchaseOptionsForTerritory) {
                    defenseEfficiencies.put(ppo, ppo.getSeaDefenseEfficiency(data, ownedLocalUnits, unitsToPlace, needDestroyer, unusedCarrierCapacity, unusedLocalCarrierCapacity));
                }
                final Optional<ProPurchaseOption> optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(defenseEfficiencies, "Sea Defense");
                if (!optionalSelectedOption.isPresent()) {
                    break;
                }
                final ProPurchaseOption selectedOption = optionalSelectedOption.get();
                if (selectedOption.isDestroyer()) {
                    needDestroyer = false;
                }
                // Create new temp units
                resourceTracker.purchase(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(t + ", added sea defender for naval superiority: " + selectedOption.getUnitType().getName() + ", unusedCarrierCapacity=" + unusedCarrierCapacity + ", unusedLocalCarrierCapacity=" + unusedLocalCarrierCapacity);
            }
        }
        // Add sea defender units to place territory
        addUnitsToPlaceTerritory(placeTerritory, unitsToPlace, purchaseTerritories);
        // Loop through adjacent purchase territories and purchase transport/amphib units
        final int distance = ProTransportUtils.findMaxMovementForTransports(purchaseOptions.getSeaTransportOptions());
        ProLogger.trace(t + ", transportMovement=" + distance);
        for (final ProPurchaseTerritory purchaseTerritory : selectedPurchaseTerritories) {
            final Territory landTerritory = purchaseTerritory.getTerritory();
            // Check if territory can produce units and has remaining production
            int remainingUnitProduction = purchaseTerritory.getRemainingUnitProduction();
            ProLogger.trace(t + ", purchaseTerritory=" + landTerritory + ", remainingUnitProduction=" + remainingUnitProduction);
            if (remainingUnitProduction <= 0) {
                continue;
            }
            // Find local owned units
            final List<Unit> ownedLocalAmphibUnits = landTerritory.getUnits().getMatches(Matches.unitIsOwnedBy(player));
            // Determine sea and transport units that can be produced in this territory
            final List<ProPurchaseOption> seaTransportPurchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getSeaTransportOptions(), t, isBid);
            final List<ProPurchaseOption> amphibPurchaseOptionsForTerritory = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getLandOptions(), landTerritory, isBid);
            // Find transports that need loaded and units to ignore that are already paired up
            final List<Unit> transportsThatNeedUnits = new ArrayList<>();
            final Set<Unit> potentialUnitsToLoad = new HashSet<>();
            final Set<Territory> seaTerritories = data.getMap().getNeighbors(landTerritory, distance, ProMatches.territoryCanMoveSeaUnits(player, data, false));
            for (final Territory seaTerritory : seaTerritories) {
                final List<Unit> unitsInTerritory = ProPurchaseUtils.getPlaceUnits(seaTerritory, purchaseTerritories);
                unitsInTerritory.addAll(seaTerritory.getUnits().getUnits());
                final List<Unit> transports = CollectionUtils.getMatches(unitsInTerritory, ProMatches.unitIsOwnedTransport(player));
                for (final Unit transport : transports) {
                    transportsThatNeedUnits.add(transport);
                    final Set<Territory> territoriesToLoadFrom = new HashSet<>(data.getMap().getNeighbors(seaTerritory, distance));
                    territoriesToLoadFrom.removeIf(potentialTerritory -> potentialTerritory.isWater() || territoryValueMap.get(potentialTerritory) > 0.25);
                    final List<Unit> units = ProTransportUtils.getUnitsToTransportFromTerritories(player, transport, territoriesToLoadFrom, new ArrayList<>(potentialUnitsToLoad), ProMatches.unitIsOwnedCombatTransportableUnit(player));
                    potentialUnitsToLoad.addAll(units);
                }
            }
            // Determine whether transports, amphib units, or both are needed
            final Set<Territory> landNeighbors = data.getMap().getNeighbors(t, Matches.territoryIsLand());
            for (final Territory neighbor : landNeighbors) {
                if (territoryValueMap.get(neighbor) <= 0.25) {
                    final List<Unit> unitsInTerritory = new ArrayList<>(neighbor.getUnits().getUnits());
                    unitsInTerritory.addAll(ProPurchaseUtils.getPlaceUnits(neighbor, purchaseTerritories));
                    potentialUnitsToLoad.addAll(CollectionUtils.getMatches(unitsInTerritory, ProMatches.unitIsOwnedCombatTransportableUnit(player)));
                }
            }
            ProLogger.trace(t + ", potentialUnitsToLoad=" + potentialUnitsToLoad + ", transportsThatNeedUnits=" + transportsThatNeedUnits);
            // Purchase transports and amphib units
            final List<Unit> amphibUnitsToPlace = new ArrayList<>();
            final List<Unit> transportUnitsToPlace = new ArrayList<>();
            while (true) {
                if (!transportsThatNeedUnits.isEmpty()) {
                    // Get next empty transport and find its capacity
                    final Unit transport = transportsThatNeedUnits.get(0);
                    int transportCapacity = UnitAttachment.get(transport.getType()).getTransportCapacity();
                    // Find any existing units that can be transported
                    final List<Unit> selectedUnits = ProTransportUtils.selectUnitsToTransportFromList(transport, new ArrayList<>(potentialUnitsToLoad));
                    if (!selectedUnits.isEmpty()) {
                        potentialUnitsToLoad.removeAll(selectedUnits);
                        transportCapacity -= ProTransportUtils.findUnitsTransportCost(selectedUnits);
                    }
                    // Purchase units until transport is full
                    while (transportCapacity > 0) {
                        // Select amphib purchase option and add units
                        ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, amphibPurchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, amphibUnitsToPlace, purchaseTerritories);
                        final Map<ProPurchaseOption, Double> amphibEfficiencies = new HashMap<>();
                        for (final ProPurchaseOption ppo : amphibPurchaseOptionsForTerritory) {
                            if (ppo.getTransportCost() <= transportCapacity) {
                                amphibEfficiencies.put(ppo, ppo.getAmphibEfficiency(data, ownedLocalAmphibUnits, amphibUnitsToPlace));
                            }
                        }
                        final Optional<ProPurchaseOption> optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(amphibEfficiencies, "Amphib");
                        if (!optionalSelectedOption.isPresent()) {
                            break;
                        }
                        final ProPurchaseOption ppo = optionalSelectedOption.get();
                        // Add amphib unit
                        final List<Unit> amphibUnits = ppo.getUnitType().create(ppo.getQuantity(), player, true);
                        amphibUnitsToPlace.addAll(amphibUnits);
                        resourceTracker.purchase(ppo);
                        remainingUnitProduction -= ppo.getQuantity();
                        transportCapacity -= ppo.getTransportCost();
                        ProLogger.trace("Selected unit=" + ppo.getUnitType().getName());
                    }
                    transportsThatNeedUnits.remove(transport);
                } else {
                    // Select purchase option
                    ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, seaTransportPurchaseOptionsForTerritory, resourceTracker, remainingUnitProduction, transportUnitsToPlace, purchaseTerritories);
                    final Map<ProPurchaseOption, Double> transportEfficiencies = new HashMap<>();
                    for (final ProPurchaseOption ppo : seaTransportPurchaseOptionsForTerritory) {
                        transportEfficiencies.put(ppo, ppo.getTransportEfficiencyRatio());
                    }
                    final Optional<ProPurchaseOption> optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(transportEfficiencies, "Sea Transport");
                    if (!optionalSelectedOption.isPresent()) {
                        break;
                    }
                    final ProPurchaseOption ppo = optionalSelectedOption.get();
                    // Add transports
                    final List<Unit> transports = ppo.getUnitType().create(ppo.getQuantity(), player, true);
                    transportUnitsToPlace.addAll(transports);
                    resourceTracker.purchase(ppo);
                    remainingUnitProduction -= ppo.getQuantity();
                    transportsThatNeedUnits.addAll(transports);
                    ProLogger.trace("Selected unit=" + ppo.getUnitType().getName() + ", potentialUnitsToLoad=" + potentialUnitsToLoad + ", transportsThatNeedUnits=" + transportsThatNeedUnits);
                }
            }
            // Add transport units to sea place territory and amphib units to land place territory
            for (final ProPlaceTerritory ppt : purchaseTerritory.getCanPlaceTerritories()) {
                if (landTerritory.equals(ppt.getTerritory())) {
                    ppt.getPlaceUnits().addAll(amphibUnitsToPlace);
                } else if (placeTerritory.equals(ppt)) {
                    ppt.getPlaceUnits().addAll(transportUnitsToPlace);
                }
            }
            ProLogger.trace(t + ", purchaseTerritory=" + landTerritory + ", transportUnitsToPlace=" + transportUnitsToPlace + ", amphibUnitsToPlace=" + amphibUnitsToPlace);
        }
    }
}
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) Route(games.strategy.engine.data.Route) HashSet(java.util.HashSet)

Example 4 with ProPurchaseOption

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

the class ProPurchaseAi method purchaseLandUnits.

private void purchaseLandUnits(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPlaceTerritory> prioritizedLandTerritories, final ProPurchaseOptionMap purchaseOptions, final Map<Territory, Double> territoryValueMap) {
    final List<Unit> unplacedUnits = player.getUnits().getMatches(Matches.unitIsNotSea());
    if (resourceTracker.isEmpty() && unplacedUnits.isEmpty()) {
        return;
    }
    ProLogger.info("Purchase land units with resources: " + resourceTracker);
    if (!unplacedUnits.isEmpty()) {
        ProLogger.info("Purchase land units with unplaced units=" + unplacedUnits);
    }
    // Loop through prioritized territories and purchase land units
    for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) {
        final Territory t = placeTerritory.getTerritory();
        ProLogger.debug("Checking land place for " + t.getName());
        // Check remaining production
        int remainingUnitProduction = purchaseTerritories.get(t).getRemainingUnitProduction();
        ProLogger.debug(t + ", remainingUnitProduction=" + remainingUnitProduction);
        if (remainingUnitProduction <= 0) {
            continue;
        }
        // Determine most cost efficient units that can be produced in this territory
        final List<ProPurchaseOption> landFodderOptions = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getLandFodderOptions(), t, isBid);
        final List<ProPurchaseOption> landAttackOptions = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getLandAttackOptions(), t, isBid);
        final List<ProPurchaseOption> landDefenseOptions = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getLandDefenseOptions(), t, isBid);
        // Determine enemy distance and locally owned units
        int enemyDistance = ProUtils.getClosestEnemyOrNeutralLandTerritoryDistance(data, player, t, territoryValueMap);
        if (enemyDistance <= 0) {
            enemyDistance = 10;
        }
        final int fodderPercent = 80 - enemyDistance * 5;
        ProLogger.debug(t + ", enemyDistance=" + enemyDistance + ", fodderPercent=" + fodderPercent);
        final Set<Territory> neighbors = data.getMap().getNeighbors(t, 2, ProMatches.territoryCanMoveLandUnits(player, data, false));
        neighbors.add(t);
        final List<Unit> ownedLocalUnits = new ArrayList<>();
        for (final Territory neighbor : neighbors) {
            ownedLocalUnits.addAll(neighbor.getUnits().getMatches(Matches.unitIsOwnedBy(player)));
        }
        // Check for unplaced units
        final List<Unit> unitsToPlace = new ArrayList<>();
        for (final Iterator<Unit> it = unplacedUnits.iterator(); it.hasNext(); ) {
            final Unit u = it.next();
            if (remainingUnitProduction > 0 && ProPurchaseUtils.canUnitsBePlaced(Collections.singletonList(u), player, t, isBid)) {
                remainingUnitProduction--;
                unitsToPlace.add(u);
                it.remove();
                ProLogger.trace("Selected unplaced unit=" + u);
            }
        }
        // Purchase as many units as possible
        int addedFodderUnits = 0;
        double attackAndDefenseDifference = 0;
        boolean selectFodderUnit = true;
        while (true) {
            // Remove options that cost too much PUs or production
            ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, landFodderOptions, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
            ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, landAttackOptions, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
            ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, landDefenseOptions, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
            // Select purchase option
            Optional<ProPurchaseOption> optionalSelectedOption = Optional.empty();
            if (!selectFodderUnit && attackAndDefenseDifference > 0 && !landDefenseOptions.isEmpty()) {
                final Map<ProPurchaseOption, Double> defenseEfficiencies = new HashMap<>();
                for (final ProPurchaseOption ppo : landDefenseOptions) {
                    defenseEfficiencies.put(ppo, ppo.getDefenseEfficiency2(enemyDistance, data, ownedLocalUnits, unitsToPlace));
                }
                optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(defenseEfficiencies, "Land Defense");
            } else if (!selectFodderUnit && !landAttackOptions.isEmpty()) {
                final Map<ProPurchaseOption, Double> attackEfficiencies = new HashMap<>();
                for (final ProPurchaseOption ppo : landAttackOptions) {
                    attackEfficiencies.put(ppo, ppo.getAttackEfficiency2(enemyDistance, data, ownedLocalUnits, unitsToPlace));
                }
                optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(attackEfficiencies, "Land Attack");
            } else if (!landFodderOptions.isEmpty()) {
                final Map<ProPurchaseOption, Double> fodderEfficiencies = new HashMap<>();
                for (final ProPurchaseOption ppo : landFodderOptions) {
                    fodderEfficiencies.put(ppo, ppo.getFodderEfficiency(enemyDistance, data, ownedLocalUnits, unitsToPlace));
                }
                optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(fodderEfficiencies, "Land Fodder");
                if (optionalSelectedOption.isPresent()) {
                    addedFodderUnits += optionalSelectedOption.get().getQuantity();
                }
            }
            if (!optionalSelectedOption.isPresent()) {
                break;
            }
            final ProPurchaseOption selectedOption = optionalSelectedOption.get();
            // Create new temp units
            resourceTracker.purchase(selectedOption);
            remainingUnitProduction -= selectedOption.getQuantity();
            unitsToPlace.addAll(selectedOption.getUnitType().create(selectedOption.getQuantity(), player, true));
            attackAndDefenseDifference += (selectedOption.getAttack() - selectedOption.getDefense());
            selectFodderUnit = ((double) addedFodderUnits / unitsToPlace.size() * 100) <= fodderPercent;
            ProLogger.trace("Selected unit=" + selectedOption.getUnitType().getName());
        }
        // Add units to place territory
        placeTerritory.getPlaceUnits().addAll(unitsToPlace);
        ProLogger.debug(t + ", placedUnits=" + unitsToPlace);
    }
}
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) 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) HashMap(java.util.HashMap) Map(java.util.Map) IntegerMap(games.strategy.util.IntegerMap) ProPurchaseOptionMap(games.strategy.triplea.ai.pro.data.ProPurchaseOptionMap)

Example 5 with ProPurchaseOption

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

the class ProPurchaseUtils method randomizePurchaseOption.

public static Optional<ProPurchaseOption> randomizePurchaseOption(final Map<ProPurchaseOption, Double> purchaseEfficiencies, final String type) {
    ProLogger.trace("Select purchase option for " + type);
    double totalEfficiency = 0;
    for (final Double efficiency : purchaseEfficiencies.values()) {
        totalEfficiency += efficiency;
    }
    if (totalEfficiency == 0) {
        return Optional.empty();
    }
    final Map<ProPurchaseOption, Double> purchasePercentages = new LinkedHashMap<>();
    double upperBound = 0.0;
    for (final ProPurchaseOption ppo : purchaseEfficiencies.keySet()) {
        final double chance = purchaseEfficiencies.get(ppo) / totalEfficiency * 100;
        upperBound += chance;
        purchasePercentages.put(ppo, upperBound);
        ProLogger.trace(ppo.getUnitType().getName() + ", probability=" + chance + ", upperBound=" + upperBound);
    }
    final double randomNumber = Math.random() * 100;
    ProLogger.trace("Random number: " + randomNumber);
    for (final ProPurchaseOption ppo : purchasePercentages.keySet()) {
        if (randomNumber <= purchasePercentages.get(ppo)) {
            return Optional.of(ppo);
        }
    }
    return Optional.of(purchasePercentages.keySet().iterator().next());
}
Also used : ProPurchaseOption(games.strategy.triplea.ai.pro.data.ProPurchaseOption) LinkedHashMap(java.util.LinkedHashMap)

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