public void UpdateStatistics(EvolutionInformation info) { Clear(); // Title float titleSize = 1f / 6f; int fontSize = 16; string titleText = "Evolution Information for Generation " + info.Generation + " (" + info.EvolutionTime + " ms)"; AddText(titleText, fontSize, Color.black, FontStyle.Bold, 0, 0, 1, titleSize, Container, TextAnchor.MiddleCenter); float numColumns = 6; int nRows = 7; float yStep = 0; // Subject numbers AddColumn(nRows, yStep, titleSize, yStep + (1 / numColumns), 1, true, new string[] { "# Subjects: " + info.NumSubjects, "# Offsprings: " + info.NumOffsprings, "# Best: " + info.NumBestSubjectsTakenOver, "# Random: " + info.NumRandomSubjectsTakenOver }); yStep += 1f / numColumns; // Species numbers AddColumn(nRows, yStep, titleSize, yStep + (1 / numColumns), 1, true, new string[] { "# Species: " + info.NumSpecies, "# Previous: " + info.NumPreviousSpecies, "# New: " + info.NumNewSpecies, "# Eliminated: " + info.NumEliminatedSpecies, "# Empty: " + info.NumEmptySpecies, "Comp. Threshh.: " + info.CompatibilityThreshhold }); yStep += 1f / numColumns; // Fitness numbers AddColumn(nRows, yStep, titleSize, yStep + (1 / numColumns), 1, true, new string[] { "Gen " + (info.Generation - 1) + " Fitness", "Max: " + (int)info.MaxFitness, "Average: " + (int)info.AverageFitness }); yStep += 1f / numColumns; // Misc info AddColumn(nRows, yStep, titleSize, yStep + (1 / numColumns), 1, true, new string[] { "Misc", "# AdpChecks: " + info.NumSubjectsCheckedForAdoption, "# Immune: " + info.NumImmuneToMutationSubjects, "Rank Limit: " + info.RankLimit, "#Gens <Limit: " + info.GensAllowedBelowLimit, "Takeovers immune: " + info.MutationImmunityForTakeOvers, "Multiple Mut / Genome: " + info.MutationInfo.MultipleMutationsPerGenomeAllowed }); yStep += 1f / numColumns; // Topology mutation numbers AddColumn(nRows, yStep, titleSize, yStep + (1 / numColumns), 1, true, new string[] { "# Topology Mutations: " + info.MutationInfo.NumTopologyMutations, "on # Genomes: " + info.MutationInfo.NumTopologyMutatedGenomes, "Chance/G (fac): " + info.MutationInfo.TopologyMutationChancePerGenome.ToString("0.##") + "(" + info.MutationInfo.MutationChanceScaleFactor.ToString("0.##") + ")", "# Con (new): " + info.MutationInfo.NumNewConnectionsMutations + " (" + info.MutationInfo.NumNewUniqueConnectionsMutations + ")", "# Node (new): " + info.MutationInfo.NumNewNodeMutations + " (" + info.MutationInfo.NumNewUniqueNodeMutations + ")" }); yStep += 1f / numColumns; // Weight mutation numbers AddColumn(nRows, yStep, titleSize, yStep + (1 / numColumns), 1, true, new string[] { "# Weight Mutations: " + info.MutationInfo.NumWeightMutations, "on # Genomes: " + info.MutationInfo.NumWeightMutatedGenomes, "Chance/G (fac): " + info.MutationInfo.WeightMutationChancePerGenome.ToString("0.##") + "(" + info.MutationInfo.MutationChanceScaleFactor.ToString("0.##") + ")", "# Replaces: " + info.MutationInfo.NumReplaceMutations, "# Shifts: " + info.MutationInfo.NumShiftMutations, "# Scales: " + info.MutationInfo.NumScaleMutations, "# Inverts: " + info.MutationInfo.NumInvertMutations, "# Swaps: " + info.MutationInfo.NumSwapMutations }); yStep += 1f / numColumns; }
public EvolutionInformation EvolveGeneration() { DateTime startTimeStamp = DateTime.Now; DateTime stamp = DateTime.Now; List <Subject> newSubjects = new List <Subject>(); int numPreviousSpecies = Species.Count; // Calculate fitness & rank of each subject and species GetFitness(); float averageFitness = Subjects.Average(x => x.Genome.Fitness); float maxFitness = Subjects.Max(x => x.Genome.Fitness); if (DebugTimestamps) { stamp = TimeStamp(stamp, "Get Fitness"); } // Eliminate species without improvement for too long int numEliminatedSpecies = EliminateBadSpecies(RankNeededToSurvive, GenerationsBelowRankAllowed); if (DebugTimestamps) { stamp = TimeStamp(stamp, "Eliminate Bad Species"); } // Take a random representative for each existing species CreateSpeciesRepresentatives(); if (DebugTimestamps) { stamp = TimeStamp(stamp, "Create Representatives"); } int numSubjectsImmuneToMutations = 0; // Take over best subjects of each species int numBestSubjects = TakeOverBestSubjects(newSubjects, TakeOverBestRatio, AreTakeOversImmuneToMutation); if (AreTakeOversImmuneToMutation) { numSubjectsImmuneToMutations += numBestSubjects; } if (DebugTimestamps) { stamp = TimeStamp(stamp, "Take over Best Subjects"); } // Take over random lucky subjects of each species int numRandomSubjects = TakeOverRandomSubjects(newSubjects, TakeOverRandomRatio, AreTakeOversImmuneToMutation); if (AreTakeOversImmuneToMutation) { numSubjectsImmuneToMutations += numRandomSubjects; } if (DebugTimestamps) { stamp = TimeStamp(stamp, "Take over Random Subjects"); } // Evaluate which species is allowed to produce how many offsprings int numOffsprings = Size - numBestSubjects - numRandomSubjects; CalculateOffspringNumberPerSpecies(numOffsprings); if (DebugTimestamps) { stamp = TimeStamp(stamp, "Calculate Offspring numbers"); } // Create offsprings with a chance to automatically have the same species as its parents List <Subject> toSpeciate = CreateOffsprings(newSubjects); int numSubjectsCheckedForAdoption = toSpeciate.Count; if (DebugTimestamps) { stamp = TimeStamp(stamp, "Create Offsprings"); } // Moves subjects from the newSubjects list to the Subjects list (that it also clears) ReplaceSubjects(newSubjects); if (DebugTimestamps) { stamp = TimeStamp(stamp, "Replace Subjects"); } // Mutate the genomes in all subjects that are not marked immuneToMutation according to chances in the mutatealgorithm MutationInformation mutationInfo = MutateAlgorithm.MutatePopulation(this, CurrentMutationChanceScaleFactor, MultipleMutationsPerGenomeAllowed, MutationChanceReductionFactorPerMutation); if (DebugTimestamps) { stamp = TimeStamp(stamp, "Mutate Population"); } // Speciate all subjects that haven't gotten a species yet int numNewSpecies = Speciator.Speciate(toSpeciate, Species); if (DebugTimestamps) { stamp = TimeStamp(stamp, "Speciate unspeciated Subjects"); } // Fill species with new subjects foreach (Species s in Species) { s.Subjects.Clear(); } foreach (Subject subject in Subjects) { subject.Genome.Species.Subjects.Add(subject); } if (DebugTimestamps) { stamp = TimeStamp(stamp, "Replace Subjects in Species"); } // Remove empty species List <Species> emptySpecies = new List <Species>(); foreach (Species species in Species) { if (species.Subjects.Count == 0) { emptySpecies.Add(species); } } foreach (Species remove in emptySpecies) { Species.Remove(remove); } int numEmptySpecies = emptySpecies.Count; if (DebugTimestamps) { stamp = TimeStamp(stamp, "Remove empty Species"); } // Go to next generation Generation++; if (CurrentMutationChanceScaleFactor > MinMutationChanceFactor) { CurrentMutationChanceScaleFactor -= MutationChanceFactorReductionPerGeneration; } // Name the subjects for (int i = 0; i < Subjects.Count; i++) { if (String.IsNullOrEmpty(Subjects[i].Name)) { Subjects[i].Name = Generation + "-" + Subjects[i].Genome.Species.Id + "-" + i; } } if (Subjects.Count != Species.Sum(x => x.Subjects.Count)) { throw new Exception("SPECIATION FAILED. The number of subjects in the species does not match the number of subjects in the population."); } // Create the evolution information object int evolutionTime = (int)((DateTime.Now - startTimeStamp).TotalMilliseconds); EvolutionInformation info = new EvolutionInformation(Generation, evolutionTime, AreTakeOversImmuneToMutation, mutationInfo, numBestSubjects, numRandomSubjects, numOffsprings, numSubjectsCheckedForAdoption, numSubjectsImmuneToMutations, numPreviousSpecies, numEliminatedSpecies, numEmptySpecies, numNewSpecies, Species.Count, SpeciesCompatiblityThreshhold, maxFitness, averageFitness, RankNeededToSurvive, GenerationsBelowRankAllowed); Debug.Log(info.ToString()); // Reset the species fitness values //foreach (Species s in Species) s.CalculateFitnessValues(); return(info); }
// Update is called once per frame void Update() { switch (SimulationPhase) { case SimulationPhase.MatchesReady: //Debug.Log("Starting matchround " + Population.Generation + "." + (MatchesPlayed + 1)); SimulationUI.TitleText.text = "Match Round " + Population.Generation + "." + (MatchesPlayed + 1); foreach (Match m in Matches) { if (m.Visual) { SimulationUI.gameObject.SetActive(false); VisualMatch = m; m.StartMatch(VisualPlayer, VisualMinion, VisualBoardHeight, MatchUI); } else { m.StartMatch(); } } SimulationPhase = SimulationPhase.MatchesRunning; break; case SimulationPhase.MatchesRunning: foreach (Match m in Matches) { m.Update(); } if (Matches.TrueForAll(x => x.Phase == MatchPhase.GameEnded)) { MatchesPlayed++; SimulationPhase = SimulationPhase.MatchesFinished; if (VisualMatch != null) { VisualMatch = null; SimulationUI.gameObject.SetActive(true); } } break; case SimulationPhase.MatchesFinished: // Update Stats UpdateStatistics(); if (MatchesPlayed >= MatchesPerGeneration) { // Init Human vs AI game if gen is finished if (SimulationUI.PlayGame.isOn) { SimulationUI.PlayGame.isOn = false; Matches.Clear(); // Create match Match match = new Match(); Player player1 = new HumanPlayer(match); Subject bestSubject = Population.Subjects.OrderByDescending(x => x.Wins).First(); Player player2 = new AIPlayer(match, bestSubject); match.InitGame(player1, player2, StartHealth, StartCardOptions, MinCardOptions, MaxCardOptions, MaxMinions, MaxMinionsPerType, FatigueDamageStartTurn, true, false); // Start match Matches.Add(match); VisualMatch = match; SimulationUI.gameObject.SetActive(false); match.StartMatch(VisualPlayer, VisualMinion, VisualBoardHeight, MatchUI); SimulationPhase = SimulationPhase.MatchesReady; } else { SimulationPhase = SimulationPhase.GenerationFinished; } } else { GenerateMatches(); SimulationPhase = SimulationPhase.MatchesReady; } break; case SimulationPhase.GenerationFinished: // Reset stats ResetStatistics(); MatchesPlayed = 0; // Evolve and Update UI EvolutionInformation info = Population.EvolveGeneration(); SimulationUI.EvoStats.UpdateStatistics(info); SimulationUI.SpeciesScoreboard.UpdateScoreboard(Population); // Generate first match round GenerateMatches(); SimulationPhase = SimulationPhase.MatchesReady; break; } }