예제 #1
0
        /// <summary>
        /// Creates a brain based on the genes of 2 parent brains.
        /// For each gene in parent1 we check if parent2 has a gene with the same innovation number, if this is the case we randomly choose a parent to get the gene from.
        /// If a gene only exists in one parent we add it no matter what.
        /// </summary>
        /// <param name="parent2Brain">The other parent.</param>
        /// <returns>Returns a child brain based on the genes of this brain and the passed brain.</returns>
        public Brain Crossover(Brain parent2Brain)
        {
            _childGenes.Clear();
            List <ConnectionGene> parent2 = new List <ConnectionGene>(parent2Brain.ConnectionGenes);

            foreach (ConnectionGene gene in ConnectionGenes)
            {
                ConnectionGene geneToRemove = default;
                ConnectionGene geneToAdd    = gene;

                ConnectionGene gene2 = parent2Brain.ConnectionGenes.SingleOrDefault(gen => gen.InnovationNumber == gene.InnovationNumber);
                if (gene2 != default)
                {
                    geneToRemove = gene2;
                    geneToAdd    = TrainingRoom.Random.NextDouble() < 0.5 ? gene : gene2;
                }

                geneToAdd = geneToAdd.Clone();

                if (geneToRemove != default)
                {
                    parent2.Remove(geneToRemove);
                }

                if (!geneToAdd.Enabled && TrainingRoom.Random.NextDouble() < TrainingRoom.TrainingRoomSettings.EnableConnectionChance)
                {
                    geneToAdd.Enabled = true;
                }

                _childGenes.Add(geneToAdd);
            }

            _childGenes.AddRange(parent2);
            return(new Brain(Guid.NewGuid(), TrainingRoom, _childGenes));
        }
예제 #2
0
        /// <summary>
        /// Creates an organism based on the genes of 2 parent organisms.
        /// For each gene in parent1 we check if parent2 has a gene with the same innovation number, if this is the case we randomly choose a parent to get the gene from.
        /// If a gene only exists in one parent we add it no matter what.
        /// </summary>
        /// <param name="parent2Organism">The other parent.</param>
        /// <param name="trainingRoomSettings">The training room settings.</param>
        /// <returns>Returns a child organism based on the genes of this organism and the passed organism.</returns>
        public Organism Crossover(Organism parent2Organism, TrainingRoomSettings trainingRoomSettings)
        {
            // Clears the temporary child genes list for re-use.
            _childGenes.Clear();

            // Copies the organisms from parent2.
            List <ConnectionGene> parent2 = new List <ConnectionGene>(parent2Organism.ConnectionGenes);

            // Pre-generates a child id for creating connection genes.
            Guid childId = Guid.NewGuid();

            foreach (ConnectionGene gene in ConnectionGenes)
            {
                // Prepares a gene to remove and add.
                ConnectionGene geneToRemove = default;
                ConnectionGene geneToAdd    = gene;

                // Tries to find a connection gene based on the current connection gene in the parent, and if not found, gives a default.
                ConnectionGene gene2 = parent2Organism.ConnectionGenes.SingleOrDefault(gen => gen.InnovationNumber == gene.InnovationNumber);

                // If the gene is not a default connection gene.
                if (gene2 != default)
                {
                    // Set it for removal.
                    geneToRemove = gene2;

                    // Depending on a random set the current gene or a random gene to add.
                    geneToAdd = trainingRoomSettings.Random.NextDouble() < 0.5 ? gene : gene2;
                }

                // Clone the gene to add with the new id.
                geneToAdd = geneToAdd.Clone(childId);

                // If the gene to remove is not default, remove it from its parent.
                if (geneToRemove != default)
                {
                    parent2.Remove(geneToRemove);
                }

                // If the gene to add is not enabled and a random is lower than the enable connection chance, enable the gene.
                if (!geneToAdd.Enabled && trainingRoomSettings.Random.NextDouble() < trainingRoomSettings.EnableConnectionChance)
                {
                    geneToAdd.Enabled = true;
                }

                // Add gene to the temporary child genes list.
                _childGenes.Add(geneToAdd);
            }

            // Add all remaining genes in the parent to the child genes.
            _childGenes.AddRange(parent2);

            // Return a new organism with all new genes.
            return(new Organism(childId, trainingRoomSettings, Generation + 1, _childGenes));
        }