Search in sources :

Example 6 with ProOtherMoveOptions

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

the class ProCombatMoveAi method tryToAttackTerritories.

private Map<Unit, Set<Territory>> tryToAttackTerritories(final List<ProTerritory> prioritizedTerritories, final List<Unit> alreadyMovedUnits) {
    final Map<Territory, ProTerritory> attackMap = territoryManager.getAttackOptions().getTerritoryMap();
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    final Map<Unit, Set<Territory>> unitAttackMap = territoryManager.getAttackOptions().getUnitMoveMap();
    final Map<Unit, Set<Territory>> transportAttackMap = territoryManager.getAttackOptions().getTransportMoveMap();
    final Map<Unit, Set<Territory>> bombardMap = territoryManager.getAttackOptions().getBombardMap();
    final List<ProTransport> transportMapList = territoryManager.getAttackOptions().getTransportList();
    // Reset lists
    for (final ProTerritory t : attackMap.values()) {
        t.getUnits().clear();
        t.getBombardTerritoryMap().clear();
        t.getAmphibAttackMap().clear();
        t.getTransportTerritoryMap().clear();
        t.setBattleResult(null);
    }
    // Loop through all units and determine attack options
    final Map<Unit, Set<Territory>> unitAttackOptions = new HashMap<>();
    for (final Unit unit : unitAttackMap.keySet()) {
        // Find number of attack options
        final Set<Territory> canAttackTerritories = new HashSet<>();
        for (final ProTerritory attackTerritoryData : prioritizedTerritories) {
            if (unitAttackMap.get(unit).contains(attackTerritoryData.getTerritory())) {
                canAttackTerritories.add(attackTerritoryData.getTerritory());
            }
        }
        // Add units with attack options to map
        if (canAttackTerritories.size() >= 1) {
            unitAttackOptions.put(unit, canAttackTerritories);
        }
    }
    // Sort units by number of attack options and cost
    Map<Unit, Set<Territory>> sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitMoveOptions(unitAttackOptions);
    // Try to set at least one destroyer in each sea territory with subs
    for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
        final Unit unit = it.next();
        final boolean isDestroyerUnit = UnitAttachment.get(unit.getType()).getIsDestroyer();
        if (!isDestroyerUnit) {
            // skip non-destroyer units
            continue;
        }
        for (final Territory t : sortedUnitAttackOptions.get(unit)) {
            // Add destroyer if territory has subs and a destroyer has been already added
            final List<Unit> defendingUnits = attackMap.get(t).getMaxEnemyDefenders(player, data);
            if (defendingUnits.stream().anyMatch(Matches.unitIsSub()) && attackMap.get(t).getUnits().stream().noneMatch(Matches.unitIsDestroyer())) {
                attackMap.get(t).addUnit(unit);
                it.remove();
                break;
            }
        }
    }
    // Set enough land and sea units in territories to have at least a chance of winning
    for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
        final Unit unit = it.next();
        final boolean isAirUnit = UnitAttachment.get(unit.getType()).getIsAir();
        if (isAirUnit) {
            // skip air units
            continue;
        }
        final TreeMap<Double, Territory> estimatesMap = new TreeMap<>();
        for (final Territory t : sortedUnitAttackOptions.get(unit)) {
            if (t.isWater() && !attackMap.get(t).isCanHold()) {
                // ignore sea territories that can't be held
                continue;
            }
            final List<Unit> defendingUnits = attackMap.get(t).getMaxEnemyDefenders(player, data);
            double estimate = ProBattleUtils.estimateStrengthDifference(t, attackMap.get(t).getUnits(), defendingUnits);
            final boolean hasAa = defendingUnits.stream().anyMatch(Matches.unitIsAaForAnything());
            if (hasAa) {
                estimate -= 10;
            }
            estimatesMap.put(estimate, t);
        }
        if (!estimatesMap.isEmpty() && estimatesMap.firstKey() < 40) {
            final Territory minWinTerritory = estimatesMap.entrySet().iterator().next().getValue();
            attackMap.get(minWinTerritory).addUnit(unit);
            it.remove();
        }
    }
    // Re-sort attack options
    sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitNeededOptionsThenAttack(player, sortedUnitAttackOptions, attackMap, ProData.unitTerritoryMap, calc);
    // Set non-air units in territories that can be held
    for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
        final Unit unit = it.next();
        final boolean isAirUnit = UnitAttachment.get(unit.getType()).getIsAir();
        if (isAirUnit) {
            // skip air units
            continue;
        }
        Territory minWinTerritory = null;
        double minWinPercentage = ProData.winPercentage;
        for (final Territory t : sortedUnitAttackOptions.get(unit)) {
            final ProTerritory patd = attackMap.get(t);
            if (!attackMap.get(t).isCurrentlyWins() && attackMap.get(t).isCanHold()) {
                if (attackMap.get(t).getBattleResult() == null) {
                    attackMap.get(t).setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                }
                final ProBattleResult result = attackMap.get(t).getBattleResult();
                if (result.getWinPercentage() < minWinPercentage || (!result.isHasLandUnitRemaining() && minWinTerritory == null)) {
                    minWinPercentage = result.getWinPercentage();
                    minWinTerritory = t;
                }
            }
        }
        if (minWinTerritory != null) {
            attackMap.get(minWinTerritory).addUnit(unit);
            attackMap.get(minWinTerritory).setBattleResult(null);
            it.remove();
        }
    }
    // Re-sort attack options
    sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitNeededOptionsThenAttack(player, sortedUnitAttackOptions, attackMap, ProData.unitTerritoryMap, calc);
    // Set air units in territories that can't be held (don't move planes to empty territories)
    for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
        final Unit unit = it.next();
        final boolean isAirUnit = UnitAttachment.get(unit.getType()).getIsAir();
        if (!isAirUnit) {
            // skip non-air units
            continue;
        }
        Territory minWinTerritory = null;
        double minWinPercentage = ProData.winPercentage;
        for (final Territory t : sortedUnitAttackOptions.get(unit)) {
            final ProTerritory patd = attackMap.get(t);
            if (!patd.isCurrentlyWins() && !patd.isCanHold()) {
                // Check if air unit should avoid this territory due to no guaranteed safe landing location
                final boolean isEnemyCapital = ProUtils.getLiveEnemyCapitals(data, player).contains(t);
                final boolean isAdjacentToAlliedCapital = Matches.territoryHasNeighborMatching(data, Matches.territoryIsInList(ProUtils.getLiveAlliedCapitals(data, player))).test(t);
                final int range = TripleAUnit.get(unit).getMovementLeft();
                final int distance = data.getMap().getDistance_IgnoreEndForCondition(ProData.unitTerritoryMap.get(unit), t, ProMatches.territoryCanMoveAirUnitsAndNoAa(player, data, true));
                final boolean usesMoreThanHalfOfRange = distance > range / 2;
                if (isAirUnit && !isEnemyCapital && !isAdjacentToAlliedCapital && usesMoreThanHalfOfRange) {
                    continue;
                }
                // Check battle results
                if (patd.getBattleResult() == null) {
                    patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                }
                final ProBattleResult result = patd.getBattleResult();
                if (result.getWinPercentage() < minWinPercentage || (!result.isHasLandUnitRemaining() && minWinTerritory == null)) {
                    final List<Unit> defendingUnits = patd.getMaxEnemyDefenders(player, data);
                    final boolean hasNoDefenders = defendingUnits.stream().noneMatch(ProMatches.unitIsEnemyAndNotInfa(player, data));
                    final boolean isOverwhelmingWin = ProBattleUtils.checkForOverwhelmingWin(t, patd.getUnits(), defendingUnits);
                    final boolean hasAa = defendingUnits.stream().anyMatch(Matches.unitIsAaForAnything());
                    if (!hasNoDefenders && !isOverwhelmingWin && (!hasAa || result.getWinPercentage() < minWinPercentage)) {
                        minWinPercentage = result.getWinPercentage();
                        minWinTerritory = t;
                        if (patd.isStrafing()) {
                            break;
                        }
                    }
                }
            }
        }
        if (minWinTerritory != null) {
            attackMap.get(minWinTerritory).addUnit(unit);
            attackMap.get(minWinTerritory).setBattleResult(null);
            it.remove();
        }
    }
    // Re-sort attack options
    sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitNeededOptionsThenAttack(player, sortedUnitAttackOptions, attackMap, ProData.unitTerritoryMap, calc);
    // Set remaining units in any territory that needs it (don't move planes to empty territories)
    for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
        final Unit unit = it.next();
        final boolean isAirUnit = UnitAttachment.get(unit.getType()).getIsAir();
        Territory minWinTerritory = null;
        double minWinPercentage = ProData.winPercentage;
        for (final Territory t : sortedUnitAttackOptions.get(unit)) {
            final ProTerritory patd = attackMap.get(t);
            if (!patd.isCurrentlyWins()) {
                // Check if air unit should avoid this territory due to no guaranteed safe landing location
                final boolean isAdjacentToAlliedFactory = Matches.territoryHasNeighborMatching(data, ProMatches.territoryHasInfraFactoryAndIsAlliedLand(player, data)).test(t);
                final int range = TripleAUnit.get(unit).getMovementLeft();
                final int distance = data.getMap().getDistance_IgnoreEndForCondition(ProData.unitTerritoryMap.get(unit), t, ProMatches.territoryCanMoveAirUnitsAndNoAa(player, data, true));
                final boolean usesMoreThanHalfOfRange = distance > range / 2;
                final boolean territoryValueIsLessThanUnitValue = patd.getValue() < ProData.unitValueMap.getInt(unit.getType());
                if (isAirUnit && !isAdjacentToAlliedFactory && usesMoreThanHalfOfRange && (territoryValueIsLessThanUnitValue || (!t.isWater() && !patd.isCanHold()))) {
                    continue;
                }
                if (patd.getBattleResult() == null) {
                    patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                }
                final ProBattleResult result = patd.getBattleResult();
                if (result.getWinPercentage() < minWinPercentage || (!result.isHasLandUnitRemaining() && minWinTerritory == null)) {
                    final List<Unit> defendingUnits = patd.getMaxEnemyDefenders(player, data);
                    final boolean hasNoDefenders = defendingUnits.stream().noneMatch(ProMatches.unitIsEnemyAndNotInfa(player, data));
                    final boolean isOverwhelmingWin = ProBattleUtils.checkForOverwhelmingWin(t, patd.getUnits(), defendingUnits);
                    final boolean hasAa = defendingUnits.stream().anyMatch(Matches.unitIsAaForAnything());
                    if (!isAirUnit || (!hasNoDefenders && !isOverwhelmingWin && (!hasAa || result.getWinPercentage() < minWinPercentage))) {
                        minWinPercentage = result.getWinPercentage();
                        minWinTerritory = t;
                    }
                }
            }
        }
        if (minWinTerritory != null) {
            attackMap.get(minWinTerritory).addUnit(unit);
            attackMap.get(minWinTerritory).setBattleResult(null);
            it.remove();
        }
    }
    // Re-sort attack options
    sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitNeededOptions(player, sortedUnitAttackOptions, attackMap, calc);
    // If transports can take casualties try placing in naval battles first
    final List<Unit> alreadyAttackedWithTransports = new ArrayList<>();
    if (!Properties.getTransportCasualtiesRestricted(data)) {
        // Loop through all my transports and see which territories they can attack from current list
        final Map<Unit, Set<Territory>> transportAttackOptions = new HashMap<>();
        for (final Unit unit : transportAttackMap.keySet()) {
            // Find number of attack options
            final Set<Territory> canAttackTerritories = new HashSet<>();
            for (final ProTerritory attackTerritoryData : prioritizedTerritories) {
                if (transportAttackMap.get(unit).contains(attackTerritoryData.getTerritory())) {
                    canAttackTerritories.add(attackTerritoryData.getTerritory());
                }
            }
            if (!canAttackTerritories.isEmpty()) {
                transportAttackOptions.put(unit, canAttackTerritories);
            }
        }
        // Loop through transports with attack options and determine if any naval battle needs it
        for (final Unit transport : transportAttackOptions.keySet()) {
            // Find current naval battle that needs transport if it isn't transporting units
            for (final Territory t : transportAttackOptions.get(transport)) {
                final ProTerritory patd = attackMap.get(t);
                final List<Unit> defendingUnits = patd.getMaxEnemyDefenders(player, data);
                if (!patd.isCurrentlyWins() && !TransportTracker.isTransporting(transport) && !defendingUnits.isEmpty()) {
                    if (patd.getBattleResult() == null) {
                        patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                    }
                    final ProBattleResult result = patd.getBattleResult();
                    if (result.getWinPercentage() < ProData.winPercentage || !result.isHasLandUnitRemaining()) {
                        patd.addUnit(transport);
                        patd.setBattleResult(null);
                        alreadyAttackedWithTransports.add(transport);
                        ProLogger.trace("Adding attack transport to: " + t.getName());
                        break;
                    }
                }
            }
        }
    }
    // Loop through all my transports and see which can make amphib attack
    final Map<Unit, Set<Territory>> amphibAttackOptions = new HashMap<>();
    for (final ProTransport proTransportData : transportMapList) {
        // If already used to attack then ignore
        if (alreadyAttackedWithTransports.contains(proTransportData.getTransport())) {
            continue;
        }
        // Find number of attack options
        final Set<Territory> canAmphibAttackTerritories = new HashSet<>();
        for (final ProTerritory attackTerritoryData : prioritizedTerritories) {
            if (proTransportData.getTransportMap().containsKey(attackTerritoryData.getTerritory())) {
                canAmphibAttackTerritories.add(attackTerritoryData.getTerritory());
            }
        }
        if (!canAmphibAttackTerritories.isEmpty()) {
            amphibAttackOptions.put(proTransportData.getTransport(), canAmphibAttackTerritories);
        }
    }
    // Loop through transports with amphib attack options and determine if any land battle needs it
    for (final Unit transport : amphibAttackOptions.keySet()) {
        // Find current land battle results for territories that unit can amphib attack
        Territory minWinTerritory = null;
        double minWinPercentage = ProData.winPercentage;
        List<Unit> minAmphibUnitsToAdd = null;
        Territory minUnloadFromTerritory = null;
        for (final Territory t : amphibAttackOptions.get(transport)) {
            final ProTerritory patd = attackMap.get(t);
            if (!patd.isCurrentlyWins()) {
                if (patd.getBattleResult() == null) {
                    patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                }
                final ProBattleResult result = patd.getBattleResult();
                if (result.getWinPercentage() < minWinPercentage || (!result.isHasLandUnitRemaining() && minWinTerritory == null)) {
                    // Get all units that have already attacked
                    final List<Unit> alreadyAttackedWithUnits = new ArrayList<>(alreadyMovedUnits);
                    alreadyAttackedWithUnits.addAll(attackMap.values().stream().map(ProTerritory::getUnits).flatMap(Collection::stream).collect(Collectors.toList()));
                    // Find units that haven't attacked and can be transported
                    for (final ProTransport proTransportData : transportMapList) {
                        if (proTransportData.getTransport().equals(transport)) {
                            // Find units to load
                            final Set<Territory> territoriesCanLoadFrom = proTransportData.getTransportMap().get(t);
                            final List<Unit> amphibUnitsToAdd = ProTransportUtils.getUnitsToTransportFromTerritories(player, transport, territoriesCanLoadFrom, alreadyAttackedWithUnits);
                            if (amphibUnitsToAdd.isEmpty()) {
                                continue;
                            }
                            // Find best territory to move transport
                            double minStrengthDifference = Double.POSITIVE_INFINITY;
                            minUnloadFromTerritory = 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(ProData.unitTerritoryMap.get(u));
                            }
                            for (final Territory territoryToMoveTransport : territoriesToMoveTransport) {
                                if (proTransportData.getSeaTransportMap().containsKey(territoryToMoveTransport) && proTransportData.getSeaTransportMap().get(territoryToMoveTransport).containsAll(loadFromTerritories)) {
                                    List<Unit> attackers = new ArrayList<>();
                                    if (enemyAttackOptions.getMax(territoryToMoveTransport) != null) {
                                        attackers = enemyAttackOptions.getMax(territoryToMoveTransport).getMaxUnits();
                                    }
                                    final List<Unit> defenders = territoryToMoveTransport.getUnits().getMatches(Matches.isUnitAllied(player, data));
                                    defenders.add(transport);
                                    final double strengthDifference = ProBattleUtils.estimateStrengthDifference(territoryToMoveTransport, attackers, defenders);
                                    if (strengthDifference < minStrengthDifference) {
                                        minStrengthDifference = strengthDifference;
                                        minUnloadFromTerritory = territoryToMoveTransport;
                                    }
                                }
                            }
                            minWinTerritory = t;
                            minWinPercentage = result.getWinPercentage();
                            minAmphibUnitsToAdd = amphibUnitsToAdd;
                            break;
                        }
                    }
                }
            }
        }
        if (minWinTerritory != null) {
            if (minUnloadFromTerritory != null) {
                attackMap.get(minWinTerritory).getTransportTerritoryMap().put(transport, minUnloadFromTerritory);
            }
            attackMap.get(minWinTerritory).addUnits(minAmphibUnitsToAdd);
            attackMap.get(minWinTerritory).putAmphibAttackMap(transport, minAmphibUnitsToAdd);
            attackMap.get(minWinTerritory).setBattleResult(null);
            for (final Unit unit : minAmphibUnitsToAdd) {
                sortedUnitAttackOptions.remove(unit);
            }
            ProLogger.trace("Adding amphibious attack to " + minWinTerritory + ", units=" + minAmphibUnitsToAdd.size() + ", unloadFrom=" + minUnloadFromTerritory);
        }
    }
    // Get all units that have already moved
    final Set<Unit> alreadyAttackedWithUnits = new HashSet<>();
    for (final ProTerritory t : attackMap.values()) {
        alreadyAttackedWithUnits.addAll(t.getUnits());
        alreadyAttackedWithUnits.addAll(t.getAmphibAttackMap().keySet());
    }
    // Loop through all my bombard units and see which can bombard
    final Map<Unit, Set<Territory>> bombardOptions = new HashMap<>();
    for (final Unit u : bombardMap.keySet()) {
        // If already used to attack then ignore
        if (alreadyAttackedWithUnits.contains(u)) {
            continue;
        }
        // Find number of bombard options
        final Set<Territory> canBombardTerritories = new HashSet<>();
        for (final ProTerritory patd : prioritizedTerritories) {
            final List<Unit> defendingUnits = patd.getMaxEnemyDefenders(player, data);
            final boolean hasDefenders = defendingUnits.stream().anyMatch(Matches.unitIsInfrastructure().negate());
            if (bombardMap.get(u).contains(patd.getTerritory()) && !patd.getTransportTerritoryMap().isEmpty() && hasDefenders && !TransportTracker.isTransporting(u)) {
                canBombardTerritories.add(patd.getTerritory());
            }
        }
        if (!canBombardTerritories.isEmpty()) {
            bombardOptions.put(u, canBombardTerritories);
        }
    }
    // Loop through bombard units to see if any amphib battles need
    for (final Unit u : bombardOptions.keySet()) {
        // Find current land battle results for territories that unit can bombard
        Territory minWinTerritory = null;
        double minWinPercentage = Double.MAX_VALUE;
        Territory minBombardFromTerritory = null;
        for (final Territory t : bombardOptions.get(u)) {
            final ProTerritory patd = attackMap.get(t);
            if (patd.getBattleResult() == null) {
                patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
            }
            final ProBattleResult result = patd.getBattleResult();
            if (result.getWinPercentage() < minWinPercentage || (!result.isHasLandUnitRemaining() && minWinTerritory == null)) {
                // Find territory to bombard from
                Territory bombardFromTerritory = null;
                for (final Territory unloadFromTerritory : patd.getTransportTerritoryMap().values()) {
                    if (patd.getBombardOptionsMap().get(u).contains(unloadFromTerritory)) {
                        bombardFromTerritory = unloadFromTerritory;
                    }
                }
                if (bombardFromTerritory != null) {
                    minWinTerritory = t;
                    minWinPercentage = result.getWinPercentage();
                    minBombardFromTerritory = bombardFromTerritory;
                }
            }
        }
        if (minWinTerritory != null) {
            attackMap.get(minWinTerritory).getBombardTerritoryMap().put(u, minBombardFromTerritory);
            attackMap.get(minWinTerritory).setBattleResult(null);
            sortedUnitAttackOptions.remove(u);
            ProLogger.trace("Adding bombard to " + minWinTerritory + ", units=" + u + ", bombardFrom=" + minBombardFromTerritory);
        }
    }
    return sortedUnitAttackOptions;
}
Also used : Territory(games.strategy.engine.data.Territory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) HashSet(java.util.HashSet) Set(java.util.Set) 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) TreeMap(java.util.TreeMap) ProTransport(games.strategy.triplea.ai.pro.data.ProTransport) Collection(java.util.Collection) ProOtherMoveOptions(games.strategy.triplea.ai.pro.data.ProOtherMoveOptions) HashSet(java.util.HashSet)

Example 7 with ProOtherMoveOptions

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

the class ProCombatMoveAi method determineUnitsToAttackWith.

private void determineUnitsToAttackWith(final List<ProTerritory> prioritizedTerritories, final List<Unit> alreadyMovedUnits) {
    ProLogger.info("Determine units to attack each territory with");
    final Map<Territory, ProTerritory> attackMap = territoryManager.getAttackOptions().getTerritoryMap();
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    final Map<Unit, Set<Territory>> unitAttackMap = territoryManager.getAttackOptions().getUnitMoveMap();
    // Assign units to territories by prioritization
    while (true) {
        Map<Unit, Set<Territory>> sortedUnitAttackOptions = tryToAttackTerritories(prioritizedTerritories, alreadyMovedUnits);
        // Clear bombers
        for (final ProTerritory t : attackMap.values()) {
            t.getBombers().clear();
        }
        // Get all units that have already moved
        final Set<Unit> alreadyAttackedWithUnits = new HashSet<>();
        for (final ProTerritory t : attackMap.values()) {
            alreadyAttackedWithUnits.addAll(t.getUnits());
            alreadyAttackedWithUnits.addAll(t.getAmphibAttackMap().keySet());
        }
        // Check to see if any territories can be bombed
        final Map<Unit, Set<Territory>> bomberMoveMap = territoryManager.getAttackOptions().getBomberMoveMap();
        for (final Unit unit : bomberMoveMap.keySet()) {
            if (alreadyAttackedWithUnits.contains(unit)) {
                continue;
            }
            Optional<Territory> maxBombingTerritory = Optional.empty();
            int maxBombingScore = MIN_BOMBING_SCORE;
            for (final Territory t : bomberMoveMap.get(unit)) {
                final boolean territoryCanBeBombed = t.getUnits().anyMatch(Matches.unitCanProduceUnitsAndCanBeDamaged());
                if (territoryCanBeBombed && canAirSafelyLandAfterAttack(unit, t)) {
                    final int noAaBombingDefense = t.getUnits().anyMatch(Matches.unitIsAaForBombingThisUnitOnly()) ? 0 : 1;
                    int maxDamage = 0;
                    final TerritoryAttachment ta = TerritoryAttachment.get(t);
                    if (ta != null) {
                        maxDamage = ta.getProduction();
                    }
                    final int numExistingBombers = attackMap.get(t).getBombers().size();
                    final int remainingDamagePotential = maxDamage - 3 * numExistingBombers;
                    final int bombingScore = (1 + 9 * noAaBombingDefense) * remainingDamagePotential;
                    if (bombingScore >= maxBombingScore) {
                        maxBombingScore = bombingScore;
                        maxBombingTerritory = Optional.of(t);
                    }
                }
            }
            if (maxBombingTerritory.isPresent()) {
                final Territory t = maxBombingTerritory.get();
                attackMap.get(t).getBombers().add(unit);
                sortedUnitAttackOptions.remove(unit);
                ProLogger.debug("Add bomber (" + unit + ") to " + t);
            }
        }
        // Re-sort attack options
        sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitNeededOptionsThenAttack(player, sortedUnitAttackOptions, attackMap, ProData.unitTerritoryMap, calc);
        // Set air units in any territory with no AA (don't move planes to empty territories)
        for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
            final Unit unit = it.next();
            final boolean isAirUnit = UnitAttachment.get(unit.getType()).getIsAir();
            if (!isAirUnit) {
                // skip non-air units
                continue;
            }
            Territory minWinTerritory = null;
            double minWinPercentage = Double.MAX_VALUE;
            for (final Territory t : sortedUnitAttackOptions.get(unit)) {
                final ProTerritory patd = attackMap.get(t);
                // Check if air unit should avoid this territory due to no guaranteed safe landing location
                final boolean isEnemyFactory = ProMatches.territoryHasInfraFactoryAndIsEnemyLand(player, data).test(t);
                if (!isEnemyFactory && !canAirSafelyLandAfterAttack(unit, t)) {
                    continue;
                }
                if (patd.getBattleResult() == null) {
                    patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                }
                final ProBattleResult result = patd.getBattleResult();
                if (result.getWinPercentage() < minWinPercentage || (!result.isHasLandUnitRemaining() && minWinTerritory == null)) {
                    final List<Unit> attackingUnits = patd.getUnits();
                    final List<Unit> defendingUnits = patd.getMaxEnemyDefenders(player, data);
                    final boolean isOverwhelmingWin = ProBattleUtils.checkForOverwhelmingWin(t, attackingUnits, defendingUnits);
                    final boolean hasAa = defendingUnits.stream().anyMatch(Matches.unitIsAaForAnything());
                    if (!hasAa && !isOverwhelmingWin) {
                        minWinPercentage = result.getWinPercentage();
                        minWinTerritory = t;
                    }
                }
            }
            if (minWinTerritory != null) {
                attackMap.get(minWinTerritory).addUnit(unit);
                attackMap.get(minWinTerritory).setBattleResult(null);
                it.remove();
            }
        }
        // Re-sort attack options
        sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitNeededOptionsThenAttack(player, sortedUnitAttackOptions, attackMap, ProData.unitTerritoryMap, calc);
        // Find territory that we can try to hold that needs unit
        for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
            final Unit unit = it.next();
            Territory minWinTerritory = null;
            for (final Territory t : sortedUnitAttackOptions.get(unit)) {
                final ProTerritory patd = attackMap.get(t);
                if (patd.isCanHold()) {
                    // Check if I already have enough attack units to win in 2 rounds
                    if (patd.getBattleResult() == null) {
                        patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                    }
                    final ProBattleResult result = patd.getBattleResult();
                    final List<Unit> attackingUnits = patd.getUnits();
                    final List<Unit> defendingUnits = patd.getMaxEnemyDefenders(player, data);
                    final boolean isOverwhelmingWin = ProBattleUtils.checkForOverwhelmingWin(t, attackingUnits, defendingUnits);
                    if (!isOverwhelmingWin && result.getBattleRounds() > 2) {
                        minWinTerritory = t;
                        break;
                    }
                }
            }
            if (minWinTerritory != null) {
                attackMap.get(minWinTerritory).addUnit(unit);
                attackMap.get(minWinTerritory).setBattleResult(null);
                it.remove();
            }
        }
        // Re-sort attack options
        sortedUnitAttackOptions = ProSortMoveOptionsUtils.sortUnitNeededOptionsThenAttack(player, sortedUnitAttackOptions, attackMap, ProData.unitTerritoryMap, calc);
        // Add sea units to any territory that significantly increases TUV gain
        for (final Iterator<Unit> it = sortedUnitAttackOptions.keySet().iterator(); it.hasNext(); ) {
            final Unit unit = it.next();
            final boolean isSeaUnit = UnitAttachment.get(unit.getType()).getIsSea();
            if (!isSeaUnit) {
                // skip non-sea units
                continue;
            }
            for (final Territory t : sortedUnitAttackOptions.get(unit)) {
                final ProTerritory patd = attackMap.get(t);
                if (attackMap.get(t).getBattleResult() == null) {
                    attackMap.get(t).setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
                }
                final ProBattleResult result = attackMap.get(t).getBattleResult();
                final List<Unit> attackers = new ArrayList<>(patd.getUnits());
                attackers.add(unit);
                final ProBattleResult result2 = calc.estimateAttackBattleResults(t, attackers, patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet());
                final double unitValue = ProData.unitValueMap.getInt(unit.getType());
                if ((result2.getTuvSwing() - unitValue / 3) > result.getTuvSwing()) {
                    attackMap.get(t).addUnit(unit);
                    attackMap.get(t).setBattleResult(null);
                    it.remove();
                    break;
                }
            }
        }
        // Determine if all attacks are worth it
        final List<Unit> usedUnits = new ArrayList<>();
        for (final ProTerritory patd : prioritizedTerritories) {
            usedUnits.addAll(patd.getUnits());
        }
        ProTerritory territoryToRemove = null;
        for (final ProTerritory patd : prioritizedTerritories) {
            final Territory t = patd.getTerritory();
            // Find battle result
            if (patd.getBattleResult() == null) {
                patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
            }
            final ProBattleResult result = patd.getBattleResult();
            // Determine enemy counter attack results
            boolean canHold = true;
            double enemyCounterTuvSwing = 0;
            if (enemyAttackOptions.getMax(t) != null && !ProMatches.territoryIsWaterAndAdjacentToOwnedFactory(player, data).test(t)) {
                List<Unit> remainingUnitsToDefendWith = CollectionUtils.getMatches(result.getAverageAttackersRemaining(), Matches.unitIsAir().negate());
                ProBattleResult result2 = calc.calculateBattleResults(t, patd.getMaxEnemyUnits(), remainingUnitsToDefendWith, patd.getMaxBombardUnits());
                if (patd.isCanHold() && result2.getTuvSwing() > 0) {
                    final List<Unit> unusedUnits = new ArrayList<>(patd.getMaxUnits());
                    unusedUnits.addAll(patd.getMaxAmphibUnits());
                    unusedUnits.removeAll(usedUnits);
                    unusedUnits.addAll(remainingUnitsToDefendWith);
                    final ProBattleResult result3 = calc.calculateBattleResults(t, patd.getMaxEnemyUnits(), unusedUnits, patd.getMaxBombardUnits());
                    if (result3.getTuvSwing() < result2.getTuvSwing()) {
                        result2 = result3;
                        remainingUnitsToDefendWith = unusedUnits;
                    }
                }
                canHold = (!result2.isHasLandUnitRemaining() && !t.isWater()) || (result2.getTuvSwing() < 0) || (result2.getWinPercentage() < ProData.minWinPercentage);
                if (result2.getTuvSwing() > 0) {
                    enemyCounterTuvSwing = result2.getTuvSwing();
                }
                ProLogger.trace("Territory=" + t.getName() + ", CanHold=" + canHold + ", MyDefenders=" + remainingUnitsToDefendWith.size() + ", EnemyAttackers=" + patd.getMaxEnemyUnits().size() + ", win%=" + result2.getWinPercentage() + ", EnemyTUVSwing=" + result2.getTuvSwing() + ", hasLandUnitRemaining=" + result2.isHasLandUnitRemaining());
            }
            // Find attack value
            final boolean isNeutral = (!t.isWater() && t.getOwner().isNull());
            final int isLand = !t.isWater() ? 1 : 0;
            final int isCanHold = canHold ? 1 : 0;
            final int isCantHoldAmphib = !canHold && !patd.getAmphibAttackMap().isEmpty() ? 1 : 0;
            final int isFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t) ? 1 : 0;
            final int isFfa = ProUtils.isFfa(data, player) ? 1 : 0;
            final int production = TerritoryAttachment.getProduction(t);
            double capitalValue = 0;
            final TerritoryAttachment ta = TerritoryAttachment.get(t);
            if (ta != null && ta.isCapital()) {
                capitalValue = ProUtils.getPlayerProduction(t.getOwner(), data);
            }
            final double territoryValue = (1 + isLand - isCantHoldAmphib + isFactory + isCanHold * (1 + 2 * isFfa + 2 * isFactory)) * production + capitalValue;
            double tuvSwing = result.getTuvSwing();
            if (isFfa == 1 && tuvSwing > 0) {
                tuvSwing *= 0.5;
            }
            final double attackValue = tuvSwing + territoryValue * result.getWinPercentage() / 100 - enemyCounterTuvSwing * 2 / 3;
            boolean allUnitsCanAttackOtherTerritory = true;
            if (isNeutral && attackValue < 0) {
                for (final Unit u : patd.getUnits()) {
                    boolean canAttackOtherTerritory = false;
                    for (final ProTerritory patd2 : prioritizedTerritories) {
                        if (!patd.equals(patd2) && unitAttackMap.get(u) != null && unitAttackMap.get(u).contains(patd2.getTerritory())) {
                            canAttackOtherTerritory = true;
                            break;
                        }
                    }
                    if (!canAttackOtherTerritory) {
                        allUnitsCanAttackOtherTerritory = false;
                        break;
                    }
                }
            }
            // Determine whether to remove attack
            if (!patd.isStrafing() && (result.getWinPercentage() < ProData.minWinPercentage || !result.isHasLandUnitRemaining() || (isNeutral && !canHold) || (attackValue < 0 && (!isNeutral || allUnitsCanAttackOtherTerritory || result.getBattleRounds() >= 4)))) {
                territoryToRemove = patd;
            }
            ProLogger.debug(patd.getResultString() + ", attackValue=" + attackValue + ", territoryValue=" + territoryValue + ", allUnitsCanAttackOtherTerritory=" + allUnitsCanAttackOtherTerritory + " with attackers=" + patd.getUnits());
        }
        // Determine whether all attacks are successful or try to hold fewer territories
        if (territoryToRemove == null) {
            break;
        }
        prioritizedTerritories.remove(territoryToRemove);
        ProLogger.debug("Removing " + territoryToRemove.getTerritory().getName());
    }
}
Also used : Territory(games.strategy.engine.data.Territory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) HashSet(java.util.HashSet) Set(java.util.Set) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) 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)

Example 8 with ProOtherMoveOptions

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

the class ProCombatMoveAi method removeTerritoriesWhereTransportsAreExposed.

private void removeTerritoriesWhereTransportsAreExposed() {
    ProLogger.info("Remove territories where transports are exposed");
    final Map<Territory, ProTerritory> attackMap = territoryManager.getAttackOptions().getTerritoryMap();
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    // Find maximum defenders for each transport territory
    final List<Territory> clearedTerritories = attackMap.entrySet().stream().filter(e -> !e.getValue().getUnits().isEmpty()).map(Map.Entry::getKey).collect(Collectors.toList());
    territoryManager.populateDefenseOptions(clearedTerritories);
    final Map<Territory, ProTerritory> defendMap = territoryManager.getDefendOptions().getTerritoryMap();
    // Remove units that have already attacked
    final Set<Unit> alreadyAttackedWithUnits = new HashSet<>();
    for (final ProTerritory t : attackMap.values()) {
        alreadyAttackedWithUnits.addAll(t.getUnits());
        alreadyAttackedWithUnits.addAll(t.getAmphibAttackMap().keySet());
    }
    for (final ProTerritory t : defendMap.values()) {
        t.getMaxUnits().removeAll(alreadyAttackedWithUnits);
    }
    // Loop through all prioritized territories
    for (final Territory t : attackMap.keySet()) {
        final ProTerritory patd = attackMap.get(t);
        ProLogger.debug("Checking territory=" + patd.getTerritory().getName() + " with tranports size=" + patd.getTransportTerritoryMap().size());
        if (!patd.getTerritory().isWater() && !patd.getTransportTerritoryMap().isEmpty()) {
            // Find all transports for each unload territory
            final Map<Territory, List<Unit>> territoryTransportAndBombardMap = new HashMap<>();
            for (final Unit u : patd.getTransportTerritoryMap().keySet()) {
                final Territory unloadTerritory = patd.getTransportTerritoryMap().get(u);
                if (territoryTransportAndBombardMap.containsKey(unloadTerritory)) {
                    territoryTransportAndBombardMap.get(unloadTerritory).add(u);
                } else {
                    final List<Unit> transports = new ArrayList<>();
                    transports.add(u);
                    territoryTransportAndBombardMap.put(unloadTerritory, transports);
                }
            }
            // Find all bombard units for each unload territory
            for (final Unit u : patd.getBombardTerritoryMap().keySet()) {
                final Territory unloadTerritory = patd.getBombardTerritoryMap().get(u);
                if (territoryTransportAndBombardMap.containsKey(unloadTerritory)) {
                    territoryTransportAndBombardMap.get(unloadTerritory).add(u);
                } else {
                    final List<Unit> transports = new ArrayList<>();
                    transports.add(u);
                    territoryTransportAndBombardMap.put(unloadTerritory, transports);
                }
            }
            // Determine counter attack results for each transport territory
            double enemyTuvSwing = 0.0;
            for (final Territory unloadTerritory : territoryTransportAndBombardMap.keySet()) {
                if (enemyAttackOptions.getMax(unloadTerritory) != null) {
                    final List<Unit> enemyAttackers = enemyAttackOptions.getMax(unloadTerritory).getMaxUnits();
                    final Set<Unit> defenders = new HashSet<>(unloadTerritory.getUnits().getMatches(ProMatches.unitIsAlliedNotOwned(player, data)));
                    defenders.addAll(territoryTransportAndBombardMap.get(unloadTerritory));
                    if (defendMap.get(unloadTerritory) != null) {
                        defenders.addAll(defendMap.get(unloadTerritory).getMaxUnits());
                    }
                    final ProBattleResult result = calc.calculateBattleResults(unloadTerritory, enemyAttackOptions.getMax(unloadTerritory).getMaxUnits(), new ArrayList<>(defenders), new HashSet<>());
                    final ProBattleResult minResult = calc.calculateBattleResults(unloadTerritory, enemyAttackOptions.getMax(unloadTerritory).getMaxUnits(), territoryTransportAndBombardMap.get(unloadTerritory), new HashSet<>());
                    final double minTuvSwing = Math.min(result.getTuvSwing(), minResult.getTuvSwing());
                    if (minTuvSwing > 0) {
                        enemyTuvSwing += minTuvSwing;
                    }
                    ProLogger.trace(unloadTerritory + ", EnemyAttackers=" + enemyAttackers.size() + ", MaxDefenders=" + defenders.size() + ", MaxEnemyTUVSwing=" + result.getTuvSwing() + ", MinDefenders=" + territoryTransportAndBombardMap.get(unloadTerritory).size() + ", MinEnemyTUVSwing=" + minResult.getTuvSwing());
                } else {
                    ProLogger.trace("Territory=" + unloadTerritory.getName() + " has no enemy attackers");
                }
            }
            // Determine whether its worth attacking
            final ProBattleResult result = calc.calculateBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet());
            int production = 0;
            int isEnemyCapital = 0;
            final TerritoryAttachment ta = TerritoryAttachment.get(t);
            if (ta != null) {
                production = ta.getProduction();
                if (ta.isCapital()) {
                    isEnemyCapital = 1;
                }
            }
            final double attackValue = result.getTuvSwing() + production * (1 + 3 * isEnemyCapital);
            if (!patd.isStrafing() && (0.75 * enemyTuvSwing) > attackValue) {
                ProLogger.debug("Removing amphib territory: " + patd.getTerritory() + ", enemyTUVSwing=" + enemyTuvSwing + ", attackValue=" + attackValue);
                attackMap.get(t).getUnits().clear();
                attackMap.get(t).getAmphibAttackMap().clear();
                attackMap.get(t).getBombardTerritoryMap().clear();
            } else {
                ProLogger.debug("Keeping amphib territory: " + patd.getTerritory() + ", enemyTUVSwing=" + enemyTuvSwing + ", attackValue=" + attackValue);
            }
        }
    }
}
Also used : Territory(games.strategy.engine.data.Territory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) HashMap(java.util.HashMap) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) ArrayList(java.util.ArrayList) ProBattleResult(games.strategy.triplea.ai.pro.data.ProBattleResult) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) ArrayList(java.util.ArrayList) List(java.util.List) ProOtherMoveOptions(games.strategy.triplea.ai.pro.data.ProOtherMoveOptions) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) HashSet(java.util.HashSet)

Example 9 with ProOtherMoveOptions

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

the class ProCombatMoveAi method determineTerritoriesThatCanBeHeld.

private void determineTerritoriesThatCanBeHeld(final List<ProTerritory> prioritizedTerritories, final Map<Territory, Double> territoryValueMap) {
    ProLogger.info("Check if we should try to hold attack territories");
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    final Map<Territory, ProTerritory> attackMap = territoryManager.getAttackOptions().getTerritoryMap();
    // Determine which territories to try and hold
    for (final ProTerritory patd : prioritizedTerritories) {
        final Territory t = patd.getTerritory();
        // If strafing then can't hold
        if (patd.isStrafing()) {
            patd.setCanHold(false);
            ProLogger.debug(t + ", strafing so CanHold=false");
            continue;
        }
        // Set max enemy attackers
        if (enemyAttackOptions.getMax(t) != null) {
            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());
        }
        // Add strategic value for factories
        int isFactory = 0;
        if (ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
            isFactory = 1;
        }
        // Determine whether its worth trying to hold territory
        double totalValue = 0.0;
        final List<Unit> nonAirAttackers = CollectionUtils.getMatches(patd.getMaxUnits(), Matches.unitIsNotAir());
        for (final Unit u : nonAirAttackers) {
            totalValue += territoryValueMap.get(ProData.unitTerritoryMap.get(u));
        }
        final double averageValue = totalValue / nonAirAttackers.size() * 0.75;
        final double territoryValue = territoryValueMap.get(t) * (1 + 4 * isFactory);
        if (!t.isWater() && territoryValue < averageValue) {
            attackMap.get(t).setCanHold(false);
            ProLogger.debug(t + ", CanHold=false, value=" + territoryValueMap.get(t) + ", averageAttackFromValue=" + averageValue);
            continue;
        }
        if (enemyAttackOptions.getMax(t) != null) {
            // Find max remaining defenders
            final Set<Unit> attackingUnits = new HashSet<>(patd.getMaxUnits());
            attackingUnits.addAll(patd.getMaxAmphibUnits());
            final ProBattleResult result = calc.estimateAttackBattleResults(t, new ArrayList<>(attackingUnits), patd.getMaxEnemyDefenders(player, data), patd.getMaxBombardUnits());
            final List<Unit> remainingUnitsToDefendWith = CollectionUtils.getMatches(result.getAverageAttackersRemaining(), Matches.unitIsAir().negate());
            ProLogger.debug(t + ", value=" + territoryValueMap.get(t) + ", averageAttackFromValue=" + averageValue + ", MyAttackers=" + attackingUnits.size() + ", RemainingUnits=" + remainingUnitsToDefendWith.size());
            // Determine counter attack results to see if I can hold it
            final ProBattleResult result2 = calc.calculateBattleResults(t, patd.getMaxEnemyUnits(), remainingUnitsToDefendWith, enemyAttackOptions.getMax(t).getMaxBombardUnits());
            final boolean canHold = (!result2.isHasLandUnitRemaining() && !t.isWater()) || (result2.getTuvSwing() < 0) || (result2.getWinPercentage() < ProData.minWinPercentage);
            patd.setCanHold(canHold);
            ProLogger.debug(t + ", CanHold=" + canHold + ", MyDefenders=" + remainingUnitsToDefendWith.size() + ", EnemyAttackers=" + patd.getMaxEnemyUnits().size() + ", win%=" + result2.getWinPercentage() + ", EnemyTUVSwing=" + result2.getTuvSwing() + ", hasLandUnitRemaining=" + result2.isHasLandUnitRemaining());
        } else {
            attackMap.get(t).setCanHold(true);
            ProLogger.debug(t + ", CanHold=true since no enemy counter attackers, value=" + territoryValueMap.get(t) + ", averageAttackFromValue=" + averageValue);
        }
    }
}
Also used : Territory(games.strategy.engine.data.Territory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) 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)

Example 10 with ProOtherMoveOptions

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

Aggregations

Territory (games.strategy.engine.data.Territory)15 Unit (games.strategy.engine.data.Unit)15 TripleAUnit (games.strategy.triplea.TripleAUnit)15 ProOtherMoveOptions (games.strategy.triplea.ai.pro.data.ProOtherMoveOptions)15 ArrayList (java.util.ArrayList)13 HashSet (java.util.HashSet)13 ProBattleResult (games.strategy.triplea.ai.pro.data.ProBattleResult)12 ProPlaceTerritory (games.strategy.triplea.ai.pro.data.ProPlaceTerritory)9 ProPurchaseTerritory (games.strategy.triplea.ai.pro.data.ProPurchaseTerritory)9 ProTerritory (games.strategy.triplea.ai.pro.data.ProTerritory)8 ProPurchaseOption (games.strategy.triplea.ai.pro.data.ProPurchaseOption)4 TerritoryAttachment (games.strategy.triplea.attachments.TerritoryAttachment)4 HashMap (java.util.HashMap)4 Set (java.util.Set)2 TreeMap (java.util.TreeMap)2 Route (games.strategy.engine.data.Route)1 ProTransport (games.strategy.triplea.ai.pro.data.ProTransport)1 PlaceableUnits (games.strategy.triplea.delegate.dataObjects.PlaceableUnits)1 Collection (java.util.Collection)1 LinkedHashSet (java.util.LinkedHashSet)1