diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProCombatMoveAi.java b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProCombatMoveAi.java index 00ca971f4fa..f04cf45fd3c 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProCombatMoveAi.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProCombatMoveAi.java @@ -105,8 +105,7 @@ Map doCombatMove(final IMoveDelegate moveDel) { } } possibleTransportTerritories.addAll(clearedTerritories); - territoryManager.populateEnemyAttackOptions( - clearedTerritories, new ArrayList<>(possibleTransportTerritories)); + territoryManager.populateEnemyAttackOptions(clearedTerritories, possibleTransportTerritories); determineTerritoriesThatCanBeHeld(attackOptions, clearedTerritories); removeTerritoriesThatArentWorthAttacking(attackOptions); diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProPurchaseAi.java b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProPurchaseAi.java index 2cc1f473717..090dd517477 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProPurchaseAi.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/ProPurchaseAi.java @@ -141,7 +141,6 @@ void repair( */ Map bid( final int pus, final IPurchaseDelegate purchaseDelegate, final GameState startOfTurnData) { - // Current data fields data = proData.getData(); this.startOfTurnData = startOfTurnData; @@ -162,7 +161,6 @@ Map bid( int previousNumUnits = 0; while (true) { - // Determine max enemy attack units and current allied defenders territoryManager.populateEnemyAttackOptions( new ArrayList<>(), new ArrayList<>(purchaseTerritories.keySet())); @@ -257,7 +255,6 @@ Map bid( Map purchase( final IPurchaseDelegate purchaseDelegate, final GameState startOfTurnData) { - // Current data fields data = proData.getData(); this.startOfTurnData = startOfTurnData; @@ -279,15 +276,14 @@ Map purchase( new HashSet<>( CollectionUtils.getMatches( data.getMap().getTerritoriesOwnedBy(player), Matches.territoryIsLand())); - for (final Territory t : purchaseTerritories.keySet()) { - for (final ProPlaceTerritory ppt : purchaseTerritories.get(t).getCanPlaceTerritories()) { + for (final ProPurchaseTerritory t : purchaseTerritories.values()) { + for (final ProPlaceTerritory ppt : t.getCanPlaceTerritories()) { placeTerritories.add(ppt.getTerritory()); } } // Determine max enemy attack units and current allied defenders - territoryManager.populateEnemyAttackOptions( - new ArrayList<>(), new ArrayList<>(placeTerritories)); + territoryManager.populateEnemyAttackOptions(List.of(), placeTerritories); findDefendersInPlaceTerritories(purchaseTerritories); // Prioritize land territories that need defended and purchase additional defenders @@ -660,7 +656,6 @@ private void purchaseDefenders( final List zeroMoveDefensePurchaseOptions, final List airPurchaseOptions, final boolean isLand) { - if (resourceTracker.isEmpty()) { return; } @@ -696,12 +691,10 @@ private void purchaseDefenders( + unusedLocalCarrierCapacity); // Determine if need destroyer - boolean needDestroyer = false; - if (enemyAttackOptions.getMax(t).getMaxUnits().stream() - .anyMatch(Matches.unitHasSubBattleAbilities()) - && ownedLocalUnits.stream().noneMatch(Matches.unitIsDestroyer())) { - needDestroyer = true; - } + boolean needDestroyer = + enemyAttackOptions.getMax(t).getMaxUnits().stream() + .anyMatch(Matches.unitHasSubBattleAbilities()) + && ownedLocalUnits.stream().noneMatch(Matches.unitIsDestroyer()); // Find all purchase territories for place territory final List unitsToPlace = new ArrayList<>(); @@ -709,7 +702,6 @@ private void purchaseDefenders( final List selectedPurchaseTerritories = getPurchaseTerritories(placeTerritory, purchaseTerritories); for (final ProPurchaseTerritory purchaseTerritory : selectedPurchaseTerritories) { - // Check remaining production int remainingUnitProduction = purchaseTerritory.getRemainingUnitProduction(); int remainingConstructions = @@ -741,7 +733,6 @@ private void purchaseDefenders( // Purchase necessary defenders while (true) { - // Select purchase option ProPurchaseValidationUtils.removeInvalidPurchaseOptions( player, @@ -1020,17 +1011,14 @@ private void purchaseLandUnits( // Loop through prioritized territories and purchase land units final Set territoriesToCheck = new HashSet<>(); + final Predicate canMoveLandUnits = + ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties()); + final Predicate isEnemyTerritory = + Matches.isTerritoryOwnedByAnyOf(ProUtils.getEnemyPlayers(player)); for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) { final Set landTerritories = - data.getMap() - .getNeighbors( - placeTerritory.getTerritory(), - 9, - ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties())); - final List enemyLandTerritories = - CollectionUtils.getMatches( - landTerritories, Matches.isTerritoryOwnedByAnyOf(ProUtils.getEnemyPlayers(player))); - territoriesToCheck.addAll(enemyLandTerritories); + data.getMap().getNeighbors(placeTerritory.getTerritory(), 9, canMoveLandUnits); + territoriesToCheck.addAll(CollectionUtils.getMatches(landTerritories, isEnemyTerritory)); } final Map territoryValueMap = ProTerritoryValueUtils.findTerritoryValues( @@ -1081,7 +1069,7 @@ private void purchaseLandUnits( for (final Iterator it = unplacedUnits.iterator(); it.hasNext(); ) { final Unit u = it.next(); if (remainingUnitProduction > 0 - && ProPurchaseValidationUtils.canUnitsBePlaced(proData, List.of(u), player, t, isBid)) { + && ProPurchaseValidationUtils.canUnitBePlaced(proData, u, player, t, isBid)) { remainingUnitProduction--; unitsToPlace.add(u); it.remove(); @@ -1094,7 +1082,6 @@ private void purchaseLandUnits( double attackAndDefenseDifference = 0; boolean selectFodderUnit = true; while (true) { - // Remove options that cost too much PUs or production ProPurchaseValidationUtils.removeInvalidPurchaseOptions( player, diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/data/ProTerritoryManager.java b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/data/ProTerritoryManager.java index 686455abc59..13789e0a3e3 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/data/ProTerritoryManager.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/data/ProTerritoryManager.java @@ -121,7 +121,8 @@ public void populateDefenseOptions(final List clearedTerritories) { } public void populateEnemyAttackOptions( - final List clearedTerritories, final List territoriesToCheck) { + final Collection clearedTerritories, + final Collection territoriesToCheck) { enemyAttackOptions = findEnemyAttackOptions(proData, player, clearedTerritories, territoriesToCheck); } @@ -415,7 +416,7 @@ private static void findAttackOptions( final List transportMapList, final List enemyTerritories, final List alliedTerritories, - final List territoriesToCheck, + final Collection territoriesToCheck, final boolean isCheckingEnemyAttacks, final boolean isIgnoringRelationships) { final GameState data = proData.getData(); @@ -534,8 +535,8 @@ private ProOtherMoveOptions findAlliedAttackOptions(final GamePlayer player) { private static ProOtherMoveOptions findEnemyAttackOptions( final ProData proData, final GamePlayer player, - final List clearedTerritories, - final List territoriesToCheck) { + final Collection clearedTerritories, + final Collection territoriesToCheck) { final GameState data = proData.getData(); // Get enemy players in order of turn diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProPurchaseValidationUtils.java b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProPurchaseValidationUtils.java index f0c8bd667f0..38049989423 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProPurchaseValidationUtils.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProPurchaseValidationUtils.java @@ -18,10 +18,10 @@ import games.strategy.triplea.attachments.TerritoryAttachment; import games.strategy.triplea.delegate.AbstractPlaceDelegate; import games.strategy.triplea.delegate.Matches; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Predicate; +import java.util.stream.Collectors; import lombok.experimental.UtilityClass; import org.triplea.java.collections.CollectionUtils; @@ -49,38 +49,22 @@ public static List findPurchaseOptionsForTerritory( final Territory t, final Territory factoryTerritory, final boolean isBid) { - final List result = new ArrayList<>(); - for (final ProPurchaseOption ppo : purchaseOptions) { - if (ProPurchaseValidationUtils.canTerritoryUsePurchaseOption( - proData, player, ppo, t, factoryTerritory, isBid)) { - result.add(ppo); - } - } - return result; + final Predicate canUsePurchaseOption = + ppo -> { + final List units = ppo.getUnitType().createTemp(ppo.getQuantity(), player); + return ProPurchaseValidationUtils.canUnitsBePlaced( + proData, units, player, t, factoryTerritory, isBid); + }; + return purchaseOptions.stream().filter(canUsePurchaseOption).collect(Collectors.toList()); } - private static boolean canTerritoryUsePurchaseOption( + public static boolean canUnitBePlaced( final ProData proData, - final GamePlayer player, - final ProPurchaseOption ppo, - final Territory t, - final Territory factoryTerritory, - final boolean isBid) { - if (ppo == null) { - return false; - } - final List units = ppo.getUnitType().createTemp(ppo.getQuantity(), player); - return ProPurchaseValidationUtils.canUnitsBePlaced( - proData, units, player, t, factoryTerritory, isBid); - } - - public static boolean canUnitsBePlaced( - final ProData proData, - final List units, + final Unit unit, final GamePlayer player, final Territory t, final boolean isBid) { - return ProPurchaseValidationUtils.canUnitsBePlaced(proData, units, player, t, t, isBid); + return ProPurchaseValidationUtils.canUnitsBePlaced(proData, List.of(unit), player, t, t, isBid); } /** Check if units can be placed in given territory by specified factory. */ diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProUtils.java b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProUtils.java index 446d4602d68..d554f0e25c5 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProUtils.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/util/ProUtils.java @@ -1,21 +1,22 @@ package games.strategy.triplea.ai.pro.util; +import static java.util.function.Predicate.not; + import com.google.common.collect.Streams; import games.strategy.engine.data.GamePlayer; import games.strategy.engine.data.GameSequence; import games.strategy.engine.data.GameState; import games.strategy.engine.data.GameStep; import games.strategy.engine.data.RelationshipTracker; -import games.strategy.engine.data.RelationshipType; import games.strategy.engine.data.Territory; import games.strategy.triplea.Properties; import games.strategy.triplea.attachments.TerritoryAttachment; import games.strategy.triplea.delegate.Matches; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.triplea.java.collections.CollectionUtils; @@ -25,9 +26,8 @@ private ProUtils() {} /** Returns a list of all players in turn order excluding {@code player}. */ public static List getOtherPlayersInTurnOrder(final GamePlayer player) { - final GameState data = player.getData(); final List players = new ArrayList<>(); - final GameSequence sequence = data.getSequence(); + final GameSequence sequence = player.getData().getSequence(); final int startIndex = sequence.getStepIndex(); for (int i = 0; i < sequence.size(); i++) { int currentIndex = startIndex + i; @@ -47,18 +47,16 @@ public static List getOtherPlayersInTurnOrder(final GamePlayer playe } public static List getAlliedPlayersInTurnOrder(final GamePlayer player) { - final GameState data = player.getData(); + final var relationshipTracker = player.getData().getRelationshipTracker(); final List players = getOtherPlayersInTurnOrder(player); - players.removeIf( - currentPlayer -> !data.getRelationshipTracker().isAllied(player, currentPlayer)); + players.removeIf(currentPlayer -> !relationshipTracker.isAllied(player, currentPlayer)); return players; } public static List getEnemyPlayersInTurnOrder(final GamePlayer player) { - final GameState data = player.getData(); + final var relationshipTracker = player.getData().getRelationshipTracker(); final List players = getOtherPlayersInTurnOrder(player); - players.removeIf( - currentPlayer -> data.getRelationshipTracker().isAllied(player, currentPlayer)); + players.removeIf(currentPlayer -> relationshipTracker.isAllied(player, currentPlayer)); return players; } @@ -76,52 +74,39 @@ public static boolean isPlayersTurnFirst( public static List getEnemyPlayers(final GamePlayer player) { final GameState data = player.getData(); - final List enemyPlayers = new ArrayList<>(); - for (final GamePlayer players : data.getPlayerList().getPlayers()) { - if (!data.getRelationshipTracker().isAllied(player, players)) { - enemyPlayers.add(players); - } - } - return enemyPlayers; + return getFilteredPlayers( + data, Matches.isAllied(player, data.getRelationshipTracker()).negate()); } private static List getAlliedPlayers(final GamePlayer player) { final GameState data = player.getData(); - final List alliedPlayers = new ArrayList<>(); - for (final GamePlayer players : data.getPlayerList().getPlayers()) { - if (data.getRelationshipTracker().isAllied(player, players)) { - alliedPlayers.add(players); - } - } - return alliedPlayers; + return getFilteredPlayers(data, Matches.isAllied(player, data.getRelationshipTracker())); } /** Given a player, finds all non-allied (enemy) players. */ public static List getPotentialEnemyPlayers(final GamePlayer player) { - final GameState data = player.getData(); - final List otherPlayers = data.getPlayerList().getPlayers(); - for (final Iterator it = otherPlayers.iterator(); it.hasNext(); ) { - final GamePlayer otherPlayer = it.next(); - final RelationshipType relation = - data.getRelationshipTracker().getRelationshipType(player, otherPlayer); - if (Matches.relationshipTypeIsAllied().test(relation) - || isPassiveNeutralPlayer(otherPlayer)) { - it.remove(); - } - } - return otherPlayers; + final var tracker = player.getData().getRelationshipTracker(); + // Remove allied and passive neutrals. + final Predicate potentialEnemy = + not(Matches.isAllied(player, tracker)).and(not(ProUtils::isPassiveNeutralPlayer)); + return getFilteredPlayers(player.getData(), potentialEnemy); + } + + private static List getFilteredPlayers( + final GameState data, final Predicate filter) { + return data.getPlayerList().getPlayers().stream().filter(filter).collect(Collectors.toList()); } /** Computes PU production amount a given player currently has based on a given game data. */ public static double getPlayerProduction(final GamePlayer player, final GameState data) { + final Predicate canCollectIncomeFrom = + Matches.territoryCanCollectIncomeFrom( + player, data.getProperties(), data.getRelationshipTracker()); int production = 0; for (final Territory place : data.getMap().getTerritories()) { // Match will Check if terr is a Land Convoy Route and check ownership of neighboring Sea // Zone, or if contested - if (place.isOwnedBy(player) - && Matches.territoryCanCollectIncomeFrom( - player, data.getProperties(), data.getRelationshipTracker()) - .test(place)) { + if (place.isOwnedBy(player) && canCollectIncomeFrom.test(place)) { production += TerritoryAttachment.getProduction(place); } } @@ -176,23 +161,15 @@ public static List getLiveAlliedCapitals( */ public static int getClosestEnemyLandTerritoryDistance( final GameState data, final GamePlayer player, final Territory t) { - final Set landTerritories = - data.getMap() - .getNeighbors( - t, - 9, - ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties())); + final Predicate canMoveLandUnits = + ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties()); + final Set landTerritories = data.getMap().getNeighbors(t, 9, canMoveLandUnits); final List enemyLandTerritories = CollectionUtils.getMatches( landTerritories, Matches.isTerritoryOwnedByAnyOf(getPotentialEnemyPlayers(player))); int minDistance = 10; for (final Territory enemyLandTerritory : enemyLandTerritories) { - final int distance = - data.getMap() - .getDistance( - t, - enemyLandTerritory, - ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties())); + final int distance = data.getMap().getDistance(t, enemyLandTerritory, canMoveLandUnits); if (distance < minDistance) { minDistance = distance; } @@ -210,12 +187,9 @@ public static int getClosestEnemyOrNeutralLandTerritoryDistance( final GamePlayer player, final Territory t, final Map territoryValueMap) { - final Set landTerritories = - data.getMap() - .getNeighbors( - t, - 9, - ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties())); + final Predicate canMoveLandUnits = + ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties()); + final Set landTerritories = data.getMap().getNeighbors(t, 9, canMoveLandUnits); final List enemyLandTerritories = CollectionUtils.getMatches( landTerritories, Matches.isTerritoryOwnedByAnyOf(getEnemyPlayers(player))); @@ -224,12 +198,7 @@ public static int getClosestEnemyOrNeutralLandTerritoryDistance( if (territoryValueMap.get(enemyLandTerritory) <= 0) { continue; } - int distance = - data.getMap() - .getDistance( - t, - enemyLandTerritory, - ProMatches.territoryCanPotentiallyMoveLandUnits(player, data.getProperties())); + int distance = data.getMap().getDistance(t, enemyLandTerritory, canMoveLandUnits); if (ProUtils.isNeutralLand(enemyLandTerritory)) { distance++; }