Search in sources :

Example 11 with Route

use of games.strategy.engine.data.Route 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 Route

use of games.strategy.engine.data.Route in project triplea by triplea-game.

the class WeakAi method getAmphibRoute.

private static Route getAmphibRoute(final PlayerID player, final GameData data) {
    if (!isAmphibAttack(player, data)) {
        return null;
    }
    final Territory ourCapitol = TerritoryAttachment.getFirstOwnedCapitalOrFirstUnownedCapital(player, data);
    final Predicate<Territory> endMatch = o -> {
        final boolean impassable = TerritoryAttachment.get(o) != null && TerritoryAttachment.get(o).getIsImpassable();
        return !impassable && !o.isWater() && Utils.hasLandRouteToEnemyOwnedCapitol(o, player, data);
    };
    final Predicate<Territory> routeCond = Matches.territoryIsWater().and(Matches.territoryHasNoEnemyUnits(player, data));
    final Route withNoEnemy = Utils.findNearest(ourCapitol, endMatch, routeCond, data);
    if (withNoEnemy != null && withNoEnemy.numberOfSteps() > 0) {
        return withNoEnemy;
    }
    // this will fail if our capitol is not next to water, c'est la vie.
    final Route route = Utils.findNearest(ourCapitol, endMatch, Matches.territoryIsWater(), data);
    if (route != null && route.numberOfSteps() == 0) {
        return null;
    }
    return route;
}
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) Route(games.strategy.engine.data.Route)

Example 13 with Route

use of games.strategy.engine.data.Route in project triplea by triplea-game.

the class WeakAi method purchase.

@Override
public void purchase(final boolean purchaseForBid, final int pusToSpend, final IPurchaseDelegate purchaseDelegate, final GameData data, final PlayerID player) {
    if (purchaseForBid) {
        // bid will only buy land units, due to weak ai placement for bid not being able to handle sea units
        final Resource pus = data.getResourceList().getResource(Constants.PUS);
        int leftToSpend = pusToSpend;
        final List<ProductionRule> rules = player.getProductionFrontier().getRules();
        final IntegerMap<ProductionRule> purchase = new IntegerMap<>();
        int minCost = Integer.MAX_VALUE;
        int i = 0;
        while ((minCost == Integer.MAX_VALUE || leftToSpend >= minCost) && i < 100000) {
            i++;
            for (final ProductionRule rule : rules) {
                final NamedAttachable resourceOrUnit = rule.getResults().keySet().iterator().next();
                if (!(resourceOrUnit instanceof UnitType)) {
                    continue;
                }
                final UnitType results = (UnitType) resourceOrUnit;
                if (Matches.unitTypeIsSea().test(results) || Matches.unitTypeIsAir().test(results) || Matches.unitTypeIsInfrastructure().test(results) || Matches.unitTypeIsAaForAnything().test(results) || Matches.unitTypeHasMaxBuildRestrictions().test(results) || Matches.unitTypeConsumesUnitsOnCreation().test(results) || Matches.unitTypeIsStatic(player).test(results)) {
                    continue;
                }
                final int cost = rule.getCosts().getInt(pus);
                if (cost < 1) {
                    continue;
                }
                if (minCost == Integer.MAX_VALUE) {
                    minCost = cost;
                }
                if (minCost > cost) {
                    minCost = cost;
                }
                // give a preference to cheap units
                if (Math.random() * cost < 2) {
                    if (cost <= leftToSpend) {
                        leftToSpend -= cost;
                        purchase.add(rule, 1);
                    }
                }
            }
        }
        purchaseDelegate.purchase(purchase);
        pause();
        return;
    }
    final boolean isAmphib = isAmphibAttack(player, data);
    final Route amphibRoute = getAmphibRoute(player, data);
    final int transportCount = countTransports(data, player);
    final int landUnitCount = countLandUnits(data, player);
    int defUnitsAtAmpibRoute = 0;
    if (isAmphib && amphibRoute != null) {
        defUnitsAtAmpibRoute = amphibRoute.getEnd().getUnits().getUnitCount();
    }
    final Resource pus = data.getResourceList().getResource(Constants.PUS);
    final int totalPu = player.getResources().getQuantity(pus);
    int leftToSpend = totalPu;
    final Territory capitol = TerritoryAttachment.getFirstOwnedCapitalOrFirstUnownedCapital(player, data);
    final List<ProductionRule> rules = player.getProductionFrontier().getRules();
    final IntegerMap<ProductionRule> purchase = new IntegerMap<>();
    final List<RepairRule> repairRules;
    final Predicate<Unit> ourFactories = Matches.unitIsOwnedBy(player).and(Matches.unitCanProduceUnits());
    final List<Territory> repairFactories = CollectionUtils.getMatches(Utils.findUnitTerr(data, ourFactories), Matches.isTerritoryOwnedBy(player));
    // figure out if anything needs to be repaired
    if (player.getRepairFrontier() != null && Properties.getDamageFromBombingDoneToUnitsInsteadOfTerritories(data)) {
        repairRules = player.getRepairFrontier().getRules();
        final IntegerMap<RepairRule> repairMap = new IntegerMap<>();
        final HashMap<Unit, IntegerMap<RepairRule>> repair = new HashMap<>();
        final Map<Unit, Territory> unitsThatCanProduceNeedingRepair = new HashMap<>();
        final int minimumUnitPrice = 3;
        int diff;
        int capProduction = 0;
        Unit capUnit = null;
        Territory capUnitTerritory = null;
        int currentProduction = 0;
        // we should sort this
        Collections.shuffle(repairFactories);
        for (final Territory fixTerr : repairFactories) {
            if (!Matches.territoryIsOwnedAndHasOwnedUnitMatching(player, Matches.unitCanProduceUnitsAndCanBeDamaged()).test(fixTerr)) {
                continue;
            }
            final Unit possibleFactoryNeedingRepair = TripleAUnit.getBiggestProducer(CollectionUtils.getMatches(fixTerr.getUnits().getUnits(), ourFactories), fixTerr, player, data, false);
            if (Matches.unitHasTakenSomeBombingUnitDamage().test(possibleFactoryNeedingRepair)) {
                unitsThatCanProduceNeedingRepair.put(possibleFactoryNeedingRepair, fixTerr);
            }
            if (fixTerr == capitol) {
                capProduction = TripleAUnit.getHowMuchCanUnitProduce(possibleFactoryNeedingRepair, fixTerr, player, data, true, true);
                capUnit = possibleFactoryNeedingRepair;
                capUnitTerritory = fixTerr;
            }
            currentProduction += TripleAUnit.getHowMuchCanUnitProduce(possibleFactoryNeedingRepair, fixTerr, player, data, true, true);
        }
        repairFactories.remove(capitol);
        unitsThatCanProduceNeedingRepair.remove(capUnit);
        // assume minimum unit price is 3, and that we are buying only that... if we over repair, oh well, that is better
        // than under-repairing
        // goal is to be able to produce all our units, and at least half of that production in the capitol
        // 
        // if capitol is super safe, we don't have to do this. and if capitol is under siege, we should repair enough to
        // place all our units here
        int maxUnits = (totalPu - 1) / minimumUnitPrice;
        if ((capProduction <= maxUnits / 2 || repairFactories.isEmpty()) && capUnit != null) {
            for (final RepairRule rrule : repairRules) {
                if (!capUnit.getType().equals(rrule.getResults().keySet().iterator().next())) {
                    continue;
                }
                if (!Matches.territoryIsOwnedAndHasOwnedUnitMatching(player, Matches.unitCanProduceUnitsAndCanBeDamaged()).test(capitol)) {
                    continue;
                }
                final TripleAUnit taUnit = (TripleAUnit) capUnit;
                diff = taUnit.getUnitDamage();
                final int unitProductionAllowNegative = TripleAUnit.getHowMuchCanUnitProduce(capUnit, capUnitTerritory, player, data, false, true) - diff;
                if (!repairFactories.isEmpty()) {
                    diff = Math.min(diff, (maxUnits / 2 - unitProductionAllowNegative) + 1);
                } else {
                    diff = Math.min(diff, (maxUnits - unitProductionAllowNegative));
                }
                diff = Math.min(diff, leftToSpend - minimumUnitPrice);
                if (diff > 0) {
                    if (unitProductionAllowNegative >= 0) {
                        currentProduction += diff;
                    } else {
                        currentProduction += diff + unitProductionAllowNegative;
                    }
                    repairMap.add(rrule, diff);
                    repair.put(capUnit, repairMap);
                    leftToSpend -= diff;
                    purchaseDelegate.purchaseRepair(repair);
                    repair.clear();
                    repairMap.clear();
                    // ideally we would adjust this after each single PU spent, then re-evaluate
                    // everything.
                    maxUnits = (leftToSpend - 1) / minimumUnitPrice;
                }
            }
        }
        int i = 0;
        while (currentProduction < maxUnits && i < 2) {
            for (final RepairRule rrule : repairRules) {
                for (final Unit fixUnit : unitsThatCanProduceNeedingRepair.keySet()) {
                    if (fixUnit == null || !fixUnit.getType().equals(rrule.getResults().keySet().iterator().next())) {
                        continue;
                    }
                    if (!Matches.territoryIsOwnedAndHasOwnedUnitMatching(player, Matches.unitCanProduceUnitsAndCanBeDamaged()).test(unitsThatCanProduceNeedingRepair.get(fixUnit))) {
                        continue;
                    }
                    // territories
                    if (currentProduction >= maxUnits) {
                        continue;
                    }
                    final TripleAUnit taUnit = (TripleAUnit) fixUnit;
                    diff = taUnit.getUnitDamage();
                    final int unitProductionAllowNegative = TripleAUnit.getHowMuchCanUnitProduce(fixUnit, unitsThatCanProduceNeedingRepair.get(fixUnit), player, data, false, true) - diff;
                    if (i == 0) {
                        if (unitProductionAllowNegative < 0) {
                            diff = Math.min(diff, (maxUnits - currentProduction) - unitProductionAllowNegative);
                        } else {
                            diff = Math.min(diff, (maxUnits - currentProduction));
                        }
                    }
                    diff = Math.min(diff, leftToSpend - minimumUnitPrice);
                    if (diff > 0) {
                        if (unitProductionAllowNegative >= 0) {
                            currentProduction += diff;
                        } else {
                            currentProduction += diff + unitProductionAllowNegative;
                        }
                        repairMap.add(rrule, diff);
                        repair.put(fixUnit, repairMap);
                        leftToSpend -= diff;
                        purchaseDelegate.purchaseRepair(repair);
                        repair.clear();
                        repairMap.clear();
                        // ideally we would adjust this after each single PU spent, then re-evaluate
                        // everything.
                        maxUnits = (leftToSpend - 1) / minimumUnitPrice;
                    }
                }
            }
            repairFactories.add(capitol);
            if (capUnit != null) {
                unitsThatCanProduceNeedingRepair.put(capUnit, capUnitTerritory);
            }
            i++;
        }
    }
    int minCost = Integer.MAX_VALUE;
    int i = 0;
    while ((minCost == Integer.MAX_VALUE || leftToSpend >= minCost) && i < 100000) {
        i++;
        for (final ProductionRule rule : rules) {
            final NamedAttachable resourceOrUnit = rule.getResults().keySet().iterator().next();
            if (!(resourceOrUnit instanceof UnitType)) {
                continue;
            }
            final UnitType results = (UnitType) resourceOrUnit;
            if (Matches.unitTypeIsAir().test(results) || Matches.unitTypeIsInfrastructure().test(results) || Matches.unitTypeIsAaForAnything().test(results) || Matches.unitTypeHasMaxBuildRestrictions().test(results) || Matches.unitTypeConsumesUnitsOnCreation().test(results) || Matches.unitTypeIsStatic(player).test(results)) {
                continue;
            }
            final int transportCapacity = UnitAttachment.get(results).getTransportCapacity();
            // buy transports if we can be amphibious
            if (Matches.unitTypeIsSea().test(results)) {
                if (!isAmphib || transportCapacity <= 0) {
                    continue;
                }
            }
            final int cost = rule.getCosts().getInt(pus);
            if (cost < 1) {
                continue;
            }
            if (minCost == Integer.MAX_VALUE) {
                minCost = cost;
            }
            if (minCost > cost) {
                minCost = cost;
            }
            // give a preferene to cheap units, and to transports
            // but dont go overboard with buying transports
            int goodNumberOfTransports = 0;
            final boolean isTransport = transportCapacity > 0;
            if (amphibRoute != null) {
                // 25% transports - can be more if frontier is far away
                goodNumberOfTransports = (landUnitCount / 4);
                // boost for transport production
                if (isTransport && defUnitsAtAmpibRoute > goodNumberOfTransports && landUnitCount > defUnitsAtAmpibRoute && defUnitsAtAmpibRoute > transportCount) {
                    final int transports = (leftToSpend / cost);
                    leftToSpend -= cost * transports;
                    purchase.add(rule, transports);
                    continue;
                }
            }
            final boolean buyBecauseTransport = (Math.random() < 0.7 && transportCount < goodNumberOfTransports) || Math.random() < 0.10;
            final boolean dontBuyBecauseTooManyTransports = transportCount > 2 * goodNumberOfTransports;
            if ((!isTransport && Math.random() * cost < 2) || (isTransport && buyBecauseTransport && !dontBuyBecauseTooManyTransports)) {
                if (cost <= leftToSpend) {
                    leftToSpend -= cost;
                    purchase.add(rule, 1);
                }
            }
        }
    }
    purchaseDelegate.purchase(purchase);
    pause();
}
Also used : IntegerMap(games.strategy.util.IntegerMap) Territory(games.strategy.engine.data.Territory) NamedAttachable(games.strategy.engine.data.NamedAttachable) HashMap(java.util.HashMap) Resource(games.strategy.engine.data.Resource) RepairRule(games.strategy.engine.data.RepairRule) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) TripleAUnit(games.strategy.triplea.TripleAUnit) ProductionRule(games.strategy.engine.data.ProductionRule) UnitType(games.strategy.engine.data.UnitType) Route(games.strategy.engine.data.Route)

Example 14 with Route

use of games.strategy.engine.data.Route in project triplea by triplea-game.

the class ProPurchaseAi method purchaseSeaAndAmphibUnits.

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

Example 15 with Route

use of games.strategy.engine.data.Route in project triplea by triplea-game.

the class ProTechAi method findAttackers.

private static List<Unit> findAttackers(final Territory start, final int maxDistance, final HashSet<Integer> ignoreDistance, final PlayerID player, final GameData data, final Predicate<Unit> unitCondition, final Predicate<Territory> routeCondition, final List<Route> routes, final boolean sea) {
    final IntegerMap<Territory> distance = new IntegerMap<>();
    final Map<Territory, Territory> visited = new HashMap<>();
    final List<Unit> units = new ArrayList<>();
    final Queue<Territory> q = new ArrayDeque<>();
    q.add(start);
    Territory current;
    distance.put(start, 0);
    visited.put(start, null);
    while (!q.isEmpty()) {
        current = q.remove();
        if (distance.getInt(current) == maxDistance) {
            break;
        }
        for (final Territory neighbor : data.getMap().getNeighbors(current)) {
            if (!distance.keySet().contains(neighbor)) {
                if (!neighbor.getUnits().anyMatch(unitCondition)) {
                    if (!routeCondition.test(neighbor)) {
                        continue;
                    }
                }
                if (sea) {
                    final Route r = new Route();
                    r.setStart(neighbor);
                    r.add(current);
                    if (MoveValidator.validateCanal(r, null, player, data) != null) {
                        continue;
                    }
                }
                distance.put(neighbor, distance.getInt(current) + 1);
                visited.put(neighbor, current);
                q.add(neighbor);
                final int dist = distance.getInt(neighbor);
                if (ignoreDistance.contains(dist)) {
                    continue;
                }
                for (final Unit u : neighbor.getUnits()) {
                    if (unitCondition.test(u) && Matches.unitHasEnoughMovementForRoutes(routes).test(u)) {
                        units.add(u);
                    }
                }
            }
        }
    }
    // pain in the ass, should just redesign stop blitz attack
    for (final Territory t : visited.keySet()) {
        final Route r = new Route();
        Territory t2 = t;
        r.setStart(t);
        while (t2 != null) {
            t2 = visited.get(t2);
            if (t2 != null) {
                r.add(t2);
            }
        }
        routes.add(r);
    }
    return units;
}
Also used : IntegerMap(games.strategy.util.IntegerMap) Territory(games.strategy.engine.data.Territory) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Unit(games.strategy.engine.data.Unit) ArrayDeque(java.util.ArrayDeque) Route(games.strategy.engine.data.Route)

Aggregations

Route (games.strategy.engine.data.Route)200 Test (org.junit.jupiter.api.Test)148 Territory (games.strategy.engine.data.Territory)132 Unit (games.strategy.engine.data.Unit)84 UnitType (games.strategy.engine.data.UnitType)83 ITestDelegateBridge (games.strategy.engine.data.ITestDelegateBridge)77 TripleAUnit (games.strategy.triplea.TripleAUnit)70 IntegerMap (games.strategy.util.IntegerMap)69 PlayerID (games.strategy.engine.data.PlayerID)64 ArrayList (java.util.ArrayList)44 GameData (games.strategy.engine.data.GameData)29 ScriptedRandomSource (games.strategy.engine.random.ScriptedRandomSource)26 HashSet (java.util.HashSet)21 HashMap (java.util.HashMap)20 Collection (java.util.Collection)15 List (java.util.List)12 Set (java.util.Set)12 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)11 Change (games.strategy.engine.data.Change)10 MoveValidationResult (games.strategy.triplea.delegate.dataObjects.MoveValidationResult)10