/// <summary> /// Assign a species to each network in the population /// </summary> private void AssignPopulationToSpecies() { foreach (NeatNetwork network in population) { // Attempt to add an existing species bool added = false; foreach (NeatSpecies species in activeSpecies) { added = species.AttemptAdd(network); if (added) { break; } } // Create a new species with this as a rep if (!added) { NeatSpecies newSpecies = new NeatSpecies(this, network); activeSpecies.Add(newSpecies); } } // Remove species with no currently active members for (int i = 0; i < activeSpecies.Count; ++i) { if (activeSpecies[i].population.Count == 0) { Debug.Log("Species (" + activeSpecies[i].colour.ToString() + ") has died after " + activeSpecies[i].generationsLived + " generations"); activeSpecies.RemoveAt(i); --i; } } }
/// <summary> /// Create the next generation of networks /// </summary> /// <param name="newPopulationSize">How large the next population should be</param> /// <returns></returns> public NeatNetwork[] BreedNextGeneration(int newPopulationSize) { SaveXML(); // Calulate the average adjusted fitness float totalFitness = 0.0f; Dictionary <NeatSpecies, float> fitness = new Dictionary <NeatSpecies, float>(); foreach (NeatSpecies species in activeSpecies) { float adjustedFitness = species.CalulateAverageAdjustedFitness(); totalFitness += adjustedFitness; fitness[species] = adjustedFitness; } // Determine how many networks each species has been allocated Dictionary <NeatSpecies, int> allocation = new Dictionary <NeatSpecies, int>(); int totalNewCount = 0; foreach (NeatSpecies species in activeSpecies) { if (totalFitness <= 0.0f) { allocation[species] = 0; } else { int alloc = (int)((fitness[species] / totalFitness) * newPopulationSize); allocation[species] = alloc; totalNewCount += alloc; } } // Handle if new count is too high or low if (totalNewCount < newPopulationSize) { // Randomly allocate the remainder for (int i = 0; i < newPopulationSize - totalNewCount; ++i) { NeatSpecies species = activeSpecies[Random.Range(0, activeSpecies.Count)]; allocation[species]++; } } else if (totalNewCount > newPopulationSize) { // Randomly deallocate the remainder for (int i = 0; i < totalNewCount - newPopulationSize; ++i) { NeatSpecies species = activeSpecies[Random.Range(0, activeSpecies.Count)]; allocation[species]--; } } // Generate new popluation List <NeatNetwork> newPopulation = new List <NeatNetwork>(); foreach (NeatSpecies species in activeSpecies) { species.NextGeneration(allocation[species], newPopulation); } population = newPopulation.ToArray(); // Assign correct species to the new networks AssignPopulationToSpecies(); generationCounter++; Debug.Log("Generation " + generationCounter + " with " + activeSpecies.Count + " species"); return(population); }