-
Notifications
You must be signed in to change notification settings - Fork 0
/
Population.pde
222 lines (198 loc) · 8.71 KB
/
Population.pde
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
class Population {
ArrayList<Player> pop = new ArrayList<Player>();
Player bestPlayer;//the best ever player
int bestScore =0;//the score of the best ever player
int gen;
ArrayList<connectionHistory> innovationHistory = new ArrayList<connectionHistory>();
ArrayList<Player> genPlayers = new ArrayList<Player>();
ArrayList<Species> species = new ArrayList<Species>();
boolean massExtinctionEvent = false;
boolean newStage = false;
int populationLife = 0;
//------------------------------------------------------------------------------------------------------------------------------------------
//constructor
Population(int size) {
for (int i =0; i<size; i++) {
pop.add(new Player());
pop.get(i).brain.generateNetwork();
pop.get(i).brain.mutate(innovationHistory);
}
}
//------------------------------------------------------------------------------------------------------------------------------------------
//update all the players which are alive
void updateAlive() {
populationLife ++;
for (int i = 0; i< pop.size(); i++) {
if (!pop.get(i).dead) {
pop.get(i).look();//get inputs for brain
pop.get(i).think();//use outputs from neural network
pop.get(i).update();//move the player according to the outputs from the neural network
if (!showNothing) {
pop.get(i).show();
}
}
}
}
//------------------------------------------------------------------------------------------------------------------------------------------
//returns true if all the players are dead sad
boolean done() {
for (int i = 0; i< pop.size(); i++) {
if (!pop.get(i).dead) {
return false;
}
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//sets the best player globally and for this gen
void setBestPlayer() {
Player tempBest = species.get(0).players.get(0);
tempBest.gen = gen;
//if best this gen is better than the global best score then set the global best as the best this gen
if (tempBest.score > bestScore) {
genPlayers.add(tempBest.cloneForReplay());
println("old best:", bestScore);
println("new best:", tempBest.score);
bestScore = tempBest.score;
bestPlayer = tempBest.cloneForReplay();
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------
//this function is called when all the players in the population are dead and a new generation needs to be made
void naturalSelection() {
speciate();//seperate the population into species
calculateFitness();//calculate the fitness of each player
sortSpecies();//sort the species to be ranked in fitness order, best first
if (massExtinctionEvent) {
massExtinction();
massExtinctionEvent = false;
}
cullSpecies();//kill off the bottom half of each species
setBestPlayer();//save the best player of this gen
killStaleSpecies();//remove species which haven't improved in the last 15(ish) generations
killBadSpecies();//kill species which are so bad that they cant reproduce
println("generation", gen, "Number of mutations", innovationHistory.size(), "species: " + species.size(), "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
float averageSum = getAvgFitnessSum();
ArrayList<Player> children = new ArrayList<Player>();//the next generation
println("Species:");
for (int j = 0; j < species.size(); j++) {//for each species
println("best unadjusted fitness:", species.get(j).bestFitness);
for (int i = 0; i < species.get(j).players.size(); i++) {
print("player " + i, "fitness: " + species.get(j).players.get(i).fitness, "score " + species.get(j).players.get(i).score, ' ');
}
println();
children.add(species.get(j).champ.clone());//add champion without any mutation
int NoOfChildren = floor(species.get(j).averageFitness/averageSum * pop.size()) -1;//the number of children this species is allowed, note -1 is because the champ is already added
for (int i = 0; i< NoOfChildren; i++) {//get the calculated amount of children from this species
children.add(species.get(j).giveMeBaby(innovationHistory));
}
}
while (children.size() < pop.size()) {//if not enough babies (due to flooring the number of children to get a whole int)
children.add(species.get(0).giveMeBaby(innovationHistory));//get babies from the best species
}
pop.clear();
pop = (ArrayList)children.clone(); //set the children as the current population
gen+=1;
for (int i = 0; i< pop.size(); i++) {//generate networks for each of the children
pop.get(i).brain.generateNetwork();
}
populationLife = 0;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//seperate population into species based on how similar they are to the leaders of each species in the previous gen
void speciate() {
for (Species s : species) {//empty species
s.players.clear();
}
for (int i = 0; i< pop.size(); i++) {//for each player
boolean speciesFound = false;
for (Species s : species) {//for each species
if (s.sameSpecies(pop.get(i).brain)) {//if the player is similar enough to be considered in the same species
s.addToSpecies(pop.get(i));//add it to the species
speciesFound = true;
break;
}
}
if (!speciesFound) {//if no species was similar enough then add a new species with this as its champion
species.add(new Species(pop.get(i)));
}
}
}
//------------------------------------------------------------------------------------------------------------------------------------------
//calculates the fitness of all of the players
void calculateFitness() {
for (int i =1; i<pop.size(); i++) {
pop.get(i).calculateFitness();
}
}
//------------------------------------------------------------------------------------------------------------------------------------------
//sorts the players within a species and the species by their fitnesses
void sortSpecies() {
//sort the players within a species
for (Species s : species) {
s.sortSpecies();
}
//sort the species by the fitness of its best player
//using selection sort like a loser
ArrayList<Species> temp = new ArrayList<Species>();
for (int i = 0; i < species.size(); i ++) {
float max = 0;
int maxIndex = 0;
for (int j = 0; j< species.size(); j++) {
if (species.get(j).bestFitness > max) {
max = species.get(j).bestFitness;
maxIndex = j;
}
}
temp.add(species.get(maxIndex));
species.remove(maxIndex);
i--;
}
species = (ArrayList)temp.clone();
}
//------------------------------------------------------------------------------------------------------------------------------------------
//kills all species which haven't improved in 15 generations
void killStaleSpecies() {
for (int i = 2; i< species.size(); i++) {
if (species.get(i).staleness >= 15) {
species.remove(i);
i--;
}
}
}
//------------------------------------------------------------------------------------------------------------------------------------------
//if a species sucks so much that it wont even be allocated 1 child for the next generation then kill it now
void killBadSpecies() {
float averageSum = getAvgFitnessSum();
for (int i = 1; i< species.size(); i++) {
if (species.get(i).averageFitness/averageSum * pop.size() < 1) {//if wont be given a single child
species.remove(i);//sad
i--;
}
}
}
//------------------------------------------------------------------------------------------------------------------------------------------
//returns the sum of each species average fitness
float getAvgFitnessSum() {
float averageSum = 0;
for (Species s : species) {
averageSum += s.averageFitness;
}
return averageSum;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//kill the bottom half of each species
void cullSpecies() {
for (Species s : species) {
s.cull(); //kill bottom half
s.fitnessSharing();//also while we're at it lets do fitness sharing
s.setAverage();//reset averages because they will have changed
}
}
void massExtinction() {
for (int i =5; i< species.size(); i++) {
species.remove(i);//sad
i--;
}
}
}