var Chromosome = function(code) {
if (code) {
this.code = code;
}
this.cost = 9999;
};
Chromosome.prototype.code = '';
Chromosome.prototype.random = function(length) {
while (length--) {
this.code += String.fromCharCode(Math.floor(Math.random() * 255));
}
};
Chromosome.prototype.mutate = function(chance) {
if (Math.random() > chance) return;
var index = Math.floor(Math.random() * this.code.length);
var upOrDown = Math.random() <= 0.5 ? -1 : 1;
var newChar = String.fromCharCode(this.code.charCodeAt(index) + upOrDown);
var newString = '';
for (i = 0; i < this.code.length; i++) {
if (i == index) newString += newChar;
else newString += this.code[i];
}
this.code = newString;
};
Chromosome.prototype.mate = function(chromosome) {
var pivot = Math.round(this.code.length / 2) - 1;
var child1 = this.code.substr(0, pivot) + chromosome.code.substr(pivot);
var child2 = chromosome.code.substr(0, pivot) + this.code.substr(pivot);
return [new Chromosome(child1), new Chromosome(child2)];
};
Chromosome.prototype.calcCost = function(compareTo) {
var total = 0;
for (i = 0; i < this.code.length; i++) {
total += (this.code.charCodeAt(i) - compareTo.charCodeAt(i)) * (this.code.charCodeAt(i) - compareTo.charCodeAt(i));
}
this.cost = total;
};
var Population = function(goal, size) {
this.members = [];
this.goal = goal;
this.generationNumber = 0;
this.size = size;
while (size--) {
var chromosome = new Chromosome();
chromosome.random(this.goal.length);
this.members.push(chromosome);
}
};
Population.prototype.display = function() {
var html = '';
html += '<div style="font-size: 20px; padding-bottom:5px;margin-left:20px;margin-top:40px;">Generation: ' + this.generationNumber + ' - Size: ' + this.members.length + '<br></div>';
for (var i = 0; i < Math.min(this.members.length, 20) ; i++) {
html += '<div style="font-size: 14px; display:inline; margin-left:50px;"><span style="margin-right:20px; display: inline-block; min-width:200px;">' + this.members[i].code.replace("\n", " ").replace("\r", " ") + '</span><span>' + this.members[i].cost + '</span><br></div></div>';
}
$("#population-container").html(html);
};
Population.prototype.sort = function() {
this.members.sort(function(a, b) {
return a.cost - b.cost;
});
this.members.splice(this.size, this.members.length);
};
Population.prototype.mate = function() {
for(var i = 0, max = this.members.length / 2; i < max; i++) {
var random = i;
while(random == i) {
random = Math.floor(Math.random() * max);
}
var children = this.members[i].mate(this.members[random]);
this.members.push(children[0]);
this.members.push(children[1]);
}
};
Population.prototype.select = function() {
var index = Math.min((this.members.length * 2) / 3, this.size);
this.members.splice(index, this.members.length);
};
Population.prototype.generation = function() {
for (var i = 0; i < this.members.length; i++) {
this.members[i].calcCost(this.goal);
}
this.sort();
this.display();
this.select();
this.mate();
for (var i = 0; i < this.members.length; i++) {
this.members[i].mutate(0.7);
this.members[i].calcCost(this.goal);
if (this.members[i].code == this.goal) {
this.sort();
this.display();
return true;
}
}
this.generationNumber++;
var scope = this;
setTimeout(
function() {
scope.generation();
},
200
);
};
var population = new Population("Hello, world!", 2000);
population.generation();
<div id="population-container">
body {
font-family:Courier New;
font-size:12px;
}