diff --git a/s183/s183.pde b/s183/s183.pde index 95bdea62..f6b99e1d 100644 --- a/s183/s183.pde +++ b/s183/s183.pde @@ -1,5 +1,5 @@ // Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day -// s182 20180629 +// s183 20180701 // Based on GA from The Nature of Code by Daniel Shiffman http://natureofcode.com Population population; diff --git a/s184/DNA.pde b/s184/DNA.pde new file mode 100644 index 00000000..f23ee056 --- /dev/null +++ b/s184/DNA.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +class DNA { + + // The genetic sequence + float[] genes; + int len = 40; // 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); + } + } + } +} diff --git a/s184/Organism.pde b/s184/Organism.pde new file mode 100644 index 00000000..2df2ce93 --- /dev/null +++ b/s184/Organism.pde @@ -0,0 +1,86 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +// The class for our "organism", contains DNA sequence, fitness value, position on screen +// Fitness Function f(t) = t (where t is "time" mouse rolls over organism) + +class Organism { + + DNA dna; // organism's DNA + float fitness; // How good is this organism? + float x, y; // Position on screen + int wh = 110; // Size of square enclosing organism + boolean mouseIsOver; // Are we rolling over this organism? + + // Create a new organism + Organism(DNA dna_, float x_, float y_) { + dna = dna_; + x = x_; + y = y_; + fitness = 1; + } + + // Display the organism + void display() { + // We are using the organism's DNA to pick properties for this organism + // Now, since every gene is a floating point between 0 and 1, we map the values + int n = int(map(dna.genes[0]+dna.genes[39], 0, 2, 3, 19)); + pushMatrix(); + pushStyle(); + translate(x, y); + for (int i = 2; i < n; i = i + 2) { + stroke(1); + stroke(dna.genes[i-1], 1, 1); + noFill(); + float x1 = map(dna.genes[i], 0, 1, -wh/4, wh/4); + float y1 = map(dna.genes[i+1], 0, 1, -wh/4, wh/4); + float x2 = map(dna.genes[i*2], 0, 1, -wh/4, wh/4); + float y2 = map(dna.genes[i*2+1], 0, 1, -wh/4, wh/4); + float x3 = map(dna.genes[i-1], 0, 1, wh/10, wh/4); + float y3 = map(dna.genes[i*2-1], 0, 1, wh/10, wh/4); + triangle(x1, y1, x2, y2, x3, y3); + } + // Draw the bounding box + popStyle(); + + rectMode(CENTER); + + if (mouseIsOver) fill(0.5, 0.5); + else noFill(); + + stroke(1); + rect(0, 0, wh, wh); + stroke(0.5); + line(-wh/2, 0, wh/2, 0); + line(0, -wh/2, 0, wh/2); + popMatrix(); + + // Display fitness value + textAlign(CENTER); + fill(1); + text(fitness, x, y+70); + } + + float getFitness() { + return fitness; + } + + DNA getDNA() { + return dna; + } + + // Increment fitness if mouse is rolling over organism + void checkMouseOver(int mx, int my) { + int cx = int(x-wh/2); + int cy = int(y-wh/2); + if (mx > cx && mx < cx + wh && my > cy && my < cy + wh) { + mouseIsOver = true; + if (mousePressed) fitness += 0.25; + } else { + mouseIsOver = false; + } + } +} diff --git a/s184/Population.pde b/s184/Population.pde new file mode 100644 index 00000000..94136571 --- /dev/null +++ b/s184/Population.pde @@ -0,0 +1,109 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +// A class to describe a population of faces +// this hasn't changed very much from example to example + +class Population { + + float mutationRate; // Mutation rate + Organism[] population; // array to hold the current population + ArrayList 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 Organism[num]; + matingPool = new ArrayList(); + generations = 0; + //for (int i = 0; i < population.length; i++) { + // population[i] = new Organism(new DNA(), 50+i*88.5, 60); + //} + float s = width/5.2; + int i = 0; + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) { + population[i] = new Organism(new DNA(), s/1.75+x*s, s/1.75+y*s); + i++; + } + } + } + + // 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].checkMouseOver(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 + Organism mom = matingPool.get(m); + Organism 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 Organism(child, population[i].x, population[i].y); + } + 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; + } +} diff --git a/s184/s183.png b/s184/s183.png new file mode 100644 index 00000000..fb72b3aa Binary files /dev/null and b/s184/s183.png differ diff --git a/s184/s184.pde b/s184/s184.pde new file mode 100644 index 00000000..95bdea62 --- /dev/null +++ b/s184/s184.pde @@ -0,0 +1,35 @@ +// Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day +// s182 20180629 +// Based on GA from The Nature of Code by Daniel Shiffman http://natureofcode.com + +Population population; + +void setup() { + size(750, 750); + colorMode(HSB, 1.0); + int popmax = 25; + float mutationRate = 0.03; // 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); +} + +void draw() { + background(0); + // Display the faces + population.display(); + population.rollover(mouseX, mouseY); + // Display some text + textAlign(LEFT); + fill(1); + text("[pressione 'e' para a calcular a próxima geração] Geração #:" + population.getGenerations(), 25, 20); +} + +// If 'e' is presses, evolve next generation +void keyPressed() { + if (key == 'e') { + randomSeed(frameCount); + population.selection(); + population.reproduction(); + //saveFrame(population.getGenerations()+"GA.png"); + } +}