private void when_asked_to_create_child()
 {
     var random = new TestRandomSource(_randomToReturn);
     _strategy = new RandomStrategy(_length);
     _strategy.SetRandomSource(random);
     _result = _strategy.CreateChild(null, null, _geneSet);
 }
        public string GetBest(int length,
                              string geneSet,
                              Func<string, int> getFitness,
                              Action<int, int, string, string> displayChild)
        {
            _randomStrategy = new RandomStrategy(length);

            int maxIndividualsInPool = geneSet.Length * 3;
            int generationCount = 1;
            var uniqueIndividuals = new HashSet<string>();
            var parents = GenerateParents(geneSet)
                .Where(x => uniqueIndividuals.Add(x.Genes))
                .Take(maxIndividualsInPool)
                .ToList();
            foreach (var individual in parents)
            {
                individual.Fitness = getFitness(individual.Genes);
            }
            parents = parents.OrderBy(x => x.Fitness).ToList();

            var bestParent = parents.First();
            displayChild(generationCount,
                         bestParent.Fitness,
                         bestParent.Genes,
                         bestParent.Strategy.Description);

            var children = GenerateChildren(parents, new[] { _randomStrategy }, geneSet)
                .Where(x => uniqueIndividuals.Add(x.Genes));

            int lastParentLine = NumberOfParentLines - 1;
            int currentParentLine = lastParentLine;

            var parentLines = Enumerable.Range(0, NumberOfParentLines)
                .Select(x => parents.ToList())
                .ToArray();

            var strategies = Enumerable.Range(0, NumberOfParentLines)
                .Select(x => _strategies.ToList())
                .ToArray();

            double halfMaxAllowableSecondsWithoutImprovement = MaxSecondsWithoutImprovement / 2;
            IEqualityComparer<Individual> individualGenesComparer = new IndividualGenesComparer();

            var stopwatch = new Stopwatch();
            stopwatch.Start();

            do
            {
                var potentialParents = new List<Individual>();
                foreach (var child in children
                    .TakeWhile(x => potentialParents.Count < maxIndividualsInPool))
                {
                    child.Fitness = getFitness(child.Genes);
                    potentialParents.Add(child);
                    if (bestParent.Fitness > child.Fitness)
                    {
                        bestParent = child;
                        var ancestors = GetAncestors(bestParent).ToList();
                        strategies[currentParentLine] = GetStrategyPool(ancestors);
                        if (ancestors.Count > maxIndividualsInPool)
                        {
                            maxIndividualsInPool = ancestors.Count;
                        }
                        displayChild(generationCount,
                                     bestParent.Fitness,
                                     bestParent.Genes,
                                     bestParent.Strategy.Description);
                    }
                }
                generationCount++;
                parentLines[currentParentLine] = parentLines[currentParentLine]
                    .Concat(potentialParents)
                    .OrderBy(x => x.Fitness)
                    .Take(maxIndividualsInPool)
                    .ToList();

                if (parentLines[currentParentLine][0].Fitness == bestParent.Fitness ||
                    stopwatch.Elapsed.TotalSeconds < halfMaxAllowableSecondsWithoutImprovement)
                {
                    if (--currentParentLine < 0)
                    {
                        currentParentLine = lastParentLine;
                    }
                }
                else
                {
                    parentLines[currentParentLine] = parentLines
                        .SelectMany(x => x.Take(5))
                        .Distinct(individualGenesComparer)
                        .ToList();
                }

                children = GenerateChildren(parentLines[currentParentLine], strategies[currentParentLine], geneSet)
                    .Where(x => uniqueIndividuals.Add(GetCanonicalGenes(x.Genes)));
            } while (bestParent.Fitness > 0 &&
                     stopwatch.Elapsed.TotalSeconds <= MaxSecondsWithoutImprovement);

            return bestParent.Genes;
        }