From 6608d2500681947dd6d9df730ac91c76d6f29a7a Mon Sep 17 00:00:00 2001 From: asvitkine Date: Sun, 9 Jul 2023 22:00:34 -0400 Subject: [PATCH 1/2] Rewrite findTargets for better performance. - Avoids O(n^2) destroyer checks. - Avoids an expensive removeAll() call. - Uses a single stream filter to process, removing an unnecessary intermediate collection in the common case when no destroyers are present. Note: This was showing up in performance profiles. --- .../steps/fire/general/TargetGroup.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java b/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java index 16cc2bf706b..bb79e35fa53 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java @@ -7,7 +7,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; -import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -44,13 +43,13 @@ public Collection getTargetUnits(final Collection units) { */ public static List newTargetGroups( final Collection units, final Collection enemyUnits) { - final Set unitTypes = units.stream().map(Unit::getType).collect(Collectors.toSet()); + final boolean destroyerPresent = unitTypes.stream().anyMatch(Matches.unitTypeIsDestroyer()); final Set enemyUnitTypes = enemyUnits.stream().map(Unit::getType).collect(Collectors.toSet()); final List targetGroups = new ArrayList<>(); for (final UnitType unitType : unitTypes) { - final Set targets = findTargets(unitType, unitTypes, enemyUnitTypes); + final Set targets = findTargets(unitType, destroyerPresent, enemyUnitTypes); if (targets.isEmpty()) { continue; } @@ -65,15 +64,21 @@ public static List newTargetGroups( } private static Set findTargets( - final UnitType unitType, final Set unitTypes, final Set enemyUnitTypes) { - final Set targets = new HashSet<>(enemyUnitTypes); - targets.removeAll(unitType.getUnitAttachment().getCanNotTarget()); - return unitTypes.stream().anyMatch(Matches.unitTypeIsDestroyer()) - ? targets - : targets.stream() - .filter( - target -> !target.getUnitAttachment().getCanNotBeTargetedBy().contains(unitType)) - .collect(Collectors.toSet()); + UnitType unitType, boolean destroyerPresent, Set enemyUnitTypes) { + Set cannotTarget = unitType.getUnitAttachment().getCanNotTarget(); + // Note: uses a single stream instead of a sequence of removeAll() calls for performance. + return enemyUnitTypes.stream() + .filter( + ut -> { + if (cannotTarget.contains(ut)) { + return false; + } + if (destroyerPresent) { + return true; + } + return !ut.getUnitAttachment().getCanNotBeTargetedBy().contains(unitType); + }) + .collect(Collectors.toSet()); } private static Optional findTargetsInTargetGroups( From 32f265c0748a2eacef4845f775fc5572ab59719a Mon Sep 17 00:00:00 2001 From: asvitkine Date: Sun, 9 Jul 2023 22:02:39 -0400 Subject: [PATCH 2/2] Better variable name. --- .../delegate/battle/steps/fire/general/TargetGroup.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java b/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java index bb79e35fa53..ada01ff32b5 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/delegate/battle/steps/fire/general/TargetGroup.java @@ -69,14 +69,14 @@ private static Set findTargets( // Note: uses a single stream instead of a sequence of removeAll() calls for performance. return enemyUnitTypes.stream() .filter( - ut -> { - if (cannotTarget.contains(ut)) { + targetUnitType -> { + if (cannotTarget.contains(targetUnitType)) { return false; } if (destroyerPresent) { return true; } - return !ut.getUnitAttachment().getCanNotBeTargetedBy().contains(unitType); + return !targetUnitType.getUnitAttachment().getCanNotBeTargetedBy().contains(unitType); }) .collect(Collectors.toSet()); }