예제 #1
0
        public void AddDna(Dna newDna, bool enforceDistinctive)
        {
            Dna addition = enforceDistinctive && GenePool.Any(dna => dna.Equals(newDna)) ?
                           Dna.CloneAndMutate(newDna, newDna.Heritage, species.MutationSeverity, species.ActivationMutationSeverity) :
                           newDna;

            GenePool.Add(addition);
            Composition.TryGetValue(addition.Heritage, out int count);
            Composition[addition.Heritage] = count + 1;
        }
예제 #2
0
        public static Generation FromPrevious(Generation previous, int spawnLocationIndex)
        {
            CarSpecies species          = previous.species;
            List <Dna> previousGenePool = previous.GenePool;
            Generation TNG = new Generation(species, previous.GenerationNumber + 1, spawnLocationIndex);

            // Create and add fresh dna into next gen
            int nNew = Mathf.RoundToInt(species.GenerationSize * species.NewDnaRate);

            if (nNew > 0)
            {
                TNG.AddMultipleDna(GenerateRandomDna(species, nNew), false);
            }

            //  Preserve elites
            var previousGenerationOrderedByFitness = previousGenePool.OrderByDescending((dna => dna.RawFitnessRating));
            int nElites = Mathf.RoundToInt(species.GenerationSize * species.ProportionUnchanged);

            if (nElites > 0)
            {
                TNG.AddMultipleDna(previousGenerationOrderedByFitness.Take(nElites).Select(dna => Dna.Clone(dna)), true);
            }

            // Add mutated versions of elites
            int nMutatedElites = Mathf.RoundToInt(species.GenerationSize * species.ProportionMutatantsOfUnchanged);

            if (((species.GenerationSize - (nElites + nMutatedElites + nNew)) % 2 == 1))
            {
                nMutatedElites++;                                                                          // make sure remaining spaces for offspring is an even number
            }
            for (int i = 0; i < nMutatedElites; i++)
            {
                Dna randomElite = Darwin.SelectRandomBasedOnFitness(
                    previousGenerationOrderedByFitness.Take(Mathf.RoundToInt(species.GenerationSize * 0.2f)).ToList()
                    );
                Dna mutatedElite = Dna.CloneAndMutate(randomElite, DnaHeritage.MutatedElite, species.MutationSeverity, species.ActivationMutationSeverity);
                TNG.AddDna(mutatedElite, true);
            }

            // Populate the rest with offspring of previous
            int nMutatedOffspring         = 0;
            int freeSpacesForOffspring    = species.GenerationSize - (nElites + nMutatedElites + nNew);
            int targetNumMutatedOffspring = Mathf.RoundToInt(freeSpacesForOffspring * species.OffspringMutationProbability);

            for (int i = 0; i < Mathf.RoundToInt(freeSpacesForOffspring / 2); i++)
            {
                Dna        parent1  = Darwin.SelectRandomBasedOnFitness(previousGenePool);
                Dna        parent2  = Darwin.SelectRandomBasedOnFitness(previousGenePool, parent1);
                List <Dna> children = new List <Dna>(2);

                /* Attempts at crossover may fail if the genomes of the 2 parents are too similar. If for example:
                 *  p1 = 1,2,3,4
                 *  p2 = 1,2,3,5
                 * then no matter how we try to cross them, the children will end up as clones of the parents. To mitigate
                 * this we try a few times and if we consistently fail, then we mutate the dna as a fallback
                 */
                bool crossoverFailed = false;
                for (int crossoverAttempt = 0; crossoverAttempt < 5; crossoverAttempt++)
                {
                    children = Dna.CreateOffspring(
                        parent1,
                        parent2,
                        species.CrossoverPasses,
                        species.IncludeActivationCrossover
                        );
                    crossoverFailed = parent1.Equals(children[0]) || parent1.Equals(children[1]) || parent2.Equals(children[0]) || parent2.Equals(children[1]) || children[0].Equals(children[1]);
                    if (!crossoverFailed)
                    {
                        break;
                    }
                }
                if (crossoverFailed)
                {
                    Debug.LogWarning("Crossover failed after several attempts - selected parent genomes are likely too similar. Falling back to mutation");
                }

                if (crossoverFailed || (nMutatedOffspring <= targetNumMutatedOffspring && Random.Range(0f, 1f) < species.OffspringMutationProbability))
                {
                    TNG.AddMultipleDna(children.ConvertAll(c => Dna.CloneAndMutate(c, DnaHeritage.MutatedOffspring, species.MutationSeverity, species.ActivationMutationSeverity)), true);
                    nMutatedOffspring += 2;
                }
                else
                {
                    TNG.AddMultipleDna(children, true);
                }
            }

            DnaUtils.DebugGenerationDiff(previousGenePool, TNG.GenePool);
            return(TNG);
        }