function population(game){ this.max = 50; this.top = 4; this.game = game; if (this.max < this.top){ this.top = this.max; } this.Population = []; this.scale = 200; this.reset = function(){ this.iteration = 1; this.mutateRate = 1; this.best_population = 0; this.best_fitness = 0; this.best_score = 0; } this.create_population = function(){ this.Population = []; for (var i=0; i<this.max; i++){ var newUnit = new synaptic.Architect.Perceptron(5, 32, 4); newUnit.index = i; newUnit.fitness = 0; newUnit.score = 0; newUnit.isWinner = false; newUnit.x = 250; newUnit.y = 100; //newUnit.round = 0; this.Population.push(newUnit); } } this.think = function(unit){ var inputs = [500,500,unit.x,unit.y,dist(unit.x,unit.y,500,500)]; var outputs = this.Population[unit.index].activate(inputs); var max = outputs.indexOf((Math.max.apply( Math,outputs))); //console.log(Math.max.apply( Math,outputs)); if (max == 0 && unit.y >= 0){ unit.y -= 1; } else if (max == 2 && unit.y <= 500){ unit.y += 1; } else if (max == 1 && unit.x <= 500){ unit.x += 1; } else if (max == 3 && unit.x >= 0){ unit.x -= 1; } //unit.round++; //this.game.draw(unit.x,unit.y); unit.fitness = dist(unit.x,unit.y,0,0); //console.log(max+"evolving"+outputs); } this.evolve = function(){ var Winners = this.select(); if (this.mutateRate == 1 && Winners[0].fitness < 0){ this.create_population(); } else{ this.mutateRate = 0.2; } for (var i=this.top; i<this.max; i++){ var parentA, parentB, offspring; if (i == this.top){ parentA = Winners[0].toJSON(); parentB = Winners[1].toJSON(); offspring = this.crossOver(parentA, parentB); } else if (i < this.max-2){ parentA = this.getRandomUnit(Winners).toJSON(); parentB = this.getRandomUnit(Winners).toJSON(); offspring = this.crossOver(parentA, parentB); } else { offspring = this.getRandomUnit(Winners).toJSON(); } // mutate the offspring offspring = this.mutation(offspring); // create a new unit using the neural network from the offspring var newUnit = synaptic.Network.fromJSON(offspring); newUnit.index = this.Population[i].index; newUnit.fitness = 0; newUnit.score = 0; newUnit.isWinner = false; newUnit.x = 250; newUnit.y = 100; //newUnit.round = 0; // update population by changing the old unit with the new one this.Population[i] = newUnit; } this.Population.sort(function(unitA, unitB){ return unitA.index - unitB.index; }); } this.select = function(){ var sortedPopulation = this.Population.sort( function(unitA, unitB){ return unitB.fitness - unitA.fitness; } ); for (var i=0; i<this.top; i++){ this.Population[i].isWinner = true; } return sortedPopulation.slice(0, this.top); } this.crossOver = function(parentA, parentB){ var cutPoint = this.random(0, parentA.neurons.length-1); for (var i = cutPoint; i < parentA.neurons.length; i++){ var biasFromParentA = parentA.neurons[i]['bias']; parentA.neurons[i]['bias'] = parentB.neurons[i]['bias']; parentB.neurons[i]['bias'] = biasFromParentA; } cutPoint = this.random(0, parentA.connections.length-1); for (var i = cutPoint; i < parentA.connections.length; i++){ var weightFromParentA = parentA.connections[i]['weight']; parentA.connections[i]['weight'] = parentB.connections[i]['weight']; parentB.connections[i]['weight'] = weightFromParentA; } return this.random(0, 1) == 1 ? parentA : parentB; } this.mutation = function(offspring){ for (var i = 0; i < offspring.neurons.length; i++){ offspring.neurons[i]['bias'] = this.mutate(offspring.neurons[i]['bias']); } for (var i = 0; i < offspring.connections.length; i++){ offspring.connections[i]['weight'] = this.mutate(offspring.connections[i]['weight']); } return offspring; } this.mutate = function(gene){ if (Math.random() < this.mutateRate) { var mutateFactor = 1 + ((Math.random() - 0.5) * 3 + (Math.random() - 0.5)); gene *= mutateFactor; } return gene; } this.random = function(min, max){ return Math.floor(Math.random()*(max-min+1) + min); } this.getRandomUnit = function(array){ return array[this.random(0, array.length-1)]; } } function dist(x1,y1,x2,y2){ var x = x2 - x1; var y = y2 - y1; return Math.sqrt(Math.pow(x,2) + Math.pow(y,2)); }