11package bwapi ;
22
3+ import java .util .ArrayList ;
4+ import java .util .Collections ;
5+ import java .util .HashMap ;
6+ import java .util .List ;
7+ import java .util .Map ;
8+ import java .util .function .Function ;
9+ import java .util .function .Predicate ;
10+ import java .util .function .Supplier ;
11+ import java .util .stream .Collectors ;
312
413class Cache <T > {
514 private int frame = -1 ;
@@ -35,4 +44,83 @@ class BooleanCache extends Cache<Boolean>{}
3544class OrderCache extends Cache <Order >{}
3645class UnitTypeCache extends Cache <UnitType >{}
3746class UpgradeTypeCache extends Cache <UpgradeType >{}
38- class TechTypeCache extends Cache <TechType >{}
47+ class TechTypeCache extends Cache <TechType >{}
48+
49+ class ConnectedUnitCache {
50+ private int lastUpdate = -1 ;
51+ private final Map <Unit , List <Unit >> connectedUnits = new HashMap <>();
52+ private final Function <Unit , Unit > condition ;
53+ private final Game game ;
54+
55+ ConnectedUnitCache (final Game game , final Function <Unit , Unit > condition ) {
56+ this .game = game ;
57+ this .condition = condition ;
58+ }
59+
60+ /**
61+ * Lazily update connectedUnits. Only users of the calls pay for it, and only
62+ * pay once per frame.
63+ * Avoids previous O(n^2) implementation which would be costly for
64+ * lategame carrier fights
65+ */
66+ List <Unit > getConnected (final Unit unit ) {
67+ final int frame = game .getFrameCount ();
68+ if (lastUpdate < frame ) {
69+ connectedUnits .values ().forEach (List ::clear );
70+ for (final Unit u : game .getAllUnits ()) {
71+ final Unit owner = condition .apply (u );
72+ if (owner != null ) {
73+ connectedUnits .computeIfAbsent (owner , k -> new ArrayList <>()).add (u );
74+ }
75+ }
76+ lastUpdate = frame ;
77+ }
78+ List <Unit > connected = connectedUnits .get (unit );
79+ return connected == null ?
80+ Collections .emptyList () :
81+ Collections .unmodifiableList (connected );
82+ }
83+
84+ void reset () {
85+ lastUpdate = -1 ;
86+ connectedUnits .clear ();
87+ }
88+ }
89+
90+ /**
91+ * Lazily filters and caches an unmodifiable List<Unit> at most once per frame.
92+ * Only callers of the corresponding getter pay for the filtering, and at most once per frame.
93+ */
94+ class UnitListCache {
95+ private final Game game ;
96+ private final Supplier <List <Unit >> source ;
97+ private final Predicate <Unit > filter ;
98+ private int lastFrame = -1 ;
99+ private List <Unit > cached = Collections .emptyList ();
100+
101+ UnitListCache (final Game game , final Predicate <Unit > filter ) {
102+ this (game , game ::getAllUnits , filter );
103+ }
104+
105+ UnitListCache (final Game game , final Supplier <List <Unit >> source , final Predicate <Unit > filter ) {
106+ this .game = game ;
107+ this .source = source ;
108+ this .filter = filter ;
109+ }
110+
111+ List <Unit > get () {
112+ final int frame = game .getFrameCount ();
113+ if (lastFrame != frame ) {
114+ cached = source .get ().stream ()
115+ .filter (filter )
116+ .collect (Collectors .collectingAndThen (Collectors .toList (), Collections ::unmodifiableList ));
117+ lastFrame = frame ;
118+ }
119+ return cached ;
120+ }
121+
122+ void reset () {
123+ lastFrame = -1 ;
124+ cached = Collections .emptyList ();
125+ }
126+ }
0 commit comments