-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPlayGod.java
More file actions
424 lines (408 loc) · 13.1 KB
/
PlayGod.java
File metadata and controls
424 lines (408 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
package assign2;
import java.util.*;
/** Controls the creation and development of the creatures, monsters and
worlds.
*/
public class PlayGod{
/**contains all the monsters.*/
private static Monster[] monsters;
/**contains all the creatures.*/
private static Creature[] creatures;
/**the amount of energy eating a berry gives a creature*/
private static int foodEnergy = 0;
/**the amount of energy lost per turn for a creature*/
private static int energyLoss = 0;
/**The starting energy each creature has*/
private static int startingEnergy = 0;
/**the length of the world, default set to 2*/
private static int worldLength = 2;
/**the width of the world, default set to 2*/
private static int worldWidth = 2;
/**The number of generations left to go through, default set to 1*/
private static int generationCount = 1;
/**number of turns per generations*/
private static int numTurns = 99;
/**the number of turns a creature get before a monster does,
* default set to 2*/
private static int monsterDelay = 2;
/**Total number of monsers in the world*/
private static int numMonsters = 1;
/**creates creatures and monsters and passes them to a world
number of generation times.
@param args, input from command line, unused.
*/
public static void main(String[] args){
int count = 0;
World world = firstCase();
world.run();
generationCount--;
System.out.println("fitness: " + getFitness());
while(generationCount > 0){
if(!evolve()){
break;
}
world = new World(worldLength, worldWidth, monsterDelay, creatures, monsters, numTurns);
world.run();
generationCount--;
System.err.println(getFitness());
count++;
System.out.println(count);
}
}
/**Takes user input and passes it to on to build the creatures and monsters
based on this.
* @return the world user input creates.
*/
public static World firstCase(){
Random variableSelect = new Random();
Scanner input = new Scanner(System.in);
int numCreatures = 1;
boolean correctInput = false;
int[][] berryGrid, mushroomGrid;
System.out.println("What length and width would you like the world? (Must be integers)");
while(!correctInput){
if(input.hasNextInt()){
worldLength = input.nextInt();
if(worldLength < 2){
System.out.println("Min value is 2.");
}
else if(input.hasNextInt()){
worldWidth = input.nextInt();
if(worldWidth < 2){
System.out.println("Min value is 2.");
}
else{
correctInput = true;
}
}
}
if(!correctInput){
System.out.println("Try again.");
}
}
correctInput = false;
System.out.println("How many Creatures and Monsters would you like?");
while(!correctInput){
if(input.hasNextInt()){
numCreatures = input.nextInt();
if(numCreatures < 1){
System.out.println("Min value is 1.");
}
else if(input.hasNextInt()){
numMonsters = input.nextInt();
if(numMonsters < 1){
System.out.println("Min value is 1.");
}
else{
correctInput = true;
}
}
}
if(!correctInput){
System.out.println("Try again.");
}
}
correctInput = false;
System.out.println("How many turns do you want each creature to have");
while(!correctInput){
if(input.hasNextInt()){
numTurns = input.nextInt();
if(numTurns < 1){
System.out.println("Min number is 1.\nTry again.");
}
else{
correctInput = true;
}
}
}
correctInput = false;
System.out.println("How many moves do you want per creature before the monsters have a turn?");
while(!correctInput){
if(input.hasNextInt()){
monsterDelay = input.nextInt();
if(monsterDelay < 1){
System.out.println("Min number is 1.\nTry again.");
}
else{
correctInput = true;
}
}
}
correctInput = false;
System.out.println("How much energy should the creatures start with?");
while(!correctInput){
if(input.hasNextInt()){
startingEnergy = input.nextInt();
if(startingEnergy < 1){
System.out.println("Min number is 1.\nTry again.");
}
else{
correctInput = true;
}
}
}
correctInput = false;
System.out.println("What is the energy loss per turn, and gain for eating berries? (Must be integers)");
while(!correctInput){
if(input.hasNextInt()){
energyLoss = input.nextInt();
if(energyLoss < 1){
System.out.println("Min value is 1.");
}
else if(input.hasNextInt()){
foodEnergy = input.nextInt();
if(foodEnergy < 1){
System.out.println("Min value is 1.");
}
else{
correctInput = true;
}
}
}
if(!correctInput){
System.out.println("Try again.");
}
}
correctInput = false;
System.out.println("How many generations do you want?");
while(!correctInput){
if(input.hasNextInt()){
generationCount = input.nextInt();
if(generationCount < 1){
System.out.println("Min number is 1.\nTry again.");
}
else{
correctInput = true;
}
}
}
creatures = makeCreatures(numCreatures, variableSelect);
monsters = makeMonsters(numMonsters, variableSelect);
return new World(worldLength, worldWidth, monsterDelay, creatures, monsters, numTurns);
}
/**makes num creatures.
* @param num, the number of creatures.
* @param variableSelect the random number generator used for picking variables.
* @return the array of creatures created.
*/
public static Creature[] makeCreatures(int num, Random variableSelect){
Creature[] creatures = new Creature[num];
int x, y, eatStrawberryInt, eatMushroomInt, reactStrawberry,
reactMushroom, reactMonster, reactCreature, defaultMove, eSWeight,
eMRWeight, rSWeight, rMRWeight, rMonWeight, rCWeight,
maxX = worldLength, maxY = worldWidth;
boolean eatStrawberry, eatMushroom;
for(int i = 0; i < num; i++){
x = variableSelect.nextInt(maxX);
y = variableSelect.nextInt(maxY);
eatStrawberryInt = variableSelect.nextInt(2);
if(eatStrawberryInt == 1){
eatStrawberry = true;
}
else{
eatStrawberry = false;
}
eatMushroomInt = variableSelect.nextInt(2);
if(eatMushroomInt == 1){
eatMushroom = true;
}
else{
eatMushroom = false;
}
reactStrawberry = variableSelect.nextInt(4) + 1;
reactMushroom = variableSelect.nextInt(4) + 1;
reactMonster = variableSelect.nextInt(4) + 1;
reactCreature = variableSelect.nextInt(4) + 1;
defaultMove = variableSelect.nextInt(5) + 1;
eSWeight = variableSelect.nextInt(1000) + 1;
eMRWeight = variableSelect.nextInt(1000) + 1;
rSWeight = variableSelect.nextInt(1000) + 1;
rMRWeight = variableSelect.nextInt(1000) + 1;
rMonWeight = variableSelect.nextInt(1000) + 1;
rCWeight = variableSelect.nextInt(1000) + 1;
creatures[i] = new Creature(x,y, startingEnergy, eatStrawberry, eatMushroom,
reactStrawberry, reactMushroom, reactMonster, reactCreature, defaultMove,
eSWeight, eMRWeight, rSWeight, rMRWeight, rMonWeight, rCWeight, foodEnergy, energyLoss);
}
return creatures;
}
/**makes num monsters.
* @param num, the number of monsters.
* @param variableSelect the random number generator used for picking variables.
* @return the array of monsters created.
*/
public static Monster[] makeMonsters(int num, Random variableSelect){
Monster[] monsters = new Monster[num];
int x, y, maxX = worldLength, maxY = worldWidth;
for(int i = 0; i < num; i++){
x = variableSelect.nextInt(maxX);
y = variableSelect.nextInt(maxY);
monsters[i] = new Monster(x,y);
}
return monsters;
}
/**setups the creatures to be passed on to the mating method.
@return returns true if there are any creatures left.
*/
public static boolean evolve(){
ArrayList<Creature> aliveCreatures = new ArrayList<Creature>();
Creature[] matingCreatures;
int size;
for(int i = 0; i < creatures.length; i++){
if(creatures[i].isAlive()){
aliveCreatures.add(creatures[i]);
}
}
if((size = aliveCreatures.size()) == 0){
System.out.println("Extinction");
return false;
}
else{
matingCreatures = aliveCreatures.toArray(new Creature[size]);
mate(matingCreatures);
}
return true;
}
/**Makes the same number of new creatures as for the next generation as there
* were creatures this generation by repeatively taking two creatures from
* aliveCreatures based on weighted random selection and passes them onto
* genesplice to create a new ceature.
* @param aliveCreatures an array of alive creatures.
*/
public static void mate(Creature[] aliveCreatures){
Random selectiveBreading = new Random();
Creature[] newCreatures = new Creature[creatures.length];
Creature creatureA, creatureB;
boolean found = false;
int totalE, creatureAIndex, creatureBIndex, cAIndex = 0, cBIndex = 0;
int[] creaturesE = new int[aliveCreatures.length];
monsters = makeMonsters(numMonsters, selectiveBreading);
creaturesE[0] = aliveCreatures[0].getEnergy();
totalE = creaturesE[0];
for(int i = 1; i < creaturesE.length; i++){
creaturesE[i] = creaturesE[i-1] + (aliveCreatures[i].getEnergy());
totalE += creaturesE[i];
}
for(int i = 0; i < newCreatures.length; i++){
creatureAIndex = selectiveBreading.nextInt(totalE);
creatureBIndex = selectiveBreading.nextInt(totalE);
for(int j = 0; j < creaturesE.length; j++){
if(creatureAIndex <= creaturesE[j]){
cAIndex = j;
break;
}
}
for(int j = 0; j < creaturesE.length; j++){
if(creatureBIndex <= creaturesE[j]){
cBIndex = j;
break;
}
}
creatureA = aliveCreatures[cAIndex];
creatureB = aliveCreatures[cBIndex];
newCreatures[i] = geneSplice(creatureA, creatureB, selectiveBreading);
}
creatures = newCreatures;
}
/**Builds a new creature based on the two parent creatures by taking a random point within the chromosome
*and taking everything up to that point from creature a and everything beyond that point from creature b
*then mutating the chromosome and passing this into the new creature.
*@param a Creatures a, used for mating.
* @param b Creature b, used for mating.
* @param splicePointSelector used to pick the point in the chromosome to splice.
* @return the new Creature.
*/
public static Creature geneSplice(Creature a, Creature b, Random splicePointSelector){
int splicePoint = splicePointSelector.nextInt(13), x = splicePointSelector.nextInt(worldWidth), y = splicePointSelector.nextInt(worldLength);
int[] chromosomeA = a.extractChromosome(), chromosomeB = b.extractChromosome(), newChromosome = new int[13];
boolean eatBerry = false, eatMushroom = false;
for(int i = 0; i < splicePoint; i++){
newChromosome[i] = chromosomeA[i];
}
for(int i = splicePoint; i < newChromosome.length; i++){
newChromosome[i] = chromosomeB[i];
}
newChromosome = mutate(newChromosome);
if(newChromosome[0] == 1){
eatBerry = true;
}
if(newChromosome[1] == 1){
eatMushroom = true;
}
return new Creature(x, y, startingEnergy, eatBerry, eatMushroom, newChromosome[2], newChromosome[3], newChromosome[4], newChromosome[5],
newChromosome[6], newChromosome[7], newChromosome[8], newChromosome[9], newChromosome[10],
newChromosome[11], newChromosome[12], foodEnergy, energyLoss);
}
/**Takes the chromosome and 1 in 200 times it changes it to a different gene.
* @param the creatures chromosome.
* @return the possibly updates creature chromosome.
*/
public static int[] mutate(int[] chromosome){
Random random = new Random();
int num = 100, num2 = 200;
int chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[0] = random.nextInt(2);
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[1] = random.nextInt(2);
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[2] = random.nextInt(4) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[3] = random.nextInt(4) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[4] = random.nextInt(4) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[5] = random.nextInt(4) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[6] = random.nextInt(4) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[7] = random.nextInt(1000) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[8] = random.nextInt(1000) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[9] = random.nextInt(1000) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[10] = random.nextInt(1000) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[11] = random.nextInt(1000) + 1;
}
chance = random.nextInt(num2) + 1;
if(chance == num){
chromosome[12] = random.nextInt(1000) + 1;
}
return chromosome;
}
/**Gets the total energy of the creatures
*/
public static double getFitness(){
double energy = 0.0, hold = 0.0;
for(int i = 0; i < creatures.length; i++){
if((hold = creatures[i].getEnergy()) >= 0){
energy += hold;
}
}
return energy;
}
}