public class World { public readonly List<Creature>[] Species = new List<Creature>[8]; public void Run(int generations) { for (int i = 0; i < generations; i++, this.age = this.Age + 1) { this.SelectBest(); this.MakeChildren(); this.Mutate(); Debug.Print("Age: {0}", i); } } private void SelectBest() { var allCreatures = new List<Creature>(this.Species.Sum(kind => kind.Count)); allCreatures.AddRange(this.Species.SelectMany(kind => kind)); allCreatures = allCreatures.OrderByDescending(creature => creature.SummaryStrength).Take(allCreatures.Count >> 1).ToList(); for (int i = 0; i < this.Species.Length; i++) { this.Species[i].ForEach(creature => creature.BreakRedundantConnections()); this.Species[i].Clear(); this.Species[i].AddRange(allCreatures.Where(creature => creature.IdOfSpecies == i)); } } private void MakeChildren() { Parallel.For( 0, this.Species.Length, i => { var temp = new List<Creature>(this.Species[i].Count << 1); // Random parents (of same species) - for supporting different genes this.Species[i].Shuffle(); Random rnd = RandomProvider.GetThreadRandom(); for (int j = 1; j < this.Species[i].Count; j += 2) { double value = rnd.NextDouble(); if (value < 0.33) { temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); } else if (value < 0.665) { temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); } else { temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); } } this.Species[i].ForEach(creature => creature.BreakRedundantConnections()); this.Species[i].Clear(); this.Species[i] = temp; }); } private void Mutate() { Parallel.ForEach(this.Species, list => list.ForEach(creature => creature.Mutate())); } }
public enum Gene : byte { SelfishGene = 1, AltruisticGene = 2, CreatureLevelGene = 4 } public enum Relation { Child, BrotherOrSister, GrandChild, NephewOrNiece, Cousin }
public class Creature { private const int GeneStrength = 128; private readonly Gene[] genes = new Gene[128]; private readonly List<Creature> childs = new List<Creature>(8); private Creature mother; private Creature father; public Creature(int idOfSpecies, World world) { Contract.Requires<ArgumentNullException>(world != null); Contract.Ensures(this.IdOfSpecies == idOfSpecies); this.IdOfSpecies = idOfSpecies; this.world = world; for (int i = 0; i < this.genes.Length; i++) { this.genes[i] = EnumHelper.CreateRandomGene(); } } public Creature(Creature mommy, Creature daddy) { Debug.Assert(mommy.IdOfSpecies == daddy.IdOfSpecies, "Interspecies relation are FORBIDDEN!!!"); this.mother = mommy; this.father = daddy; mommy.childs.Add(this); daddy.childs.Add(this); this.world = mommy.world; this.IdOfSpecies = mommy.IdOfSpecies; for (int i = 0; i < this.genes.Length; i++) { this.genes[i] = EnumHelper.ChooseRandomGene(mommy.genes[i], daddy.genes[i]); } } public int SummaryStrength { get { double sum = 0.0; World world = this.world; string cacheKey = $"AltruisticGenesOutStrength{this.IdOfSpecies}"; object cachedValue = Cache.Get(cacheKey, world.Age); if (cachedValue != null) { sum = (double)cachedValue; } else { for (int i = 0; i < world.Species[this.IdOfSpecies].Count; i++) { if (world.Species[this.IdOfSpecies][i] != this) { sum += world.Species[this.IdOfSpecies][i].AltruisticGenesOutStrength; } } Cache.Put(cacheKey, world.Age, sum); } return this.ThisCreatureGenesStrength + (int)sum + (int)this.HelpFromRelations; } } private int ThisCreatureGenesStrength => this.genes.Sum(g => g == Gene.CreatureLevelGene ? GeneStrength : GeneStrength >> 1); private double AltruisticGenesOutStrength { get { int sum = 0; for (int i = 0; i < this.genes.Length; i++) { Gene gene = this.genes[i]; if (gene == Gene.AltruisticGene) { sum += GeneStrength >> 1; } } return (double)sum / (this.world.Species[this.IdOfSpecies].Count - 1); } } private double HelpFromRelations { get { Creature mommy = this.mother; Creature daddy = this.father; if (mommy == null) { return 0; } if (mommy.mother == null) { return mommy.GetSelfishGenesOutStrength(Relation.Child) + daddy.GetSelfishGenesOutStrength(Relation.Child) + mommy.childs.Sum( brother => brother == this ? 0 : brother.GetSelfishGenesOutStrength(Relation.BrotherOrSister)); } return mommy.GetSelfishGenesOutStrength(Relation.Child) + daddy.GetSelfishGenesOutStrength(Relation.Child) + mommy.childs.Sum( brother => brother == this ? 0 : brother.GetSelfishGenesOutStrength(Relation.BrotherOrSister)) + mommy.mother.GetSelfishGenesOutStrength(Relation.GrandChild) + mommy.father.GetSelfishGenesOutStrength(Relation.GrandChild) + daddy.mother.GetSelfishGenesOutStrength(Relation.GrandChild) + daddy.father.GetSelfishGenesOutStrength(Relation.GrandChild) + mommy.mother.childs.Sum( aunt => aunt == mommy ? 0 : aunt.GetSelfishGenesOutStrength(Relation.NephewOrNiece)) + daddy.mother.childs.Sum( uncle => uncle == daddy ? 0 : uncle.GetSelfishGenesOutStrength(Relation.NephewOrNiece)) + mommy.mother.childs.Sum( aunt => aunt == mommy ? 0 : aunt.childs.Sum(cousin => cousin.GetSelfishGenesOutStrength(Relation.Cousin))) + daddy.mother.childs.Sum( uncle => uncle == daddy ? 0 : uncle.childs.Sum(cousin => cousin.GetSelfishGenesOutStrength(Relation.Cousin))); } } public void Mutate() { // Tries to change 6 genes with 50% probability int length = this.genes.Length; int rnd = RandomProvider.GetThreadRandom().Next(length << 1); int limit = Math.Min(length, rnd + 6); for (; rnd < limit; rnd++) { this.genes[rnd] = EnumHelper.CreateRandomGene(); } } public void BreakRedundantConnections() { Creature mommy = this.mother; Creature daddy = this.father; if (mommy?.mother?.mother != null) { mommy.mother.mother?.childs.Clear(); mommy.mother.mother = null; mommy.mother.father?.childs.Clear(); mommy.mother.father = null; mommy.father.mother?.childs.Clear(); mommy.father.mother = null; mommy.father.father?.childs.Clear(); mommy.father.father = null; daddy.mother.mother?.childs.Clear(); daddy.mother.mother = null; daddy.mother.father?.childs.Clear(); daddy.mother.father = null; daddy.father.mother?.childs.Clear(); daddy.father.mother = null; daddy.father.father?.childs.Clear(); daddy.father.father = null; } } private double GetSelfishGenesOutStrength(Relation whoAreYou) { Creature mommy = this.mother; Creature daddy = this.father; int summarySelfishStrength = this.genes.Sum(g => g == Gene.SelfishGene ? GeneStrength >> 1 : 0); switch (whoAreYou) { case Relation.Child: return summarySelfishStrength / this.childs.Count * 30.78; case Relation.BrotherOrSister: Debug.Assert(mommy.childs.Count > 1, "LIER! He is not our brother!"); return summarySelfishStrength / (mommy.childs.Count - 1) * 30.78; case Relation.GrandChild: return summarySelfishStrength / this.childs.Sum(creature => creature.childs.Count) * 15.38; case Relation.NephewOrNiece: Debug.Assert(mommy.childs.Count > 1, "LIER! We don't have any brothers!"); return summarySelfishStrength / mommy.childs.Sum(brother => brother == this ? 0 : brother.childs.Count) * 15.38; case Relation.Cousin: return summarySelfishStrength / (mommy.mother.childs.Sum(aunt => aunt == mommy ? 0 : aunt.childs.Count) + daddy.mother.childs.Sum(uncle => uncle == daddy ? 0 : uncle.childs.Count)) * 7.68; default: throw new NotImplementedException("Unknown enum value"); } } }
Source: https://habr.com/ru/post/267399/
All Articles