// The Genetic Algorithm
   // Implementation based on Dan Shiffman's Nature of Code, 2012 [Chapter 9]
   // By: Deepak Kumar [2021]
   // Fixes a number of issues with Dan's code.
   // 1. Make it generic to target phrases of any length
   // 2. Fitness of an individual is computed as soon as it is created/modified/mutated
   // 3. [MAJOR FIX] Entire new population is generated (Dan's replaces old pop as it produces offspring).
   //
   // To try any phrase, specify it in setup()
   //
   // GA parameters/variables
   float mutationRate = 0.01;      // Mutation rate, needs to be small
   int totalPopulation = 200;      // size of the population
   DNA[] population;               // The population
   ArrayList<DNA> matingPool;      // Mating pool
   String target;                  // target string
   // Display/output font object
   PFont f;
void setup() {
   size(800, 360);
   f = createFont("Consolas", 36);
   
   // THIS IS THE TARGET STRING, change as desired
   target = "To be, or not to be.";
   
   // Initializations
   mutationRate = 0.01;
   population = new DNA[totalPopulation];
   
   // Create population of Generation 1
   for (int i=0; i < population.length; i++)
   population[i] = new DNA(target.length());
   // Average fitness
   float avgFitness, sum = 0.0;
   for (int i = 0; i < population.length; i++) {
   sum = sum + population[i].fitness;
   }
   avgFitness = sum/population.length;
   //println("Starting Avg. Fitness = " + str(avgFitness));
   println("0,"+str(avgFitness));
   } // setup()
void draw() {
   background(0);
   
   // Mating pool
   ArrayList<DNA> matingPool = new ArrayList<DNA>();
   for (int i = 0; i < population.length; i++) {
   int n = int(population[i].fitness * 100);
   for (int j = 0; j < n; j++) {
   matingPool.add(population[i]);
   }
   }
   
   // Reproduction
   DNA[] newPopulation = new DNA[totalPopulation];  // ===
   for (int i = 0; i < population.length; i++) {
   int a = int(random(matingPool.size()));
   int b = int(random(matingPool.size()));
   
   DNA parentA = matingPool.get(a);
   DNA parentB = matingPool.get(b);
   
   // Crossover
   DNA child = parentA.crossover(parentB);
   
   // mutation
   child.mutate(mutationRate);
   newPopulation[i] = child;
   }
   population = newPopulation;
   
   // output from this generation
   // Average fitness
   float avgFitness, sum = 0.0;
   for (int i = 0; i < population.length; i++) {
   sum = sum + population[i].fitness;
   }
   avgFitness = sum/population.length;
 // Best individual and its fitness
   float bestFitness = population[0].fitness;
   int bestIndiv = 0;
   for (int i = 1; i < population.length; i++) {
   // find fittest individual
   if (population[i].fitness > bestFitness) {
   bestFitness = population[i].fitness;
   bestIndiv = i;
   }
 }
   
   // Ouput from this generation
   println(frameCount+","+str(avgFitness));
   String phrase = population[bestIndiv].getPhrase();
 textFont(f, 24);
   text("Target: " + target, 10, 40);
   text("Generation: " + str(frameCount), 10, 90);
   text("Avg. Fitness: " + str(avgFitness), 10, 140); 
   text("Phrase: " + phrase, 10, 190);
   text("Fitness: " + str(population[bestIndiv].fitness), 10, 240);
   
   if (phrase.equals(target)) {
   println("Done.");
   noLoop();
   }
   
   } // draw()