Search in sources :

Example 16 with ProBattleResult

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

the class ProNonCombatMoveAi method moveUnitsToDefendTerritories.

private void moveUnitsToDefendTerritories(final List<ProTerritory> prioritizedTerritories, final int enemyDistance, final Map<Territory, Double> territoryValueMap) {
    ProLogger.info("Determine units to defend territories with");
    if (prioritizedTerritories.isEmpty()) {
        return;
    }
    final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
    final Map<Unit, Set<Territory>> unitMoveMap = territoryManager.getDefendOptions().getUnitMoveMap();
    final Map<Unit, Set<Territory>> transportMoveMap = territoryManager.getDefendOptions().getTransportMoveMap();
    final List<ProTransport> transportMapList = territoryManager.getDefendOptions().getTransportList();
    // Assign units to territories by prioritization
    int numToDefend = 1;
    while (true) {
        // Reset lists
        for (final ProTerritory t : moveMap.values()) {
            t.getTempUnits().clear();
            t.getTempAmphibAttackMap().clear();
            t.getTransportTerritoryMap().clear();
            t.setBattleResult(null);
        }
        // Determine number of territories to defend
        if (numToDefend <= 0) {
            break;
        }
        final List<ProTerritory> territoriesToTryToDefend = prioritizedTerritories.subList(0, numToDefend);
        // Loop through all units and determine defend options
        final Map<Unit, Set<Territory>> unitDefendOptions = new HashMap<>();
        for (final Unit unit : unitMoveMap.keySet()) {
            // Find number of move options
            final Set<Territory> canDefendTerritories = new LinkedHashSet<>();
            for (final ProTerritory attackTerritoryData : territoriesToTryToDefend) {
                if (unitMoveMap.get(unit).contains(attackTerritoryData.getTerritory())) {
                    canDefendTerritories.add(attackTerritoryData.getTerritory());
                }
            }
            unitDefendOptions.put(unit, canDefendTerritories);
        }
        // Sort units by number of defend options and cost
        final Map<Unit, Set<Territory>> sortedUnitMoveOptions = ProSortMoveOptionsUtils.sortUnitMoveOptions(unitDefendOptions);
        // Set enough units in territories to have at least a chance of winning
        for (final Iterator<Unit> it = sortedUnitMoveOptions.keySet().iterator(); it.hasNext(); ) {
            final Unit unit = it.next();
            final boolean isAirUnit = UnitAttachment.get(unit.getType()).getIsAir();
            if (isAirUnit || Matches.unitIsCarrier().test(unit)) {
                // skip air and carrier units
                continue;
            }
            final TreeMap<Double, Territory> estimatesMap = new TreeMap<>();
            for (final Territory t : sortedUnitMoveOptions.get(unit)) {
                List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsAlliedNotOwnedAir(player, data).negate());
                if (t.isWater()) {
                    defendingUnits = moveMap.get(t).getAllDefenders();
                }
                final double estimate = ProBattleUtils.estimateStrengthDifference(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits);
                estimatesMap.put(estimate, t);
            }
            if (!estimatesMap.isEmpty() && estimatesMap.lastKey() > 60) {
                final Territory minWinTerritory = estimatesMap.lastEntry().getValue();
                moveMap.get(minWinTerritory).addTempUnit(unit);
                it.remove();
            }
        }
        // Set non-air units in territories
        for (final Iterator<Unit> it = sortedUnitMoveOptions.keySet().iterator(); it.hasNext(); ) {
            final Unit unit = it.next();
            if (Matches.unitCanLandOnCarrier().test(unit)) {
                continue;
            }
            Territory maxWinTerritory = null;
            double maxWinPercentage = -1;
            for (final Territory t : sortedUnitMoveOptions.get(unit)) {
                List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsAlliedNotOwnedAir(player, data).negate());
                if (t.isWater()) {
                    defendingUnits = moveMap.get(t).getAllDefenders();
                }
                if (moveMap.get(t).getBattleResult() == null) {
                    moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
                }
                final ProBattleResult result = moveMap.get(t).getBattleResult();
                final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
                if (result.getWinPercentage() > maxWinPercentage && ((t.equals(ProData.myCapital) && result.getWinPercentage() > (100 - ProData.winPercentage)) || (hasFactory && result.getWinPercentage() > (100 - ProData.minWinPercentage)) || result.getTuvSwing() >= 0)) {
                    maxWinTerritory = t;
                    maxWinPercentage = result.getWinPercentage();
                }
            }
            if (maxWinTerritory != null) {
                moveMap.get(maxWinTerritory).addTempUnit(unit);
                moveMap.get(maxWinTerritory).setBattleResult(null);
                it.remove();
                // If carrier has dependent allied fighters then move them too
                if (Matches.unitIsCarrier().test(unit)) {
                    final Territory unitTerritory = unitTerritoryMap.get(unit);
                    final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
                    if (carrierMustMoveWith.containsKey(unit)) {
                        moveMap.get(maxWinTerritory).getTempUnits().addAll(carrierMustMoveWith.get(unit));
                    }
                }
            }
        }
        // Set air units in territories
        for (final Iterator<Unit> it = sortedUnitMoveOptions.keySet().iterator(); it.hasNext(); ) {
            final Unit unit = it.next();
            Territory maxWinTerritory = null;
            double maxWinPercentage = -1;
            for (final Territory t : sortedUnitMoveOptions.get(unit)) {
                if (t.isWater() && Matches.unitIsAir().test(unit)) {
                    if (!ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), unit)) {
                        // skip moving air to water if not enough carrier capacity
                        continue;
                    }
                }
                if (!t.isWater() && !t.getOwner().equals(player) && Matches.unitIsAir().test(unit) && !ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
                    // skip moving air units to allied land without a factory
                    continue;
                }
                List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsAlliedNotOwnedAir(player, data).negate());
                if (t.isWater()) {
                    defendingUnits = moveMap.get(t).getAllDefenders();
                }
                if (moveMap.get(t).getBattleResult() == null) {
                    moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
                }
                final ProBattleResult result = moveMap.get(t).getBattleResult();
                final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
                if (result.getWinPercentage() > maxWinPercentage && ((t.equals(ProData.myCapital) && result.getWinPercentage() > (100 - ProData.winPercentage)) || (hasFactory && result.getWinPercentage() > (100 - ProData.minWinPercentage)) || result.getTuvSwing() >= 0)) {
                    maxWinTerritory = t;
                    maxWinPercentage = result.getWinPercentage();
                }
            }
            if (maxWinTerritory != null) {
                moveMap.get(maxWinTerritory).addTempUnit(unit);
                moveMap.get(maxWinTerritory).setBattleResult(null);
                it.remove();
            }
        }
        // Loop through all my transports and see which territories they can defend from current list
        final List<Unit> alreadyMovedTransports = new ArrayList<>();
        if (!Properties.getTransportCasualtiesRestricted(data)) {
            final Map<Unit, Set<Territory>> transportDefendOptions = new HashMap<>();
            for (final Unit unit : transportMoveMap.keySet()) {
                // Find number of defend options
                final Set<Territory> canDefendTerritories = new HashSet<>();
                for (final ProTerritory attackTerritoryData : territoriesToTryToDefend) {
                    if (transportMoveMap.get(unit).contains(attackTerritoryData.getTerritory())) {
                        canDefendTerritories.add(attackTerritoryData.getTerritory());
                    }
                }
                if (!canDefendTerritories.isEmpty()) {
                    transportDefendOptions.put(unit, canDefendTerritories);
                }
            }
            // Loop through transports with move options and determine if any naval defense needs it
            for (final Unit transport : transportDefendOptions.keySet()) {
                // Find current naval defense that needs transport if it isn't transporting units
                for (final Territory t : transportDefendOptions.get(transport)) {
                    if (!TransportTracker.isTransporting(transport)) {
                        final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
                        if (moveMap.get(t).getBattleResult() == null) {
                            moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
                        }
                        final ProBattleResult result = moveMap.get(t).getBattleResult();
                        if (result.getTuvSwing() > 0) {
                            moveMap.get(t).addTempUnit(transport);
                            moveMap.get(t).setBattleResult(null);
                            alreadyMovedTransports.add(transport);
                            ProLogger.trace("Adding defend transport to: " + t.getName());
                            break;
                        }
                    }
                }
            }
        }
        // Loop through all my transports and see which can make amphib move
        final Map<Unit, Set<Territory>> amphibMoveOptions = new HashMap<>();
        for (final ProTransport proTransportData : transportMapList) {
            // If already used to defend then ignore
            if (alreadyMovedTransports.contains(proTransportData.getTransport())) {
                continue;
            }
            // Find number of amphib move options
            final Set<Territory> canAmphibMoveTerritories = new HashSet<>();
            for (final ProTerritory attackTerritoryData : territoriesToTryToDefend) {
                if (proTransportData.getTransportMap().containsKey(attackTerritoryData.getTerritory())) {
                    canAmphibMoveTerritories.add(attackTerritoryData.getTerritory());
                }
            }
            if (!canAmphibMoveTerritories.isEmpty()) {
                amphibMoveOptions.put(proTransportData.getTransport(), canAmphibMoveTerritories);
            }
        }
        // Loop through transports with amphib move options and determine if any land defense needs it
        for (final Unit transport : amphibMoveOptions.keySet()) {
            // Find current land defense results for territories that unit can amphib move
            for (final Territory t : amphibMoveOptions.get(transport)) {
                final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
                if (moveMap.get(t).getBattleResult() == null) {
                    moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
                }
                final ProBattleResult result = moveMap.get(t).getBattleResult();
                final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
                if ((t.equals(ProData.myCapital) && result.getWinPercentage() > (100 - ProData.winPercentage)) || (hasFactory && result.getWinPercentage() > (100 - ProData.minWinPercentage)) || result.getTuvSwing() > 0) {
                    // Get all units that have already moved
                    final List<Unit> alreadyMovedUnits = new ArrayList<>();
                    for (final ProTerritory t2 : moveMap.values()) {
                        alreadyMovedUnits.addAll(t2.getUnits());
                        alreadyMovedUnits.addAll(t2.getTempUnits());
                    }
                    // Find units that haven't moved and can be transported
                    boolean addedAmphibUnits = false;
                    for (final ProTransport proTransportData : transportMapList) {
                        if (proTransportData.getTransport().equals(transport)) {
                            // Find units to transport
                            final Set<Territory> territoriesCanLoadFrom = proTransportData.getTransportMap().get(t);
                            final List<Unit> amphibUnitsToAdd = ProTransportUtils.getUnitsToTransportFromTerritories(player, transport, territoriesCanLoadFrom, alreadyMovedUnits);
                            if (amphibUnitsToAdd.isEmpty()) {
                                continue;
                            }
                            // Find safest territory to unload from
                            double minStrengthDifference = Double.POSITIVE_INFINITY;
                            Territory minTerritory = null;
                            final Set<Territory> territoriesToMoveTransport = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, false));
                            final Set<Territory> loadFromTerritories = new HashSet<>();
                            for (final Unit u : amphibUnitsToAdd) {
                                loadFromTerritories.add(unitTerritoryMap.get(u));
                            }
                            for (final Territory territoryToMoveTransport : territoriesToMoveTransport) {
                                if (proTransportData.getSeaTransportMap().containsKey(territoryToMoveTransport) && proTransportData.getSeaTransportMap().get(territoryToMoveTransport).containsAll(loadFromTerritories) && moveMap.get(territoryToMoveTransport) != null && (moveMap.get(territoryToMoveTransport).isCanHold() || hasFactory)) {
                                    final List<Unit> attackers = moveMap.get(territoryToMoveTransport).getMaxEnemyUnits();
                                    final List<Unit> defenders = moveMap.get(territoryToMoveTransport).getAllDefenders();
                                    defenders.add(transport);
                                    final double strengthDifference = ProBattleUtils.estimateStrengthDifference(territoryToMoveTransport, attackers, defenders);
                                    if (strengthDifference < minStrengthDifference) {
                                        minTerritory = territoryToMoveTransport;
                                        minStrengthDifference = strengthDifference;
                                    }
                                }
                            }
                            if (minTerritory != null) {
                                // Add amphib defense
                                moveMap.get(t).getTransportTerritoryMap().put(transport, minTerritory);
                                moveMap.get(t).addTempUnits(amphibUnitsToAdd);
                                moveMap.get(t).putTempAmphibAttackMap(transport, amphibUnitsToAdd);
                                moveMap.get(t).setBattleResult(null);
                                for (final Unit unit : amphibUnitsToAdd) {
                                    sortedUnitMoveOptions.remove(unit);
                                }
                                ProLogger.trace("Adding amphibious defense to: " + t + ", units=" + amphibUnitsToAdd + ", unloadTerritory=" + minTerritory);
                                addedAmphibUnits = true;
                                break;
                            }
                        }
                    }
                    if (addedAmphibUnits) {
                        break;
                    }
                }
            }
        }
        // Determine if all defenses are successful
        boolean areSuccessful = true;
        boolean containsCapital = false;
        ProLogger.debug("Current number of territories: " + numToDefend);
        for (final ProTerritory patd : territoriesToTryToDefend) {
            final Territory t = patd.getTerritory();
            // Find defense result and hold value based on used defenders TUV
            final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
            moveMap.get(t).setBattleResult(calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
            final ProBattleResult result = patd.getBattleResult();
            int isFactory = 0;
            if (ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
                isFactory = 1;
            }
            int isMyCapital = 0;
            if (t.equals(ProData.myCapital)) {
                isMyCapital = 1;
                containsCapital = true;
            }
            final double extraUnitValue = TuvUtils.getTuv(moveMap.get(t).getTempUnits(), ProData.unitValueMap);
            final List<Unit> unsafeTransports = new ArrayList<>();
            for (final Unit transport : moveMap.get(t).getTransportTerritoryMap().keySet()) {
                final Territory transportTerritory = moveMap.get(t).getTransportTerritoryMap().get(transport);
                if (!moveMap.get(transportTerritory).isCanHold()) {
                    unsafeTransports.add(transport);
                }
            }
            final int unsafeTransportValue = TuvUtils.getTuv(unsafeTransports, ProData.unitValueMap);
            final double holdValue = extraUnitValue / 8 * (1 + 0.5 * isFactory) * (1 + 2 * isMyCapital) - unsafeTransportValue;
            // Find strategic value
            boolean hasHigherStrategicValue = true;
            if (!t.isWater() && !t.equals(ProData.myCapital) && !ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
                double totalValue = 0.0;
                final List<Unit> nonAirDefenders = CollectionUtils.getMatches(moveMap.get(t).getTempUnits(), Matches.unitIsNotAir());
                for (final Unit u : nonAirDefenders) {
                    totalValue += territoryValueMap.get(unitTerritoryMap.get(u));
                }
                final double averageValue = totalValue / nonAirDefenders.size();
                if (territoryValueMap.get(t) < averageValue) {
                    hasHigherStrategicValue = false;
                    ProLogger.trace(t + " has lower value then move from with value=" + territoryValueMap.get(t) + ", averageMoveFromValue=" + averageValue);
                }
            }
            // Check if its worth defending
            if ((result.getTuvSwing() - holdValue) > patd.getMinBattleResult().getTuvSwing() || (!hasHigherStrategicValue && (result.getTuvSwing() + extraUnitValue / 2) >= patd.getMinBattleResult().getTuvSwing())) {
                areSuccessful = false;
            }
            ProLogger.debug(patd.getResultString() + ", holdValue=" + holdValue + ", minTUVSwing=" + patd.getMinBattleResult().getTuvSwing() + ", hasHighStrategicValue=" + hasHigherStrategicValue + ", defenders=" + defendingUnits + ", attackers=" + moveMap.get(t).getMaxEnemyUnits());
        }
        final Territory currentTerritory = prioritizedTerritories.get(numToDefend - 1).getTerritory();
        if (ProData.myCapital != null) {
            // Check capital defense
            if (containsCapital && !currentTerritory.equals(ProData.myCapital) && moveMap.get(ProData.myCapital).getBattleResult().getWinPercentage() > (100 - ProData.winPercentage)) {
                if (!Collections.disjoint(moveMap.get(currentTerritory).getAllDefenders(), moveMap.get(ProData.myCapital).getMaxDefenders())) {
                    areSuccessful = false;
                    ProLogger.debug("Capital isn't safe after defense moves with winPercentage=" + moveMap.get(ProData.myCapital).getBattleResult().getWinPercentage());
                }
            }
            // Check capital local superiority
            if (!currentTerritory.isWater() && enemyDistance >= 2 && enemyDistance <= 3) {
                final int distance = data.getMap().getDistance(ProData.myCapital, currentTerritory, ProMatches.territoryCanMoveLandUnits(player, data, true));
                if (distance > 0 && (enemyDistance == distance || enemyDistance == (distance - 1)) && !ProBattleUtils.territoryHasLocalLandSuperiorityAfterMoves(ProData.myCapital, enemyDistance, player, moveMap)) {
                    areSuccessful = false;
                    ProLogger.debug("Capital doesn't have local land superiority after defense moves with enemyDistance=" + enemyDistance);
                }
            }
        }
        // Determine whether to try more territories, remove a territory, or end
        if (areSuccessful) {
            numToDefend++;
            for (final ProTerritory patd : territoriesToTryToDefend) {
                patd.setCanAttack(true);
            }
            // Can defend all territories in list so end
            if (numToDefend > prioritizedTerritories.size()) {
                break;
            }
        } else {
            // Remove territory last territory in prioritized list since we can't hold them all
            ProLogger.debug("Removing territory: " + currentTerritory);
            prioritizedTerritories.get(numToDefend - 1).setCanHold(false);
            prioritizedTerritories.remove(numToDefend - 1);
            if (numToDefend > prioritizedTerritories.size()) {
                numToDefend--;
            }
        }
    }
    // Add temp units to move lists
    for (final ProTerritory t : moveMap.values()) {
        // Handle allied units such as fighters on carriers
        final List<Unit> alliedUnits = CollectionUtils.getMatches(t.getTempUnits(), Matches.unitIsOwnedBy(player).negate());
        for (final Unit alliedUnit : alliedUnits) {
            t.addCantMoveUnit(alliedUnit);
            t.getTempUnits().remove(alliedUnit);
        }
        t.addUnits(t.getTempUnits());
        t.putAllAmphibAttackMap(t.getTempAmphibAttackMap());
        for (final Unit u : t.getTempUnits()) {
            if (Matches.unitIsTransport().test(u)) {
                transportMoveMap.remove(u);
                transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
            } else {
                unitMoveMap.remove(u);
            }
        }
        for (final Unit u : t.getTempAmphibAttackMap().keySet()) {
            transportMoveMap.remove(u);
            transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
        }
        t.getTempUnits().clear();
        t.getTempAmphibAttackMap().clear();
    }
    ProLogger.debug("Final number of territories: " + (numToDefend - 1));
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) HashMap(java.util.HashMap) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) ArrayList(java.util.ArrayList) ProBattleResult(games.strategy.triplea.ai.pro.data.ProBattleResult) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) Territory(games.strategy.engine.data.Territory) TreeMap(java.util.TreeMap) ProTransport(games.strategy.triplea.ai.pro.data.ProTransport) Collection(java.util.Collection)

Example 17 with ProBattleResult

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

the class ProNonCombatMoveAi method moveUnitsToBestTerritories.

private void moveUnitsToBestTerritories() {
    final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
    final Map<Unit, Set<Territory>> unitMoveMap = territoryManager.getDefendOptions().getUnitMoveMap();
    final Map<Unit, Set<Territory>> transportMoveMap = territoryManager.getDefendOptions().getTransportMoveMap();
    final List<ProTransport> transportMapList = territoryManager.getDefendOptions().getTransportList();
    while (true) {
        ProLogger.info("Move units to best value territories");
        final Set<Territory> territoriesToDefend = new HashSet<>();
        final Map<Unit, Set<Territory>> currentUnitMoveMap = new HashMap<>(unitMoveMap);
        final Map<Unit, Set<Territory>> currentTransportMoveMap = new HashMap<>(transportMoveMap);
        final List<ProTransport> currentTransportMapList = new ArrayList<>(transportMapList);
        // Reset lists
        for (final ProTerritory t : moveMap.values()) {
            t.getTempUnits().clear();
            for (final Unit transport : t.getTempAmphibAttackMap().keySet()) {
                t.getTransportTerritoryMap().remove(transport);
            }
            t.getTempAmphibAttackMap().clear();
            t.setBattleResult(null);
        }
        ProLogger.debug("Move amphib units");
        // Transport amphib units to best territory
        for (final Iterator<ProTransport> it = currentTransportMapList.iterator(); it.hasNext(); ) {
            final ProTransport amphibData = it.next();
            final Unit transport = amphibData.getTransport();
            // Get all units that have already moved
            final List<Unit> alreadyMovedUnits = new ArrayList<>();
            for (final ProTerritory t : moveMap.values()) {
                alreadyMovedUnits.addAll(t.getUnits());
                alreadyMovedUnits.addAll(t.getTempUnits());
            }
            // Transport amphib units to best land territory
            Territory maxValueTerritory = null;
            List<Unit> maxAmphibUnitsToAdd = null;
            double maxValue = Double.MIN_VALUE;
            double maxSeaValue = 0;
            Territory maxUnloadFromTerritory = null;
            for (final Territory t : amphibData.getTransportMap().keySet()) {
                if (moveMap.get(t).getValue() >= maxValue) {
                    // Find units to load
                    final Set<Territory> territoriesCanLoadFrom = amphibData.getTransportMap().get(t);
                    final List<Unit> amphibUnitsToAdd = ProTransportUtils.getUnitsToTransportThatCantMoveToHigherValue(player, transport, territoriesCanLoadFrom, alreadyMovedUnits, moveMap, currentUnitMoveMap, moveMap.get(t).getValue());
                    if (amphibUnitsToAdd.isEmpty()) {
                        continue;
                    }
                    // Find best territory to move transport
                    final Set<Territory> loadFromTerritories = new HashSet<>();
                    for (final Unit u : amphibUnitsToAdd) {
                        loadFromTerritories.add(unitTerritoryMap.get(u));
                    }
                    final Set<Territory> territoriesToMoveTransport = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, false));
                    for (final Territory territoryToMoveTransport : territoriesToMoveTransport) {
                        if (amphibData.getSeaTransportMap().containsKey(territoryToMoveTransport) && amphibData.getSeaTransportMap().get(territoryToMoveTransport).containsAll(loadFromTerritories) && moveMap.get(territoryToMoveTransport) != null && moveMap.get(territoryToMoveTransport).isCanHold() && (moveMap.get(t).getValue() > maxValue || moveMap.get(territoryToMoveTransport).getValue() > maxSeaValue)) {
                            maxValueTerritory = t;
                            maxAmphibUnitsToAdd = amphibUnitsToAdd;
                            maxValue = moveMap.get(t).getValue();
                            maxSeaValue = moveMap.get(territoryToMoveTransport).getValue();
                            maxUnloadFromTerritory = territoryToMoveTransport;
                        }
                    }
                }
            }
            if (maxValueTerritory != null) {
                ProLogger.trace(transport + " moved to " + maxUnloadFromTerritory + " and unloading to best land at " + maxValueTerritory + " with " + maxAmphibUnitsToAdd + ", value=" + maxValue);
                moveMap.get(maxValueTerritory).addTempUnits(maxAmphibUnitsToAdd);
                moveMap.get(maxValueTerritory).putTempAmphibAttackMap(transport, maxAmphibUnitsToAdd);
                moveMap.get(maxValueTerritory).getTransportTerritoryMap().put(transport, maxUnloadFromTerritory);
                currentTransportMoveMap.remove(transport);
                for (final Unit unit : maxAmphibUnitsToAdd) {
                    currentUnitMoveMap.remove(unit);
                }
                territoriesToDefend.add(maxUnloadFromTerritory);
                it.remove();
                continue;
            }
            // Transport amphib units to best sea territory
            for (final Territory t : amphibData.getSeaTransportMap().keySet()) {
                if (moveMap.get(t) != null && moveMap.get(t).getValue() > maxValue) {
                    // Find units to load
                    final Set<Territory> territoriesCanLoadFrom = amphibData.getSeaTransportMap().get(t);
                    // Don't transport adjacent units
                    territoriesCanLoadFrom.removeAll(data.getMap().getNeighbors(t));
                    final List<Unit> amphibUnitsToAdd = ProTransportUtils.getUnitsToTransportThatCantMoveToHigherValue(player, transport, territoriesCanLoadFrom, alreadyMovedUnits, moveMap, currentUnitMoveMap, 0.1);
                    if (!amphibUnitsToAdd.isEmpty()) {
                        maxValueTerritory = t;
                        maxAmphibUnitsToAdd = amphibUnitsToAdd;
                        maxValue = moveMap.get(t).getValue();
                    }
                }
            }
            if (maxValueTerritory != null) {
                final Set<Territory> possibleUnloadTerritories = data.getMap().getNeighbors(maxValueTerritory, ProMatches.territoryCanMoveLandUnitsAndIsAllied(player, data));
                Territory unloadToTerritory = null;
                int maxNumSeaNeighbors = 0;
                for (final Territory t : possibleUnloadTerritories) {
                    final int numSeaNeighbors = data.getMap().getNeighbors(t, Matches.territoryIsWater()).size();
                    final boolean isAdjacentToEnemy = ProMatches.territoryIsOrAdjacentToEnemyNotNeutralLand(player, data).test(t);
                    if (moveMap.get(t) != null && (moveMap.get(t).isCanHold() || !isAdjacentToEnemy) && numSeaNeighbors > maxNumSeaNeighbors) {
                        unloadToTerritory = t;
                        maxNumSeaNeighbors = numSeaNeighbors;
                    }
                }
                if (unloadToTerritory != null) {
                    moveMap.get(unloadToTerritory).addTempUnits(maxAmphibUnitsToAdd);
                    moveMap.get(unloadToTerritory).putTempAmphibAttackMap(transport, maxAmphibUnitsToAdd);
                    moveMap.get(unloadToTerritory).getTransportTerritoryMap().put(transport, maxValueTerritory);
                    ProLogger.trace(transport + " moved to best sea at " + maxValueTerritory + " and unloading to " + unloadToTerritory + " with " + maxAmphibUnitsToAdd + ", value=" + maxValue);
                } else {
                    moveMap.get(maxValueTerritory).addTempUnits(maxAmphibUnitsToAdd);
                    moveMap.get(maxValueTerritory).putTempAmphibAttackMap(transport, maxAmphibUnitsToAdd);
                    moveMap.get(maxValueTerritory).getTransportTerritoryMap().put(transport, maxValueTerritory);
                    ProLogger.trace(transport + " moved to best sea at " + maxValueTerritory + " with " + maxAmphibUnitsToAdd + ", value=" + maxValue);
                }
                currentTransportMoveMap.remove(transport);
                for (final Unit unit : maxAmphibUnitsToAdd) {
                    currentUnitMoveMap.remove(unit);
                }
                territoriesToDefend.add(maxValueTerritory);
                it.remove();
            }
        }
        ProLogger.debug("Move empty transports to best loading territory");
        // TODO: consider which territory is 'safest'
        for (final Iterator<Unit> it = currentTransportMoveMap.keySet().iterator(); it.hasNext(); ) {
            final Unit transport = it.next();
            final Territory currentTerritory = unitTerritoryMap.get(transport);
            final int moves = TripleAUnit.get(transport).getMovementLeft();
            if (TransportTracker.isTransporting(transport) || moves <= 0) {
                continue;
            }
            final List<ProTerritory> priorizitedLoadTerritories = new ArrayList<>();
            for (final Territory t : moveMap.keySet()) {
                // Check if land with adjacent sea that can be reached and that I'm not already adjacent to
                final boolean territoryHasTransportableUnits = Matches.territoryHasUnitsThatMatch(ProMatches.unitIsOwnedTransportableUnitAndCanBeLoaded(player, transport, false)).test(t);
                final int distance = data.getMap().getDistance_IgnoreEndForCondition(currentTerritory, t, ProMatches.territoryCanMoveSeaUnits(player, data, true));
                final boolean hasSeaNeighbor = Matches.territoryHasNeighborMatching(data, Matches.territoryIsWater()).test(t);
                final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsOwnedLand(player).test(t);
                if (!t.isWater() && hasSeaNeighbor && distance > 0 && !(distance == 1 && territoryHasTransportableUnits && !hasFactory)) {
                    // TODO: add calculation of transports vs units
                    final double territoryValue = moveMap.get(t).getValue();
                    final int numUnitsToLoad = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsOwnedTransportableUnit(player)).size();
                    final boolean hasUnconqueredFactory = ProMatches.territoryHasInfraFactoryAndIsOwnedLand(player).test(t) && !AbstractMoveDelegate.getBattleTracker(data).wasConquered(t);
                    int factoryProduction = 0;
                    if (hasUnconqueredFactory) {
                        factoryProduction = TerritoryAttachment.getProduction(t);
                    }
                    int numTurnsAway = (distance - 1) / moves;
                    if (distance <= moves) {
                        numTurnsAway = 0;
                    }
                    final double value = territoryValue + 0.5 * numTurnsAway - 0.1 * numUnitsToLoad - 0.1 * factoryProduction;
                    moveMap.get(t).setLoadValue(value);
                    priorizitedLoadTerritories.add(moveMap.get(t));
                }
            }
            // Sort prioritized territories
            priorizitedLoadTerritories.sort(Comparator.comparingDouble(ProTerritory::getLoadValue));
            // Move towards best loading territory if route is safe
            for (final ProTerritory patd : priorizitedLoadTerritories) {
                boolean movedTransport = false;
                final Set<Territory> cantHoldTerritories = new HashSet<>();
                while (true) {
                    final Predicate<Territory> match = ProMatches.territoryCanMoveSeaUnitsThrough(player, data, false).and(Matches.territoryIsInList(cantHoldTerritories).negate());
                    final Route route = data.getMap().getRoute_IgnoreEnd(currentTerritory, patd.getTerritory(), match);
                    if (route == null || MoveValidator.validateCanal(route, Collections.singletonList(transport), player, data) != null) {
                        break;
                    }
                    final List<Territory> territories = route.getAllTerritories();
                    territories.remove(territories.size() - 1);
                    final Territory moveToTerritory = territories.get(Math.min(territories.size() - 1, moves));
                    final ProTerritory patd2 = moveMap.get(moveToTerritory);
                    if (patd2 != null && patd2.isCanHold()) {
                        ProLogger.trace(transport + " moved towards best loading territory " + patd.getTerritory() + " and moved to " + moveToTerritory);
                        patd2.addTempUnit(transport);
                        territoriesToDefend.add(moveToTerritory);
                        it.remove();
                        movedTransport = true;
                        break;
                    }
                    if (!cantHoldTerritories.add(moveToTerritory)) {
                        break;
                    }
                }
                if (movedTransport) {
                    break;
                }
            }
        }
        ProLogger.debug("Move remaining transports to safest territory");
        // Move remaining transports to safest territory
        for (final Iterator<Unit> it = currentTransportMoveMap.keySet().iterator(); it.hasNext(); ) {
            final Unit transport = it.next();
            // Get all units that have already moved
            final List<Unit> alreadyMovedUnits = new ArrayList<>();
            for (final ProTerritory t : moveMap.values()) {
                alreadyMovedUnits.addAll(t.getUnits());
            }
            // Find safest territory
            double minStrengthDifference = Double.POSITIVE_INFINITY;
            Territory minTerritory = null;
            for (final Territory t : currentTransportMoveMap.get(transport)) {
                final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
                final List<Unit> defenders = moveMap.get(t).getMaxDefenders();
                defenders.removeAll(alreadyMovedUnits);
                defenders.addAll(moveMap.get(t).getUnits());
                defenders.removeAll(ProTransportUtils.getAirThatCantLandOnCarrier(player, t, defenders));
                final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
                // TODO: add logic to move towards closest factory
                ProLogger.trace(transport + " at " + t + ", strengthDifference=" + strengthDifference + ", attackers=" + attackers + ", defenders=" + defenders);
                if (strengthDifference < minStrengthDifference) {
                    minStrengthDifference = strengthDifference;
                    minTerritory = t;
                }
            }
            if (minTerritory != null) {
                // TODO: consider which is 'safest'
                if (TransportTracker.isTransporting(transport)) {
                    final List<Unit> amphibUnits = (List<Unit>) TransportTracker.transporting(transport);
                    final Set<Territory> possibleUnloadTerritories = data.getMap().getNeighbors(minTerritory, ProMatches.territoryCanMoveLandUnitsAndIsAllied(player, data));
                    if (!possibleUnloadTerritories.isEmpty()) {
                        // Find best unload territory
                        Territory unloadToTerritory = possibleUnloadTerritories.iterator().next();
                        for (final Territory t : possibleUnloadTerritories) {
                            if (moveMap.get(t) != null && moveMap.get(t).isCanHold()) {
                                unloadToTerritory = t;
                            }
                        }
                        ProLogger.trace(transport + " moved to safest territory at " + minTerritory + " and unloading to " + unloadToTerritory + " with " + amphibUnits + ", strengthDifference=" + minStrengthDifference);
                        moveMap.get(unloadToTerritory).addTempUnits(amphibUnits);
                        moveMap.get(unloadToTerritory).putTempAmphibAttackMap(transport, amphibUnits);
                        moveMap.get(unloadToTerritory).getTransportTerritoryMap().put(transport, minTerritory);
                        for (final Unit unit : amphibUnits) {
                            currentUnitMoveMap.remove(unit);
                        }
                        it.remove();
                    } else {
                        // Move transport with units since no unload options
                        ProLogger.trace(transport + " moved to safest territory at " + minTerritory + " with " + amphibUnits + ", strengthDifference=" + minStrengthDifference);
                        moveMap.get(minTerritory).addTempUnits(amphibUnits);
                        moveMap.get(minTerritory).putTempAmphibAttackMap(transport, amphibUnits);
                        moveMap.get(minTerritory).getTransportTerritoryMap().put(transport, minTerritory);
                        for (final Unit unit : amphibUnits) {
                            currentUnitMoveMap.remove(unit);
                        }
                        it.remove();
                    }
                } else {
                    // If not transporting units
                    ProLogger.trace(transport + " moved to safest territory at " + minTerritory + ", strengthDifference=" + minStrengthDifference);
                    moveMap.get(minTerritory).addTempUnit(transport);
                    it.remove();
                }
            }
        }
        // Get all transport final territories
        ProMoveUtils.calculateAmphibRoutes(player, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), moveMap, false);
        for (final ProTerritory t : moveMap.values()) {
            for (final Map.Entry<Unit, Territory> entry : t.getTransportTerritoryMap().entrySet()) {
                final ProTerritory territory = moveMap.get(entry.getValue());
                if (territory != null) {
                    territory.addTempUnit(entry.getKey());
                }
            }
        }
        ProLogger.debug("Move sea units");
        // Move sea units to defend transports
        for (final Iterator<Unit> it = currentUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
            final Unit u = it.next();
            if (Matches.unitIsSea().test(u)) {
                for (final Territory t : currentUnitMoveMap.get(u)) {
                    if (moveMap.get(t).isCanHold() && !moveMap.get(t).getAllDefenders().isEmpty() && moveMap.get(t).getAllDefenders().stream().anyMatch(ProMatches.unitIsOwnedTransport(player))) {
                        final List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), Matches.unitIsNotLand());
                        if (moveMap.get(t).getBattleResult() == null) {
                            moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
                        }
                        final ProBattleResult result = moveMap.get(t).getBattleResult();
                        ProLogger.trace(t.getName() + " TUVSwing=" + result.getTuvSwing() + ", Win%=" + result.getWinPercentage() + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits().size() + ", defenders=" + defendingUnits.size());
                        if (result.getWinPercentage() > (100 - ProData.winPercentage) || result.getTuvSwing() > 0) {
                            ProLogger.trace(u + " added sea to defend transport at " + t);
                            moveMap.get(t).addTempUnit(u);
                            moveMap.get(t).setBattleResult(null);
                            territoriesToDefend.add(t);
                            it.remove();
                            // If carrier has dependent allied fighters then move them too
                            if (Matches.unitIsCarrier().test(u)) {
                                final Territory unitTerritory = unitTerritoryMap.get(u);
                                final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
                                if (carrierMustMoveWith.containsKey(u)) {
                                    moveMap.get(t).getTempUnits().addAll(carrierMustMoveWith.get(u));
                                }
                            }
                            break;
                        }
                    }
                }
            }
        }
        // Move air units to defend transports
        for (final Iterator<Unit> it = currentUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
            final Unit u = it.next();
            if (Matches.unitCanLandOnCarrier().test(u)) {
                for (final Territory t : currentUnitMoveMap.get(u)) {
                    if (t.isWater() && moveMap.get(t).isCanHold() && !moveMap.get(t).getAllDefenders().isEmpty() && moveMap.get(t).getAllDefenders().stream().anyMatch(ProMatches.unitIsOwnedTransport(player))) {
                        if (!ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), u)) {
                            continue;
                        }
                        final List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), Matches.unitIsNotLand());
                        if (moveMap.get(t).getBattleResult() == null) {
                            moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
                        }
                        final ProBattleResult result = moveMap.get(t).getBattleResult();
                        ProLogger.trace(t.getName() + " TUVSwing=" + result.getTuvSwing() + ", Win%=" + result.getWinPercentage() + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits().size() + ", defenders=" + defendingUnits.size());
                        if (result.getWinPercentage() > (100 - ProData.winPercentage) || result.getTuvSwing() > 0) {
                            ProLogger.trace(u + " added air to defend transport at " + t);
                            moveMap.get(t).addTempUnit(u);
                            moveMap.get(t).setBattleResult(null);
                            territoriesToDefend.add(t);
                            it.remove();
                            break;
                        }
                    }
                }
            }
        }
        // Move sea units to best location or safest location
        for (final Iterator<Unit> it = currentUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
            final Unit u = it.next();
            if (Matches.unitIsSea().test(u)) {
                Territory maxValueTerritory = null;
                double maxValue = 0;
                for (final Territory t : currentUnitMoveMap.get(u)) {
                    if (moveMap.get(t).isCanHold()) {
                        final int transports = CollectionUtils.countMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsOwnedTransport(player));
                        final double value = (1 + transports) * moveMap.get(t).getSeaValue() + (1 + transports * 100) * moveMap.get(t).getValue() / 10000;
                        ProLogger.trace(t + ", value=" + value + ", seaValue=" + moveMap.get(t).getSeaValue() + ", tValue=" + moveMap.get(t).getValue() + ", transports=" + transports);
                        if (value > maxValue) {
                            maxValue = value;
                            maxValueTerritory = t;
                        }
                    }
                }
                if (maxValueTerritory != null) {
                    ProLogger.trace(u + " added to best territory " + maxValueTerritory + ", value=" + maxValue);
                    moveMap.get(maxValueTerritory).addTempUnit(u);
                    moveMap.get(maxValueTerritory).setBattleResult(null);
                    territoriesToDefend.add(maxValueTerritory);
                    it.remove();
                    // If carrier has dependent allied fighters then move them too
                    if (Matches.unitIsCarrier().test(u)) {
                        final Territory unitTerritory = unitTerritoryMap.get(u);
                        final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
                        if (carrierMustMoveWith.containsKey(u)) {
                            moveMap.get(maxValueTerritory).getTempUnits().addAll(carrierMustMoveWith.get(u));
                        }
                    }
                } else {
                    // Get all units that have already moved
                    final List<Unit> alreadyMovedUnits = new ArrayList<>();
                    for (final ProTerritory t : moveMap.values()) {
                        alreadyMovedUnits.addAll(t.getUnits());
                    }
                    // Find safest territory
                    double minStrengthDifference = Double.POSITIVE_INFINITY;
                    Territory minTerritory = null;
                    for (final Territory t : currentUnitMoveMap.get(u)) {
                        final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
                        final List<Unit> defenders = moveMap.get(t).getMaxDefenders();
                        defenders.removeAll(alreadyMovedUnits);
                        defenders.addAll(moveMap.get(t).getUnits());
                        final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
                        if (strengthDifference < minStrengthDifference) {
                            minStrengthDifference = strengthDifference;
                            minTerritory = t;
                        }
                    }
                    if (minTerritory != null) {
                        ProLogger.trace(u + " moved to safest territory at " + minTerritory + ", strengthDifference=" + minStrengthDifference);
                        moveMap.get(minTerritory).addTempUnit(u);
                        moveMap.get(minTerritory).setBattleResult(null);
                        it.remove();
                        // If carrier has dependent allied fighters then move them too
                        if (Matches.unitIsCarrier().test(u)) {
                            final Territory unitTerritory = unitTerritoryMap.get(u);
                            final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
                            if (carrierMustMoveWith.containsKey(u)) {
                                moveMap.get(minTerritory).getTempUnits().addAll(carrierMustMoveWith.get(u));
                            }
                        }
                    } else {
                        final Territory currentTerritory = unitTerritoryMap.get(u);
                        ProLogger.trace(u + " added to current territory since no better options at " + currentTerritory);
                        moveMap.get(currentTerritory).addTempUnit(u);
                        moveMap.get(currentTerritory).setBattleResult(null);
                        it.remove();
                    }
                }
            }
        }
        // Determine if all defenses are successful
        ProLogger.debug("Checking if all sea moves are safe for " + territoriesToDefend);
        boolean areSuccessful = true;
        for (final Territory t : territoriesToDefend) {
            // Find result with temp units
            final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
            moveMap.get(t).setBattleResult(calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
            final ProBattleResult result = moveMap.get(t).getBattleResult();
            int isWater = 0;
            if (t.isWater()) {
                isWater = 1;
            }
            final double extraUnitValue = TuvUtils.getTuv(moveMap.get(t).getTempUnits(), ProData.unitValueMap);
            final double holdValue = result.getTuvSwing() - (extraUnitValue / 8 * (1 + isWater));
            // Find min result without temp units
            final List<Unit> minDefendingUnits = new ArrayList<>(defendingUnits);
            minDefendingUnits.removeAll(moveMap.get(t).getTempUnits());
            final ProBattleResult minResult = calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), minDefendingUnits, moveMap.get(t).getMaxEnemyBombardUnits());
            // Check if territory is worth defending with temp units
            if (holdValue > minResult.getTuvSwing()) {
                areSuccessful = false;
                moveMap.get(t).setCanHold(false);
                moveMap.get(t).setValue(0);
                moveMap.get(t).setSeaValue(0);
                ProLogger.trace(t + " unable to defend so removing with holdValue=" + holdValue + ", minTUVSwing=" + minResult.getTuvSwing() + ", defenders=" + defendingUnits + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits());
            }
            ProLogger.trace(moveMap.get(t).getResultString() + ", holdValue=" + holdValue + ", minTUVSwing=" + minResult.getTuvSwing());
        }
        // Determine whether to try more territories, remove a territory, or end
        if (areSuccessful) {
            break;
        }
    }
    // Add temp units to move lists
    for (final ProTerritory t : moveMap.values()) {
        // Handle allied units such as fighters on carriers
        final List<Unit> alliedUnits = CollectionUtils.getMatches(t.getTempUnits(), Matches.unitIsOwnedBy(player).negate());
        for (final Unit alliedUnit : alliedUnits) {
            t.addCantMoveUnit(alliedUnit);
            t.getTempUnits().remove(alliedUnit);
        }
        t.addUnits(t.getTempUnits());
        t.putAllAmphibAttackMap(t.getTempAmphibAttackMap());
        for (final Unit u : t.getTempUnits()) {
            if (Matches.unitIsTransport().test(u)) {
                transportMoveMap.remove(u);
                transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
            } else {
                unitMoveMap.remove(u);
            }
        }
        for (final Unit u : t.getTempAmphibAttackMap().keySet()) {
            transportMoveMap.remove(u);
            transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
        }
        t.getTempUnits().clear();
        t.getTempAmphibAttackMap().clear();
    }
    ProLogger.info("Move land units");
    // TODO: consider if territory ends up being safe
    for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
        final Unit u = it.next();
        if (Matches.unitIsLand().test(u)) {
            Territory maxValueTerritory = null;
            double maxValue = 0;
            int maxNeedAmphibUnitValue = Integer.MIN_VALUE;
            for (final Territory t : unitMoveMap.get(u)) {
                if (moveMap.get(t).isCanHold() && moveMap.get(t).getValue() >= maxValue) {
                    // Find transport capacity of neighboring (distance 1) transports
                    final List<Unit> transports1 = new ArrayList<>();
                    final Set<Territory> seaNeighbors = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, true));
                    for (final Territory neighborTerritory : seaNeighbors) {
                        if (moveMap.containsKey(neighborTerritory)) {
                            transports1.addAll(CollectionUtils.getMatches(moveMap.get(neighborTerritory).getAllDefenders(), ProMatches.unitIsOwnedTransport(player)));
                        }
                    }
                    int transportCapacity1 = 0;
                    for (final Unit transport : transports1) {
                        transportCapacity1 += UnitAttachment.get(transport.getType()).getTransportCapacity();
                    }
                    // Find transport capacity of nearby (distance 2) transports
                    final List<Unit> transports2 = new ArrayList<>();
                    final Set<Territory> nearbySeaTerritories = data.getMap().getNeighbors(t, 2, ProMatches.territoryCanMoveSeaUnits(player, data, true));
                    nearbySeaTerritories.removeAll(seaNeighbors);
                    for (final Territory neighborTerritory : nearbySeaTerritories) {
                        if (moveMap.containsKey(neighborTerritory)) {
                            transports2.addAll(CollectionUtils.getMatches(moveMap.get(neighborTerritory).getAllDefenders(), ProMatches.unitIsOwnedTransport(player)));
                        }
                    }
                    int transportCapacity2 = 0;
                    for (final Unit transport : transports2) {
                        transportCapacity2 += UnitAttachment.get(transport.getType()).getTransportCapacity();
                    }
                    final List<Unit> unitsToTransport = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsOwnedTransportableUnit(player));
                    // Find transport cost of potential amphib units
                    int transportCost = 0;
                    for (final Unit unit : unitsToTransport) {
                        transportCost += UnitAttachment.get(unit.getType()).getTransportCost();
                    }
                    // Find territory that needs amphib units that most
                    int hasFactory = 0;
                    if (ProMatches.territoryHasInfraFactoryAndIsOwnedLandAdjacentToSea(player, data).test(t)) {
                        hasFactory = 1;
                    }
                    final int neededNeighborTransportValue = Math.max(0, transportCapacity1 - transportCost);
                    final int neededNearbyTransportValue = Math.max(0, transportCapacity1 + transportCapacity2 - transportCost);
                    final int needAmphibUnitValue = 1000 * neededNeighborTransportValue + 100 * neededNearbyTransportValue + (1 + 10 * hasFactory) * data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, true)).size();
                    if (moveMap.get(t).getValue() > maxValue || needAmphibUnitValue > maxNeedAmphibUnitValue) {
                        maxValue = moveMap.get(t).getValue();
                        maxNeedAmphibUnitValue = needAmphibUnitValue;
                        maxValueTerritory = t;
                    }
                }
            }
            if (maxValueTerritory != null) {
                ProLogger.trace(u + " moved to " + maxValueTerritory + " with value=" + maxValue + ", numNeededTransportUnits=" + maxNeedAmphibUnitValue);
                moveMap.get(maxValueTerritory).addUnit(u);
                it.remove();
            }
        }
    }
    // Move land units towards nearest factory that is adjacent to the sea
    final Set<Territory> myFactoriesAdjacentToSea = new HashSet<>(CollectionUtils.getMatches(data.getMap().getTerritories(), ProMatches.territoryHasInfraFactoryAndIsOwnedLandAdjacentToSea(player, data)));
    for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
        final Unit u = it.next();
        if (Matches.unitIsLand().test(u)) {
            int minDistance = Integer.MAX_VALUE;
            Territory minTerritory = null;
            for (final Territory t : unitMoveMap.get(u)) {
                if (moveMap.get(t).isCanHold()) {
                    for (final Territory factory : myFactoriesAdjacentToSea) {
                        int distance = data.getMap().getDistance(t, factory, ProMatches.territoryCanMoveLandUnits(player, data, true));
                        if (distance < 0) {
                            distance = 10 * data.getMap().getDistance(t, factory);
                        }
                        if (distance >= 0 && distance < minDistance) {
                            minDistance = distance;
                            minTerritory = t;
                        }
                    }
                }
            }
            if (minTerritory != null) {
                ProLogger.trace(u.getType().getName() + " moved towards closest factory adjacent to sea at " + minTerritory.getName());
                moveMap.get(minTerritory).addUnit(u);
                it.remove();
            }
        }
    }
    ProLogger.info("Move land units to safest territory");
    // Move any remaining land units to safest territory (this is rarely used)
    for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
        final Unit u = it.next();
        if (Matches.unitIsLand().test(u)) {
            // Get all units that have already moved
            final List<Unit> alreadyMovedUnits = moveMap.values().stream().map(ProTerritory::getUnits).flatMap(Collection::stream).collect(Collectors.toList());
            // Find safest territory
            double minStrengthDifference = Double.POSITIVE_INFINITY;
            Territory minTerritory = null;
            for (final Territory t : unitMoveMap.get(u)) {
                final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
                final List<Unit> defenders = moveMap.get(t).getMaxDefenders();
                defenders.removeAll(alreadyMovedUnits);
                defenders.addAll(moveMap.get(t).getUnits());
                final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
                if (strengthDifference < minStrengthDifference) {
                    minStrengthDifference = strengthDifference;
                    minTerritory = t;
                }
            }
            if (minTerritory != null) {
                ProLogger.debug(u.getType().getName() + " moved to safest territory at " + minTerritory.getName() + " with strengthDifference=" + minStrengthDifference);
                moveMap.get(minTerritory).addUnit(u);
                it.remove();
            }
        }
    }
    ProLogger.info("Move air units");
    // Get list of territories that can't be held
    final List<Territory> territoriesThatCantBeHeld = moveMap.entrySet().stream().filter(e -> !e.getValue().isCanHold()).map(Map.Entry::getKey).collect(Collectors.toList());
    // Move air units to safe territory with most attack options
    for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
        final Unit u = it.next();
        if (Matches.unitIsNotAir().test(u)) {
            continue;
        }
        double maxAirValue = 0;
        Territory maxTerritory = null;
        for (final Territory t : unitMoveMap.get(u)) {
            if (!moveMap.get(t).isCanHold()) {
                continue;
            }
            if (t.isWater() && !ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), u)) {
                ProLogger.trace(t + " already at MAX carrier capacity");
                continue;
            }
            // Check to see if the territory is safe
            final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
            defendingUnits.add(u);
            if (moveMap.get(t).getBattleResult() == null) {
                moveMap.get(t).setBattleResult(calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
            }
            final ProBattleResult result = moveMap.get(t).getBattleResult();
            ProLogger.trace(t + ", TUVSwing=" + result.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", defendingUnits=" + defendingUnits + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits());
            if (result.getWinPercentage() >= ProData.minWinPercentage || result.getTuvSwing() > 0) {
                moveMap.get(t).setCanHold(false);
                continue;
            }
            // Determine if territory can be held with owned units
            final List<Unit> myDefenders = CollectionUtils.getMatches(defendingUnits, Matches.unitIsOwnedBy(player));
            final ProBattleResult result2 = calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), myDefenders, moveMap.get(t).getMaxEnemyBombardUnits());
            int cantHoldWithoutAllies = 0;
            if (result2.getWinPercentage() >= ProData.minWinPercentage || result2.getTuvSwing() > 0) {
                cantHoldWithoutAllies = 1;
            }
            // Find number of potential attack options next turn
            final int range = TripleAUnit.get(u).getMaxMovementAllowed();
            final Set<Territory> possibleAttackTerritories = data.getMap().getNeighbors(t, range / 2, ProMatches.territoryCanMoveAirUnits(player, data, true));
            final int numEnemyAttackTerritories = CollectionUtils.countMatches(possibleAttackTerritories, ProMatches.territoryIsEnemyNotNeutralLand(player, data));
            final int numLandAttackTerritories = CollectionUtils.countMatches(possibleAttackTerritories, ProMatches.territoryIsEnemyOrCantBeHeldAndIsAdjacentToMyLandUnits(player, data, territoriesThatCantBeHeld));
            final int numSeaAttackTerritories = CollectionUtils.countMatches(possibleAttackTerritories, Matches.territoryHasEnemySeaUnits(player, data).and(Matches.territoryHasUnitsThatMatch(Matches.unitIsNotSub())));
            final Set<Territory> possibleMoveTerritories = data.getMap().getNeighbors(t, range, ProMatches.territoryCanMoveAirUnits(player, data, true));
            final int numNearbyEnemyTerritories = CollectionUtils.countMatches(possibleMoveTerritories, ProMatches.territoryIsEnemyNotNeutralLand(player, data));
            // Check if number of attack territories and value are max
            final int isntFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t) ? 0 : 1;
            final int hasOwnedCarrier = moveMap.get(t).getAllDefenders().stream().anyMatch(ProMatches.unitIsOwnedCarrier(player)) ? 1 : 0;
            final double airValue = (200.0 * numSeaAttackTerritories + 100 * numLandAttackTerritories + 10 * numEnemyAttackTerritories + numNearbyEnemyTerritories) / (1 + cantHoldWithoutAllies) / (1 + cantHoldWithoutAllies * isntFactory) * (1 + hasOwnedCarrier);
            if (airValue > maxAirValue) {
                maxAirValue = airValue;
                maxTerritory = t;
            }
            ProLogger.trace("Safe territory: " + t + ", airValue=" + airValue + ", numLandAttackOptions=" + numLandAttackTerritories + ", numSeaAttackTerritories=" + numSeaAttackTerritories + ", numEnemyAttackTerritories=" + numEnemyAttackTerritories);
        }
        if (maxTerritory != null) {
            ProLogger.debug(u.getType().getName() + " added to safe territory with most attack options " + maxTerritory + ", maxAirValue=" + maxAirValue);
            moveMap.get(maxTerritory).addUnit(u);
            moveMap.get(maxTerritory).setBattleResult(null);
            it.remove();
        }
    }
    // Move air units to safest territory
    for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
        final Unit u = it.next();
        if (Matches.unitIsNotAir().test(u)) {
            continue;
        }
        double minStrengthDifference = Double.POSITIVE_INFINITY;
        Territory minTerritory = null;
        for (final Territory t : unitMoveMap.get(u)) {
            if (t.isWater() && !ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), u)) {
                ProLogger.trace(t + " already at MAX carrier capacity");
                continue;
            }
            final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
            final List<Unit> defenders = moveMap.get(t).getAllDefenders();
            defenders.add(u);
            final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
            ProLogger.trace("Unsafe territory: " + t + " with strengthDifference=" + strengthDifference);
            if (strengthDifference < minStrengthDifference) {
                minStrengthDifference = strengthDifference;
                minTerritory = t;
            }
        }
        if (minTerritory != null) {
            ProLogger.debug(u.getType().getName() + " added to safest territory at " + minTerritory + " with strengthDifference=" + minStrengthDifference);
            moveMap.get(minTerritory).addUnit(u);
            it.remove();
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) HashMap(java.util.HashMap) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) ArrayList(java.util.ArrayList) ProBattleResult(games.strategy.triplea.ai.pro.data.ProBattleResult) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) List(java.util.List) ArrayList(java.util.ArrayList) Route(games.strategy.engine.data.Route) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) Territory(games.strategy.engine.data.Territory) ProTransport(games.strategy.triplea.ai.pro.data.ProTransport) Collection(java.util.Collection) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 18 with ProBattleResult

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

the class ProNonCombatMoveAi method determineIfMoveTerritoriesCanBeHeld.

private void determineIfMoveTerritoriesCanBeHeld() {
    ProLogger.info("Find max enemy attackers and if territories can be held");
    final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    // Determine which territories can possibly be held
    for (final Territory t : moveMap.keySet()) {
        final ProTerritory patd = moveMap.get(t);
        // Check if no enemy attackers
        if (enemyAttackOptions.getMax(t) == null) {
            ProLogger.debug("Territory=" + t.getName() + ", CanHold=true since has no enemy attackers");
            continue;
        }
        // Check if min defenders can hold it (not considering AA)
        final Set<Unit> enemyAttackingUnits = new HashSet<>(enemyAttackOptions.getMax(t).getMaxUnits());
        enemyAttackingUnits.addAll(enemyAttackOptions.getMax(t).getMaxAmphibUnits());
        patd.setMaxEnemyUnits(new ArrayList<>(enemyAttackingUnits));
        patd.setMaxEnemyBombardUnits(enemyAttackOptions.getMax(t).getMaxBombardUnits());
        final List<Unit> minDefendingUnitsAndNotAa = CollectionUtils.getMatches(patd.getCantMoveUnits(), Matches.unitIsAaForAnything().negate());
        final ProBattleResult minResult = calc.calculateBattleResults(t, new ArrayList<>(enemyAttackingUnits), minDefendingUnitsAndNotAa, enemyAttackOptions.getMax(t).getMaxBombardUnits());
        patd.setMinBattleResult(minResult);
        if (minResult.getTuvSwing() <= 0 && !minDefendingUnitsAndNotAa.isEmpty()) {
            ProLogger.debug("Territory=" + t.getName() + ", CanHold=true" + ", MinDefenders=" + minDefendingUnitsAndNotAa.size() + ", EnemyAttackers=" + enemyAttackingUnits.size() + ", win%=" + minResult.getWinPercentage() + ", EnemyTUVSwing=" + minResult.getTuvSwing() + ", hasLandUnitRemaining=" + minResult.isHasLandUnitRemaining());
            continue;
        }
        // Check if max defenders can hold it (not considering AA)
        final Set<Unit> defendingUnits = new HashSet<>(patd.getMaxUnits());
        defendingUnits.addAll(patd.getMaxAmphibUnits());
        defendingUnits.addAll(patd.getCantMoveUnits());
        final List<Unit> defendingUnitsAndNotAa = CollectionUtils.getMatches(defendingUnits, Matches.unitIsAaForAnything().negate());
        final ProBattleResult result = calc.calculateBattleResults(t, new ArrayList<>(enemyAttackingUnits), defendingUnitsAndNotAa, enemyAttackOptions.getMax(t).getMaxBombardUnits());
        int isFactory = 0;
        if (ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
            isFactory = 1;
        }
        int isMyCapital = 0;
        if (t.equals(ProData.myCapital)) {
            isMyCapital = 1;
        }
        final List<Unit> extraUnits = new ArrayList<>(defendingUnitsAndNotAa);
        extraUnits.removeAll(minDefendingUnitsAndNotAa);
        final double extraUnitValue = TuvUtils.getTuv(extraUnits, ProData.unitValueMap);
        final double holdValue = extraUnitValue / 8 * (1 + 0.5 * isFactory) * (1 + 2 * isMyCapital);
        if (minDefendingUnitsAndNotAa.size() != defendingUnitsAndNotAa.size() && (result.getTuvSwing() - holdValue) < minResult.getTuvSwing()) {
            ProLogger.debug("Territory=" + t.getName() + ", CanHold=true" + ", MaxDefenders=" + defendingUnitsAndNotAa.size() + ", EnemyAttackers=" + enemyAttackingUnits.size() + ", minTUVSwing=" + minResult.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", EnemyTUVSwing=" + result.getTuvSwing() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", holdValue=" + holdValue);
            continue;
        }
        // Can't hold territory
        patd.setCanHold(false);
        ProLogger.debug("Can't hold Territory=" + t.getName() + ", MaxDefenders=" + defendingUnitsAndNotAa.size() + ", EnemyAttackers=" + enemyAttackingUnits.size() + ", minTUVSwing=" + minResult.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", EnemyTUVSwing=" + result.getTuvSwing() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", holdValue=" + holdValue);
    }
}
Also used : ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) Territory(games.strategy.engine.data.Territory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) ArrayList(java.util.ArrayList) ProBattleResult(games.strategy.triplea.ai.pro.data.ProBattleResult) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) ProOtherMoveOptions(games.strategy.triplea.ai.pro.data.ProOtherMoveOptions) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 19 with ProBattleResult

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

the class ProNonCombatMoveAi method moveInfraUnits.

private Map<Territory, ProTerritory> moveInfraUnits(Map<Territory, ProTerritory> factoryMoveMap, final Map<Unit, Set<Territory>> infraUnitMoveMap) {
    ProLogger.info("Determine where to move infra units");
    final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
    // Move factory units
    if (factoryMoveMap == null) {
        ProLogger.debug("Creating factory move map");
        // Determine and store where to move factories
        factoryMoveMap = new HashMap<>();
        for (final Iterator<Unit> it = infraUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
            final Unit u = it.next();
            // Only check factory units
            if (Matches.unitCanProduceUnits().test(u)) {
                Territory maxValueTerritory = null;
                double maxValue = 0;
                for (final Territory t : infraUnitMoveMap.get(u)) {
                    if (!moveMap.get(t).isCanHold()) {
                        continue;
                    }
                    // Check if territory is safe after all current moves
                    if (moveMap.get(t).getBattleResult() == null) {
                        final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
                        moveMap.get(t).setBattleResult(calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
                    }
                    final ProBattleResult result = moveMap.get(t).getBattleResult();
                    if (result.getWinPercentage() >= ProData.minWinPercentage || result.getTuvSwing() > 0) {
                        moveMap.get(t).setCanHold(false);
                        continue;
                    }
                    // Find value by checking if territory is not conquered and doesn't already have a factory
                    final List<Unit> units = new ArrayList<>(moveMap.get(t).getCantMoveUnits());
                    units.addAll(moveMap.get(t).getUnits());
                    final int production = TerritoryAttachment.get(t).getProduction();
                    double value = 0.1 * moveMap.get(t).getValue();
                    if (ProMatches.territoryIsNotConqueredOwnedLand(player, data).test(t) && units.stream().noneMatch(Matches.unitCanProduceUnitsAndIsInfrastructure())) {
                        value = moveMap.get(t).getValue() * production + 0.01 * production;
                    }
                    ProLogger.trace(t.getName() + " has value=" + value + ", strategicValue=" + moveMap.get(t).getValue() + ", production=" + production);
                    if (value > maxValue) {
                        maxValue = value;
                        maxValueTerritory = t;
                    }
                }
                if (maxValueTerritory != null) {
                    ProLogger.debug(u.getType().getName() + " moved to " + maxValueTerritory.getName() + " with value=" + maxValue);
                    moveMap.get(maxValueTerritory).addUnit(u);
                    if (factoryMoveMap.containsKey(maxValueTerritory)) {
                        factoryMoveMap.get(maxValueTerritory).addUnit(u);
                    } else {
                        final ProTerritory patd = new ProTerritory(maxValueTerritory);
                        patd.addUnit(u);
                        factoryMoveMap.put(maxValueTerritory, patd);
                    }
                    it.remove();
                }
            }
        }
    } else {
        ProLogger.debug("Using stored factory move map");
        // Transfer stored factory moves to move map
        for (final Territory t : factoryMoveMap.keySet()) {
            moveMap.get(t).addUnits(factoryMoveMap.get(t).getUnits());
        }
    }
    ProLogger.debug("Move infra AA units");
    // Move AA units
    for (final Iterator<Unit> it = infraUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
        final Unit u = it.next();
        final Territory currentTerritory = unitTerritoryMap.get(u);
        // Only check AA units whose territory can't be held and don't have factories
        if (Matches.unitIsAaForAnything().test(u) && !moveMap.get(currentTerritory).isCanHold() && !ProMatches.territoryHasInfraFactoryAndIsLand().test(currentTerritory)) {
            Territory maxValueTerritory = null;
            double maxValue = 0;
            for (final Territory t : infraUnitMoveMap.get(u)) {
                if (!moveMap.get(t).isCanHold()) {
                    continue;
                }
                // Consider max stack of 1 AA in classic
                final Route r = data.getMap().getRoute_IgnoreEnd(currentTerritory, t, ProMatches.territoryCanMoveLandUnitsThrough(player, data, u, currentTerritory, false, new ArrayList<>()));
                final MoveValidationResult mvr = MoveValidator.validateMove(Collections.singletonList(u), r, player, new ArrayList<>(), new HashMap<>(), true, null, data);
                if (!mvr.isMoveValid()) {
                    continue;
                }
                // Find value and try to move to territory that doesn't already have AA
                final List<Unit> units = new ArrayList<>(moveMap.get(t).getCantMoveUnits());
                units.addAll(moveMap.get(t).getUnits());
                final boolean hasAa = units.stream().anyMatch(Matches.unitIsAaForAnything());
                double value = moveMap.get(t).getValue();
                if (hasAa) {
                    value *= 0.01;
                }
                ProLogger.trace(t.getName() + " has value=" + value);
                if (value > maxValue) {
                    maxValue = value;
                    maxValueTerritory = t;
                }
            }
            if (maxValueTerritory != null) {
                ProLogger.debug(u.getType().getName() + " moved to " + maxValueTerritory.getName() + " with value=" + maxValue);
                moveMap.get(maxValueTerritory).addUnit(u);
                it.remove();
            }
        }
    }
    return factoryMoveMap;
}
Also used : ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) Territory(games.strategy.engine.data.Territory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) ArrayList(java.util.ArrayList) ProBattleResult(games.strategy.triplea.ai.pro.data.ProBattleResult) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) MoveValidationResult(games.strategy.triplea.delegate.dataObjects.MoveValidationResult) Route(games.strategy.engine.data.Route)

Example 20 with ProBattleResult

use of games.strategy.triplea.ai.pro.data.ProBattleResult 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)

Aggregations

ProBattleResult (games.strategy.triplea.ai.pro.data.ProBattleResult)24 ArrayList (java.util.ArrayList)21 Territory (games.strategy.engine.data.Territory)20 Unit (games.strategy.engine.data.Unit)20 TripleAUnit (games.strategy.triplea.TripleAUnit)15 HashSet (java.util.HashSet)15 ProOtherMoveOptions (games.strategy.triplea.ai.pro.data.ProOtherMoveOptions)12 ProTerritory (games.strategy.triplea.ai.pro.data.ProTerritory)12 ProPlaceTerritory (games.strategy.triplea.ai.pro.data.ProPlaceTerritory)10 ProPurchaseTerritory (games.strategy.triplea.ai.pro.data.ProPurchaseTerritory)10 HashMap (java.util.HashMap)7 List (java.util.List)6 GameData (games.strategy.engine.data.GameData)5 TerritoryAttachment (games.strategy.triplea.attachments.TerritoryAttachment)5 Collection (java.util.Collection)5 Set (java.util.Set)5 PlayerID (games.strategy.engine.data.PlayerID)4 BattleDelegate (games.strategy.triplea.delegate.BattleDelegate)4 IBattle (games.strategy.triplea.delegate.IBattle)4 TreeMap (java.util.TreeMap)4