-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpopulation.js
131 lines (120 loc) · 3.78 KB
/
population.js
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
/**
* The overseer of all of the players - makes batch operations and delivers offsprings
*
*/
class Bx_Population {
/**
* Creates a new population - the parameters derives from the specified Game object.
*
* @param {Bx_Game} game The game (you've lost)
* @returns {Bx_Population}
*/
constructor(game) {
this.generation = 1;
this.population = [];
this.game = game;
for (var i = 0; i < this.game.data.population_size; i++) {
this.population.push(new Bx_Player(game));
}
}
/**
* Moves every player to the next position
*
* @param {int} i Number of steps... to where exactly?
*/
step(i) {
for (var player = 0; player < this.game.data.population_size; player++) {
this.population[player].step(i);
}
}
/**
* Renders position of every player
*
* @param {int} step Number of steps taken to get here (wherever here is)
*/
render(step) {
for (var player = 0; player < this.game.data.population_size; player++) {
this.population[player].render(step);
}
}
/**
* Clears the board before the next step
*/
clear() {
Bx_Render.clearPlayers(this.game);
}
/**
* Creates the next generation of the fearsome warriors.
*
* It chooses randomly (even the worst parent can have a child),
* but the chance of being chosen (even multiple times) is relative to the relative fitness
*/
finishedAndDeathCounter() {
var totalDeaths = 0;
var totalFinished = 0;
var numGen = this.generation % 10;
for (let player = 0; player < this.game.data.population_size; player++) {
if (this.population[player].dead) {
totalDeaths++;
} else if (this.population[player].finished) {
totalFinished++;
}
}
numDeaths.innerText =
'Reached Goal: ' +
totalFinished +
' out of ' +
this.game.data.population_size +
' dots';
numFinished.innerText =
'Deaths: ' +
totalDeaths +
' out of ' +
this.game.data.population_size +
' dots';
genCounter.innerText = this.generation;
var deaths2 = 'deaths' + numGen; // fix over here lots of bugs with displaying data in table.
var finished2 = 'finished' + numGen;
document.getElementById(deaths2).innerHTML = totalDeaths;
document.getElementById(finished2).innerHTML = totalFinished;
}
newGeneration() {
this.finishedAndDeathCounter();
var totalFitness = 0;
var randomPoints = [];
// Calculates total fitness and generates a bunch of random numbers (See below)
for (var player = 0; player < this.game.data.population_size; player++) {
totalFitness += this.population[player].calculateFitness();
randomPoints.push(Math.random());
}
//Sorts the population by the fitness & the random points by the size
this.population.sort(function (a, b) {
return b.fitness - a.fitness;
});
randomPoints.sort(function (a, b) {
return a - b;
});
// Clones the best of the last generation without mutating
var players = [this.population[0].clone(true)];
// Creates the other offsprings considering the relative fitness
var currentMax = 0.0;
var currentPoint = randomPoints.shift();
for (var player = 0; player < this.game.data.population_size; player++) {
currentMax += this.population[player].fitness;
while (currentPoint * totalFitness < currentMax) {
players.push(this.population[player].clone(false));
var currentPoint = randomPoints.shift();
if (typeof currentPoint === 'undefined') {
break;
}
}
if (typeof currentPoint === 'undefined') {
break;
}
}
this.population = players;
this.generation += 1;
gen = 'gen' + (this.generation % 10);
document.GetElementById().innerHTML = this.generation;
}
}