/// <summary>
        /// Generates a random individual.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> Generate(
            Solver <List <int>, GeneticProblem, Fitness> solver)
        {
            // create new genomes list.
            List <int> genome = new List <int>();

            // build cities to place (in a thread-safe way!)
            List <int> cities_to_place = new List <int>();

            lock (solver)
            {
                for (int idx = 0; idx < solver.Problem.Along.Count; idx++)
                {
                    cities_to_place.Add(solver.Problem.Along[idx]);
                }
            }

            BestPlacementHelper helper = BestPlacementHelper.Instance();

            helper.DoFast(
                solver.Problem,
                solver.FitnessCalculator as FitnessCalculator,
                genome,
                cities_to_place);

            Individual individual = new Individual(genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
        /// <summary>
        /// Take a piece of the genome and re-do best placement.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="mutating"></param>
        /// <returns></returns>
        private Individual <List <int>, GeneticProblem, Fitness> MutateByTakingPiece(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> mutating)
        {
            // take a random piece.
            int idx1 = 0;
            int idx2 = 0;

            while (idx2 - idx1 == 0)
            {
                idx1 = solver.Random.Next(mutating.Genomes.Count - 1) + 1;
                idx2 = solver.Random.Next(mutating.Genomes.Count - 1) + 1;
                if (idx1 > idx2)
                {
                    int temp = idx1;
                    idx1 = idx2;
                    idx2 = temp;
                }
            }

            // if the genome range is big take it from the best individual.
            Individual <List <int>, GeneticProblem, Fitness> source =
                (mutating as Individual <List <int>, GeneticProblem, Fitness>);
            Individual <List <int>, GeneticProblem, Fitness> target =
                (mutating as Individual <List <int>, GeneticProblem, Fitness>);

            List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1);
            List <int> new_genome   = target.Genomes.GetRange(0, target.Genomes.Count);

            // insert the piece into the worst individual.
            // remove nodes in the source_piece.
            foreach (int source_node in source_piece)
            {
                new_genome.Remove(source_node);
            }

            // apply best placement algorithm to place the selected genomes.
            //List<int> genome = new List<int>();
            BestPlacementHelper helper = BestPlacementHelper.Instance();

            helper.DoFast(
                solver.Problem,
                solver.FitnessCalculator as FitnessCalculator,
                new_genome,
                source_piece);

            Individual individual = new Individual(new_genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
        /// <summary>
        /// Generates one individual.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual <List <Genome>, Problem, Fitness> Generate(
            Solver <List <Genome>, Problem, Fitness> solver)
        {
            IRandomGenerator random = new RandomGenerator();

            // generate a list of cities to place.
            List <int> cities = new List <int>();

            for (int city_to_place = 0; city_to_place < solver.Problem.Cities; city_to_place++)
            {
                cities.Add(city_to_place);
            }

            // create new individuals.
            Individual individual =
                new Individual(new List <Genome>());

            //individual.Initialize();

            // place one random city in each round.
            for (int round_idx = 0; round_idx < solver.Problem.InitialVehicles; round_idx++)
            {
                // select a random city to place.
                int city_idx = random.Generate(cities.Count);
                int city     = cities[city_idx];
                cities.RemoveAt(city_idx);

                // create new genome.
                Genome genome = new Genome();
                genome.Add(city);
                individual.Genomes.Add(genome);
            }

            individual = BestPlacementHelper.DoFast(
                solver.Problem,
                (solver.FitnessCalculator as FitnessCalculator),
                individual,
                cities);

            return(individual);
        }
        CrossOver(Solver <List <int>, GeneticProblem, Fitness> solver,
                  Individual <List <int>, GeneticProblem, Fitness> parent1,
                  Individual <List <int>, GeneticProblem, Fitness> parent2)
        {
            // take a random piece.
            int idx1 = 0;
            int idx2 = 0;

            while (idx2 - idx1 == 0)
            {
                idx1 = solver.Random.Next(parent1.Genomes.Count - 1) + 1;
                idx2 = solver.Random.Next(parent2.Genomes.Count - 1) + 1;
                if (idx1 > idx2)
                {
                    int temp = idx1;
                    idx1 = idx2;
                    idx2 = temp;
                }
            }

            // if the genome range is big take it from the best individual.
            Individual <List <int>, GeneticProblem, Fitness> source =
                (parent1 as Individual <List <int>, GeneticProblem, Fitness>);
            Individual <List <int>, GeneticProblem, Fitness> target =
                (parent2 as Individual <List <int>, GeneticProblem, Fitness>);

            if (idx2 - idx1 < parent1.Genomes.Count / 2)
            { // the range is small; take the worste genomes.
                if (source.Fitness.CompareTo(target.Fitness) > 0)
                {
                    Individual <List <int>, GeneticProblem, Fitness> temp = source;
                    source = target;
                    target = temp;
                }
                else
                {
                    // do nothing.
                }
            }
            else
            { // the range is big; take the good genomes.
                if (source.Fitness.CompareTo(target.Fitness) > 0)
                {
                    // do nothing.
                }
                else
                {
                    Individual <List <int>, GeneticProblem, Fitness> temp = source;
                    source = target;
                    target = temp;
                }
            }
            List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1);
            List <int> new_genome   = target.Genomes.GetRange(0, target.Genomes.Count);

            // insert the piece into the worst individual.
            // remove nodes in the source_piece.
            foreach (int source_node in source_piece)
            {
                new_genome.Remove(source_node);
            }

            // apply best placement algorithm to place the selected genomes.
            //List<int> genome = new List<int>();
            BestPlacementHelper helper = BestPlacementHelper.Instance();

            helper.DoFast(
                solver.Problem,
                solver.FitnessCalculator as FitnessCalculator,
                new_genome,
                source_piece);

            // return a new individual based on the new genome list.
            Individual individual = new Individual(new_genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }