5
5
6
6
import java .util .Collection ;
7
7
import java .util .Collections ;
8
+ import java .util .Objects ;
8
9
import java .util .function .ToIntFunction ;
9
10
11
+ import static java .lang .Math .min ;
12
+
10
13
/**
11
14
* Used to simulate 2 groups of agents engaging each other. Either use the default constructor which
12
15
* initialized the default behavior or customize the behaviors. Ie. if you want to simulate one
23
26
* Be cautious when modifying {@link Agent}s after they have been added to the simulation.
24
27
*/
25
28
public class Simulator {
26
- /**
27
- * Use to count health and shields as equal, maybe useful in PvP?
28
- */
29
+ /** Use to count health and shields as equal, maybe useful in PvP? */
29
30
public static final ToIntFunction <Agent > HEALTH_AND_SHIELD =
30
- agent -> agent .getHealth () + agent .getShields ();
31
- /**
32
- * Use to count shields as half the value of health.
33
- */
31
+ agent -> agent .getHealth () + agent .getShields ();
32
+ /** Use to count shields as half the value of health. */
34
33
public static final ToIntFunction <Agent > HEALTH_AND_HALFED_SHIELD =
35
- agent -> agent .getHealth () + agent .getShields () / 2 ;
34
+ agent -> agent .getHealth () + agent .getShields () / 2 ;
36
35
37
36
private static final int MAX_MAP_DIMENSION = 8192 ;
38
37
private static final int TILE_SIZE = 16 ;
@@ -46,14 +45,28 @@ public class Simulator {
46
45
final byte [] collision = new byte [COLLISION_MAP_DIMENSION * COLLISION_MAP_DIMENSION ];
47
46
private final Behavior playerABehavior ;
48
47
private final Behavior playerBBehavior ;
48
+ private final int frameSkip ;
49
49
50
50
public Simulator () {
51
- this (new RoleBasedBehavior (), new RoleBasedBehavior () );
51
+ this (1 );
52
52
}
53
53
54
54
public Simulator (Behavior playerABehavior , Behavior playerBBehavior ) {
55
+ this (1 , playerABehavior , playerBBehavior );
56
+ }
57
+
58
+ public Simulator (int frameSkip ) {
59
+ this (frameSkip , new RoleBasedBehavior (), new RoleBasedBehavior ());
60
+ }
61
+
62
+ public Simulator (int frameSkip , Behavior playerABehavior , Behavior playerBBehavior ) {
63
+ if (frameSkip < 1 ) throw new IllegalArgumentException ("frameSkip must be >= 1" );
64
+ Objects .requireNonNull (playerABehavior , "Behavior of player A must be set" );
65
+ Objects .requireNonNull (playerBBehavior , "Behavior of player B must be set" );
66
+
55
67
this .playerABehavior = playerABehavior ;
56
68
this .playerBBehavior = playerBBehavior ;
69
+ this .frameSkip = frameSkip ;
57
70
}
58
71
59
72
public Simulator addAgentA (Agent agent ) {
@@ -127,7 +140,9 @@ public int simulate() {
127
140
* @return the actual number of frames simulated, usually the given number of frames
128
141
*/
129
142
public int simulate (int frames ) {
130
- while (frames -- != 0 && !playerA .isEmpty () && !playerB .isEmpty ()) {
143
+ if (frames > 0 ) frames = (frames + frameSkip - 1 ) / frameSkip ;
144
+ while (frames != 0 && !playerA .isEmpty () && !playerB .isEmpty ()) {
145
+ frames -= frameSkip ;
131
146
if (!step ()) {
132
147
break ;
133
148
}
@@ -166,14 +181,14 @@ private boolean step() {
166
181
simRunning |=
167
182
agent .isLockeddown
168
183
|| agent .isStasised
169
- || playerABehavior .simUnit (agent , playerA , playerB );
184
+ || playerABehavior .simUnit (frameSkip , agent , playerA , playerB );
170
185
}
171
186
for (int i = playerB .size () - 1 ; i >= 0 ; i --) {
172
187
Agent agent = playerB .get (i );
173
188
simRunning |=
174
189
agent .isLockeddown
175
190
|| agent .isStasised
176
- || playerBBehavior .simUnit (agent , playerB , playerA );
191
+ || playerBBehavior .simUnit (frameSkip , agent , playerB , playerA );
177
192
}
178
193
removeDead (playerA );
179
194
removeDead (playerB );
@@ -206,31 +221,14 @@ private void updateStats(UnorderedCollection<Agent> agents) {
206
221
agent .vy = 0 ;
207
222
agent .healedThisFrame = false ;
208
223
209
- if (agent .cooldown > 0 ) {
210
- agent .cooldown --;
211
- }
212
- if (agent .shieldsShifted < agent .maxShieldsShifted ) {
213
- agent .shieldsShifted += 7 ;
214
- if (agent .shieldsShifted > agent .maxShieldsShifted ) {
215
- agent .shieldsShifted = agent .maxShieldsShifted ;
216
- }
217
- }
218
- if (agent .plagueDamagePerFrameShifted < agent .healthShifted ) {
219
- agent .healthShifted -= agent .plagueDamagePerFrameShifted ;
220
- }
221
- if (agent .remainingStimFrames > 0 ) {
222
- agent .remainingStimFrames --;
223
- }
224
- if (agent .regeneratesHealth && agent .healthShifted < agent .maxHealthShifted ) {
225
- agent .healthShifted += 4 ;
226
- if (agent .healthShifted > agent .maxHealthShifted ) {
227
- agent .healthShifted = agent .maxHealthShifted ;
228
- }
229
- }
230
- agent .energyShifted += 8 ;
231
- if (agent .energyShifted > agent .maxEnergyShifted ) {
232
- agent .energyShifted = agent .maxEnergyShifted ;
233
- }
224
+ agent .cooldown = agent .cooldown - frameSkip ;
225
+ agent .shieldsShifted = min (agent .maxShieldsShifted , agent .shieldsShifted + 7 * frameSkip );
226
+ if (agent .plagueDamagePerFrameShifted * frameSkip < agent .healthShifted )
227
+ agent .healthShifted -= agent .plagueDamagePerFrameShifted * frameSkip ;
228
+ agent .remainingStimFrames = agent .remainingStimFrames - frameSkip ;
229
+ if (agent .regeneratesHealth )
230
+ agent .healthShifted = min (agent .maxHealthShifted , agent .healthShifted + 4 * frameSkip );
231
+ agent .energyShifted = min (agent .energyShifted + 8 * frameSkip , agent .maxEnergyShifted );
234
232
}
235
233
}
236
234
@@ -290,18 +288,21 @@ public RoleBasedBehavior() {
290
288
291
289
@ Override
292
290
public boolean simUnit (
293
- Agent agent , UnorderedCollection <Agent > allies , UnorderedCollection <Agent > enemies ) {
291
+ int frameSkip ,
292
+ Agent agent ,
293
+ UnorderedCollection <Agent > allies ,
294
+ UnorderedCollection <Agent > enemies ) {
294
295
if (agent .isSuicider ) {
295
- return suiciderSimulator .simUnit (agent , allies , enemies );
296
+ return suiciderSimulator .simUnit (frameSkip , agent , allies , enemies );
296
297
}
297
298
if (agent .isHealer ) {
298
- return healerSimulator .simUnit (agent , allies , enemies );
299
+ return healerSimulator .simUnit (frameSkip , agent , allies , enemies );
299
300
}
300
- if (agent .isRepairer && repairerSimulator .simUnit (agent , allies , enemies )) {
301
+ if (agent .isRepairer && repairerSimulator .simUnit (frameSkip , agent , allies , enemies )) {
301
302
return true ;
302
303
// Otherwise FIGHT, you puny SCV!
303
304
}
304
- return attackerSimulator .simUnit (agent , allies , enemies );
305
+ return attackerSimulator .simUnit (frameSkip , agent , allies , enemies );
305
306
}
306
307
}
307
308
@@ -312,7 +313,10 @@ public boolean simUnit(
312
313
public interface Behavior {
313
314
314
315
boolean simUnit (
315
- Agent agent , UnorderedCollection <Agent > allies , UnorderedCollection <Agent > enemies );
316
+ int frameSkip ,
317
+ Agent agent ,
318
+ UnorderedCollection <Agent > allies ,
319
+ UnorderedCollection <Agent > enemies );
316
320
}
317
321
318
322
public static class IntEvaluation {
@@ -333,7 +337,6 @@ public int delta() {
333
337
return evalA - evalB ;
334
338
}
335
339
336
-
337
340
public int dot (IntEvaluation other ) {
338
341
return evalA * other .evalA - evalB * other .evalB ;
339
342
}
0 commit comments