/// <summary>
 /// Возвращает лист состоящий из точек не входящих в интервал
 /// </summary>
 /// <param name="includedPoints">Входящие в интервал точки</param>
 /// <param name="allPoints">Все точки</param>
 /// <returns>Не входящие в интервал точки</returns>
 List <Fraction> GetNotIncludedPoints()
 {
     foreach (var point in Points)
     {
         try
         {
             if (!IncludedPoints.Contains(point) && !NotIncludedPoints.Contains(point))
             {
                 NotIncludedPoints.Add(point);
             }
         }
         catch (NullReferenceException)
         {
             return(Points);
         }
     }
     return(NotIncludedPoints);
 }
        //В интервал добавляет корень кратности 2
        string AddRootsOfMultiplicityTwo(Fraction point, int key, bool isMidInterval, bool isIncluded = false)
        {
            Random rnd    = new Random(key);
            string result = string.Empty;

            if (isIncluded)
            {
                StrictInequality = false;
            }

            if (RootsOfMultiplicityTwo.Contains(point))
            {
                if (rnd.Next(2) == 1 || isIncluded)
                {
                    //Добавляем корень в числитель дважды
                    IncludedPoints.Add(point);
                    IncludedPoints.Add(point);
                    //Если точка расположена между интервалами, то ее надо вывести
                    if (!StrictInequality)
                    {
                        result += !isMidInterval ? $"{{{point}}}U" : "";
                    }
                }
                else
                {
                    //Добавляем корень в знаменатель и еще куда-то
                    NotIncludedPoints.Add(point);
                    if (rnd.Next(2) == 0)
                    {
                        IncludedPoints.Add(point);
                    }
                    else
                    {
                        NotIncludedPoints.Add(point);
                    }
                    //Если точка расположена внутри интервала, то она делит этот
                    //интервал на две части
                    result += isMidInterval ? $"{point})U({point} " : "";
                }
            }

            return(result);
        }
        /// <summary>
        /// Создает интервал без (+inf... и ...-inf)
        /// </summary>
        /// <param name="key">Ключ генерации интервала</param>
        /// <param name="borders">Границы интервалов</param>
        /// <returns>Интервал без (+inf... и ...-inf)</returns>
        string CreateIntervalsWithoutInf(int key, List <Fraction> borders)
        {
            Random rnd    = new Random(key);
            string result = string.Empty;

            int rndValue               = rnd.Next(2);
            int startIndex             = 0;
            int countRootsMultTwoInEnd = 0;
            int k = borders.Count() - 1;

            while (k >= 1 && borders[k].Equals(borders[k - 1]))
            {
                countRootsMultTwoInEnd += 2;
                k -= 2;
            }
            int endIndex = borders.Count() - rndValue - countRootsMultTwoInEnd;

            endIndex = endIndex < 0 ? 0 : endIndex;

            if (RootsOfMultiplicityTwo.Count() * 2 != borders.Count())
            {
                //Выбирается способ записи точек в интервале
                //borders.count() % 2 == 0 и rndValue == 0: ()()()
                //borders.count() % 2 == 0 и rndValue == 1: )()(
                //borders.count() % 2 == 1 и rndValue == 0: )()()
                //borders.count() % 2 == 1 и rndValue == 1: ()()(
                if (borders.Count() % 2 == 1 ^ rndValue == 1)
                {
                    //Добавляем корень кратности 2 в промежуток
                    while (RootsOfMultiplicityTwo.Contains(borders[startIndex]))
                    {
                        result     += AddRootsOfMultiplicityTwo(borders[startIndex], key, true);
                        startIndex += 2;
                    }

                    char bracket = GenerateBracket(key + rnd.Next(10), true);
                    if (bracket == ']')
                    {
                        RightPoints.Add(borders[startIndex]);
                        IncludedPoints.Add(borders[startIndex]);
                    }
                    else
                    {
                        RightPoints.Add(borders[startIndex]);
                        NotIncludedPoints.Add(borders[startIndex]);
                    }
                    result += $" {borders[startIndex++]}{bracket}U";
                }
                //Еще один корень кратности 2
                while (startIndex < borders.Count() && RootsOfMultiplicityTwo.Contains(borders[startIndex]))
                {
                    result     += AddRootsOfMultiplicityTwo(borders[startIndex], key, false);
                    startIndex += RootsOfMultiplicityTwo.Contains(borders[startIndex]) ? 2 : 0;
                }

                for (int i = startIndex; i < endIndex; i += 2)
                {
                    //Проверяем содержиться ли корень в списке с
                    //корнями кратности 2
                    if (RootsOfMultiplicityTwo.Contains(borders[i]))
                    {
                        result += AddRootsOfMultiplicityTwo(borders[i], key, false);
                        continue;
                    }

                    char bracketRight = GenerateBracket(key + rnd.Next(10), true);
                    char bracketLeft  = GenerateBracket(key + rnd.Next(10), false);
                    if (bracketLeft == '[')
                    {
                        IncludedPoints.Add(borders[i]);
                        LeftPoints.Add(borders[i]);
                    }

                    result += $"{bracketLeft}{borders[i]} ";

                    result += AddRootsOfMultiplicityTwo(borders[i], key, true);
                    i      += RootsOfMultiplicityTwo.Contains(borders[i]) ? 2 : 0;

                    if (bracketRight == ']')
                    {
                        IncludedPoints.Add(borders[i + 1]);
                        RightPoints.Add(borders[i + 1]);
                    }
                    result += $"{borders[i + 1]}{bracketRight}U";
                }

                result = result.Trim('U');

                if (rndValue == 1 && endIndex >= startIndex)
                {
                    char bracket = GenerateBracket(key + rnd.Next(10), false);
                    if (bracket == '[')
                    {
                        IncludedPoints.Add(borders[endIndex]);
                        LeftPoints.Add(borders[endIndex]);
                    }
                    else
                    {
                        NotIncludedPoints.Add(borders[endIndex]);
                        LeftPoints.Add(borders[endIndex]);
                    }
                    result += $"U{bracket}{borders[endIndex++]}";
                    while (endIndex < borders.Count() && RootsOfMultiplicityTwo.Contains(borders[endIndex]))
                    {
                        result   += AddRootsOfMultiplicityTwo(borders[endIndex], key, true);
                        endIndex += 2;
                    }
                }
            }

            //Добавляем конечные корни кратности 2
            while (endIndex < borders.Count() && RootsOfMultiplicityTwo.Contains(borders[endIndex]))
            {
                //Если получилось так, что у ответа неравенства нет интервалов, полуинтервалов или промежутков,
                //то корни кратности 2 точно будут включенными, а не выколотыми
                result   += AddRootsOfMultiplicityTwo(borders[endIndex], key, false, result == "");
                endIndex += 2;
            }

            if (StrictInequality)
            {
                result = result.Replace('[', '(');
                result = result.Replace(']', ')');
            }

            return(result.Trim('U'));
        }