private void Evolve() { var actorAndScoreList = Actors.Select(actor => ScoreActor(actor, _environment)) .OrderBy(actor => actor.Score).ToList(); Generations.Add(new Generation { Actors = actorAndScoreList, GenerationNumber = Generations.Count + 1 }); var betterBias = _aiWeight.BetterBias; // How likely it is that a better actor is used than a worse one. var betterCutoff = _aiWeight.BetterCutoff; // Percentage of what are considered good actors vs bad ones. var betterBiasCount = (int)Math.Round(Actors.Count * betterCutoff); var elitism = _aiWeight.ElitismBias; // The percentage that gets copied directly to the new generation. var mutationChance = _aiWeight.MutationChance; var elitismCount = (int)Math.Round(Actors.Count * elitism); for (var eliteIndex = 0; eliteIndex < elitismCount; eliteIndex++) { if (MaxActions != null && MaxActions > 0) { UpdateActor(eliteIndex, actorAndScoreList[eliteIndex].Lander.Actions.Take((int)MaxActions)); } else { UpdateActor(eliteIndex, actorAndScoreList[eliteIndex].Lander.Actions); } } for (var actorIndex = 0 + elitismCount; actorIndex < Actors.Count; actorIndex += 2) { var firstParent = GetBiasedActor(betterBias, betterBiasCount, actorAndScoreList); var secondParent = GetBiasedActor(betterBias, betterBiasCount, actorAndScoreList); var randomModifier = Randomizer.GetValueBetween(0.0, 1.0, 2); var moreParentActionCount = firstParent.Lander.Actions.Count > secondParent.Lander.Actions.Count ? firstParent.Lander.Actions.Count : secondParent.Lander.Actions.Count; for (var childIndex = 0; childIndex < 2; childIndex++) { var childPuppet = Actors.First().Original.Clone(); var childActions = new List <string>(); for (var actionIndex = 0; actionIndex < moreParentActionCount && actionIndex < (MaxActions ?? int.MaxValue); actionIndex++) { var firstParentAction = firstParent.Lander.Actions.ElementAtOrDefault(actionIndex); var secondParentAction = secondParent.Lander.Actions.ElementAtOrDefault(actionIndex); string childAction; if (firstParentAction == null && secondParentAction == null || Randomizer.Gamble(mutationChance)) { childAction = MarsLanderActor.GetRandomActions(1, _randomNessProvider).First(); } else { // If a parent's action index is null, take both from the other parent. The below algorithm is then not needed // --> Because taking both values from the same parent simply results into the same action // Also, depending on the child index, we apply one of two possible algorithms: // ChildIndex = 0: NewAction = randomModifier * firstParentAction + (1 - randomModifier) * secondParentAction // ChildIndex = 1: NewAction = (1 - randomModifier) * firstParentAction + randomModifier * secondParentAction if (firstParentAction == null) { childAction = secondParentAction; } else if (secondParentAction == null) { childAction = firstParentAction; } else { var firstParentActionArray = firstParentAction !.Split(" "); var firstParentAngle = int.Parse(firstParentActionArray[0]); var firstParentPower = int.Parse(firstParentActionArray[1]); var secondParentActionArray = secondParentAction !.Split(" "); var secondParentAngle = int.Parse(secondParentActionArray[0]); var secondParentPower = int.Parse(secondParentActionArray[1]); if (childIndex == 0) { var newAngle = Math.Round(randomModifier * firstParentAngle + (1 - randomModifier) * secondParentAngle); var newPower = Math.Round(randomModifier * firstParentPower + (1 - randomModifier) * secondParentPower); childAction = $"{newAngle} {newPower}"; } else { var newAngle = Math.Round((1 - randomModifier) * firstParentAngle + randomModifier * secondParentAngle); var newPower = Math.Round((1 - randomModifier) * firstParentPower + randomModifier * secondParentPower); childAction = $"{newAngle} {newPower}"; } } } childPuppet.Apply(childAction, _environment); childActions.Add(childAction); if (!childPuppet.WillHitLandingZone(_environment, 1) || MaxActions != null) { continue; } var applicableAction = childPuppet.GetApplicableAction("0 4"); childPuppet.Apply(applicableAction, _environment); childActions.Add(applicableAction); break; } UpdateActor(actorIndex + childIndex, childActions); } } }
public void SetSelectedActor(int actorId) { SelectedActor = Actors.First(x => x.Id == actorId); }