Search in sources :

Example 11 with TerritoryAttachment

use of games.strategy.triplea.attachments.TerritoryAttachment in project triplea by triplea-game.

the class WeakAi method populateCombatMove.

private static void populateCombatMove(final GameData data, final List<Collection<Unit>> moveUnits, final List<Route> moveRoutes, final PlayerID player) {
    populateBomberCombat(data, moveUnits, moveRoutes, player);
    final Collection<Unit> unitsAlreadyMoved = new HashSet<>();
    // find the territories we can just walk into
    final Predicate<Territory> walkInto = Matches.isTerritoryEnemyAndNotUnownedWaterOrImpassableOrRestricted(player, data).or(Matches.isTerritoryFreeNeutral(data));
    final List<Territory> enemyOwned = CollectionUtils.getMatches(data.getMap().getTerritories(), walkInto);
    Collections.shuffle(enemyOwned);
    enemyOwned.sort((o1, o2) -> {
        // -1 means o1 goes first. 1 means o2 goes first. zero means they are equal.
        if (Objects.equals(o1, o2)) {
            return 0;
        }
        if (o1 == null) {
            return 1;
        }
        if (o2 == null) {
            return -1;
        }
        final TerritoryAttachment ta1 = TerritoryAttachment.get(o1);
        final TerritoryAttachment ta2 = TerritoryAttachment.get(o2);
        if (ta1 == null && ta2 == null) {
            return 0;
        }
        if (ta1 == null) {
            return 1;
        }
        if (ta2 == null) {
            return -1;
        }
        // take capitols first if we can
        if (ta1.isCapital() && !ta2.isCapital()) {
            return -1;
        }
        if (!ta1.isCapital() && ta2.isCapital()) {
            return 1;
        }
        final boolean factoryInT1 = o1.getUnits().anyMatch(Matches.unitCanProduceUnits());
        final boolean factoryInT2 = o2.getUnits().anyMatch(Matches.unitCanProduceUnits());
        // next take territories which can produce
        if (factoryInT1 && !factoryInT2) {
            return -1;
        }
        if (!factoryInT1 && factoryInT2) {
            return 1;
        }
        final boolean infrastructureInT1 = o1.getUnits().anyMatch(Matches.unitIsInfrastructure());
        final boolean infrastructureInT2 = o2.getUnits().anyMatch(Matches.unitIsInfrastructure());
        // next take territories with infrastructure
        if (infrastructureInT1 && !infrastructureInT2) {
            return -1;
        }
        if (!infrastructureInT1 && infrastructureInT2) {
            return 1;
        }
        // next take territories with largest PU value
        return ta2.getProduction() - ta1.getProduction();
    });
    final List<Territory> isWaterTerr = Utils.onlyWaterTerr(enemyOwned);
    enemyOwned.removeAll(isWaterTerr);
    // first find the territories we can just walk into
    for (final Territory enemy : enemyOwned) {
        if (AiUtils.strength(enemy.getUnits().getUnits(), false, false) == 0) {
            // only take it with 1 unit
            boolean taken = false;
            for (final Territory attackFrom : data.getMap().getNeighbors(enemy, Matches.territoryHasLandUnitsOwnedBy(player))) {
                if (taken) {
                    break;
                }
                // get the cheapest unit to move in
                final List<Unit> unitsSortedByCost = new ArrayList<>(attackFrom.getUnits().getUnits());
                unitsSortedByCost.sort(AiUtils.getCostComparator());
                for (final Unit unit : unitsSortedByCost) {
                    final Predicate<Unit> match = Matches.unitIsOwnedBy(player).and(Matches.unitIsLand()).and(Matches.unitIsNotInfrastructure()).and(Matches.unitCanMove()).and(Matches.unitIsNotAa()).and(Matches.unitCanNotMoveDuringCombatMove().negate());
                    if (!unitsAlreadyMoved.contains(unit) && match.test(unit)) {
                        moveRoutes.add(data.getMap().getRoute(attackFrom, enemy));
                        // number of units, to leave units free to move elsewhere
                        if (attackFrom.isWater()) {
                            final List<Unit> units = attackFrom.getUnits().getMatches(Matches.unitIsLandAndOwnedBy(player));
                            moveUnits.add(CollectionUtils.difference(units, unitsAlreadyMoved));
                            unitsAlreadyMoved.addAll(units);
                        } else {
                            moveUnits.add(Collections.singleton(unit));
                        }
                        unitsAlreadyMoved.add(unit);
                        taken = true;
                        break;
                    }
                }
            }
        }
    }
    // find the territories we can reasonably expect to take
    for (final Territory enemy : enemyOwned) {
        final float enemyStrength = AiUtils.strength(enemy.getUnits().getUnits(), false, false);
        if (enemyStrength > 0) {
            final Predicate<Unit> attackable = Matches.unitIsOwnedBy(player).and(Matches.unitIsStrategicBomber().negate()).and(o -> !unitsAlreadyMoved.contains(o)).and(Matches.unitIsNotAa()).and(Matches.unitCanMove()).and(Matches.unitIsNotInfrastructure()).and(Matches.unitCanNotMoveDuringCombatMove().negate()).and(Matches.unitIsNotSea());
            final Set<Territory> dontMoveFrom = new HashSet<>();
            // find our strength that we can attack with
            float ourStrength = 0;
            final Collection<Territory> attackFrom = data.getMap().getNeighbors(enemy, Matches.territoryHasLandUnitsOwnedBy(player));
            for (final Territory owned : attackFrom) {
                if (TerritoryAttachment.get(owned) != null && TerritoryAttachment.get(owned).isCapital() && (Utils.getStrengthOfPotentialAttackers(owned, data) > AiUtils.strength(owned.getUnits().getUnits(), false, false))) {
                    dontMoveFrom.add(owned);
                    continue;
                }
                ourStrength += AiUtils.strength(owned.getUnits().getMatches(attackable), true, false);
            }
            // prevents 2 infantry from attacking 1 infantry
            if (ourStrength > 1.37 * enemyStrength) {
                // this is all we need to take it, dont go overboard, since we may be able to use the units to attack
                // somewhere else
                double remainingStrengthNeeded = (2.5 * enemyStrength) + 4;
                for (final Territory owned : attackFrom) {
                    if (dontMoveFrom.contains(owned)) {
                        continue;
                    }
                    List<Unit> units = owned.getUnits().getMatches(attackable);
                    // 2) we can potentially attack another territory
                    if (!owned.isWater() && data.getMap().getNeighbors(owned, Matches.territoryHasEnemyLandUnits(player, data)).size() > 1) {
                        units = Utils.getUnitsUpToStrength(remainingStrengthNeeded, units, false);
                    }
                    remainingStrengthNeeded -= AiUtils.strength(units, true, false);
                    if (units.size() > 0) {
                        unitsAlreadyMoved.addAll(units);
                        moveUnits.add(units);
                        moveRoutes.add(data.getMap().getRoute(owned, enemy));
                    }
                }
            }
        }
    }
}
Also used : IPurchaseDelegate(games.strategy.triplea.delegate.remote.IPurchaseDelegate) Constants(games.strategy.triplea.Constants) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) HashMap(java.util.HashMap) NamedAttachable(games.strategy.engine.data.NamedAttachable) Properties(games.strategy.triplea.Properties) Resource(games.strategy.engine.data.Resource) ArrayList(java.util.ArrayList) PlaceableUnits(games.strategy.triplea.delegate.dataObjects.PlaceableUnits) HashSet(java.util.HashSet) Route(games.strategy.engine.data.Route) DelegateFinder(games.strategy.triplea.delegate.DelegateFinder) TransportTracker(games.strategy.triplea.delegate.TransportTracker) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) Map(java.util.Map) UnitType(games.strategy.engine.data.UnitType) TripleAUnit(games.strategy.triplea.TripleAUnit) AbstractAi(games.strategy.triplea.ai.AbstractAi) RepairRule(games.strategy.engine.data.RepairRule) CollectionUtils(games.strategy.util.CollectionUtils) IntegerMap(games.strategy.util.IntegerMap) Unit(games.strategy.engine.data.Unit) Iterator(java.util.Iterator) Predicate(java.util.function.Predicate) Collection(java.util.Collection) Set(java.util.Set) Territory(games.strategy.engine.data.Territory) Streams(com.google.common.collect.Streams) Objects(java.util.Objects) GameData(games.strategy.engine.data.GameData) List(java.util.List) PlayerID(games.strategy.engine.data.PlayerID) IMoveDelegate(games.strategy.triplea.delegate.remote.IMoveDelegate) Matches(games.strategy.triplea.delegate.Matches) BattleDelegate(games.strategy.triplea.delegate.BattleDelegate) IAbstractPlaceDelegate(games.strategy.triplea.delegate.remote.IAbstractPlaceDelegate) ITechDelegate(games.strategy.triplea.delegate.remote.ITechDelegate) ProductionRule(games.strategy.engine.data.ProductionRule) Collections(java.util.Collections) AiUtils(games.strategy.triplea.ai.AiUtils) Territory(games.strategy.engine.data.Territory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) HashSet(java.util.HashSet)

Example 12 with TerritoryAttachment

use of games.strategy.triplea.attachments.TerritoryAttachment in project triplea by triplea-game.

the class ProPurchaseAi method prioritizeTerritoriesToDefend.

private List<ProPlaceTerritory> prioritizeTerritoriesToDefend(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final boolean isLand) {
    ProLogger.info("Prioritize territories to defend with isLand=" + isLand);
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    // Determine which territories need defended
    final Set<ProPlaceTerritory> needToDefendTerritories = new HashSet<>();
    for (final ProPurchaseTerritory ppt : purchaseTerritories.values()) {
        // Check if any of the place territories can't be held with current defenders
        for (final ProPlaceTerritory placeTerritory : ppt.getCanPlaceTerritories()) {
            final Territory t = placeTerritory.getTerritory();
            if (enemyAttackOptions.getMax(t) == null || (t.isWater() && placeTerritory.getDefendingUnits().isEmpty()) || (isLand && t.isWater()) || (!isLand && !t.isWater())) {
                continue;
            }
            // Find current battle result
            final Set<Unit> enemyAttackingUnits = new HashSet<>(enemyAttackOptions.getMax(t).getMaxUnits());
            enemyAttackingUnits.addAll(enemyAttackOptions.getMax(t).getMaxAmphibUnits());
            final ProBattleResult result = calc.calculateBattleResults(t, new ArrayList<>(enemyAttackingUnits), placeTerritory.getDefendingUnits(), enemyAttackOptions.getMax(t).getMaxBombardUnits());
            placeTerritory.setMinBattleResult(result);
            double holdValue = 0;
            if (t.isWater()) {
                final double unitValue = TuvUtils.getTuv(CollectionUtils.getMatches(placeTerritory.getDefendingUnits(), Matches.unitIsOwnedBy(player)), ProData.unitValueMap);
                holdValue = unitValue / 8;
            }
            ProLogger.trace(t.getName() + " TUVSwing=" + result.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", holdValue=" + holdValue + ", enemyAttackers=" + enemyAttackingUnits + ", defenders=" + placeTerritory.getDefendingUnits());
            // If it can't currently be held then add to list
            final boolean isLandAndCanOnlyBeAttackedByAir = !t.isWater() && !enemyAttackingUnits.isEmpty() && enemyAttackingUnits.stream().allMatch(Matches.unitIsAir());
            if ((!t.isWater() && result.isHasLandUnitRemaining()) || result.getTuvSwing() > holdValue || (t.equals(ProData.myCapital) && !isLandAndCanOnlyBeAttackedByAir && result.getWinPercentage() > (100 - ProData.winPercentage))) {
                needToDefendTerritories.add(placeTerritory);
            }
        }
    }
    // Calculate value of defending territory
    for (final ProPlaceTerritory placeTerritory : needToDefendTerritories) {
        final Territory t = placeTerritory.getTerritory();
        // Determine if it is my capital or adjacent to my capital
        int isMyCapital = 0;
        if (t.equals(ProData.myCapital)) {
            isMyCapital = 1;
        }
        // Determine if it has a factory
        int isFactory = 0;
        if (ProMatches.territoryHasInfraFactoryAndIsOwnedLand(player).test(t)) {
            isFactory = 1;
        }
        // Determine production value and if it is an enemy capital
        int production = 0;
        final TerritoryAttachment ta = TerritoryAttachment.get(t);
        if (ta != null) {
            production = ta.getProduction();
        }
        // Determine defending unit value
        double defendingUnitValue = TuvUtils.getTuv(placeTerritory.getDefendingUnits(), ProData.unitValueMap);
        if (t.isWater() && placeTerritory.getDefendingUnits().stream().noneMatch(Matches.unitIsOwnedBy(player))) {
            defendingUnitValue = 0;
        }
        // Calculate defense value for prioritization
        final double territoryValue = (2 * production + 4 * isFactory + 0.5 * defendingUnitValue) * (1 + isFactory) * (1 + 10 * isMyCapital);
        placeTerritory.setDefenseValue(territoryValue);
    }
    // Remove any territories with negative defense value
    needToDefendTerritories.removeIf(ppt -> ppt.getDefenseValue() <= 0);
    // Sort territories by value
    final List<ProPlaceTerritory> sortedTerritories = new ArrayList<>(needToDefendTerritories);
    sortedTerritories.sort(Comparator.comparingDouble(ProPlaceTerritory::getDefenseValue));
    for (final ProPlaceTerritory placeTerritory : sortedTerritories) {
        ProLogger.debug(placeTerritory.toString() + " defenseValue=" + placeTerritory.getDefenseValue());
    }
    return sortedTerritories;
}
Also used : ProPlaceTerritory(games.strategy.triplea.ai.pro.data.ProPlaceTerritory) ProPurchaseTerritory(games.strategy.triplea.ai.pro.data.ProPurchaseTerritory) Territory(games.strategy.engine.data.Territory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) 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) ProOtherMoveOptions(games.strategy.triplea.ai.pro.data.ProOtherMoveOptions) HashSet(java.util.HashSet)

Example 13 with TerritoryAttachment

use of games.strategy.triplea.attachments.TerritoryAttachment in project triplea by triplea-game.

the class ProCombatMoveAi method prioritizeAttackOptions.

private List<ProTerritory> prioritizeAttackOptions(final PlayerID player, final List<ProTerritory> attackOptions) {
    ProLogger.info("Prioritizing territories to try to attack");
    // Calculate value of attacking territory
    for (final Iterator<ProTerritory> it = attackOptions.iterator(); it.hasNext(); ) {
        final ProTerritory patd = it.next();
        final Territory t = patd.getTerritory();
        // Determine territory attack properties
        final int isLand = !t.isWater() ? 1 : 0;
        final int isNeutral = (!t.isWater() && t.getOwner().isNull()) ? 1 : 0;
        final int isCanHold = patd.isCanHold() ? 1 : 0;
        final int isAmphib = patd.isNeedAmphibUnits() ? 1 : 0;
        final List<Unit> defendingUnits = CollectionUtils.getMatches(patd.getMaxEnemyDefenders(player, data), ProMatches.unitIsEnemyAndNotInfa(player, data));
        final int isEmptyLand = (defendingUnits.isEmpty() && !patd.isNeedAmphibUnits()) ? 1 : 0;
        final boolean isAdjacentToMyCapital = !data.getMap().getNeighbors(t, Matches.territoryIs(ProData.myCapital)).isEmpty();
        final int isNotNeutralAdjacentToMyCapital = (isAdjacentToMyCapital && ProMatches.territoryIsEnemyNotNeutralLand(player, data).test(t)) ? 1 : 0;
        final int isFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t) ? 1 : 0;
        final int isFfa = ProUtils.isFfa(data, player) ? 1 : 0;
        // Determine production value and if it is an enemy capital
        int production = 0;
        int isEnemyCapital = 0;
        final TerritoryAttachment ta = TerritoryAttachment.get(t);
        if (ta != null) {
            production = ta.getProduction();
            if (ta.isCapital()) {
                isEnemyCapital = 1;
            }
        }
        // Calculate attack value for prioritization
        double tuvSwing = patd.getMaxBattleResult().getTuvSwing();
        if (isFfa == 1 && tuvSwing > 0) {
            tuvSwing *= 0.5;
        }
        final double territoryValue = (1 + isLand + isCanHold * (1 + 2 * isFfa)) * (1 + isEmptyLand) * (1 + isFactory) * (1 - 0.5 * isAmphib) * production;
        double attackValue = (tuvSwing + territoryValue) * (1 + 4 * isEnemyCapital) * (1 + 2 * isNotNeutralAdjacentToMyCapital) * (1 - 0.9 * isNeutral);
        // Check if a negative value neutral territory should be attacked
        if (attackValue <= 0 && !patd.isNeedAmphibUnits() && !t.isWater() && t.getOwner().isNull()) {
            // Determine enemy neighbor territory production value for neutral land territories
            double nearbyEnemyValue = 0;
            final List<Territory> cantReachEnemyTerritories = new ArrayList<>();
            final Set<Territory> nearbyTerritories = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveLandUnits(player, data, true));
            final List<Territory> nearbyEnemyTerritories = CollectionUtils.getMatches(nearbyTerritories, Matches.isTerritoryEnemy(player, data));
            final List<Territory> nearbyTerritoriesWithOwnedUnits = CollectionUtils.getMatches(nearbyTerritories, Matches.territoryHasUnitsOwnedBy(player));
            for (final Territory nearbyEnemyTerritory : nearbyEnemyTerritories) {
                boolean allAlliedNeighborsHaveRoute = true;
                for (final Territory nearbyAlliedTerritory : nearbyTerritoriesWithOwnedUnits) {
                    final int distance = data.getMap().getDistance_IgnoreEndForCondition(nearbyAlliedTerritory, nearbyEnemyTerritory, ProMatches.territoryIsEnemyNotNeutralOrAllied(player, data));
                    if (distance < 0 || distance > 2) {
                        allAlliedNeighborsHaveRoute = false;
                        break;
                    }
                }
                if (!allAlliedNeighborsHaveRoute) {
                    final double value = ProTerritoryValueUtils.findTerritoryAttackValue(player, nearbyEnemyTerritory);
                    if (value > 0) {
                        nearbyEnemyValue += value;
                    }
                    cantReachEnemyTerritories.add(nearbyEnemyTerritory);
                }
            }
            ProLogger.debug(t.getName() + " calculated nearby enemy value=" + nearbyEnemyValue + " from " + cantReachEnemyTerritories);
            if (nearbyEnemyValue > 0) {
                ProLogger.trace(t.getName() + " updating negative neutral attack value=" + attackValue);
                attackValue = nearbyEnemyValue * .001 / (1 - attackValue);
            } else {
                // Check if overwhelming attack strength (more than 5 times)
                final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, patd.getMaxUnits(), patd.getMaxEnemyDefenders(player, data));
                ProLogger.debug(t.getName() + " calculated strengthDifference=" + strengthDifference);
                if (strengthDifference > 500) {
                    ProLogger.trace(t.getName() + " updating negative neutral attack value=" + attackValue);
                    attackValue = strengthDifference * .00001 / (1 - attackValue);
                }
            }
        }
        // Remove negative value territories
        patd.setValue(attackValue);
        if (attackValue <= 0 || (isDefensive && attackValue <= 8 && data.getMap().getDistance(ProData.myCapital, t) <= 3)) {
            ProLogger.debug("Removing territory that has a negative attack value: " + t.getName() + ", AttackValue=" + patd.getValue());
            it.remove();
        }
    }
    // Sort attack territories by value
    attackOptions.sort(Comparator.comparingDouble(ProTerritory::getValue));
    // Log prioritized territories
    for (final ProTerritory patd : attackOptions) {
        ProLogger.debug("AttackValue=" + patd.getValue() + ", TUVSwing=" + patd.getMaxBattleResult().getTuvSwing() + ", isAmphib=" + patd.isNeedAmphibUnits() + ", " + patd.getTerritory().getName());
    }
    return attackOptions;
}
Also used : Territory(games.strategy.engine.data.Territory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 14 with TerritoryAttachment

use of games.strategy.triplea.attachments.TerritoryAttachment in project triplea by triplea-game.

the class ProNonCombatMoveAi method moveOneDefenderToLandTerritoriesBorderingEnemy.

private List<Territory> moveOneDefenderToLandTerritoriesBorderingEnemy() {
    ProLogger.info("Determine which territories to defend with one land unit");
    final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
    final Map<Unit, Set<Territory>> unitMoveMap = territoryManager.getDefendOptions().getUnitMoveMap();
    // Find land territories with no can't move units and adjacent to enemy land units
    final List<Territory> territoriesToDefendWithOneUnit = new ArrayList<>();
    for (final Territory t : moveMap.keySet()) {
        final boolean hasAlliedLandUnits = moveMap.get(t).getCantMoveUnits().stream().anyMatch(ProMatches.unitIsAlliedLandAndNotInfra(player, data));
        if (!t.isWater() && !hasAlliedLandUnits && ProMatches.territoryHasNeighborOwnedByAndHasLandUnit(data, ProUtils.getPotentialEnemyPlayers(player)).test(t)) {
            territoriesToDefendWithOneUnit.add(t);
        }
    }
    final List<Territory> result = new ArrayList<>(territoriesToDefendWithOneUnit);
    // Sort units by number of defend options and cost
    final Map<Unit, Set<Territory>> sortedUnitMoveOptions = ProSortMoveOptionsUtils.sortUnitMoveOptions(unitMoveMap);
    // Set unit with the fewest move options in each territory
    for (final Unit unit : sortedUnitMoveOptions.keySet()) {
        if (Matches.unitIsLand().test(unit)) {
            for (final Territory t : sortedUnitMoveOptions.get(unit)) {
                final int unitValue = ProData.unitValueMap.getInt(unit.getType());
                int production = 0;
                final TerritoryAttachment ta = TerritoryAttachment.get(t);
                if (ta != null) {
                    production = ta.getProduction();
                }
                // or where unit value is less than production + 3 (avoid sacrificing expensive units to block)
                if (territoriesToDefendWithOneUnit.contains(t) && (unitValue <= (production + 3) || Matches.territoryHasUnitsOwnedBy(player).test(t))) {
                    moveMap.get(t).addUnit(unit);
                    unitMoveMap.remove(unit);
                    territoriesToDefendWithOneUnit.remove(t);
                    ProLogger.debug(t + ", added one land unit: " + unit);
                    break;
                }
            }
            if (territoriesToDefendWithOneUnit.isEmpty()) {
                break;
            }
        }
    }
    // Only return territories that received a defender
    result.removeAll(territoriesToDefendWithOneUnit);
    return result;
}
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) Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) ProTerritory(games.strategy.triplea.ai.pro.data.ProTerritory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 15 with TerritoryAttachment

use of games.strategy.triplea.attachments.TerritoryAttachment in project triplea by triplea-game.

the class ProNonCombatMoveAi method prioritizeDefendOptions.

private List<ProTerritory> prioritizeDefendOptions(final Map<Territory, ProTerritory> factoryMoveMap, final Map<Territory, Double> territoryValueMap) {
    ProLogger.info("Prioritizing territories to try to defend");
    final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
    final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
    // Calculate value of defending territory
    for (final Territory t : moveMap.keySet()) {
        // Determine if it is my capital or adjacent to my capital
        int isMyCapital = 0;
        if (t.equals(ProData.myCapital)) {
            isMyCapital = 1;
        }
        // Determine if it has a factory
        int isFactory = 0;
        if (ProMatches.territoryHasInfraFactoryAndIsLand().test(t) || (factoryMoveMap != null && factoryMoveMap.containsKey(t))) {
            isFactory = 1;
        }
        // Determine production value and if it is an enemy capital
        int production = 0;
        int isEnemyOrAlliedCapital = 0;
        final TerritoryAttachment ta = TerritoryAttachment.get(t);
        if (ta != null) {
            production = ta.getProduction();
            if (ta.isCapital() && !t.equals(ProData.myCapital)) {
                isEnemyOrAlliedCapital = 1;
            }
        }
        // Determine neighbor value
        double neighborValue = 0;
        if (!t.isWater()) {
            final Set<Territory> landNeighbors = data.getMap().getNeighbors(t, Matches.territoryIsLand());
            for (final Territory neighbor : landNeighbors) {
                double neighborProduction = TerritoryAttachment.getProduction(neighbor);
                if (Matches.isTerritoryAllied(player, data).test(neighbor)) {
                    neighborProduction = 0.1 * neighborProduction;
                }
                neighborValue += neighborProduction;
            }
        }
        // Determine defending unit value
        final int cantMoveUnitValue = TuvUtils.getTuv(moveMap.get(t).getCantMoveUnits(), ProData.unitValueMap);
        double unitOwnerMultiplier = 1;
        if (moveMap.get(t).getCantMoveUnits().stream().noneMatch(Matches.unitIsOwnedBy(player))) {
            if (t.isWater() && moveMap.get(t).getCantMoveUnits().stream().noneMatch(Matches.unitIsTransportButNotCombatTransport())) {
                unitOwnerMultiplier = 0;
            } else {
                unitOwnerMultiplier = 0.5;
            }
        }
        // Calculate defense value for prioritization
        final double territoryValue = unitOwnerMultiplier * (2 * production + 10 * isFactory + 0.5 * cantMoveUnitValue + 0.5 * neighborValue) * (1 + 10 * isMyCapital) * (1 + 4 * isEnemyOrAlliedCapital);
        moveMap.get(t).setValue(territoryValue);
    }
    // Sort attack territories by value
    final List<ProTerritory> prioritizedTerritories = new ArrayList<>(moveMap.values());
    prioritizedTerritories.sort(Comparator.comparingDouble(ProTerritory::getValue));
    // Remove territories that I'm not going to try to defend
    for (final Iterator<ProTerritory> it = prioritizedTerritories.iterator(); it.hasNext(); ) {
        final ProTerritory patd = it.next();
        final Territory t = patd.getTerritory();
        final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
        final ProBattleResult minResult = patd.getMinBattleResult();
        final int cantMoveUnitValue = TuvUtils.getTuv(moveMap.get(t).getCantMoveUnits(), ProData.unitValueMap);
        final List<Unit> maxEnemyUnits = patd.getMaxEnemyUnits();
        final boolean isLandAndCanOnlyBeAttackedByAir = !t.isWater() && !maxEnemyUnits.isEmpty() && maxEnemyUnits.stream().allMatch(Matches.unitIsAir());
        final boolean isNotFactoryAndShouldHold = !hasFactory && (minResult.getTuvSwing() <= 0 || !minResult.isHasLandUnitRemaining());
        final boolean canAlreadyBeHeld = minResult.getTuvSwing() <= 0 && minResult.getWinPercentage() < (100 - ProData.winPercentage);
        final boolean isNotFactoryAndHasNoEnemyNeighbors = !t.isWater() && !hasFactory && !ProMatches.territoryHasNeighborOwnedByAndHasLandUnit(data, ProUtils.getPotentialEnemyPlayers(player)).test(t);
        final boolean isNotFactoryAndOnlyAmphib = !t.isWater() && !hasFactory && moveMap.get(t).getMaxUnits().stream().noneMatch(Matches.unitIsLand()) && cantMoveUnitValue < 5;
        if (!patd.isCanHold() || patd.getValue() <= 0 || isLandAndCanOnlyBeAttackedByAir || isNotFactoryAndShouldHold || canAlreadyBeHeld || isNotFactoryAndHasNoEnemyNeighbors || isNotFactoryAndOnlyAmphib) {
            final double tuvSwing = minResult.getTuvSwing();
            final boolean hasRemainingLandUnit = minResult.isHasLandUnitRemaining();
            ProLogger.debug("Removing territory=" + t.getName() + ", value=" + patd.getValue() + ", CanHold=" + patd.isCanHold() + ", isLandAndCanOnlyBeAttackedByAir=" + isLandAndCanOnlyBeAttackedByAir + ", isNotFactoryAndShouldHold=" + isNotFactoryAndShouldHold + ", canAlreadyBeHeld=" + canAlreadyBeHeld + ", isNotFactoryAndHasNoEnemyNeighbors=" + isNotFactoryAndHasNoEnemyNeighbors + ", isNotFactoryAndOnlyAmphib=" + isNotFactoryAndOnlyAmphib + ", tuvSwing=" + tuvSwing + ", hasRemainingLandUnit=" + hasRemainingLandUnit + ", maxEnemyUnits=" + patd.getMaxEnemyUnits().size());
            it.remove();
        }
    }
    // Add best sea production territory for sea factories
    List<Territory> seaFactories = CollectionUtils.getMatches(data.getMap().getTerritories(), ProMatches.territoryHasInfraFactoryAndIsNotConqueredOwnedLand(player, data));
    seaFactories = CollectionUtils.getMatches(seaFactories, ProMatches.territoryHasInfraFactoryAndIsOwnedLandAdjacentToSea(player, data));
    for (final Territory t : seaFactories) {
        if (territoryValueMap.get(t) >= 1) {
            continue;
        }
        final Set<Territory> neighbors = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, true));
        double maxValue = 0;
        Territory maxTerritory = null;
        for (final Territory neighbor : neighbors) {
            if (moveMap.get(neighbor) != null && moveMap.get(neighbor).isCanHold() && territoryValueMap.get(neighbor) > maxValue) {
                maxTerritory = neighbor;
                maxValue = territoryValueMap.get(neighbor);
            }
        }
        if (maxTerritory != null && enemyAttackOptions.getMax(maxTerritory) != null) {
            boolean alreadyAdded = false;
            for (final ProTerritory patd : prioritizedTerritories) {
                if (patd.getTerritory().equals(maxTerritory)) {
                    alreadyAdded = true;
                }
            }
            if (!alreadyAdded) {
                prioritizedTerritories.add(moveMap.get(maxTerritory));
            }
        }
    }
    // Log prioritized territories
    for (final ProTerritory attackTerritoryData : prioritizedTerritories) {
        ProLogger.debug("Value=" + attackTerritoryData.getValue() + ", " + attackTerritoryData.getTerritory().getName());
    }
    return prioritizedTerritories;
}
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) 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)

Aggregations

TerritoryAttachment (games.strategy.triplea.attachments.TerritoryAttachment)36 Territory (games.strategy.engine.data.Territory)29 Unit (games.strategy.engine.data.Unit)24 TripleAUnit (games.strategy.triplea.TripleAUnit)19 ArrayList (java.util.ArrayList)14 PlayerID (games.strategy.engine.data.PlayerID)13 GameData (games.strategy.engine.data.GameData)9 HashSet (java.util.HashSet)8 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)7 ProTerritory (games.strategy.triplea.ai.pro.data.ProTerritory)6 UnitType (games.strategy.engine.data.UnitType)5 ProBattleResult (games.strategy.triplea.ai.pro.data.ProBattleResult)5 CompositeChange (games.strategy.engine.data.CompositeChange)4 Resource (games.strategy.engine.data.Resource)4 ProOtherMoveOptions (games.strategy.triplea.ai.pro.data.ProOtherMoveOptions)4 PlayerAttachment (games.strategy.triplea.attachments.PlayerAttachment)4 IntegerMap (games.strategy.util.IntegerMap)4 RelationshipTracker (games.strategy.engine.data.RelationshipTracker)3 ProPlaceTerritory (games.strategy.triplea.ai.pro.data.ProPlaceTerritory)3 ProPurchaseTerritory (games.strategy.triplea.ai.pro.data.ProPurchaseTerritory)3