/* The Population class allows us to describe and control a collection of virtual organisms, and guide them through generations of evolution and selection. Each of our organisms is an instance of the DNA class. This type of evolution system has an end point; Once a DNA object reaches the goal (matching the phrase the population is trying to replicate) the system stops, as the fitness of the population has reached 100% */ class Population { // The maximum number of organisms in any generation int maxOrganisms; // The rate at which the organisms mutate float mutationRate; // The array holding our current population of organisms DNA[] population; // The fitness score of each organism in the population array float[] fitness; // The mating pool we use when creating a new generation ArrayList geneticPool; // The phrase the organisms are trying to evolve to match String targetPhrase; // Total number of generations so far int generations; // Has the population reached 100% fitness (matched the targetPhrase) boolean finished; /* Our constructor initializes the population with the maximum number of organisms, each with a random set of DNA. */ public Population(String targetPhrase_, float mutationRate_, int maxOrganisms_) { // keep track of our parameters passed in targetPhrase = targetPhrase_; mutationRate = mutationRate_; maxOrganisms = maxOrganisms_; // Create our new population population = new DNA[maxOrganisms]; for (int i = 0; i < maxOrganisms; i++) { population[i] = new DNA(targetPhrase.length()); } // create the fitness array fitness = new float[maxOrganisms]; calcFitness(); // initialize the gene pool geneticPool = new ArrayList(); // Setup the remained of the properties generations = 0; finished = false; } public void simulate() { // Run the evolution simulation on our objects naturalSelection(); generate(); calcFitness(); } // Calculate all of the fitness scores for our objects public void calcFitness() { for (int i = 0; i < population.length; i++) { fitness[i] = population[i].getFitness(targetPhrase); } } // Create the genetic pool that we'll use later on to select // a new generation of organisms // // To create the gene pool we calculate how fit each DNA object // is in comparison to the whole population. Each object is added // to the gene pool a number of times corresponding to how fit it is. // Therefor the more fit a DNA object, the more often it is added to the // gene pool, and the more likely it will be to pass on it's DNA public void naturalSelection() { // clear the gene pool geneticPool.clear(); // get the total fitness of the whole population float totalFitness = getTotalFitness(); // For each DNA object calculate it's relative fitness to the whole // group. for (int i = 0; i < population.length; i++) { // get the relative fitness float fitnessNormal = fitness[i] / totalFitness; // figure out how many entries to the gene pool this object gets int poolEntries = (int)(fitnessNormal * 10000.0f); // add the object to the gene pool the appropriate number of times for (int j = 0; j < poolEntries; j++) { geneticPool.add(population[i]); } } } // To create a new geneation we pick two parent DNA sequences from // the gene pool (for clarity we'll call them 'mom' and 'dad'). Once // we have the parents, we can let the DNA class do the work for us, // and place the new DNA object into the population array public void generate() { for (int i = 0; i < population.length; i++) { // pick two random candidates from the gene pool int m = (int)random(geneticPool.size()); int d = (int)random(geneticPool.size()); // get the parent DNA object DNA mom = (DNA)geneticPool.get(m); DNA dad = (DNA)geneticPool.get(d); // create the new DNA object DNA child = mom.mate(dad); // mutation child.mutate(mutationRate); // add to the current population population[i] = child; } generations++; } // We want to see things in progress, so this method gives us // the String of DNA of the current most fit DNA object public String getBestFit() { // find the most fit object and record it's position in // the population and its fitness score float mostFit = 0.0f; int index = 0; for (int i = 0; i < population.length; i++) { if (fitness[i] > mostFit) { index = i; mostFit = fitness[i]; } } // check to see if the population is finished evolving if (mostFit == 1.0f) { finished = true; } return population[index].toString(); } public boolean isFinished() { return finished; } public int getGenerations() { return generations; } // Calculate the total fitness score of the population public float getTotalFitness() { float total = 0.0f; for (int i = 0; i < population.length; i++) { total += fitness[i]; } return total; } // Calculate the current average fitness of the population public float getAverageFitness() { float totalFitness = getTotalFitness(); return totalFitness / (float)population.length; } }