From 29619dbfb3434602bca3eacde339fd95e5becfe0 Mon Sep 17 00:00:00 2001 From: Marco de Zeeuw Date: Fri, 20 Apr 2018 10:33:29 +0200 Subject: [PATCH] Changed mutate to also check if it should mutate at all based on the rate. Changed the mutation rate because of the mentioned mutation-changes. Doubled vehicle.maxforce so it has more control over itself. Changed the border-inputs according to the entire canvas instead of the 50px wide stroke. Lastly I've added a fallback for when almost all vehicles die, which would probably never happen in the current reproduction-rate. --- examples/neuroevolution-steering/sketch.js | 11 +++-- examples/neuroevolution-steering/vehicle.js | 49 +++++++++++++-------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/examples/neuroevolution-steering/sketch.js b/examples/neuroevolution-steering/sketch.js index cb303dc..2ab06a3 100644 --- a/examples/neuroevolution-steering/sketch.js +++ b/examples/neuroevolution-steering/sketch.js @@ -28,7 +28,7 @@ let foodBuffer = 50; // How many sensors does each vehicle have? let totalSensors = 8; // How far can each vehicle see? -let sensorLength = 150; +let sensorLength = 50; // What's the angle in between sensors let sensorAngle = (Math.PI * 2) / totalSensors; @@ -94,14 +94,19 @@ function draw() { if (population.length < 20) { for (let v of population) { // Every vehicle has a chance of cloning itself according to score - // Argument to "clone" is probability - let newVehicle = v.clone(0.1 * v.score / record); + let probability = 0.1 * v.score / record; + let newVehicle = v.clone(probability); // If there is a child if (newVehicle != null) { population.push(newVehicle); } } } + // Make sure we never run out of vehicles, but favor reproduction + if (population.length <= 2) { + let vehicle = new Vehicle(); + population.push(vehicle); + } } // Draw all the food diff --git a/examples/neuroevolution-steering/vehicle.js b/examples/neuroevolution-steering/vehicle.js index c866a40..7cecda3 100644 --- a/examples/neuroevolution-steering/vehicle.js +++ b/examples/neuroevolution-steering/vehicle.js @@ -4,17 +4,9 @@ // Evolutionary "Steering Behavior" Simulation - -// Mutation function to be passed into Vehicle's brain -function mutate(x) { - if (random(1) < 0.1) { - let offset = randomGaussian() * 0.5; - let newx = x + offset; - return newx; - } else { - return x; - } -} +// Neural Network parameters +// Mutation rate is set quite high because there is no crossover +const mutationRate = 0.25; // This is a class for an individual sensor // Each vehicle will have N sensors @@ -37,7 +29,7 @@ class Vehicle { this.velocity = createVector(); this.position = createVector(random(width), random(height)); this.r = 4; - this.maxforce = 0.1; + this.maxforce = 0.2; this.maxspeed = 4; this.minspeed = 0.25; this.maxhealth = 3; @@ -54,7 +46,7 @@ class Vehicle { // If a brain is passed via constructor copy it if (brain) { this.brain = brain.copy(); - this.brain.mutate(mutate); + this.mutate(mutationRate); // Otherwise make a new brain } else { // inputs are all the sensors plus position and velocity info @@ -64,10 +56,28 @@ class Vehicle { this.brain = new NeuralNetwork(inputs, 32, 2); } - // Health keeps vehicl alive + // Health keeps vehicle alive this.health = 1; } + mutate(rate) { + // Check if this should be mutated at all + if (Math.random() < rate) { + // This is how we adjust weights ever so slightly + function mutate(x) { + // Mutate only so much of the values + if (Math.random() < rate) { + var offset = randomGaussian() * 0.5; + // var offset = random(-0.1, 0.1); + var newx = x + offset; + return newx; + } else { + return x; + } + } + this.brain.mutate(mutate); + } + } // Called each time step update() { @@ -147,11 +157,12 @@ class Vehicle { // Create inputs let inputs = []; - // This is goofy but these 4 inputs are mapped to distance from edges - inputs[0] = constrain(map(this.position.x, foodBuffer, 0, 0, 1), 0, 1); - inputs[1] = constrain(map(this.position.y, foodBuffer, 0, 0, 1), 0, 1); - inputs[2] = constrain(map(this.position.x, width - foodBuffer, width, 0, 1), 0, 1); - inputs[3] = constrain(map(this.position.y, height - foodBuffer, height, 0, 1), 0, 1); + // These inputs are the location of the vehicle + inputs[0] = this.position.x / width; + inputs[1] = this.position.y / height; + // These inputs are the distance of the vehicle to east- and west borders + inputs[2] = 1 - inputs[0]; + inputs[3] = 1 - inputs[1]; // These inputs are the current velocity vector inputs[4] = this.velocity.x / this.maxspeed; inputs[5] = this.velocity.y / this.maxspeed;