updating nature of code examples for noc repo

This commit is contained in:
Daniel Shiffman
2013-04-30 22:03:23 -04:00
parent 9a6b1dcdb6
commit 0c3140899e
61 changed files with 1540 additions and 179 deletions
@@ -7,7 +7,7 @@
Network network;
void setup() {
size(750,200);
size(640,360);
// Create the Network object
network = new Network(width/2, height/2);
@@ -17,7 +17,7 @@ void setup() {
Neuron output = new Neuron(250, 0);
for (int i = 0; i < layers; i++) {
for (int j = 0; j < inputs; j++) {
float x = map(i, 0, layers, -300, 300);
float x = map(i, 0, layers, -250, 300);
float y = map(j, 0, inputs-1, -75, 75);
Neuron n = new Neuron(x, y);
if (i > 0) {
@@ -27,7 +27,7 @@ float f(float x) {
}
void setup() {
size(800, 200);
size(640, 360);
// The perceptron has 3 inputs -- x, y, and bias
// Second value is "Learning Constant"
@@ -11,7 +11,7 @@ PVector desired;
ArrayList<PVector> targets;
void setup() {
size(800, 200);
size(640, 360);
// The Vehicle's desired location
desired = new PVector(width/2,height/2);
@@ -35,19 +35,20 @@ void makeTargets() {
void draw() {
background(255);
// Draw a rectangle to show the Vehicle's goal
rectMode(CENTER);
// Draw a circle to show the Vehicle's goal
stroke(0);
strokeWeight(2);
fill(0, 100);
rect(desired.x, desired.y, 36, 36);
ellipse(desired.x, desired.y, 36, 36);
// Draw the targets
for (PVector target : targets) {
fill(0, 100);
noFill();
stroke(0);
strokeWeight(2);
ellipse(target.x, target.y, 30, 30);
ellipse(target.x, target.y, 16, 16);
line(target.x,target.y-16,target.x,target.y+16);
line(target.x-16,target.y,target.x+16,target.y);
}
// Update the Vehicle
@@ -7,15 +7,15 @@
Network network;
void setup() {
size(800, 200);
size(640, 360);
// Create the Network object
network = new Network(width/2,height/2);
// Create a bunch of Neurons
Neuron a = new Neuron(-300,0);
Neuron a = new Neuron(-200,0);
Neuron b = new Neuron(0,75);
Neuron c = new Neuron(0,-75);
Neuron d = new Neuron(300,0);
Neuron d = new Neuron(200,0);
// Connect them
network.connect(a,b);
@@ -7,17 +7,17 @@
Network network;
void setup() {
size(800, 200);
size(640, 360);
// Create the Network object
network = new Network(width/2, height/2);
// Create a bunch of Neurons
Neuron a = new Neuron(-350, 0);
Neuron b = new Neuron(-200, 0);
Neuron a = new Neuron(-275, 0);
Neuron b = new Neuron(-150, 0);
Neuron c = new Neuron(0, 75);
Neuron d = new Neuron(0, -75);
Neuron e = new Neuron(200, 0);
Neuron f = new Neuron(350, 0);
Neuron e = new Neuron(150, 0);
Neuron f = new Neuron(275, 0);
// Connect them
network.connect(a, b,1);
@@ -11,7 +11,7 @@ class Mover {
Mover(float m, float x, float y) {
mass = m;
location = new PVector(random(width), random(height));
location = new PVector(x, y);
velocity = new PVector(1, 0);
acceleration = new PVector(0, 0);
}
@@ -30,8 +30,8 @@ class ParticleSystem {
}
}
void addParticle(Particle p) {
particles.add(p);
void addParticle() {
particles.add(new Particle(origin));
}
// A method to test if the particle system still has particles
@@ -9,7 +9,6 @@ import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.*;
// A reference to our box2d world
PBox2D box2d;
@@ -0,0 +1,44 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Separation
// Via Reynolds: http://www.red3d.com/cwr/steer/
// A list of vehicles
ArrayList<Vehicle> vehicles;
void setup() {
size(640,360);
// We are now making random vehicles and storing them in an ArrayList
vehicles = new ArrayList<Vehicle>();
for (int i = 0; i < 100; i++) {
vehicles.add(new Vehicle(random(width),random(height)));
}
}
void draw() {
background(255);
for (Vehicle v : vehicles) {
// Path following and separation are worked on in this function
v.align(vehicles);
// Call the generic run method (update, borders, display, etc.)
v.update();
v.borders();
v.display();
}
// Instructions
fill(0);
text("Drag the mouse to generate new vehicles.",10,height-16);
}
void mouseDragged() {
vehicles.add(new Vehicle(mouseX,mouseY));
}
@@ -0,0 +1,89 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Vehicle class
class Vehicle {
// All the usual stuff
PVector location;
PVector velocity;
PVector acceleration;
float r;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
// Constructor initialize all values
Vehicle(float x, float y) {
location = new PVector(x, y);
r = 12;
maxspeed = 3;
maxforce = 0.2;
acceleration = new PVector(0, 0);
velocity = PVector.random2D();
velocity.mult(random(1,4));
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
// Alignment
// For every nearby boid in the system, calculate the average velocity
void align (ArrayList<Vehicle> boids) {
float neighbordist = 30;
PVector sum = new PVector(0, 0);
int count = 0;
for (Vehicle other : vehicles) {
float d = PVector.dist(location, other.location);
if ((d > 0) && (d < neighbordist)) {
sum.add(other.velocity);
count++;
}
}
if (count > 0) {
sum.div((float)count);
sum.normalize();
sum.mult(maxspeed);
PVector steer = PVector.sub(sum, velocity);
steer.limit(maxforce);
applyForce(steer);
}
}
// Method to update location
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
location.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
void display() {
fill(175);
stroke(0);
pushMatrix();
translate(location.x, location.y);
ellipse(0, 0, r, r);
popMatrix();
}
// Wraparound
void borders() {
if (location.x < -r) location.x = width+r;
if (location.y < -r) location.y = height+r;
if (location.x > width+r) location.x = -r;
if (location.y > height+r) location.y = -r;
}
}
@@ -11,9 +11,8 @@ Vehicle wanderer;
boolean debug = true;
void setup() {
size(740,200);
size(640,360);
wanderer = new Vehicle(width/2,height/2);
smooth();
}
void draw() {
@@ -0,0 +1,52 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Flow Field Following
// Via Reynolds: http://www.red3d.com/cwr/steer/FlowFollow.html
// Using this variable to decide whether to draw all the stuff
boolean debug = true;
// Flowfield object
FlowField flowfield;
// An ArrayList of vehicles
ArrayList<Vehicle> vehicles;
void setup() {
size(640, 360);
// Make a new flow field with "resolution" of 16
flowfield = new FlowField(20);
vehicles = new ArrayList<Vehicle>();
// Make a whole bunch of vehicles with random maxspeed and maxforce values
for (int i = 0; i < 120; i++) {
vehicles.add(new Vehicle(new PVector(random(width), random(height)), random(2, 5), random(0.1, 0.5)));
}
}
void draw() {
background(255);
flowfield.update();
// Display the flowfield in "debug" mode
if (debug) flowfield.display();
// Tell all the vehicles to follow the flow field
for (Vehicle v : vehicles) {
v.follow(flowfield);
v.run();
}
// Instructions
fill(0);
text("Hit space bar to toggle debugging lines.\nClick the mouse to generate a new flow field.",10,height-20);
}
void keyPressed() {
if (key == ' ') {
debug = !debug;
}
}
@@ -0,0 +1,81 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Flow Field Following
class FlowField {
// A flow field is a two dimensional array of PVectors
PVector[][] field;
int cols, rows; // Columns and Rows
int resolution; // How large is each "cell" of the flow field
float zoff = 0.0; // 3rd dimension of noise
FlowField(int r) {
resolution = r;
// Determine the number of columns and rows based on sketch's width and height
cols = width/resolution;
rows = height/resolution;
field = new PVector[cols][rows];
update();
}
void update() {
float xoff = 0;
for (int i = 0; i < cols; i++) {
float yoff = 0;
for (int j = 0; j < rows; j++) {
float theta = map(noise(xoff,yoff,zoff),0,1,0,TWO_PI);
// Make a vector from an angle
field[i][j] = PVector.fromAngle(theta);
yoff += 0.1;
}
xoff += 0.1;
}
// Animate by changing 3rd dimension of noise every frame
zoff += 0.01;
}
// Draw every vector
void display() {
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
drawVector(field[i][j],i*resolution,j*resolution,resolution-2);
}
}
}
// Renders a vector object 'v' as an arrow and a location 'x,y'
void drawVector(PVector v, float x, float y, float scayl) {
pushMatrix();
float arrowsize = 4;
// Translate to location to render vector
translate(x,y);
stroke(0,150);
// Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate
rotate(v.heading2D());
// Calculate length of vector & scale it to be bigger or smaller if necessary
float len = v.mag()*scayl;
// Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction)
line(0,0,len,0);
//line(len,0,len-arrowsize,+arrowsize/2);
//line(len,0,len-arrowsize,-arrowsize/2);
popMatrix();
}
PVector lookup(PVector lookup) {
int column = int(constrain(lookup.x/resolution,0,cols-1));
int row = int(constrain(lookup.y/resolution,0,rows-1));
return field[column][row].get();
}
}
@@ -0,0 +1,87 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Flow Field Following
class Vehicle {
// The usual stuff
PVector location;
PVector velocity;
PVector acceleration;
float r;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
Vehicle(PVector l, float ms, float mf) {
location = l.get();
r = 3.0;
maxspeed = ms;
maxforce = mf;
acceleration = new PVector(0,0);
velocity = new PVector(0,0);
}
public void run() {
update();
borders();
display();
}
// Implementing Reynolds' flow field following algorithm
// http://www.red3d.com/cwr/steer/FlowFollow.html
void follow(FlowField flow) {
// What is the vector at that spot in the flow field?
PVector desired = flow.lookup(location);
// Scale it up by maxspeed
desired.mult(maxspeed);
// Steering is desired minus velocity
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce); // Limit to maximum steering force
applyForce(steer);
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
// Method to update location
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
location.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
void display() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + radians(90);
fill(175);
stroke(0);
pushMatrix();
translate(location.x,location.y);
rotate(theta);
beginShape(TRIANGLES);
vertex(0, -r*2);
vertex(-r, r*2);
vertex(r, r*2);
endShape();
popMatrix();
}
// Wraparound
void borders() {
if (location.x < -r) location.x = width+r;
if (location.y < -r) location.y = height+r;
if (location.x > width+r) location.x = -r;
if (location.y > height+r) location.y = -r;
}
}
@@ -6,8 +6,7 @@
// Using the dot product to compute the angle between two vectors
void setup() {
size(383, 200);
smooth();
size(640, 360);
}
void draw() {
@@ -16,7 +16,7 @@ Path path;
ArrayList<Vehicle> vehicles;
void setup() {
size(720,200);
size(640,360);
// Call a function to generate new Path object
newPath();
@@ -0,0 +1,242 @@
// Flocking
// Daniel Shiffman <http://www.shiffman.net>
// The Nature of Code, Spring 2009
// Boid class
// Methods for Separation, Cohesion, Alignment added
class Boid {
PVector location;
PVector velocity;
PVector acceleration;
float r;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
color col;
Boid(float x, float y) {
acceleration = new PVector(0, 0);
velocity = new PVector(random(-1, 1), random(-1, 1));
location = new PVector(x, y);
r = 5.0;
maxspeed = 3;
maxforce = 0.05;
col = color(175);
}
void run(ArrayList<Boid> boids) {
//flock(boids);
update();
borders();
render();
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
// We accumulate a new acceleration each time based on three rules
void flock(ArrayList<Boid> boids) {
PVector sep = separate(boids); // Separation
PVector ali = align(boids); // Alignment
PVector coh = cohesion(boids); // Cohesion
// Not for every boid yet
// PVector view = view(boids); // view
// Arbitrarily weight these forces
sep.mult(1.5);
ali.mult(1.0);
coh.mult(1.0);
// Not for every boid yet
// view.mult(1.0);
// Add the force vectors to acceleration
applyForce(sep);
applyForce(ali);
applyForce(coh);
// Not for every boid yet
// applyForce(view);
}
// Method to update location
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
location.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
PVector seek(PVector target) {
PVector desired = PVector.sub(target, location); // A vector pointing from the location to the target
// Normalize desired and scale to maximum speed
desired.normalize();
desired.mult(maxspeed);
// Steering = Desired minus Velocity
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce); // Limit to maximum steering force
return steer;
}
void render() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading() + radians(90);
fill(col);
stroke(0);
pushMatrix();
translate(location.x, location.y);
rotate(theta);
beginShape(TRIANGLES);
vertex(0, -r*2);
vertex(-r, r*2);
vertex(r, r*2);
endShape();
popMatrix();
}
// Wraparound
void borders() {
if (location.x < -r) location.x = width+r;
if (location.y < -r) location.y = height+r;
if (location.x > width+r) location.x = -r;
if (location.y > height+r) location.y = -r;
}
// Separation
// Method checks for nearby boids and steers away
PVector separate (ArrayList<Boid> boids) {
float desiredseparation = 25.0f;
PVector steer = new PVector(0, 0, 0);
int count = 0;
// For every boid in the system, check if it's too close
for (Boid other : boids) {
float d = PVector.dist(location, other.location);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
PVector diff = PVector.sub(location, other.location);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
steer.div((float)count);
}
// As long as the vector is greater than 0
if (steer.mag() > 0) {
// Implement Reynolds: Steering = Desired - Velocity
steer.normalize();
steer.mult(maxspeed);
steer.sub(velocity);
steer.limit(maxforce);
}
return steer;
}
// Alignment
// For every nearby boid in the system, calculate the average velocity
PVector align (ArrayList<Boid> boids) {
float neighbordist = 50;
PVector sum = new PVector(0, 0);
int count = 0;
for (Boid other : boids) {
float d = PVector.dist(location, other.location);
if ((d > 0) && (d < neighbordist)) {
sum.add(other.velocity);
count++;
}
}
if (count > 0) {
sum.div((float)count);
sum.normalize();
sum.mult(maxspeed);
PVector steer = PVector.sub(sum, velocity);
steer.limit(maxforce);
return steer;
}
else {
return new PVector(0, 0);
}
}
// Cohesion
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
PVector cohesion (ArrayList<Boid> boids) {
float neighbordist = 50;
PVector sum = new PVector(0, 0); // Start with empty vector to accumulate all locations
int count = 0;
for (Boid other : boids) {
float d = PVector.dist(location, other.location);
if ((d > 0) && (d < neighbordist)) {
sum.add(other.location); // Add location
count++;
}
}
if (count > 0) {
sum.div(count);
return seek(sum); // Steer towards the location
}
else {
return new PVector(0, 0);
}
}
// View
// move laterally away from any boid that blocks the view
// Right now we are just drawing the view and highlighting boids
PVector view (ArrayList<Boid> boids) {
// How far can it see?
float sightDistance = 100;
float periphery = PI/4;
for (Boid other : boids) {
// A vector that points to another boid and that angle
PVector comparison = PVector.sub(other.location, location);
// How far is it
float d = PVector.dist(location, other.location);
// What is the angle between the other boid and this one's current direction
float diff = PVector.angleBetween(comparison, velocity);
// If it's within the periphery and close enough to see it
if (diff < periphery && d > 0 && d < sightDistance) {
// Just change its color
other.highlight();
}
}
// Debug Drawing
float currentHeading = velocity.heading();
pushMatrix();
translate(location.x, location.y);
rotate(currentHeading);
fill(0, 100);
arc(0, 0, sightDistance*2, sightDistance*2, -periphery, periphery);
popMatrix();
return new PVector();
}
void highlight() {
col = color(255, 0, 0);
}
}
@@ -0,0 +1,31 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Exercise 6.17: Implement Flake's "View" rule
// This answer doesn't implement the rule, but rather demonstrates how a boid can
// detect what is "in front" of it based on peripheral vision
Flock flock;
void setup() {
size(640,360);
flock = new Flock();
// Add an initial set of boids into the system
for (int i = 0; i < 25; i++) {
Boid b = new Boid(width/2+random(0,75),height/2+random(0,75));
flock.addBoid(b);
}
}
void draw() {
background(255);
flock.run();
}
// Add a new boid into the System
void mouseDragged() {
flock.addBoid(new Boid(mouseX,mouseY));
}
@@ -0,0 +1,37 @@
// Flocking
// Daniel Shiffman <http://www.shiffman.net>
// The Nature of Code, Spring 2011
// Flock class
// Does very little, simply manages the ArrayList of all the boids
class Flock {
ArrayList<Boid> boids; // An ArrayList for all the boids
Flock() {
boids = new ArrayList<Boid>(); // Initialize the ArrayList
}
void run() {
for (Boid b : boids) {
b.col = color(175);
}
Boid b1 = boids.get(0);
b1.col = color(0, 0, 255);
b1.view(boids);
for (Boid b : boids) {
b.flock(boids); // Passing the entire list of boids to each boid individually
}
for (Boid b : boids) {
b.run(boids); // Passing the entire list of boids to each boid individually
}
}
void addBoid(Boid b) {
boids.add(b);
}
}
@@ -0,0 +1,85 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Flow Field Following
class FlowField {
// A flow field is a two dimensional array of PVectors
PVector[][] field;
int cols, rows; // Columns and Rows
int resolution; // How large is each "cell" of the flow field
FlowField(int r) {
resolution = r;
// Determine the number of columns and rows based on sketch's width and height
cols = width/resolution;
rows = height/resolution;
field = new PVector[cols][rows];
init();
}
void init() {
// Reseed noise so we get a new flow field every time
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
int x = i*resolution;
int y = j*resolution;
int c = img.pixels[x + y * img.width];
// Map brightness to an angle
float theta = 0;//map(brightness(c),0,255,0,PI/2);
// Polar to cartesian coordinate transformation to get x and y components of the vector
field[i][j] = PVector.fromAngle(theta);
// Map magnitude to an angle (how fast is the desired velocity in the flow field)
float m = map(brightness(c),0,255,0,1);
field[i][j].mult(m);
}
}
}
// Draw every vector
void display() {
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
drawVector(field[i][j],i*resolution,j*resolution,resolution-2);
}
}
}
// Renders a vector object 'v' as an arrow and a location 'x,y'
void drawVector(PVector v, float x, float y, float scayl) {
pushMatrix();
float arrowsize = 4;
// Translate to location to render vector
translate(x,y);
strokeWeight(2);
stroke(255,0,0);
// Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate
rotate(v.heading2D());
// Calculate length of vector & scale it to be bigger or smaller if necessary
float len = v.mag()*scayl;
// Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction)
line(0,0,len,0);
//line(len,0,len-arrowsize,+arrowsize/2);
//line(len,0,len-arrowsize,-arrowsize/2);
popMatrix();
}
PVector lookup(PVector lookup) {
int column = int(constrain(lookup.x/resolution,0,cols-1));
int row = int(constrain(lookup.y/resolution,0,rows-1));
return field[column][row].get();
}
}
@@ -0,0 +1,59 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Flow Field Following
// Via Reynolds: http://www.red3d.com/cwr/steer/FlowFollow.html
// Using this variable to decide whether to draw all the stuff
boolean debug = true;
PImage img;
// Flowfield object
FlowField flowfield;
// An ArrayList of vehicles
ArrayList<Vehicle> vehicles;
void setup() {
size(600, 568);
img = loadImage("sil.jpg");
// Make a new flow field with "resolution" of 16
flowfield = new FlowField(20);
vehicles = new ArrayList<Vehicle>();
// Make a whole bunch of vehicles with random maxspeed and maxforce values
for (int i = 0; i < 120; i++) {
vehicles.add(new Vehicle(new PVector(random(width), random(height)), random(2, 5), random(0.1, 0.5)));
}
}
void draw() {
background(255);
image(img,0,0);
// Display the flowfield in "debug" mode
if (debug) flowfield.display();
// Tell all the vehicles to follow the flow field
for (Vehicle v : vehicles) {
v.follow(flowfield);
v.run();
}
// Instructions
fill(0);
text("Hit space bar to toggle debugging lines.\nClick the mouse to generate a new flow field.",10,height-20);
}
void keyPressed() {
if (key == ' ') {
debug = !debug;
}
}
// Make a new flowfield
void mousePressed() {
flowfield.init();
}
@@ -0,0 +1,87 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Flow Field Following
class Vehicle {
// The usual stuff
PVector location;
PVector velocity;
PVector acceleration;
float r;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
Vehicle(PVector l, float ms, float mf) {
location = l.get();
r = 3.0;
maxspeed = ms;
maxforce = mf;
acceleration = new PVector(0,0);
velocity = new PVector(0,0);
}
public void run() {
update();
borders();
display();
}
// Implementing Reynolds' flow field following algorithm
// http://www.red3d.com/cwr/steer/FlowFollow.html
void follow(FlowField flow) {
// What is the vector at that spot in the flow field?
PVector desired = flow.lookup(location);
// Scale it up by maxspeed
desired.mult(maxspeed);
// Steering is desired minus velocity
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce); // Limit to maximum steering force
applyForce(steer);
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
// Method to update location
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
location.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
void display() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + radians(90);
fill(175);
stroke(0);
pushMatrix();
translate(location.x,location.y);
rotate(theta);
beginShape(TRIANGLES);
vertex(0, -r*2);
vertex(-r, r*2);
vertex(r, r*2);
endShape();
popMatrix();
}
// Wraparound
void borders() {
if (location.x < -r) location.x = width+r;
if (location.y < -r) location.y = height+r;
if (location.x > width+r) location.x = -r;
if (location.y > height+r) location.y = -r;
}
}
@@ -45,9 +45,9 @@ class Vehicle {
void seek(PVector target) {
PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target
// Normalize desired and scale to maximum speed
desired.normalize();
desired.mult(maxspeed);
// Scale to maximum speed
desired.setMag(maxspeed);
// Steering = Desired minus velocity
PVector steer = PVector.sub(desired,velocity);
steer.limit(maxforce); // Limit to maximum steering force
@@ -11,26 +11,23 @@ Vehicle v;
void setup() {
size(800, 200);
v = new Vehicle(width/2, height/2);
smooth();
}
void draw() {
if (mousePressed) {
background(255);
background(255);
PVector mouse = new PVector(mouseX, mouseY);
PVector mouse = new PVector(mouseX, mouseY);
// Draw an ellipse at the mouse location
fill(200);
stroke(0);
strokeWeight(2);
ellipse(mouse.x, mouse.y, 48, 48);
// Draw an ellipse at the mouse location
fill(200);
stroke(0);
strokeWeight(2);
ellipse(mouse.x, mouse.y, 48, 48);
// Call the appropriate steering behaviors for our agents
v.seek(mouse);
v.update();
v.display();
}
// Call the appropriate steering behaviors for our agents
v.seek(mouse);
v.update();
v.display();
}
@@ -43,13 +43,12 @@ class Vehicle {
void arrive(PVector target) {
PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target
float d = desired.mag();
// Normalize desired and scale with arbitrary damping within 100 pixels
desired.normalize();
// Scale with arbitrary damping within 100 pixels
if (d < 100) {
float m = map(d,0,100,0,maxspeed);
desired.mult(m);
desired.setMag(m);
} else {
desired.mult(maxspeed);
desired.setMag(maxspeed);
}
// Steering = Desired minus Velocity
@@ -11,11 +11,9 @@ boolean debug = true;
float d = 25;
void setup() {
size(800, 200);
size(640, 360);
v = new Vehicle(width/2, height/2);
smooth();
}
void draw() {
@@ -13,9 +13,8 @@ float d = 25;
void setup() {
size(800, 200);
size(640, 360);
v = new Vehicle(width/2, height/2);
smooth();
}
void draw() {
@@ -21,8 +21,8 @@ void setup() {
path = new Path();
// Each vehicle has different maxspeed and maxforce for demo purposes
car1 = new Vehicle(new PVector(0, height/2), 3, 0.05);
car2 = new Vehicle(new PVector(0, height/2), 5, 0.1);
car1 = new Vehicle(new PVector(0, height/2), 2, 0.02);
car2 = new Vehicle(new PVector(0, height/2), 3, 0.05);
}
void draw() {
@@ -36,6 +36,10 @@ void draw() {
car1.run();
car2.run();
// Check if it gets to the end of the path since it's not a loop
car1.borders(path);
car2.borders(path);
// Instructions
fill(0);
text("Hit space bar to toggle debugging lines.", 10, height-30);
@@ -27,8 +27,7 @@ class Vehicle {
// Main "run" function
void run() {
update();
borders();
render();
display();
}
@@ -36,10 +35,10 @@ class Vehicle {
// http://www.red3d.com/cwr/steer/PathFollow.html
void follow(Path p) {
// Predict location 25 (arbitrary choice) frames ahead
// Predict location 50 (arbitrary choice) frames ahead
PVector predict = velocity.get();
predict.normalize();
predict.mult(25);
predict.mult(50);
PVector predictLoc = PVector.add(location, predict);
// Look at the line segment
@@ -134,7 +133,7 @@ class Vehicle {
applyForce(steer);
}
void render() {
void display() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + radians(90);
fill(175);
@@ -151,11 +150,11 @@ class Vehicle {
}
// Wraparound
void borders() {
if (location.x < -r) location.x = width+r;
//if (location.y < -r) location.y = height+r;
if (location.x > width+r) location.x = -r;
//if (location.y > height+r) location.y = -r;
void borders(Path p) {
if (location.x > p.end.x + r) {
location.x = p.start.x - r;
location.y = p.start.y + (location.y-p.end.y);
}
}
}
@@ -21,8 +21,8 @@ void setup() {
newPath();
// Each vehicle has different maxspeed and maxforce for demo purposes
car1 = new Vehicle(new PVector(0, height/2), 3, 0.1);
car2 = new Vehicle(new PVector(0, height/2), 5, 0.2);
car1 = new Vehicle(new PVector(0, height/2), 2, 0.04);
car2 = new Vehicle(new PVector(0, height/2), 3, 0.1);
}
void draw() {
@@ -35,6 +35,9 @@ void draw() {
// Call the generic run method (update, borders, display, etc.)
car1.run();
car2.run();
car1.borders(path);
car2.borders(path);
// Instructions
fill(0);
@@ -45,10 +48,10 @@ void newPath() {
// A path is a series of connected points
// A more sophisticated path might be a curve
path = new Path();
path.addPoint(0, height/2);
path.addPoint(-20, height/2);
path.addPoint(random(0, width/2), random(0, height));
path.addPoint(random(width/2, width), random(0, height));
path.addPoint(width, height/2);
path.addPoint(width+20, height/2);
}
public void keyPressed() {
@@ -22,6 +22,15 @@ class Path {
PVector point = new PVector(x, y);
points.add(point);
}
PVector getStart() {
return points.get(0);
}
PVector getEnd() {
return points.get(points.size()-1);
}
// Draw the path
void display() {
@@ -29,8 +29,7 @@ class Vehicle {
// Main "run" function
public void run() {
update();
borders();
render();
display();
}
@@ -38,10 +37,11 @@ class Vehicle {
// http://www.red3d.com/cwr/steer/PathFollow.html
void follow(Path p) {
// Predict location 25 (arbitrary choice) frames ahead
// Predict location 50 (arbitrary choice) frames ahead
// This could be based on speed
PVector predict = velocity.get();
predict.normalize();
predict.mult(25);
predict.mult(50);
PVector predictLoc = PVector.add(location, predict);
// Now we must find the normal to the path from the predicted location
@@ -165,7 +165,7 @@ class Vehicle {
applyForce(steer);
}
void render() {
void display() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + radians(90);
fill(175);
@@ -182,11 +182,11 @@ class Vehicle {
}
// Wraparound
void borders() {
if (location.x < -r) location.x = width+r;
//if (location.y < -r) location.y = height+r;
if (location.x > width+r) location.x = -r;
//if (location.y > height+r) location.y = -r;
void borders(Path p) {
if (location.x > p.getEnd().x + r) {
location.x = p.getStart().x - r;
location.y = p.getStart().y + (location.y-p.getEnd().y);
}
}
}
@@ -30,7 +30,7 @@ class Vehicle {
void applyBehaviors(ArrayList<Vehicle> vehicles) {
PVector separateForce = separate(vehicles);
PVector seekForce = seek(new PVector(mouseX,mouseY));
separateForce.mult(map(mouseX,0,width,0,2));
separateForce.mult(2);
seekForce.mult(1);
applyForce(separateForce);
applyForce(seekForce);
@@ -0,0 +1,41 @@
void setup() {
size(600, 360);
}
void draw() {
background(255);
PVector a = new PVector(20,300);
PVector b = new PVector(500,250);
PVector mouse = new PVector(mouseX,mouseY);
stroke(0);
strokeWeight(2);
line(a.x,a.y,b.x,b.y);
line(a.x,a.y,mouse.x,mouse.y);
fill(0);
ellipse(a.x,a.y,8,8);
ellipse(b.x,b.y,8,8);
ellipse(mouse.x,mouse.y,8,8);
PVector norm = scalarProjection(mouse,a,b);
strokeWeight(1);
stroke(50);
line(mouse.x,mouse.y,norm.x,norm.y);
noStroke();
fill(255,0,0);
ellipse(norm.x,norm.y,16,16);
}
PVector scalarProjection(PVector p, PVector a, PVector b) {
PVector ap = PVector.sub(p, a);
PVector ab = PVector.sub(b, a);
ab.normalize(); // Normalize the line
ab.mult(ap.dot(ab));
PVector normalPoint = PVector.add(a, ab);
return normalPoint;
}
@@ -20,8 +20,6 @@ void setup() {
circleLocation = new PVector(width/2,height/2);
circleRadius = height/2-25;
smooth();
}
void draw() {
@@ -33,18 +33,14 @@ void setup() {
for (int i = 0; i < 50; i++) {
flock.addBoid(new Boid(new PVector(random(width),random(height))));
}
smooth();
}
void draw() {
// We must always step through time!
box2d.step();
background(255);
flock.run();
}
void mousePressed() {
@@ -9,10 +9,6 @@
// Rules: Cohesion, Separation, Alignment
// Click mouse to add boids into the system
import processing.opengl.*;
Flock flock;
PVector center;
@@ -21,7 +17,7 @@ boolean scrollbar = false;
void setup() {
size(1024,768,OPENGL);
size(displayWidth,displayHeight,P2D);
setupScrollbars();
center = new PVector(width/2,height/2);
colorMode(RGB,255,255,255,100);
@@ -10,7 +10,7 @@ class CA {
int generation; // How many generations?
int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1}
int w = 5;
int w = 4;
int[][] matrix; // Store a history of generations in 2D array, not just one
int cols;
@@ -66,10 +66,12 @@ class CA {
for (int j = 0; j < rows; j++) {
int y = j - offset;
if (y <= 0) y = rows + y;
if (matrix[i][j] == 1) fill(0);
else fill(255);
noStroke();
rect(i*w, (y-1)*w, w, w);
// Only draw if cell state is 1
if (matrix[i][j] == 1) {
fill(0);
noStroke();
rect(i*w, (y-1)*w, w, w);
}
}
}
}
@@ -12,26 +12,20 @@ CA ca; // An object to describe a Wolfram elementary Cellular Automata
void setup() {
size(800, 200);
frameRate(30);
size(640, 800);
frameRate(24);
background(255);
int[] ruleset = {0,1,1,1,1,0,1,1}; // Rule 222
//int[] ruleset = {0,1,1,1,1,1,0,1}; // Rule 190
//int[] ruleset = {0,1,1,1,1,0,0,0}; // Rule 30
//int[] ruleset = {0,1,1,1,0,1,1,0}; // Rule 110
//int[] ruleset = {0,1,1,1,1,0,1,1}; // Rule 222
//int[] ruleset = {0,1,1,1,1,1,0,1}; // Rule 190
//int[] ruleset = {0,1,1,1,1,0,0,0}; // Rule 30
//int[] ruleset = {0,1,1,1,0,1,1,0}; // Rule 110
int[] ruleset = {0,1,0,1,1,0,1,0}; // Rule 90
ca = new CA(ruleset); // Initialize CA
}
void draw() {
background(255);
ca.display(); // Draw the CA
ca.generate();
}
void mousePressed() {
saveFrame("222-####.png");
//background(255);
//ca.randomize();
//ca.restart();
}
@@ -0,0 +1,42 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Cell {
float x, y;
float w;
float xoff;
float yoff;
int state;
Cell(float x_, float y_, float w_) {
x = x_;
y = y_;
w = w_;
xoff = w/2;
yoff = sin(radians(60))*w;
state = int(random(2));
}
void display() {
fill(state*255);
stroke(0);
pushMatrix();
translate(x,y);
beginShape();
vertex(0, yoff);
vertex(xoff, 0);
vertex(xoff+w, 0);
vertex(2*w, yoff);
vertex(xoff+w, 2*yoff);
vertex(xoff, 2*yoff);
vertex(0, yoff);
endShape();
popMatrix();
}
}
@@ -0,0 +1,24 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Outline for game of life
// This is just a grid of hexagons right now
GOL gol;
void setup() {
size(640, 360);
gol = new GOL();
}
void draw() {
background(255);
gol.display();
}
// reset board when mouse is pressed
void mousePressed() {
gol.init();
}
@@ -0,0 +1,44 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class GOL {
float w = 20;
float h = sin(radians(60))*w;
int columns, rows;
// Game of life board
Cell[][] board;
GOL() {
// Initialize rows, columns and set-up arrays
columns = width/int(w*3);
rows = height/int(h);
board = new Cell[columns][rows];
init();
}
void init() {
float h = sin(radians(60))*w;
for (int i = 0; i < columns; i++) {
for (int j = 0; j < rows; j++) {
if (j % 2 == 0) board[i][j] = new Cell(i*w*3, j*h,w);
else board[i][j] = new Cell(i*w*3+w+h/2, j*h, w);
}
}
}
// This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0'
void display() {
for ( int i = 0; i < columns;i++) {
for ( int j = 0; j < rows;j++) {
board[i][j].display();
}
}
}
}
@@ -12,6 +12,7 @@ GOL gol;
void setup() {
size(640, 360);
frameRate(24);
gol = new GOL();
}
@@ -9,8 +9,7 @@
float theta;
void setup() {
size(800, 200);
smooth();
size(640, 360);
}
void draw() {
@@ -0,0 +1,68 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Recursive Tree (w/ ArrayList)
// A class for one branch in the system
class Branch {
// Each has a location, velocity, and timer
// We could implement this same idea with different data
PVector start;
PVector end;
PVector vel;
float timer;
float timerstart;
boolean growing = true;
Branch(PVector l, PVector v, float n) {
start = l.get();
end = l.get();
vel = v.get();
timerstart = n;
timer = timerstart;
}
// Move location
void update() {
if (growing) {
end.add(vel);
}
}
// Draw a dot at location
void render() {
stroke(0);
line(start.x,start.y,end.x,end.y);
}
// Did the timer run out?
boolean timeToBranch() {
timer--;
if (timer < 0 && growing) {
growing = false;
return true;
}
else {
return false;
}
}
// Create a new branch at the current location, but change direction by a given angle
Branch branch(float angle) {
// What is my current heading
float theta = vel.heading2D();
// What is my current speed
float mag = vel.mag();
// Turn me
theta += radians(angle);
// Look, polar coordinates to cartesian!!
PVector newvel = new PVector(mag*cos(theta),mag*sin(theta));
// Return a new Branch
return new Branch(end,newvel,timerstart*0.66f);
}
}
@@ -0,0 +1,59 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Recursive Tree (w/ ArrayList)
// Nature of Code, Chapter 8
// Recursive branching "structure" without an explicitly recursive function
// Instead we have an ArrayList to hold onto N number of elements
// For every element in the ArrayList, we add 2 more elements, etc. (this is the recursion)
// An arraylist that will keep track of all current branches
ArrayList<Branch> tree;
ArrayList<Leaf> leaves;
void setup() {
size(640,360);
background(255);
// Setup the arraylist and add one branch to it
tree = new ArrayList<Branch>();
leaves = new ArrayList<Leaf>();
// A branch has a starting location, a starting "velocity", and a starting "timer"
Branch b = new Branch(new PVector(width/2,height),new PVector(0,-1),100);
// Add to arraylist
tree.add(b);
}
void draw() {
background(255);
// Let's stop when the arraylist gets too big
// For every branch in the arraylist
for (int i = tree.size()-1; i >= 0; i--) {
// Get the branch, update and draw it
Branch b = tree.get(i);
b.update();
b.render();
// If it's ready to split
if (b.timeToBranch()) {
if (tree.size() < 1024) {
//tree.remove(i); // Delete it
tree.add(b.branch( 30)); // Add one going right
tree.add(b.branch(-25)); // Add one going left
}
else {
leaves.add(new Leaf(b.end));
}
}
}
for (Leaf leaf : leaves) {
leaf.display();
}
}
@@ -0,0 +1,23 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Recursive Tree (w/ ArrayList)
// A class for a leaf that gets placed at the end of
// the last branches
class Leaf {
PVector loc;
Leaf(PVector l) {
loc = l.get();
}
void display() {
noStroke();
fill(50,100);
ellipse(loc.x,loc.y,4,4);
}
}
@@ -0,0 +1,74 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Stochastic Tree with angles fluctuating with Perlin noise
// Nature of Code, Chapter 8
// Perlin noise offset
float yoff = 0;
// Random seed to control randomness while drawing the tree
int seed = 5;
void setup() {
size(800, 200);
smooth();
}
void draw() {
background(255);
fill(0);
//text("Click mouse to generate a new tree", 10, height-20);
stroke(0);
// Start the tree from the bottom of the screen
translate(width/2, height);
// Move alogn through noise
yoff += 0.005;
randomSeed(seed);
// Start the recursive branching!
branch(60, 0);
}
void mousePressed() {
// New tree starts with new noise offset and new random seed
yoff = random(1000);
seed = millis();
}
void branch(float h, float xoff) {
// thickness of the branch is mapped to its length
float sw = map(h, 2, 100, 1, 5);
strokeWeight(sw);
// Draw the branch
line(0, 0, 0, -h);
// Move along to end
translate(0, -h);
// Each branch will be 2/3rds the size of the previous one
h *= 0.7f;
// Move along through noise space
xoff += 0.1;
if (h > 4) {
// Random number of branches
int n = int(random(0, 5));
for (int i = 0; i < n; i++) {
// Here the angle is controlled by perlin noise
// This is a totally arbitrary way to do it, try others!
float theta = map(noise(xoff+i, yoff), 0, 1, -PI/3, PI/3);
if (n%2==0) theta *= -1;
pushMatrix(); // Save the current state of transformation (i.e. where are we now)
rotate(theta); // Rotate by theta
branch(h, xoff); // Ok, now call myself to branch again
popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state
}
}
}
@@ -9,8 +9,7 @@
float theta;
void setup() {
size(250, 200);
smooth();
size(640, 360);
}
void draw() {
@@ -6,7 +6,7 @@ LSystem lsys;
Turtle turtle;
void setup() {
size(800, 200);
size(600, 600);
/*
// Create an empty ruleset
Rule[] ruleset = new Rule[2];
@@ -52,6 +52,7 @@ void mousePressed() {
if (counter < 5) {
pushMatrix();
lsys.generate();
//println(lsys.getSentence());
turtle.setToDo(lsys.getSentence());
turtle.changeLen(0.5);
popMatrix();
@@ -15,8 +15,7 @@ class DNA {
DNA(int num) {
genes = new PVector[num];
for (int i = 0; i < genes.length; i++) {
float angle = random(TWO_PI);
genes[i] = new PVector(cos(angle), sin(angle));
genes[i] = PVector.random2D();
}
}
@@ -46,10 +45,38 @@ class DNA {
void mutate(float m) {
for (int i = 0; i < genes.length; i++) {
if (random(1) < m) {
float angle = random(TWO_PI);
genes[i] = new PVector(cos(angle), sin(angle));
genes[i] = PVector.random2D();
}
}
}
void debugDraw() {
int cols = width / gridscale;
int rows = height / gridscale;
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
drawVector(genes[i+j*cols],i*gridscale,j*gridscale,gridscale-2);
}
}
}
// Renders a vector object 'v' as an arrow and a location 'x,y'
void drawVector(PVector v, float x, float y, float scayl) {
pushMatrix();
float arrowsize = 4;
// Translate to location to render vector
translate(x+gridscale/2,y);
stroke(0,100);
// Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate
rotate(v.heading());
// Calculate length of vector & scale it to be bigger or smaller if necessary
float len = v.mag()*scayl;
// Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction)
line(-len/2,0,len/2,0);
//noFill();
//ellipse(-len/2,0,2,2);
popMatrix();
}
}
@@ -1,4 +1,4 @@
// The Nature of Code
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
@@ -12,7 +12,7 @@
import java.awt.Rectangle;
int gridscale = 24; // Scale of grid is 1/24 of screen size
int gridscale = 10; // Scale of grid is 1/24 of screen size
// DNA needs one vector for every spot on the grid
// (it's like a pixel array, but with vectors instead of colors)
@@ -20,9 +20,6 @@ int dnasize;
int lifetime; // How long should each generation live
// Global maxforce and maxspeed (hmmm, could make this part of DNA??)
float maxspeed = 4.0;
float maxforce = 1.0;
Population population; // Population
int lifecycle; // Timer for cycle of generation
@@ -33,10 +30,14 @@ int diam = 24; // Size of target
ArrayList<Obstacle> obstacles; //an array list to keep track of all the obstacles!
boolean debug = false;
Rectangle newObstacle = null;
void setup() {
size(640,480);
size(640,360);
dnasize = (width / gridscale) * (height / gridscale);
lifetime = width/2;
lifetime = width/3;
// Initialize variables
lifecycle = 0;
@@ -46,22 +47,23 @@ void setup() {
// Create a population with a mutation rate, and population max
int popmax = 1000;
float mutationRate = 0.05;
float mutationRate = 0.02;
population = new Population(mutationRate,popmax);
// Create the obstacle course
obstacles = new ArrayList<Obstacle>();
obstacles.add(new Obstacle(width/4,40,10,height-80));
obstacles.add(new Obstacle(width/2,0,10,height/2-10));
obstacles.add(new Obstacle(width/2,height-height/2+10,10,height/2-10));
obstacles.add(new Obstacle(2*width/3,height/2-height/8,10,height/4));
/*obstacles.add(new Obstacle(width/4,80,10,height-160));
obstacles.add(new Obstacle(width/2,0,10,height/2-20));
obstacles.add(new Obstacle(width/2,height-height/2+20,10,height/2-20));
obstacles.add(new Obstacle(2*width/3,height/2-height/8,10,height/4));*/
}
void draw() {
background(255);
// Draw the start and target locations
start.display();
// Draw the target locations
target.display();
// Draw the obstacles
@@ -89,15 +91,31 @@ void draw() {
textAlign(RIGHT);
fill(0);
text("Generation #:" + population.getGenerations(),width-10,18);
text("Cycles left:" + ((lifetime-lifecycle)/10),width-10,36);
text("Cycles left:" + ((lifetime-lifecycle)),width-10,36);
text("Record cycles: " + recordtime,width-10,54);
if (newObstacle != null) {
rect(newObstacle.x,newObstacle.y,newObstacle.width,newObstacle.height);
}
}
// Move the target if the mouse is pressed
// System will adapt to new target
void mousePressed() {
target = new Obstacle(mouseX,mouseY,diam,diam);
recordtime = lifetime;
void keyPressed() {
if (key == 'd') {
debug = !debug;
}
}
void mousePressed() {
newObstacle = new Rectangle(mouseX,mouseY,0,0);
}
void mouseDragged() {
newObstacle.width = mouseX-newObstacle.x;
newObstacle.height = mouseY-newObstacle.y;
}
void mouseReleased() {
obstacles.add(new Obstacle(newObstacle));
newObstacle = null;
}
@@ -16,6 +16,10 @@ class Obstacle {
Obstacle(int x, int y, int w, int h) {
r = new Rectangle(x,y,w,h);
}
Obstacle(Rectangle r_) {
r = r_;
}
void display() {
stroke(0);
@@ -11,17 +11,19 @@ class Population {
ArrayList<Rocket> darwin; // ArrayList which we will use for our "mating pool"
int generations; // Number of generations
int order; // Keep track of the order of creature's finishing the maze
int order; // Keep track of the order of creature's finishing the maze
// Initialize the population
Population(float m, int num) {
// Initialize the population
Population(float m, int num) {
mutationRate = m;
population = new Rocket[num];
darwin = new ArrayList<Rocket>();
generations = 0;
//make a new set of creatures
for (int i = 0; i < population.length; i++) {
PVector location = new PVector(start.r.x+start.r.width/2,start.r.y+start.r.height/2);
PVector location = new PVector(start.r.x+start.r.width/2, start.r.y+start.r.height/2);
population[i] = new Rocket(location, new DNA(dnasize));
}
order = 1; // The first one to finish will be #1
@@ -29,14 +31,31 @@ class Population {
void live (ArrayList<Obstacle> o) {
// For every creature
float record = 100000;
int closest = 0;
for (int i = 0; i < population.length; i++) {
// If it finishes, mark it down as done!
if ((population[i].finished()) && (!population[i].stopped())) {
if ((population[i].finished())) {
population[i].setFinish(order);
order++;
}
// Run it
population[i].run(o);
if (population[i].recordDist < record) {// && !population[i].dead) {
record = population[i].recordDist;
closest = i;
}
}
population[closest].highlight();
// Drawing one example of the DNA
if (debug) {
population[closest].dna.debugDraw();
}
}
@@ -63,18 +82,25 @@ class Population {
// Calculate total fitness of whole population
float totalFitness = getTotalFitness();
float avgFitness = totalFitness/population.length;
// Calculate normalized fitness for each member of the population
// Based on normalized fitness, each member will get added to the mating pool a certain number of times a la roulette wheel
// A higher fitness = more entries to mating pool = more likely to be picked as a parent
// A lower fitness = fewer entries to mating pool = less likely to be picked as a parent
int count = 0;
for (int i = 0; i < population.length; i++) {
float fitnessNormal = population[i].getFitness() / totalFitness;
int n = (int) (fitnessNormal * 50000); // Arbitrary multiplier, consider mapping fix
for (int j = 0; j < n; j++) {
darwin.add(population[i]);
}
float fitness = population[i].getFitness();
//if (fitness > avgFitness) {
count++;
float fitnessNormal = fitness / totalFitness;
int n = (int) (fitnessNormal * 50000); // Arbitrary multiplier, consider mapping fix
for (int j = 0; j < n; j++) {
darwin.add(population[i]);
}
//}
}
//println("Total: " + count + " " + population.length);
}
// Making the next generation
@@ -94,7 +120,7 @@ class Population {
// Mutate their genes
child.mutate(mutationRate);
// Fill the new population with the new child
PVector location = new PVector(start.r.x+start.r.width/2,start.r.y+start.r.height/2);
PVector location = new PVector(start.r.x+start.r.width/2, start.r.y+start.r.height/2);
population[i] = new Rocket(location, child);
}
generations++;
@@ -112,5 +138,5 @@ class Population {
}
return total;
}
}
@@ -15,11 +15,17 @@ class Rocket {
PVector acceleration;
float r;
float recordDist;
float fitness;
DNA dna;
// Could make this part of DNA??)
float maxspeed = 6.0;
float maxforce = 1.0;
boolean stopped; // Am I stuck?
boolean dead; // Did I hit an obstacle?
int finish; // What was my finish? (first, second, etc. . . )
//constructor
@@ -46,6 +52,8 @@ class Rocket {
}
// Reward finishing faster and getting closer
fitness = (1.0f / pow(finish,1.5)) * (1 / (pow(d,6)));
//if (dead) fitness = 0;
}
void setFinish(int f) {
@@ -60,6 +68,7 @@ class Rocket {
// If I hit an edge or an obstacle
if ((borders()) || (obstacles(o))) {
stopped = true;
dead = true;
}
}
// Draw me!
@@ -78,7 +87,9 @@ class Rocket {
// Did I make it to the target?
boolean finished() {
float d = dist(location.x,location.y,target.r.x,target.r.y);
if (d < recordDist) recordDist = d;
if (d < recordDist) {
recordDist = d;
}
if (target.contains(location)) {
stopped = true;
return true;
@@ -105,11 +116,13 @@ class Rocket {
y = constrain(y,0,height/gridscale-1); // Make sure we are not off the edge
// Get the steering vector out of our genes in the right spot
// We could do (desired - velocity) to be more in line with the Reynolds flow field following
acceleration.add(dna.genes[x+y*width/gridscale]);
// This is all the same stuff we've done before
acceleration.mult(maxforce);
// A little Reynolds steering here
PVector desired = dna.genes[x+y*(width/gridscale)].get();
desired.mult(maxspeed);
PVector steer = PVector.sub(desired,velocity);
acceleration.add(steer);
acceleration.limit(maxforce);
velocity.add(acceleration);
velocity.limit(maxspeed);
location.add(velocity);
@@ -121,7 +134,7 @@ class Rocket {
//fill(0,150);
//stroke(0);
//ellipse(location.x,location.y,r,r);
float theta = velocity.heading2D() + PI/2;
float theta = velocity.heading() + PI/2;
fill(200,100);
stroke(0);
pushMatrix();
@@ -133,8 +146,14 @@ class Rocket {
vertex(r, r*2);
endShape();
popMatrix();
}
void highlight() {
stroke(0);
line(location.x,location.y,target.r.x,target.r.y);
fill(255,0,0,100);
ellipse(location.x,location.y,16,16);
}
float getFitness() {
@@ -41,6 +41,8 @@ class DNA {
score++;
}
}
fitness = (float)score / (float)target.length();
}
@@ -36,7 +36,7 @@ float mutationRate;
Population population;
void setup() {
size(800, 200);
size(640, 360);
f = createFont("Courier", 32, true);
target = "To be or not to be.";
popmax = 150;
@@ -71,19 +71,19 @@ void displayInfo() {
fill(0);
textSize(16);
textSize(24);
text("Best phrase:",20,30);
textSize(32);
text(answer, 20, 75);
textSize(40);
text(answer, 20, 100);
textSize(12);
text("total generations: " + population.getGenerations(), 20, 140);
text("average fitness: " + nf(population.getAverageFitness(), 0, 2), 20, 155);
text("total populationation: " + popmax, 20, 170);
text("mutation rate: " + int(mutationRate * 100) + "%", 20, 185);
textSize(18);
text("total generations: " + population.getGenerations(), 20, 160);
text("average fitness: " + nf(population.getAverageFitness(), 0, 2), 20, 180);
text("total population: " + popmax, 20, 200);
text("mutation rate: " + int(mutationRate * 100) + "%", 20, 220);
textSize(10);
text("All phrases:\n" + population.allPhrases(), 650, 10);
text("All phrases:\n" + population.allPhrases(), 500, 10);
}
@@ -29,7 +29,7 @@ class Population {
finished = false;
generations = 0;
perfectScore = int(pow(2,target.length()));
perfectScore = 1;
}
// Fill our fitness array with a value for every member of the population
@@ -82,7 +82,7 @@ class Population {
// Compute the current "most fit" member of the population
String getBest() {
float worldrecord = 0.0f;
float worldrecord = 0.0;
int index = 0;
for (int i = 0; i < population.length; i++) {
if (population[i].fitness > worldrecord) {
@@ -90,7 +90,7 @@ class Population {
worldrecord = population[i].fitness;
}
}
if (worldrecord == perfectScore ) finished = true;
return population[index].getPhrase();
}
@@ -23,9 +23,9 @@ int lifeCounter; // Timer for cycle of generation
PVector target; // Target location
void setup() {
size(800, 200);
size(640, 360);
// The number of cycles we will allow a generation to live
lifetime = 200;
lifetime = height;
// Initialize variables
lifeCounter = 0;
@@ -28,7 +28,7 @@ Obstacle target; // Target location
ArrayList<Obstacle> obstacles; //an array list to keep track of all the obstacles!
void setup() {
size(800, 200);
size(640, 360);
// The number of cycles we will allow a generation to live
lifetime = 300;
@@ -44,7 +44,7 @@ void setup() {
// Create the obstacle course
obstacles = new ArrayList<Obstacle>();
obstacles.add(new Obstacle(300, height/2, width-600, 10));
obstacles.add(new Obstacle(width/2-100, height/2, 200, 10));
}
void draw() {
@@ -13,7 +13,7 @@
World world;
void setup() {
size(800, 200);
size(640, 360);
// World starts with 20 creatures
// and 20 pieces of food
world = new World(20);
@@ -30,4 +30,8 @@ void mousePressed() {
world.born(mouseX,mouseY);
}
void mouseDragged() {
world.born(mouseX,mouseY);
}