Skip to content

Commit

Permalink
Lecture 13
Browse files Browse the repository at this point in the history
  • Loading branch information
maxzanoni committed Dec 6, 2019
1 parent e04525d commit 7a32f51
Show file tree
Hide file tree
Showing 20 changed files with 1,387 additions and 0 deletions.
49 changes: 49 additions & 0 deletions Lectures/Lecture13/Faces_interactiveselection/Button.pde
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@


class Button {
Rectangle r; // Button's rectangle
String txt; // Button's text
boolean clickedOn; // Did i click on it?
boolean rolloverOn; // Did i rollover it?

Button(int x, int y, int w, int h, String s) {
r = new Rectangle(x,y,w,h);
txt = s;
}

void display() {
// Draw rectangle and text based on whether rollover or clicked
rectMode(CORNER);
stroke(0); noFill();
if (rolloverOn) fill(0.5);
if (clickedOn) fill(0);
rect(r.x,r.y,r.width,r.height);
float b = 0.0;
if (clickedOn) b = 1;
else if (rolloverOn) b = 0.2;
else b = 0;
fill(b);
textAlign(LEFT);
text(txt,r.x+10,r.y+14);

}


// Methods to check rollover, clicked, or released (must be called from appropriate
// Places in draw, mousePressed, mouseReleased
boolean rollover(int mx, int my) {
if (r.contains(mx,my)) rolloverOn = true;
else rolloverOn = false;
return rolloverOn;
}

boolean clicked(int mx, int my) {
if (r.contains(mx,my)) clickedOn = true;
return clickedOn;
}

void released() {
clickedOn = false;
}

}
43 changes: 43 additions & 0 deletions Lectures/Lecture13/Faces_interactiveselection/DNA.pde
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

class DNA {

// The genetic sequence
float[] genes;
int len = 20; // Arbitrary length

//Constructor (makes a random DNA)
DNA() {
// DNA is random floating point values between 0 and 1 (!!)
genes = new float[len];
for (int i = 0; i < genes.length; i++) {
genes[i] = random(0,1);
}
}

DNA(float[] newgenes) {
genes = newgenes;
}


// Crossover
// Creates new DNA sequence from two (this &
DNA crossover(DNA partner) {
float[] child = new float[genes.length];
int crossover = int(random(genes.length));
for (int i = 0; i < genes.length; i++) {
if (i > crossover) child[i] = genes[i];
else child[i] = partner.genes[i];
}
DNA newgenes = new DNA(child);
return newgenes;
}

// Based on a mutation probability, picks a new random character in array spots
void mutate(float m) {
for (int i = 0; i < genes.length; i++) {
if (random(1) < m) {
genes[i] = random(0,1);
}
}
}
}
97 changes: 97 additions & 0 deletions Lectures/Lecture13/Faces_interactiveselection/Face.pde
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

// The class for our "face", contains DNA sequence, fitness value, position on screen

// Fitness Function f(t) = t (where t is "time" mouse rolls over face)

class Face {

DNA dna; // Face's DNA
float fitness; // How good is this face?
float x, y; // Position on screen
int wh = 70; // Size of square enclosing face
boolean rolloverOn; // Are we rolling over this face?

Rectangle r;

// Create a new face
Face(DNA dna_, float x_, float y_) {
dna = dna_;
x = x_;
y = y_;
fitness = 1;
// Using java.awt.Rectangle (see: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Rectangle.html)
r = new Rectangle(int(x-wh/2), int(y-wh/2), int(wh), int(wh));
}

// Display the face
void display() {
// We are using the face's DNA to pick properties for this face
// such as: head size, color, eye position, etc.
// Now, since every gene is a floating point between 0 and 1, we map the values
float r = map(dna.genes[0],0,1,0,70);
color c = color(dna.genes[1],dna.genes[2],dna.genes[3]);
float eye_y = map(dna.genes[4],0,1,0,5);
float eye_x = map(dna.genes[5],0,1,0,10);
float eye_size = map(dna.genes[5],0,1,0,10);
color eyecolor = color(dna.genes[4],dna.genes[5],dna.genes[6]);
color mouthColor = color(dna.genes[7],dna.genes[8],dna.genes[9]);
float mouth_y = map(dna.genes[5],0,1,0,25);
float mouth_x = map(dna.genes[5],0,1,-25,25);
float mouthw = map(dna.genes[5],0,1,0,50);
float mouthh = map(dna.genes[5],0,1,0,10);

// Once we calculate all the above properties, we use those variables to draw rects, ellipses, etc.
pushMatrix();
translate(x, y);
noStroke();

// Draw the head
smooth();
fill(c);
ellipseMode(CENTER);
ellipse(0, 0, r, r);

// Draw the eyes
fill(eyecolor);
rectMode(CENTER);
rect(-eye_x, -eye_y, eye_size, eye_size);
rect( eye_x, -eye_y, eye_size, eye_size);

// Draw the mouth
fill(mouthColor);
rectMode(CENTER);
rect(mouth_x, mouth_y, mouthw, mouthh);

// Draw the bounding box
stroke(0.25);
if (rolloverOn) fill(0, 0.25);
else noFill();
rectMode(CENTER);
rect(0, 0, wh, wh);
popMatrix();

// Display fitness value
textAlign(CENTER);
if (rolloverOn) fill(0);
else fill(0.25);
text(int(fitness), x, y+55);
}

float getFitness() {
return fitness;
}

DNA getDNA() {
return dna;
}

// Increment fitness if mouse is rolling over face
void rollover(int mx, int my) {
if (r.contains(mx, my)) {
rolloverOn = true;
fitness += 0.25;
} else {
rolloverOn = false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@


Population population;
Button button;

void setup() {
size(800,200);
colorMode(RGB,1.0);
smooth();
int popmax = 10;
float mutationRate = 0.05; // A pretty high mutation rate here, our population is rather small we need to enforce variety
// Create a population with a target phrase, mutation rate, and population max
population = new Population(mutationRate,popmax);
// A simple button class
button = new Button(15,150,160,20, "evolve new generation");
}

void draw() {
background(1.0);
// Display the faces
population.display();
population.rollover(mouseX,mouseY);
// Display some text
textAlign(LEFT);
fill(0);
text("Generation #:" + population.getGenerations(),15,190);

// Display the button
button.display();
button.rollover(mouseX,mouseY);

}

// If the button is clicked, evolve next generation
void mousePressed() {
if (button.clicked(mouseX,mouseY)) {
population.selection();
population.reproduction();
}
}

void mouseReleased() {
button.released();
}
95 changes: 95 additions & 0 deletions Lectures/Lecture13/Faces_interactiveselection/Population.pde
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@

// A class to describe a population of faces
// this hasn't changed very much from example to example

class Population {

float mutationRate; // Mutation rate
Face[] population; // array to hold the current population
ArrayList<Face> matingPool; // ArrayList which we will use for our "mating pool"
int generations; // Number of generations

// Create the population
Population(float m, int num) {
mutationRate = m;
population = new Face[num];
matingPool = new ArrayList<Face>();
generations = 0;
for (int i = 0; i < population.length; i++) {
population[i] = new Face(new DNA(), 50+i*75, 60);
}
}

// Display all faces
void display() {
for (int i = 0; i < population.length; i++) {
population[i].display();
}
}

// Are we rolling over any of the faces?
void rollover(int mx, int my) {
for (int i = 0; i < population.length; i++) {
population[i].rollover(mx, my);
}
}

// Generate a mating pool
void selection() {
// Clear the ArrayList
matingPool.clear();

// Calculate total fitness of whole population
float maxFitness = getMaxFitness();

// Calculate fitness for each member of the population (scaled to value between 0 and 1)
// Based on fitness, each member will get added to the mating pool a certain number of times
// 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
for (int i = 0; i < population.length; i++) {
float fitnessNormal = map(population[i].getFitness(), 0, maxFitness, 0, 1);
int n = (int) (fitnessNormal * 100); // Arbitrary multiplier
for (int j = 0; j < n; j++) {
matingPool.add(population[i]);
}
}
}

// Making the next generation
void reproduction() {
// Refill the population with children from the mating pool
for (int i = 0; i < population.length; i++) {
// Sping the wheel of fortune to pick two parents
int m = int(random(matingPool.size()));
int d = int(random(matingPool.size()));
// Pick two parents
Face mom = matingPool.get(m);
Face dad = matingPool.get(d);
// Get their genes
DNA momgenes = mom.getDNA();
DNA dadgenes = dad.getDNA();
// Mate their genes
DNA child = momgenes.crossover(dadgenes);
// Mutate their genes
child.mutate(mutationRate);
// Fill the new population with the new child
population[i] = new Face(child, 50+i*75, 60);
}
generations++;
}

int getGenerations() {
return generations;
}

// Find highest fintess for the population
float getMaxFitness() {
float record = 0;
for (int i = 0; i < population.length; i++) {
if (population[i].getFitness() > record) {
record = population[i].getFitness();
}
}
return record;
}
}
21 changes: 21 additions & 0 deletions Lectures/Lecture13/Faces_interactiveselection/Rectangle.pde
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Re-implementing java.awt.Rectangle
// so JS mode works

class Rectangle {
int x;
int y;
int width;
int height;

Rectangle(int x_, int y_, int w, int h) {
x = x_;
y = y_;
width = w;
height = h;
}

boolean contains(int px, int py) {
return (px > x && px < x + width && py > y && py < y + height);
}

}
Loading

0 comments on commit 7a32f51

Please sign in to comment.