private async Task <IndividualSet> CalcFitness(IndividualSet individualSet)
        {
            var    substitution     = new Substitution(Alphabet, individualSet.Select(i => i.Key).ToList());
            string decryptedMessage = substitution.Decrypt(EncryptedText);

            IEnumerable <double> results = await Task.WhenAll(
                CalcFittingQuotient(decryptedMessage, _twoLettersFrequencies),
                CalcFittingQuotient(decryptedMessage, _threeLettersFrequencies));

            individualSet.Fitness = TwoLettersFittingQuotientCoef * results.ElementAt(0) +
                                    ThreeLettersFittingQuotientCoef * results.ElementAt(1);

            return(individualSet);
        }
        private IEnumerable <IndividualSet> GeneratePoputation(int size)
        {
            var           random     = new Random();
            var           population = new HashSet <IndividualSet>(size, new IndividualSetsComparer());
            IndividualSet individualSet;
            Individual    individual;

            while (population.Count != size)
            {
                individualSet = new IndividualSet(IndividualSetMembersCount);
                while (individualSet.Count != IndividualSetMembersCount)
                {
                    individual = new Individual(new string(Alphabet.ToCharArray().OrderBy(s => (random.Next(2) % 2) == 0).ToArray()), Alphabet.Length);
                    individualSet.Add(individual);
                }
                population.Add(individualSet);
            }

            return(population);
        }
        private List <IndividualSet> Crossover(IndividualSet firstSet, IndividualSet secondSet, bool needsMutation = false)
        {
            IndividualSet firstChildSet  = new IndividualSet(IndividualSetMembersCount);
            IndividualSet secondChildSet = new IndividualSet(IndividualSetMembersCount);

            var random = new Random();

            char[]            firstChildKey, secondChildKey;
            LinkedList <char> firstKeyCopy, secondKeyCopy;
            List <(int index, int indicator)> positions;

            for (int keyIndex = 0; keyIndex < firstSet.Count; keyIndex++)
            {
                firstChildKey  = new char[Alphabet.Length];
                secondChildKey = new char[Alphabet.Length];

                firstKeyCopy  = new LinkedList <char>(firstSet[keyIndex].Key);
                secondKeyCopy = new LinkedList <char>(secondSet[keyIndex].Key);

                positions = Enumerable.Range(0, Alphabet.Length)
                            .Select(i => (i, random.Next(0, 2))).ToList();
                foreach ((int letterIndex, int indicator) in positions)
                {
                    if (indicator == 0)
                    {
                        firstChildKey[letterIndex] = firstSet[keyIndex].Key[letterIndex];
                        secondKeyCopy.Remove(firstSet[keyIndex].Key[letterIndex]);
                    }
                    else
                    {
                        secondChildKey[letterIndex] = secondSet[keyIndex].Key[letterIndex];
                        firstKeyCopy.Remove(secondSet[keyIndex].Key[letterIndex]);
                    }
                }

                foreach ((int index, int indicator) in positions)
                {
                    if (indicator == 1)
                    {
                        firstChildKey[index] = secondKeyCopy.First.Value;
                        secondKeyCopy.RemoveFirst();
                    }
                    else
                    {
                        secondChildKey[index] = firstKeyCopy.First.Value;
                        firstKeyCopy.RemoveFirst();
                    }
                }

                if (needsMutation)
                {
                    int randomPos         = random.Next(0, Alphabet.Length);
                    int firstLetterIndex  = random.Next(0, randomPos);
                    int secondLetterIndex = random.Next(randomPos, Alphabet.Length);

                    Swap(firstChildKey, firstLetterIndex, secondLetterIndex);
                    Swap(secondChildKey, firstLetterIndex, secondLetterIndex);
                }

                firstChildSet.Add(new Individual(new string(firstChildKey), Alphabet.Length));
                secondChildSet.Add(new Individual(new string(secondChildKey), Alphabet.Length));
            }

            return(new List <IndividualSet> {
                firstChildSet, secondChildSet
            });

            void Swap(char[] childKey, int firstLetterIndex, int secondLetterIndex)
            {
                char temp = childKey[firstLetterIndex];

                childKey[firstLetterIndex]  = childKey[secondLetterIndex];
                childKey[secondLetterIndex] = temp;
            }
        }