Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions examples/neuro-evolution/index.html

This file was deleted.

1 change: 0 additions & 1 deletion examples/neuro-evolution/libraries/p5.dom.min.js

This file was deleted.

13 changes: 0 additions & 13 deletions examples/neuro-evolution/libraries/p5.min.js

This file was deleted.

12 changes: 0 additions & 12 deletions examples/neuro-evolution/sketch.js

This file was deleted.

114 changes: 114 additions & 0 deletions examples/neuroevolution-flappybird/bird.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Daniel Shiffman
// Nature of Code: Intelligence and Learning
// https://github.com/shiffman/NOC-S17-2-Intelligence-Learning

// This flappy bird implementation is adapted from:
// https://youtu.be/cXgA1d_E-jY&

// Mutation function to be passed into bird.brain
function mutate(x) {
if (random(1) < 0.1) {
let offset = randomGaussian() * 0.5;
let newx = x + offset;
return newx;
} else {
return x;
}
}

class Bird {
constructor(brain) {
// position and size of bird
this.x = 64;
this.y = height / 2;
this.r = 12;

// Gravity, lift and velocity
this.gravity = 0.8;
this.lift = -12;
this.velocity = 0;

// Is this a copy of another Bird or a new one?
// The Neural Network is the bird's "brain"
if (brain instanceof NeuralNetwork) {
this.brain = brain.copy();
this.brain.mutate(mutate);
} else {
this.brain = new NeuralNetwork(5, 8, 2);
}

// Score is how many frames it's been alive
this.score = 0;
// Fitness is normalized version of score
this.fitness = 0;
}

// Create a copy of this bird
copy() {
return new Bird(this.brain);
}

// Display the bird
show() {
fill(255, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2, this.r * 2);
}

// This is the key function now that decides
// if it should jump or not jump!
think(pipes) {
// First find the closest pipe
let closest = null;
let record = Infinity;
for (let i = 0; i < pipes.length; i++) {
let diff = pipes[i].x - this.x;
if (diff > 0 && diff < record) {
record = diff;
closest = pipes[i];
}
}

if (closest != null) {
// Now create the inputs to the neural network
let inputs = [];
// x position of closest pipe
inputs[0] = map(closest.x, this.x, width, 0, 1);
// top of closest pipe opening
inputs[1] = map(closest.top, 0, height, 0, 1);
// bottom of closest pipe opening
inputs[2] = map(closest.bottom, 0, height, 0, 1);
// bird's y position
inputs[3] = map(this.y, 0, height, 0, 1);
// bird's y velocity
inputs[4] = map(this.velocity, -5, 5, 0, 1);

// Get the outputs from the network
let action = this.brain.predict(inputs);
// Decide to jump or not!
if (action[1] > action[0]) {
this.up();
}
}
}

// Jump up
up() {
this.velocity += this.lift;
}

bottomTop() {
// Bird dies when hits bottom?
return (this.y > height || this.y < 0);
}

// Update bird's position based on velocity, gravity, etc.
update() {
this.velocity += this.gravity;
// this.velocity *= 0.9;
this.y += this.velocity;

// Every frame it is alive increases the score
this.score++;
}
}
87 changes: 87 additions & 0 deletions examples/neuroevolution-flappybird/ga.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Daniel Shiffman
// Nature of Code: Intelligence and Learning
// https://github.com/shiffman/NOC-S17-2-Intelligence-Learning

// This flappy bird implementation is adapted from:
// https://youtu.be/cXgA1d_E-jY&


// This file includes functions for creating a new generation
// of birds.

// Start the game over
function resetGame() {
counter = 0;
// Resetting best bird score to 0
if (bestBird) {
bestBird.score = 0;
}
pipes = [];
}

// Create the next generation
function nextGeneration() {
resetGame();
// Normalize the fitness values 0-1
normalizeFitness(allBirds);
// Generate a new set of birds
activeBirds = generate(allBirds);
// Copy those birds to another array
allBirds = activeBirds.slice();
}

// Generate a new population of birds
function generate(oldBirds) {
let newBirds = [];
for (let i = 0; i < oldBirds.length; i++) {
// Select a bird based on fitness
let bird = poolSelection(oldBirds);
newBirds[i] = bird;
}
return newBirds;
}

// Normalize the fitness of all birds
function normalizeFitness(birds) {
// Make score exponentially better?
for (let i = 0; i < birds.length; i++) {
birds[i].score = pow(birds[i].score, 2);
}

// Add up all the scores
let sum = 0;
for (let i = 0; i < birds.length; i++) {
sum += birds[i].score;
}
// Divide by the sum
for (let i = 0; i < birds.length; i++) {
birds[i].fitness = birds[i].score / sum;
}
}


// An algorithm for picking one bird from an array
// based on fitness
function poolSelection(birds) {
// Start at 0
let index = 0;

// Pick a random number between 0 and 1
let r = random(1);

// Keep subtracting probabilities until you get less than zero
// Higher probabilities will be more likely to be fixed since they will
// subtract a larger number towards zero
while (r > 0) {
r -= birds[index].fitness;
// And move on to the next
index += 1;
}

// Go back one
index -= 1;

// Make sure it's a copy!
// (this includes mutation)
return birds[index].copy();
}
30 changes: 30 additions & 0 deletions examples/neuroevolution-flappybird/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<html>

<head>
<meta charset="UTF-8">
<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.min.js"></script>
<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.min.js"></script>
<script language="javascript" type="text/javascript" src="../../lib/nn.js"></script>
<script language="javascript" type="text/javascript" src="../../lib/matrix.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<script language="javascript" type="text/javascript" src="ga.js"></script>
<script language="javascript" type="text/javascript" src="bird.js"></script>
<script language="javascript" type="text/javascript" src="pipe.js"></script>

</head>

<body>
<div id="canvascontainer"></div>
<p>
speed: <input id="speedSlider" type="range" min="1" max="10" value="1"> <span id="speed">1</span>
<br/> high score: <span id="hs">0</span>
<br/> all time high score: <span id="ahs">0</span>
</p>
<p>
<button id="best">run best so far</button>
</p>


</body>

</html>
58 changes: 58 additions & 0 deletions examples/neuroevolution-flappybird/pipe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Daniel Shiffman
// Nature of Code: Intelligence and Learning
// https://github.com/shiffman/NOC-S17-2-Intelligence-Learning

// This flappy bird implementation is adapted from:
// https://youtu.be/cXgA1d_E-jY&

class Pipe {
constructor() {

// How big is the empty space
let spacing = 125;
// Where is th center of the empty space
let centery = random(spacing, height - spacing);

// Top and bottom of pipe
this.top = centery - spacing / 2;
this.bottom = height - (centery + spacing / 2);
// Starts at the edge
this.x = width;
// Width of pipe
this.w = 80;
// How fast
this.speed = 6;
}

// Did this pipe hit a bird?
hits(bird) {
if ((bird.y - bird.r) < this.top || (bird.y + bird.r) > (height - this.bottom)) {
if (bird.x > this.x && bird.x < this.x + this.w) {
return true;
}
}
return false;
}

// Draw the pipe
show() {
stroke(255);
fill(200);
rect(this.x, 0, this.w, this.top);
rect(this.x, height - this.bottom, this.w, this.bottom);
}

// Update the pipe
update() {
this.x -= this.speed;
}

// Has it moved offscreen?
offscreen() {
if (this.x < -this.w) {
return true;
} else {
return false;
}
}
}
Loading