-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPopulation.pde
More file actions
215 lines (171 loc) · 7.47 KB
/
Population.pde
File metadata and controls
215 lines (171 loc) · 7.47 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
class Population {
Snake[] snakes;//all the snakes in the population
int gen = 1;//which generation we are up to
int globalBest = 4;// the best score ever achieved by this population
long globalBestFitness = 0; // the best fitness ever achieved by this population
int currentBest = 4;//the current best score
int currentBestSnake = 0; //the position of the current best snake (highest score) in the array
Snake globalBestSnake; //a clone of the best snake this population has ever seen
int populationID = floor(random(10000)); // a random number to identify the population, used for saving snakes
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//constructor
Population(int size) {
snakes = new Snake[size];
//initiate all the snakes
for (int i =0; i<snakes.length; i++) {
snakes[i] = new Snake();
}
globalBestSnake = snakes[0].clone();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//used to help improve legends
Population(int size, Snake best) {
snakes = new Snake[size];
//set all the snakes as mutated clones of the legend snake
for (int i =0; i<snakes.length; i++) {
snakes[i] = best.clone();
snakes[i].mutate(globalMutationRate);
}
globalBestSnake = best.clone();
}
//used to help improve legends
Population(Snake best) {
snakes = new Snake[2000];
//set all the snakes as the legend snake
for (int i =0; i<snakes.length; i++) {
snakes[i] = best.clone();
snakes[i].test = true;
}
//globalBestSnake = best.clone();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//updates all the snakes in the population which are currently alive
void updateAlive() {
for (int i = 0; i< snakes.length; i++) {
if (snakes[i].alive) {
snakes[i].look(); //get inputs for brain
snakes[i].setVelocity(); //get outputs from the neural net
snakes[i].move(); //move the snake in the direction indicated by the neural net
if (snakes[i].alive && (showAll || (i == currentBestSnake)))//if still alive show the snake
{
snakes[i].show();
}
}
}
setCurrentBest(); //after updating every snake renew the best snake
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//test if all the snakes in this population are dead
boolean done() {
for (int i = 0; i< snakes.length; i++) {
if (snakes[i].alive) {
return false;
}
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//calculates fitness of every snake
void calcFitness() {
for (int i = 0; i< snakes.length; i++) {
snakes[i].calcFitness();
}
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//creates the next generation of snakes by natural selection
void naturalSelection() {
Snake[] newSnakes = new Snake[snakes.length]; //next generation of snakes
//set the first snake as the best snake without crossover or mutation
setBestSnake();
newSnakes[0] = globalBestSnake.clone();
for (int i = 1; i<newSnakes.length; i++) {
//select 2 parents based on fitness
Snake parent1 = selectSnake();
Snake parent2 = selectSnake();
//crossover the 2 snakes to create the child
Snake child = parent1.crossover(parent2);
//mutate the child (weird thing to type)
child.mutate(globalMutationRate);
//add the child to the next generation
newSnakes[i] = child;
//newSnakes[i] = selectSnake().clone().mutate(globalMutationRate); //uncomment this line to do natural selection without crossover
}
snakes = newSnakes.clone();// set the current generation to the next generation
gen+=1;
currentBest = 4;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//chooses snake from the population to return randomly(considering fitness)
Snake selectSnake() {
//this function works by randomly choosing a value between 0 and the sum of all the fitnesses
//then go through all the snakes and add their fitness to a running sum and if that sum is greater than the random value generated that snake is chosen
//since snakes with a higher fitness function add more to the running sum then they have a higher chance of being chosen
//calculate the sum of all the fitnesses
long fitnessSum = 0;
for (int i =0; i<snakes.length; i++) {
fitnessSum += snakes[i].fitness;
}
//set random value
long rand = floor(random(fitnessSum));
//initialise the running sum
long runningSum = 0;
for (int i = 0; i< snakes.length; i++) {
runningSum += snakes[i].fitness;
if (runningSum > rand) {
return snakes[i];
}
}
//unreachable code to make the parser happy
return snakes[0];
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//sets the best snakes globally and for this gen
void setBestSnake() {
//calculate max fitness
long max =0;
int maxIndex = 0;
for (int i =0; i<snakes.length; i++) {
if (snakes[i].fitness > max) {
max = snakes[i].fitness;
maxIndex = i;
}
}
//if best this gen is better than the global best then set the global best as the best this gen
if(max > globalBestFitness){
globalBestFitness = max;
globalBestSnake = snakes[maxIndex].clone();
}
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//mutates all the snakes
void mutate() {
for (int i =1; i<snakes.length; i++) {
snakes[i].mutate(globalMutationRate);
}
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//sets the current best snake, used when just showing one snake at a time
void setCurrentBest() {
if (!done()) {//if any snakes alive
float max =0;
int maxIndex = 0;
for (int i =0; i<snakes.length; i++) {
if (snakes[i].alive && snakes[i].len > max) {
max = snakes[i].len;
maxIndex = i;
}
}
if (max > currentBest) {
currentBest = floor(max);
}
//if the best length is more than 1 greater than the 5 stored in currentBest snake then set it;
//the + 5 is to stop the current best snake from jumping from snake to snake
if (!snakes[currentBestSnake].alive || max > snakes[currentBestSnake].len +5 ) {
currentBestSnake = maxIndex;
}
if (currentBest > globalBest) {
globalBest = currentBest;
}
}
}
}