#include "HEAD.h"





//Определения функций приема данных

column GetInfoColumn(ifstream & in)//Ввод колонок чисел из файла.

//Да, он немного тупой.

{

    column::chislo TempGet [21];

    column::chislo TempHelper;

    int counter = 0;

    in >> TempHelper.number;

    while(!in.fail())

    {

        TempGet[counter++].number = TempHelper.number;

        if(in.peek() == '\n')

            break;

         in >> TempHelper.number;

    }

    in.clear();

    while(in.get() != '\n')

        ;

    column TempObject(TempGet, counter);

    //cout << "The column has been writed." << endl;

    //TempGet = nullptr;

    //delete [] TempGet;

    return TempObject;

}



// Определения методов storage-классов

column::column(chislo stroka_ [], int kol_vo_)

{

    //stroka = new chislo [kol_vo_];

    for(int x = 0; x < kol_vo_; x++)

        stroka[x] = stroka_[x];

    kol_vo = kol_vo_;

}



column::column(const column & target)

{

    //stroka = new chislo [target.kol_vo];

    for(int x = 0; x < target.kol_vo; ++x)

        stroka[x] = target.stroka[x];

    kol_vo = target.kol_vo;

    is_locked = target.is_locked;

    monolith_check = target.monolith_check;

    is_full = target.is_full;

}



//column::column(column && target)

//{

    //stroka = new chislo [target.kol_vo];

    //stroka = target.stroka;

    //target.stroka = nullptr;

    //kol_vo = target.kol_vo;

//}



column column::operator=(const column & target)

{

    if(&target == this)

        return *this;

    //delete [] stroka;

    //stroka = new chislo [target.kol_vo];

    for(int x = 0; x < target.kol_vo; ++x)

        stroka[x] = target.stroka[x];

        kol_vo = target.kol_vo;

        is_locked = target.is_locked;

        monolith_check = target.monolith_check;

        is_full = target.is_full;

        return *this;

}



void column::show() const

{

    for(int x = 0; x < kol_vo; ++x)

    {

        //if(stroka[x].range_fst_ps > stroka[x].range_lst_ps)

           //cout << "ERROR!";

      cout << stroka[x].number << ": "

      << stroka[x].range_fst_ps << " "

        << stroka[x].range_lst_ps << "  ";

    }

    //cout << is_locked;

    cout << endl;

}



column::~column()

{

//    delete [] stroka;

}



//SetRange

/*Диапазон - ВСЕ клетки, в которых может находится закрашеный ряд или его части

Функция выполняет установку двух диапазонных границ (range bounds)

путем расстановки колонки в два крайних положения.

Пример:

Строка в 10 клеток:

            . . . . . . . . . .

            Ee числа:

            3 4

            Тогда:

            ЛЕВОЕ крайнее положение:

            x x x 0 x x x x 0 0

            ПРАВОЕ крайнее положение:

            0 0 x x x 0 x x x x

            (Внимание! Здесь и далее клетки закр. ряда МОГУТ ВХОДИТЬ в клетку, соотвествующую ГРАНИЦЕ

             диапазона)

            При порядковой нумерации клеток от нуля включительно (0, 1, 2...)

            Диапазон первого числа: 0 - 4.

            Аналогично для второго числа.

            Аналогично для столбцов.

*/



//Определения алгоритм-функций

void SetRangeStr(column target [], int max_column, char testpnt [] [30])

{

    int determinate; //кол-во неопределенных клеток

    int sum = 0; //сумма чисел в строке / столбце

    for(int x = 0; x < str_count; x++)

    {

       for(int y = 0; y < target[x].kol_vo; y++)

       sum += target[x].stroka[y].number;

       determinate = (max_str_len - sum) - (target[x].kol_vo - 1);

       // сумма и неопр. клетки



       for(int y = 0; y < target[x].kol_vo; y++)

       {

        //Установка флага

       int num = target[x].stroka[y].number;

       if(num - determinate > 0)

       {

            target[x].monolith_check = true;

            break;

       }

       else

            target[x].monolith_check = false;

       }

    }

    //Range-установка

    //fst pos

    for(int x = 0; x < str_count; x++)

    {

    int cnt = target[x].kol_vo;

    int pntpos = 0;

    for(int z = 0; z < cnt; z++)

    {

        int temp = target[x].stroka[z].number;

        int help = pntpos;

        target[x].stroka[z].range_fst_ps = pntpos;

        for(; pntpos < temp + help; pntpos++)

        {



        }

        pntpos++;

    }

    }

    //lst pos

    for(int x = 0; x < str_count; x++)

    {

    int cnt = target[x].kol_vo;

    int pntpos = max_str_len - 1;

    for(int z = cnt - 1; z >= 0; z--)

    {

        int temp = target[x].stroka[z].number;

        int help = pntpos;

        target[x].stroka[z].range_lst_ps = pntpos;

        for(; pntpos > help - temp; pntpos--)

        {



        }

        pntpos--;

    }

    }

}



void SetRangeStb(column target [], int max_column, char testpnt [] [30])

{

    int determinate; //кол-во неопределенных клеток

    int sum = 0; //сумма чисел в строке / столбце

    for(int x = 0; x < stb_count; x++)

    {

       for(int y = 0; y < target[x].kol_vo; y++)

       sum += target[x].stroka[y].number;

       determinate = (max_stb_len - sum) - (target[x].kol_vo - 1);

       // сумма и детерминат



       for(int y = 0; y < target[x].kol_vo; y++)

       {

           //Установка флага

       int num = target[x].stroka[y].number;

       if(num - determinate > 0)

       {

            target[x].monolith_check = true;

            break;

       }

       else

            target[x].monolith_check = false;

       }

    }

    //Range-установка

    //fst pos

    for(int x = 0; x < stb_count; x++)

    {

    int cnt = target[x].kol_vo;

    int pntpos = 0;

    for(int z = 0; z < cnt; z++)

    {

        int temp = target[x].stroka[z].number;

        int help = pntpos;

        target[x].stroka[z].range_fst_ps = pntpos;

        for(; pntpos < temp + help; pntpos++)

        {



        }

        pntpos++;

    }

    }

    //lst pos

    for(int x = 0; x < stb_count; x++)

    {

    int cnt = target[x].kol_vo;

    int pntpos = max_stb_len - 1;

    for(int z = cnt - 1; z >= 0; z--)

    {

        int temp = target[x].stroka[z].number;

        int help = pntpos;

        target[x].stroka[z].range_lst_ps = pntpos;

        for(; pntpos > help - temp; pntpos--)

        {



        }

        pntpos--;

    }

    }

}





//Monolith

/* Суть функции в том, что она как бы расставляет закрашенные ряды клеток

в два крайних положения: верхнее и нижнее (или левое и правое для строк).

Затем она определяет перекрещивающиеся ряды из этих двух положений.

Если перекр. ряды соотвествуют одному и тому же числу, а это число имеет

ОДИН И ТОТ ЖЕ порядковый номер - перекрещивающиеся клетки двух рядов будут

ТОЧНО закрашеными.

Пример: Строка в 10 клеток:

        . . . . . . . . . .

        Ее числа:

        4 4

        Тогда:

        ЛЕВОЕ крайнее положение:

        x x x x 0 x x x x 0 (0 - ТОЧНО пустая клетка)

        ПРАВОЕ крайнее положение:

        0 x x x x 0 x x x x

        Если считать с нуля включительно (0, 1, 2...):

        Клетки с номерами 1 - 3 включительно перекрещиваются в двух рядах, соотвествующих числу

        с ОДИНАКОВЫМ порядковым номером (для первой четверки - 0, для второй - 1)

        и будут ТОЧНО закрашеными.

        Аналогично для клеток с номерами 6 - 8 включительно.

        Аналогично для столбцов.

        */



bool monolithstr(column target [], int max_column, char testpnt [] [30])

{

    int check_return = 0;

    for(int x = 0; x < str_count; x++)

    {

        for(int y = 0; y < target[x].kol_vo; y++)

      {

        int range = target[x].stroka[y].range_lst_ps -

        target[x].stroka[y].range_fst_ps + 1;

        int result = range - target[x].stroka[y].number;

        int num = target[x].stroka[y].number;

        if(result >= num)

        {

            //Monolith false

        }

        else if(result < num)

        {

            //Monolith true

            check_return++;

            int skos = result;

            int fst_pnt = target[x].stroka[y].range_fst_ps + skos;

            int lst_pnt = target[x].stroka[y].range_lst_ps - skos;

            for(int z = fst_pnt; z <= lst_pnt; z++)

            {

                if(z < 0 || z >= stb_count)

                throw column::bad_access(z);

                testpnt [x][z] = 'x';

            }



        }

      }

    }

    if(check_return > 0)

        return true;

    else

        return false;

}



bool monolithstb(column target [], int max_column, char testpnt [] [30])

{

    int check_return = 0;

    for(int x = 0; x < stb_count; x++)

    {

        for(int y = 0; y < target[x].kol_vo; y++)

      {

        int range = target[x].stroka[y].range_lst_ps -

        target[x].stroka[y].range_fst_ps + 1;

        int result = range - target[x].stroka[y].number;

        int num = target[x].stroka[y].number;

        if(result >= num)

        {

            //Monolith false

        }

        else if(result < num)

        {

            //Monolith true

            check_return++;

            int skos = result;

            int fst_pnt = target[x].stroka[y].range_fst_ps + skos;

            int lst_pnt = target[x].stroka[y].range_lst_ps - skos;

            for(int z = fst_pnt; z <= lst_pnt; z++)

            {

                if(z < 0 || z >= str_count)

                throw column::bad_access(z);

                testpnt [z][x] = 'x';

            }



        }

      }

    }

    if(check_return > 0)

        return true;

    else

        return false;

}



/* Функция-цикл.

Осуществляет проход по колонкам, ища:

Закрашеные клетки

Неопределенные клетки

и закрывая колонки (за пояснениями насчет закрытия в функции LockLine)

*/

void CycleStr(column target [], int max_column, char testpnt [] [30])

{

    int count_of_zakr = 0;

    int str;

    int str_pos;

    for(int x = 0; x < str_count; x++)

    {

       for(int y = 0; y < stb_count; y++)

       {

           if(testpnt[x][y] == 'x')

           {

               if(count_of_zakr == 0)

               {

                str = x;

                str_pos = y;

               }

               for(; y < max_str_len && testpnt [x][y] == 'x'; y++)

               count_of_zakr++;

           }

           if(count_of_zakr > 0)

           {

           RazvertStr(target, str, str_pos, str_pos + count_of_zakr - 1, testpnt);

           count_of_zakr = 0;

           }

       }

    }



    for(int x = 0; x < str_count; x++)

    {

       for(int y = 0; y < stb_count; y++)

       {

           if(testpnt[x][y] == '.')

           {

                str = x;

                str_pos = y;

                SetVoidStr(target, str, str_pos, testpnt);

           }

       }

    }



    for(int x = 0; x < str_count; x++)

    {

       target[x].is_locked = LockLineStr(target, x, testpnt);

    }

}



void CycleStb(column target [], int max_column, char testpnt [] [30])

{

    int count_of_zakr = 0;

    int str;

    int str_pos;

    for(int x = 0; x < stb_count; x++)

    {

       for(int y = 0; y < str_count; y++)

       {

           if(testpnt[y][x] == 'x')

           {

               if(count_of_zakr == 0)

               {

                str = x;

                str_pos = y;

               }

           for(; y < max_stb_len && testpnt [y][x] == 'x'; y++)

               count_of_zakr++;

           }

           if(count_of_zakr > 0)

           {

           RazvertStb(target, str, str_pos, str_pos + count_of_zakr - 1, testpnt);

           count_of_zakr = 0;

           }

       }

    }

    for(int x = 0; x < stb_count; x++)

    {

       for(int y = 0; y < str_count; y++)

       {

           if(testpnt[y][x] == '.')

           {

                str = x;

                str_pos = y;

                SetVoidStb(target, str, str_pos, testpnt);

           }

       }

    }



    for(int x = 0; x < stb_count; x++)

    {

       target[x].is_locked = LockLineStb(target, x, testpnt);

    }



}



/*Razvert

Осуществляет дальнейшее развертывание обнаруженых в цикле закрашеных ряда / клетки

если это возможно.

Аналогично для столбцов.

Итак - прикол номер раз.

Если убрать лесенку else ifов то может показаться что начнется сквозное выполнение

блоков if (больше одного за раз, короче).

Но СПЕЦИАЛЬНО введеная переменная multc доказывает что это не так.

Иначе говоря все дело только в потере времени на проверку всех ifов

Внимание вопрос: почему количество пакетов состояний (описаны в заголовочном, класс pack)

в стек-контейнере storage, определяемое переменной counter в main()

РЕЗКО подлетает при введении elsoв?

если их убрать - кол-во состояний будет где-то 80 - 90 в среднем, но если

подключить - оно взлетит АЖ ДО 200(!1!1!!0101001!?!)?!

Ведь разницы ТОЧНО нет? Да?

Прикол номер два. В комментарии с меткой ! содержится цепочка вызовов operator <<.

Представьте, что точно такой же оператор был и в функции RazvertStb.

Сейчас, почему-то, программа зациклилась на обработке тех файлов, которые раньше шли без проблем.

Когда я в первый раз попытался убрать эти строки в ОДНОЙ ИЗ ФУНКЦИЙ (по причине дальнейшей ненужности),

программа начала некорректно работать (неправильно рисовать закр. ряды).

Когда я возвращал все назад - обработка шла нормально.

Нарушение начиналось при удалении либо ДВУХ операторов, либо при удалении

оператора из НИЖНЕЙ функции (RazvertStb). При удалении из RazvertStr все было нормально.

И еще одно. Совершенно неважно, что именно выводилось в консоль в этих цепочках.

Если в конце не было манипулятора endl, программа начинала некорректно работать, даже при

присутствии ДВУХ операторов.

Интересно, формулировка "результат не определен" сюда относится?

Напишите, пожалуйста.

*/









void RazvertStr(column target [], int str, int str_pos, int lst_pos, char testpnt [] [30])

{

    // ! cout << str << " " << str_pos << " " << lst_pos << endl;

    //str - текущая проверяемая в цикле строка (нумерация от нуля)

    //str_pos - первая(слева направо и сверху вниз) позиция закр. ряда

    //lst_pos - вторая позиция закр. ряда

    //testpnt - здесь и далее: двумерный однобайтный символьный массив за неимением лучшего

    //представляющий поле кроссворда

    int square_pos_fst = str_pos;//Не смущайтесь словом square. Очередная причуда

    int square_pos_last = lst_pos;

    if(str < 0 || str >= str_count)//Здесь и далее: куча исключений для перехвата

        //в rand-цикле (за пояснениями в main()) попыток доступа в невыделенную памать.

        //Второе условие неправильного(wrong) состояния поля кроссворда (за пояснениями туда же)

        throw column::bad_access(str);

   if(square_pos_fst < 0 || square_pos_fst >= max_str_len)

        throw column::bad_access(square_pos_fst);

    if(square_pos_last < 0 || square_pos_last >= max_str_len)

        throw column::bad_access(square_pos_last);

    int len = lst_pos - str_pos + 1;//Длина закр. ряда

    int cross_count = 0;//Счетчик кол-ва пересечений с другими диапазонами

    int index_chisla [target[str].kol_vo];//Порядковый номер структуры chislo в массиве stroka

    int range_holders [target[str].kol_vo];//Holderы или "владельцы" диапазонов

    //то есть те числа которым соотвествует диапазон

    ///

    int RNGF;

    int RNGL;

    int multc = 0;//Доказательство первого бага

    ///

    for(int x = 0; x < target[str].kol_vo; x++)

    {

        if(square_pos_fst >= target[str].stroka[x].range_fst_ps &&

            square_pos_last <= target[str].stroka[x].range_lst_ps)

        {

            range_holders[cross_count] = target[str].stroka[x].number;

            index_chisla[cross_count++] = x;

        }

    }

    bool all_menshe;//Начало счетчик-блока (возможно что в нем и проблема: теоретически МОГУТ

                // быть ситуации когда блок неправильно определит состояние взаимодействия закр. ряда

                // c остальными данными (другими диапазонами или закр. рядами))

    int holders_leveller_cnt = 0;//Счетчик, показывающий количество равенств len

    //"владельцам" других пересекающихся диапазонов

    int once_holder_count = 0;

    int neo_once_holder_count = 0;

    int neo_holder_pos;//Позиция недоопределенного числа в колонке

    int holder_pos;//Позиция определенного числа в колонке

    //Эти две позиции могут быть неинициализированы в DoOpred функциях

    //однако это будет перехвачено соотвествующими исключениями

    bool neopredel_SST;//Флаг недоопределенного состояния

    int neopredel_SST_helper = cross_count;

    for(int x = 0; x < cross_count; x++)

    {

        if(len < range_holders[x])

        {

            neo_holder_pos = index_chisla[x];

            //Даже если этот блок и будет выполнен несколько раз и

            //это приведет к неправильному решению кроссворда в дальнейшем,

            //то ошибки здесь нет.

            //Соотвествующие исключения неверного индекса доступа к testpnt или функция

            //CheckRight перехватят ошибку, что является ОБЯЗАТЕЛЬНЫМ условием правильной работы

            //rand-цикла

        }

        if(len != range_holders[x])

        {

            neopredel_SST_helper--;

        }

        if(len == range_holders[x])

        {

            holder_pos = index_chisla[x];

            holders_leveller_cnt++;

        }

        if(len > range_holders[x])

        {

            neo_once_holder_count++;

            once_holder_count++;

        }



    }

    neopredel_SST = neopredel_SST_helper == 0;// да ? / нет ?

    //Состояние закр. ряда считается недоопределенным, если

    //его длина не равна ни одному из "владельцев" пересекающихся

    //с ним диапазонов.

    all_menshe = (holders_leveller_cnt == 1

                  && once_holder_count == cross_count - 1);

    //Длина закр. ряда больше всех "владельцев" пересекающихся с ним диапазонов

    //если длина равна ТОЛЬКО ОДНОМУ "владельцу" И БОЛЬШЕ всех остальных.

    //Конец счетчик-блока

    ///ЕСЛИ РЯД ОПРЕДЕЛЕН (то есть равен при остальных условиях (они ниже) своим возможным "владельцам")

    if(cross_count == 1)//Находится ТОЛЬКО в своем range и определена.

    {

        if(len == range_holders[0])

        {

            multc++;

            if(square_pos_last < max_str_len - 1)

                testpnt[str][square_pos_last + 1] = '0';

            if(square_pos_fst > 0)

                testpnt[str][square_pos_fst - 1] = '0';

            target[str].stroka[index_chisla[0]].range_fst_ps = square_pos_fst;

            target[str].stroka[index_chisla[0]].range_lst_ps = square_pos_last;

        }

        ///Для отладки

        RNGF = target[str].stroka[index_chisla[0]].range_fst_ps;

        RNGL = target[str].stroka[index_chisla[0]].range_lst_ps;

        if(RNGF > RNGL)

            cout << "OPREDELEN, CROSS == 1!" << endl;



    }



    else if(cross_count > 1 && cross_count == holders_leveller_cnt)

    //Если закраш ряд определен, пересечений несколько и ВСЕ holderы

    //пересечений равны

    {

        multc++;

        if(len == range_holders [0])//Равна любому holdery так как holderы одинаковы

        {

        if(square_pos_last < max_str_len - 1)

                testpnt[str] [square_pos_last + 1] = '0';

        if(square_pos_fst > 0)

                testpnt[str] [square_pos_fst - 1] = '0';

        }

    }



    else if(cross_count > 1 && all_menshe)

        //ИЛИ закраш ряд определен, пересечений несколько и ВСЕ holderы

        // пересечений меньше

    {

        multc++;

       if(square_pos_last < max_str_len - 1)

                testpnt[str] [square_pos_last + 1] = '0';

        if(square_pos_fst > 0)

                testpnt[str] [square_pos_fst - 1] = '0';

        if(holder_pos < 0 || holder_pos >= target[str].kol_vo)

        throw column::bad_access(0);

        target[str].stroka[holder_pos].range_fst_ps = square_pos_fst;

        target[str].stroka[holder_pos].range_lst_ps = square_pos_last;

        ///

        RNGF = target[str].stroka[holder_pos].range_fst_ps;

        RNGL = target[str].stroka[holder_pos].range_lst_ps;

        if(RNGF > RNGL)

            cout << "OPREDELEN, CROSS > 1, ALL HLD MENSHE!" << endl;

    }



    ///ЕСЛИ РЯД НЕДООПРЕДЕЛЕН (то есть МЕНЬШЕ при остальных условиях (они ниже) своих возможных "владельцев")

    else if(neopredel_SST && neo_once_holder_count == cross_count - 1 && cross_count > 1)

    //ИЛИ закраш ряд недоопределен, пересечений несколько и ВСЕ holderы

    // пересечений меньше

    {

        multc++;

        DoOpredStr(target, str, str_pos, lst_pos, neo_holder_pos, testpnt);

    }



    else if(neopredel_SST && cross_count == 1)

    //ИЛИ закраш ряд недоопределен, пересечение только одно

    {

        multc++;

        DoOpredStr(target, str, str_pos, lst_pos, neo_holder_pos, testpnt);

    }



     if(multc > 1)

        cin.get();

}



void RazvertStb(column target [], int str, int str_pos, int lst_pos, char testpnt [] [30])

{

    int square_pos_fst = str_pos;

    int square_pos_last = lst_pos;

    if(str < 0 || str >= stb_count)

        throw column::bad_access(str);

    if(square_pos_fst < 0 || square_pos_fst >= max_stb_len)

        throw column::bad_access(square_pos_fst);

    if(square_pos_last < 0 || square_pos_last >= max_stb_len)

        throw column::bad_access(square_pos_last);

    int len = lst_pos - str_pos + 1;

    int cross_count = 0;

    int index_chisla [target[str].kol_vo];

    int range_holders [target[str].kol_vo];

    ///

    int RNGHLD;

    int RNGF;

    int multc = 0;

    int RNGL;

    bool IFDEF = false;

    ///

    for(int x = 0; x < target[str].kol_vo; x++)

    {

        if(square_pos_fst >= target[str].stroka[x].range_fst_ps &&

            square_pos_last <= target[str].stroka[x].range_lst_ps)

        {

            RNGHLD = target[str].stroka[x].number;

            RNGL = target[str].stroka[x].range_lst_ps;

            RNGF = target[str].stroka[x].range_fst_ps;

            range_holders[cross_count] = target[str].stroka[x].number;

            index_chisla[cross_count++] = x;

        }

    }

    bool all_menshe;

    int holders_leveller_cnt = 0;

    int once_holder_count = 0;

    int neo_once_holder_count = 0;

    int neo_holder_pos;

    int holder_pos;

    bool neopredel_SST;

    int neopredel_SST_helper = cross_count;

    for(int x = 0; x < cross_count; x++)

    {

        if(len < range_holders[x])

        {

            IFDEF = true;

            neo_holder_pos = index_chisla[x];

        }

        if(len != range_holders[x])

        {

            neopredel_SST_helper--;

        }

        if(len == range_holders[x])

        {

            holder_pos = index_chisla[x];

            holders_leveller_cnt++;

        }

        if(len > range_holders[x])

        {

            neo_once_holder_count++;

            once_holder_count++;

        }



    }

    neopredel_SST = neopredel_SST_helper == 0;// да ? / нет ?

    all_menshe = (holders_leveller_cnt == 1

                  && once_holder_count == cross_count - 1);



    ///ЕСЛИ РЯД ОПРЕДЕЛЕН

    if(cross_count == 1)//Находится ТОЛЬКО в своем range и определена

    {

        if(len == range_holders[0])

        {

            multc++;

            if(square_pos_last < max_stb_len - 1)

                testpnt[square_pos_last + 1][str] = '0';

            if(square_pos_fst > 0)

                testpnt[square_pos_fst - 1][str] = '0';

            target[str].stroka[index_chisla[0]].range_fst_ps = square_pos_fst;

            target[str].stroka[index_chisla[0]].range_lst_ps = square_pos_last;

        }



    }



    else if(cross_count > 1 && cross_count == holders_leveller_cnt)

    //Если закраш ряд определен, пересечений несколько и ВСЕ holderы

    //пересечений равны

    {

        multc++;

        if(len == range_holders [0])//Равна любому holdery так как holderы одинаковы

        {

        if(square_pos_last < max_stb_len - 1)

                testpnt[square_pos_last + 1] [str] = '0';

        if(square_pos_fst > 0)

                testpnt[square_pos_fst - 1] [str] = '0';

        }

    }



    else if(cross_count > 1 && all_menshe)

        //ИЛИ закраш ряд определен, пересечений несколько и ВСЕ holderы

        // пересечений меньше

    {

        multc++;

        if(square_pos_last < max_stb_len - 1)

                testpnt[square_pos_last + 1] [str] = '0';

        if(square_pos_fst > 0)

                testpnt[square_pos_fst - 1] [str] = '0';

        if(holder_pos < 0 || holder_pos >= target[str].kol_vo)

        throw column::bad_access(0);

        target[str].stroka[holder_pos].range_fst_ps = square_pos_fst;

        target[str].stroka[holder_pos].range_lst_ps = square_pos_last;

    }



    ///ЕСЛИ РЯД НЕДООПРЕДЕЛЕН

    else if(neopredel_SST && neo_once_holder_count == cross_count - 1 && cross_count > 1)

    //ИЛИ закраш ряд недоопределен, пересечений несколько и ВСЕ holderы

    // пересечений меньше

    {

        multc++;

        DoOpredStb(target, str, str_pos, lst_pos, neo_holder_pos, testpnt);

    }



    else if(neopredel_SST && cross_count == 1)

    //ИЛИ закраш ряд недоопределен, пересечение только одно

    {

        multc++;

        DoOpredStb(target, str, str_pos, lst_pos, neo_holder_pos, testpnt);

    }

    if(multc > 1)

        cin.get();



}



/*DoOpred

Эти функции пытаются доопределить закрашеный ряд, если это возможно.

Первые два блока if дорисовывают ряд, если дистанции между его краями и границами диапазона

это позволяют.

Пример:

Строка в 10 клеток:

            . . . . . . . . . .

            Ее числа:

            4

            Стал известен закр. ряд в позициях:

            . x x . . . . . . .

            Range 4: 0 - 9

            Первая дистанция:

            1 - 0 = 1

            Удовлетворяет условию dist <= 4 - 2 //(holder - 2)

            Тогда пока выполняется условие: 'счетчик цикла' < 4 - 2 - 1 //(kol_vo_iter_fst < holder - len - distance_fst)

            1.Начать закрашивать ряд с клетки, расположеной ПОСЛЕ его правой границы (клетка с номером 3).

            2.Увеличивать переменную square_pos_last_now.

            Строка после манипуляций:

            . x x x . . . . . .

            Обратно аналогично для distance_last.

            Если после прохода двух if блоков длина закр. ряда будет равна своему числу,

            то будут выставлены границы (символы 0 - точно пустая клетка).

            Аналогично для столбцов.

            */







void DoOpredStr(column target [], int strk, int str_pos, int lst_pos,

              int neo_holder_pos, char testpnt [] [30])

{

    //strk, str_pos, lst_pos и прочие переменные имеют тот же смысл, что и в Razvert функциях

    if(neo_holder_pos < 0 || neo_holder_pos >= target[strk].kol_vo)

        throw column::bad_access(0);

    //Даже если сюда и попадет неинициализированный neo_holder_pos,

    //содержаший, однако, подходящее значение - ошибка рано или поздно "всплывет",

    //a rand-цикл выполнит откат к предыдущему состоянию.

    int square_pos_fst = str_pos;

    int square_pos_last = lst_pos;

    int square_pos_fst_now = str_pos;

    int square_pos_last_now = lst_pos;

    int len = lst_pos - str_pos + 1;

    int len_now = len;

    int holder = target[strk].stroka[neo_holder_pos].number;

    int distance_fst = square_pos_fst -

    target[strk].stroka[neo_holder_pos].range_fst_ps;

    int distance_last = target[strk].stroka[neo_holder_pos].range_lst_ps

    - square_pos_last;

    int kol_vo_iter_fst;

    int kol_vo_iter_lst;

    bool return_v = false;

    if(distance_fst <= holder - 2 && distance_fst != distance_last)

    {

        for(kol_vo_iter_fst = 0; kol_vo_iter_fst < holder - len - distance_fst;

        kol_vo_iter_fst++)

        {

        if(strk < 0 || strk >= str_count)

        throw column::bad_access(strk);

        if(square_pos_last + 1 + kol_vo_iter_fst < 0 ||

           square_pos_last + 1 + kol_vo_iter_fst >= max_str_len)

        throw column::bad_access(square_pos_last + 1 + kol_vo_iter_fst);

        testpnt [strk][square_pos_last + 1 + kol_vo_iter_fst] = 'x';

        square_pos_last_now++;

        }

        len_now += kol_vo_iter_fst;

        if(len_now == holder)

            return_v = true;

        else

            return_v = false;

    }

    if(distance_last <= holder - 2 && distance_fst != distance_last)

    {

        for(kol_vo_iter_lst = 0; kol_vo_iter_lst < holder - len - distance_last;

        kol_vo_iter_lst++)

        {

        if(strk < 0 || strk >= str_count)

        throw column::bad_access(strk);

        if(square_pos_last - 1 - kol_vo_iter_lst < 0 ||

           square_pos_last - 1 - kol_vo_iter_lst >= max_str_len)

        throw column::bad_access(square_pos_last - 1 - kol_vo_iter_lst);

            testpnt [strk][square_pos_fst - 1 - kol_vo_iter_lst] = 'x';

            square_pos_fst_now--;

        }

        len_now += kol_vo_iter_lst;

        if(len_now == holder)

            return_v = true;

        else

            return_v = false;

    }

    if(return_v == true)

    {

        if(square_pos_last_now != max_str_len - 1)

        {

        if(strk < 0 || strk >= str_count)

        throw column::bad_access(strk);

        if(square_pos_last_now + 1 < 0 ||

           square_pos_last_now + 1 >= max_str_len)

        throw column::bad_access(square_pos_last_now + 1);

                testpnt[strk] [square_pos_last_now + 1] = '0';

        }

        if(square_pos_fst_now != 0)

        {

        if(strk < 0 || strk >= str_count)

        throw column::bad_access(strk);

        if(square_pos_fst_now - 1 < 0 ||

           square_pos_fst_now - 1 >= max_str_len)

        throw column::bad_access(square_pos_fst_now - 1);

                testpnt[strk] [square_pos_fst_now - 1] = '0';

        }

    }

        target[strk].stroka[neo_holder_pos].range_fst_ps =

        square_pos_fst_now - (holder - len_now);

        target[strk].stroka[neo_holder_pos].range_lst_ps =

        square_pos_last_now + (holder - len_now);

        ///

        int RNGF;

        int RNGL;

        RNGF = target[strk].stroka[neo_holder_pos].range_fst_ps;

        RNGL = target[strk].stroka[neo_holder_pos].range_lst_ps;

        if(RNGF > RNGL)

            ;

            //cout << "IN DOOPRED FCTN" << endl;

}





void DoOpredStb(column target [], int strk, int str_pos, int lst_pos,

              int neo_holder_pos, char testpnt [] [30])

{

    if(neo_holder_pos < 0 || neo_holder_pos >= target[strk].kol_vo)

        throw column::bad_access(0);

    int square_pos_fst = str_pos;

    int square_pos_last = lst_pos;

    int square_pos_fst_now = str_pos;

    int square_pos_last_now = lst_pos;

    int len = lst_pos - str_pos + 1;

    int len_now = len;

    int holder = target[strk].stroka[neo_holder_pos].number;

    int distance_fst = square_pos_fst -

    target[strk].stroka[neo_holder_pos].range_fst_ps;

    int distance_last = target[strk].stroka[neo_holder_pos].range_lst_ps

    - square_pos_last;

    int kol_vo_iter_fst;

    int kol_vo_iter_lst;

    bool return_v = false;

    if(distance_fst <= holder - 2 && distance_fst != distance_last)

    {

        for(kol_vo_iter_fst = 0; kol_vo_iter_fst < holder - len - distance_fst;

        kol_vo_iter_fst++)

        {

        if(strk < 0 || strk >= stb_count)

        throw column::bad_access(strk);

        if(square_pos_last + 1 + kol_vo_iter_fst < 0 ||

           square_pos_last + 1 + kol_vo_iter_fst >= max_stb_len)

        throw column::bad_access(square_pos_last + 1 + kol_vo_iter_fst);

        testpnt [square_pos_last + 1 + kol_vo_iter_fst][strk] = 'x';

        square_pos_last_now++;

        }

        len_now += kol_vo_iter_fst;

        if(len_now == holder)

            return_v = true;

        else

            return_v = false;



    }

    if(distance_last <= holder - 2 && distance_fst != distance_last)

    {

        for(kol_vo_iter_lst = 0; kol_vo_iter_lst < holder - len - distance_last;

        kol_vo_iter_lst++)

        {

        if(strk < 0 || strk >= stb_count)

        throw column::bad_access(strk);

        if(square_pos_fst - 1 - kol_vo_iter_lst < 0 ||

           square_pos_fst - 1 - kol_vo_iter_lst >= max_stb_len)

        throw column::bad_access(square_pos_fst - 1 - kol_vo_iter_lst);

            testpnt [square_pos_fst - 1 - kol_vo_iter_lst][strk] = 'x';

            square_pos_fst_now--;

        }

        len_now += kol_vo_iter_lst;

        if(len_now == holder)

            return_v = true;

        else

            return_v = false;

    }

    if(return_v == true)

    {

        if(square_pos_last_now != max_stb_len - 1)

        {

        if(strk < 0 || strk >= stb_count)

        throw column::bad_access(strk);

        if(square_pos_last_now + 1 < 0 ||

           square_pos_last_now + 1 >= max_stb_len)

        throw column::bad_access(square_pos_last_now + 1);

                testpnt[square_pos_last_now + 1] [strk] = '0';

        }

        if(square_pos_fst_now != 0)

        {

        if(strk < 0 || strk >= stb_count)

        throw column::bad_access(strk);

        if(square_pos_last_now - 1 < 0 ||

           square_pos_last_now - 1 >= max_stb_len)

        throw column::bad_access(square_pos_last_now - 1);

                testpnt[square_pos_fst_now - 1] [strk] = '0';

        }

    }

        target[strk].stroka[neo_holder_pos].range_fst_ps =

        square_pos_fst_now - (holder - len_now);

        target[strk].stroka[neo_holder_pos].range_lst_ps =

        square_pos_last_now + (holder - len_now);

}





/*SetVoid

Эти функции определяют, можно ли обьявить неопределенную клетку ТОЧНО пустой

Если клетка лежит ВНЕ ВСЕХ диапазонов колонки, то она ТОЧНО пуста.

*/



void SetVoidStr(column target [], int strk, int strk_pos, char testpnt [] [30])

{

    int point_pos = strk_pos;

    int cross_count = 0;

    for(int x = 0; x < target[strk].kol_vo; x++)

    {

        if(point_pos >= target[strk].stroka[x].range_fst_ps &&

            point_pos <= target[strk].stroka[x].range_lst_ps)

        {

            cross_count++;

        }

        DeleteRangeStr(target, strk, target[strk].stroka[x].range_fst_ps,

                   x, target[strk].stroka[x].range_lst_ps, testpnt);

    }



    if(cross_count == 0)

    {

        if(strk < 0 || strk >= str_count)

        throw column::bad_access(strk);

        if(point_pos < 0 ||

           point_pos >= max_str_len)

        throw column::bad_access(point_pos);

        testpnt [strk] [point_pos] = '0';

    }

}





void SetVoidStb(column target [], int strk, int strk_pos, char testpnt [] [30])

{

    int point_pos = strk_pos;

    int cross_count = 0;

    for(int x = 0; x < target[strk].kol_vo; x++)

    {

        if(point_pos >= target[strk].stroka[x].range_fst_ps &&

            point_pos <= target[strk].stroka[x].range_lst_ps)

        {

            cross_count++;

        }

        DeleteRangeStb(target, strk, target[strk].stroka[x].range_fst_ps,

                   x, target[strk].stroka[x].range_lst_ps, testpnt);

    }

    if(cross_count == 0)

    {

        if(strk < 0 || strk >= stb_count)

        throw column::bad_access(strk);

        if(point_pos < 0 ||

           point_pos >= max_stb_len)

        throw column::bad_access(point_pos);

        testpnt [point_pos] [strk] = '0';

    }

}



/*DeleteRange

Эти функции сокращают вожможный диапазон чисел в колонку.

Вызов из SetVoid надо бы сделать в самом начале цикла. Но мне лень.

Итак, если где-то в диапазоне найдена ТОЧНО пустая клетка, диапазон

разбивается на две части. Если holder диапазона НЕ ПОМЕЩАЕТСЯ в одну из этих частей,

то диапазон свертывается в соответствующем направлении.

Пример:

Строка из 10 клеток:

             . . . . . . . . . .

             Ee число:

             5

             Диапазон этого числа: 0 - 9

             Если в диапазоне обнаружена 0

             . . 0 . . . . . . .

             Тогда:

             fst_dist < holder

             Диапазон после манипуляций равен:

             3 - 9

             Обратно аналогично для lst_dist.

Вторая часть функции сканирует диапазон в поисках закр. рядов, БОЛЬШИХ по длине, чем holder

этого диапазона. Если найден такой ряд, то диапазон будет свернут в соотвествующем направлении.

Аналогично для столбцов.

*/



void DeleteRangeStr(column target [], int strk, int fst_ps, int index, int lst_pos,

                 char testpnt [] [30])

{

    //strk - номер соотв. строки

    //fst_ps - первая граница диапазона

    //index - это номер исследуемой структуры chislo

    //lst_pos - последняя граница диапазона

    if(strk < 0 || strk >= str_count)

        throw column::bad_access(strk);

    int mid_pos;

    int fst_dist;

    int lst_dist;

    int holder = target[strk].stroka[index].number;

    for(int x = fst_ps; x <= lst_pos; x++)

    {

        if(x < 0 || x >= stb_count)

        throw column::bad_access(x);

        if(testpnt [strk] [x] == '0')

        {

            mid_pos = x;

            fst_dist = mid_pos - fst_ps;

            lst_dist = lst_pos - mid_pos;

            if(fst_dist < holder)

            {

                target [strk].stroka[index].range_fst_ps = mid_pos + 1;

                fst_ps = mid_pos + 1;

            }

            if(lst_dist < holder)

            {

                target [strk].stroka[index].range_lst_ps = mid_pos - 1;

                lst_pos = mid_pos - 1;

            }

        }

    }



    ///

    fst_ps = target[strk].stroka[index].range_fst_ps;

    lst_pos = target[strk].stroka[index].range_lst_ps;

    int count_of_zakr = 0;

    int help_pos;

    for(int x = fst_ps; x <= lst_pos; x++)

    {

        if(x < 0 || x >= stb_count)

        throw column::bad_access(x);

        if(testpnt [strk] [x] == 'x')

        {

        if(count_of_zakr == 0)

        {

            fst_dist = x - fst_ps - 1;

            help_pos = x;

        }

        for(; x <= lst_pos && testpnt [strk][x] == 'x'; x++)

               count_of_zakr++;

        }



        if(count_of_zakr > 0 && count_of_zakr > holder)

        {

            lst_dist = lst_pos - x;

            if(fst_dist < holder)

            target [strk].stroka[index].range_fst_ps = x + 1;

            if(lst_dist < holder)

            target [strk].stroka[index].range_lst_ps = help_pos - 2;

        }

        count_of_zakr = 0;

    }

}



void DeleteRangeStb(column target [], int strk, int fst_ps, int index, int lst_pos,

                 char testpnt [] [30])

{

    if(strk < 0 || strk >= stb_count)

        throw column::bad_access(strk);

    int mid_pos;

    int fst_dist;

    int lst_dist;

    int holder = target[strk].stroka[index].number;

    for(int x = fst_ps; x <= lst_pos; x++)

    {

        if(x < 0 || x >= str_count)

        throw column::bad_access(x);

        if(testpnt [x] [strk] == '0')

        {

            mid_pos = x;

            fst_dist = mid_pos - fst_ps;

            lst_dist = lst_pos - mid_pos;

            if(fst_dist < holder)

            {

                target [strk].stroka[index].range_fst_ps = mid_pos + 1;

                fst_ps = mid_pos + 1;

            }

            if(lst_dist < holder)

            {

                target [strk].stroka[index].range_lst_ps = mid_pos - 1;

                lst_pos = mid_pos - 1;

            }

        }

    }

    fst_ps = target[strk].stroka[index].range_fst_ps;

    lst_pos = target[strk].stroka[index].range_lst_ps;

    int count_of_zakr = 0;

    int help_pos;

    for(int x = fst_ps; x <= lst_pos; x++)

    {

        if(x < 0 || x >= str_count)

        throw column::bad_access(x);

        if(testpnt [x] [strk] == 'x')

        {

        if(count_of_zakr == 0)

        {

            fst_dist = x - fst_ps - 1;

            help_pos = x;

        }

        for(; x <= lst_pos && testpnt [x] [strk] == 'x'; x++)

               count_of_zakr++;

        }

        if(count_of_zakr > 0 && count_of_zakr > holder)

        {

            lst_dist = lst_pos - x;

            if(fst_dist < holder)

            target [strk].stroka[index].range_fst_ps = x + 1;

            if(lst_dist < holder)

            target [strk].stroka[index].range_lst_ps = help_pos - 2;

        }

        count_of_zakr = 0;

    }

}



/*LockLine

Эта функция проверяет, закрыта ли линия и возвращает флаг, который присваивается

переменной is_locked в обьекте column.

Ряд считается ЗАКРЫТЫМ, если в нем расположены закрашенные определенные ряды в таком порядке,

какой задан numberами в структурах число.

При этом такое расположение НЕ ОБЯЗАТЕЛЬНО верно окончательно.

Пример:

Строка в 10 клеток:

            . . . . . . . . . .

            Ее числа:

            3 4

            Тогда ТАКАЯ линия будет ЗАКРЫТОЙ:

            . x x x . x x x x .

            Клетки . будут в дальнейшем выставлены функцией в символ 0.

Аналогично для столбцов.

*/



bool LockLineStr(column target [], int strk, char testpnt [] [30])

{

    ///

    ///

    /*struct line

    {

        int fst_block_pos;

        int lst_block_pos;

        int holder;

        int ranges_in_pack;

    };

    line temp;

    line block [target[strk].kol_vo];

    int block_counter = 0;

    int poradok_counter = 0;

    for(int x = 0; x < target[strk].kol_vo - 1; x++)

    {

        if(target[strk].stroka[x].number ==

           target[strk].stroka[x + 1].number)

        {

                if(poradok_counter == 0)

                {

                poradok_counter = x;

                temp.holder = target[strk].stroka[x].number;

                temp.ranges_in_pack = 2;

                temp.fst_block_pos = target[strk].stroka[x].range_fst_ps;

                temp.lst_block_pos = target[strk].stroka[x + 1].range_lst_ps;

                }

                else if(poradok_counter > 0 && poradok_counter == x - 1)

                {

                temp.ranges_in_pack++;

                temp.lst_block_pos = target[strk].stroka[x + 1].range_lst_ps;

                poradok_counter++;

                }

                if(poradok_counter != x - 1)

                {

                    poradok_counter = 0;

                    block [block_counter++] = temp;

                }

        }

    }



    for(int x = 0; x < block_counter; x++)

    {

    int kol_vo_mest = 0;

    int mest_counter = 0;

    for(int y = block[x].fst_block_pos; y <= block[x].lst_block_pos; y++)

    {

        if(testpnt [strk] [y] == '.')

        {

            for(; y <= block[x].lst_block_pos &&

            testpnt [strk] [y] == '.'; y++)

                mest_counter++;

        }

        if(mest_counter > 0 && mest_counter == block[x].holder)

        {

        kol_vo_mest++;

        mest_counter = 0;

        }

    }

       if(kol_vo_mest == block[x].ranges_in_pack && strk == 11)

       {

          //cout << block[x].fst_block_pos << " "

          //<< block[x].lst_block_pos << endl;

       }

    }*/

    ///

    ///

    if(strk < 0 || strk >= str_count)

        throw column::bad_access(strk);

    int count_of_kletka = 0;

    int target_ryad [target[strk].kol_vo];//Целевой ряд numberов

    int massive_counter = 0;

    for(int x = 0; x < max_str_len; x++)

    {

        if(testpnt [strk] [x] == 'x')

        {

                for(; x < max_str_len && testpnt [strk] [x] == 'x'; x++)

                count_of_kletka++;

        }

        if(count_of_kletka > 0)

        {

            if(massive_counter >= target[strk].kol_vo)//Проверка на случай если в строке очень уж много частей закр. рядов

            return false;

            target_ryad[massive_counter++] = count_of_kletka;

            count_of_kletka = 0;

        }

    }

    if(massive_counter != target[strk].kol_vo)//Тоже проверка: кол во элементов в массиве должно быть равно заданному GetInfoColumn кол ву numberов

        return false;

    for(int x = 0; x < massive_counter; x++)//Массив должен быть равен последовательности numberов в колонке

    {

        if(target_ryad[x] == target[strk].stroka[x].number)

        {



        }

        else

            return false;

    }

    count_of_kletka = 0;

    massive_counter = 0;

    for(int x = 0; x < max_str_len; x++)//Выстановка символов 0

    {

        if(x < 0 || x >= max_str_len)

        throw column::bad_access(x);

        if(testpnt [strk] [x] != 'x')

            testpnt [strk] [x] = '0';



        if(testpnt [strk] [x] == 'x')

        {

            target[strk].stroka[massive_counter].range_fst_ps = x;

            for(; x < max_str_len && testpnt [strk] [x] == 'x'; x++)

                count_of_kletka++;

            target[strk].stroka[massive_counter++].range_lst_ps = x - 1;

            count_of_kletka = 0;

        }

    }

    return true;

}





bool LockLineStb(column target [], int strk, char testpnt [] [30])

{

   /*struct line

    {

        int fst_block_pos;

        int lst_block_pos;

        int holder;

        int ranges_in_pack;

    };

    line temp;

    line block [target[strk].kol_vo];

    int block_counter = 0;

    int poradok_counter = 0;

    for(int x = 0; x < target[strk].kol_vo - 1; x++)

    {

        if(target[strk].stroka[x].number ==

           target[strk].stroka[x + 1].number)

        {

                if(poradok_counter > 0 && poradok_counter == x - 1)

                {

                temp.ranges_in_pack++;

                temp.lst_block_pos = target[strk].stroka[x + 1].range_lst_ps;

                poradok_counter++;

                }

                if(poradok_counter == 0)

                {

                poradok_counter = x;

                temp.holder = target[strk].stroka[x].number;

                temp.ranges_in_pack = 2;

                temp.fst_block_pos = target[strk].stroka[x].range_fst_ps;

                temp.lst_block_pos = target[strk].stroka[x + 1].range_lst_ps;

                }

        }

        else if(poradok_counter > 0)

        {

                    poradok_counter = 0;

                    block [block_counter++] = temp;

        }

    }

     ///

    for(int x = 0; x < block_counter; x++)

    {

    int kol_vo_mest = 0;

    int mest_counter = 0;

    for(int y = block[x].fst_block_pos; y <= block[x].lst_block_pos; y++)

    {

        if(testpnt [y] [strk] == '.')

        {

            for(; y <= block[x].lst_block_pos &&

            testpnt [y] [strk] == '.'; y++)

                mest_counter++;

        }

        if(mest_counter > 0 && mest_counter == block[x].holder)

        {

        kol_vo_mest++;

        mest_counter = 0;

        }

    }

       if(kol_vo_mest == block[x].ranges_in_pack && strk == 1)

       {

          //cout << "HERE: " << block[x].fst_block_pos << " "

          //<< block[x].lst_block_pos << endl;

       }

    }*/

    ///

    if(strk < 0 || strk >= stb_count)

        throw column::bad_access(strk);

    int count_of_kletka = 0;

    int target_ryad [target[strk].kol_vo];

    int massive_counter = 0;

    for(int x = 0; x < max_stb_len; x++)

    {

        if(testpnt [x] [strk] == 'x')

        {

                for(; x < max_stb_len && testpnt [x] [strk] == 'x'; x++)

                count_of_kletka++;

        }

        if(count_of_kletka > 0)

        {

            if(massive_counter >= target[strk].kol_vo)

            return false;

            target_ryad[massive_counter++] = count_of_kletka;

            count_of_kletka = 0;

        }

    }



    if(massive_counter != target[strk].kol_vo)

        return false;



    for(int x = 0; x < massive_counter; x++)

    {

        if(target_ryad[x] == target[strk].stroka[x].number)

        {



        }

        else

            return false;

    }

    count_of_kletka = 0;

    massive_counter = 0;

    for(int x = 0; x < max_stb_len; x++)

    {

        if(x < 0 || x >= max_stb_len)

        throw column::bad_access(x);

        if(testpnt [x] [strk] != 'x')

            testpnt [x] [strk] = '0';



        if(testpnt [x] [strk] == 'x')

        {

            target[strk].stroka[massive_counter].range_fst_ps = x;

            for(; x < max_stb_len && testpnt [x] [strk] == 'x'; x++)

                count_of_kletka++;

            target[strk].stroka[massive_counter++].range_lst_ps = x - 1;

            count_of_kletka = 0;

        }

    }

    return true;

}



/*CheckRight

Просто, но надежно проверяет ПРАВИЛЬНОСТЬ расположения клеток в поле кроссворда.

Даже если ошибка не будет замечена сейчас, она все равно проявится потом.

*/



bool CheckRight(column target_str [], column target_stb [], char testpnt [] [30])

{

    for(int x = 0; x < str_count; x++)

    {

        for(int y = 0; y < target_str[x].kol_vo; y++)

        {

        int holder = target_str[x].stroka[y].number;

        int dist = target_str[x].stroka[y].range_lst_ps -

        target_str[x].stroka[y].range_fst_ps + 1;

        if(target_str[x].stroka[y].range_fst_ps >

           target_str[x].stroka[y].range_lst_ps || holder > dist)

           {

                return false;

           }

        }

    }



    for(int x = 0; x < stb_count; x++)

    {

        for(int y = 0; y < target_stb[x].kol_vo; y++)

        {

        int holder = target_stb[x].stroka[y].number;

        int dist = target_stb[x].stroka[y].range_lst_ps -

        target_stb[x].stroka[y].range_fst_ps + 1;

        if(target_stb[x].stroka[y].range_fst_ps >

           target_stb[x].stroka[y].range_lst_ps || holder > dist)

           {

              cout << "WHAT COLUMN:" << x << endl;

              return false;

           }

        }

    }

    ///

    int error_counter = 0;//Два счетчика

    //введены потому, что неправильное состояние признается лишь тогда,

    //когда в диапазоне нет НИ ОДНОГО места для holderа

    int norm_counter = 0;

    for(int x = 0; x < str_count; x++)

    {

        for(int y = 0; y < target_str[x].kol_vo; y++)

        {

        int holder = target_str[x].stroka[y].number;

        int help_pos = target_str[x].stroka[y].range_fst_ps;

        for(int z = target_str[x].stroka[y].range_fst_ps;

        z <= target_str[x].stroka[y].range_lst_ps; z++)

        {

        if(z < 0 || z >= stb_count)

        {

        return false;//Тут можно не генерировать исключение

        }

            if(testpnt [x][z] == '0')

            {

                int fst_dist = z - help_pos;

                int lst_dist = target_str[x].stroka[y].range_lst_ps -

                z;

                if(holder > fst_dist && holder > lst_dist)

                {

                    error_counter++;

                    norm_counter--;

                }

                norm_counter++;

                help_pos = z + 1;

            }

        }

        if(norm_counter == 0 && error_counter > 0)

        {

            return false;

        }

        }

    }

    ///

    error_counter = 0;

    norm_counter = 0;

    for(int x = 0; x < stb_count; x++)

    {

        for(int y = 0; y < target_stb[x].kol_vo; y++)

        {

        int holder = target_stb[x].stroka[y].number;

        int help_pos = target_stb[x].stroka[y].range_fst_ps;

        for(int z = target_stb[x].stroka[y].range_fst_ps;

        z <= target_stb[x].stroka[y].range_lst_ps; z++)

        {

        if(z < 0 || z >= str_count)

        {

        return false;

        }

            if(testpnt [z][x] == '0')

            {

                int fst_dist = z - help_pos;

                int lst_dist = target_stb[x].stroka[y].range_lst_ps -

                z;

                if(holder > fst_dist && holder > lst_dist)

                {

                    error_counter++;

                    norm_counter--;

                }

                norm_counter++;

                help_pos = z + 1;

            }

        }

         if(norm_counter == 0 && error_counter > 0)

         {

            return false;

         }

        }

    }

    ///

    /*

    for(int x = 0; x < str_count; x++)

    {

        int counter = 0;

        for(int y = 0; y < max_str_len; y++)

        {

            if(testpnt [x] [y] == '.')

                counter++;

        }

        if(counter > 0)

            ;

        else

        {

            target_str[x].is_full = true;

        }

    }

    for(int x = 0; x < str_count; x++)

    {

        if(target_str[x].is_full == true &&

           target_str[x].is_locked == false)

           {

            return false;

           }

    }



    for(int x = 0; x < stb_count; x++)

    {

        int counter = 0;

        for(int y = 0; y < max_stb_len; y++)

        {

            if(testpnt [y] [x] == '.')

                counter++;

        }

        if(counter > 0)

            ;

        else

            target_stb[x].is_full = true;

    }

    for(int x = 0; x < stb_count; x++)

    {

        if(target_stb[x].is_full == true &&

           target_stb[x].is_locked == false)

           {

            return false;

           }

    }

    ///



    int count_of_zakr = 0;

    for(int x = 0; x < str_count; x++)

    {

        for(int y = 0; y < target_str[x].kol_vo; y++)

        {

        int holder = target_str[x].stroka[y].number;

        int range = target_str[x].stroka[y].range_lst_ps

        - target_str[x].stroka[y].range_fst_ps + 1;

        for(int z = target_str[x].stroka[y].range_fst_ps;

        z <= target_str[x].stroka[y].range_lst_ps; z++)

        {

        if(z < 0 || z >= max_str_len)

        return false;

        if(testpnt [x][z] == 'x')

            {

                for(; z <= target_str[x].stroka[y].range_lst_ps

                && testpnt [x][z] == 'x'; z++)

                count_of_zakr++;

            }

        if(count_of_zakr > holder)

        {

            int wrong_counter = 0;

            for(int h = 0; h < target_str[x].kol_vo; h++)

                if(count_of_zakr > target_str[x].stroka[h].number)

                wrong_counter++;

            if(wrong_counter == target_str[x].kol_vo)

            return false;

            if(range - count_of_zakr < holder)

            {

            return false;

            }

        }

        count_of_zakr = 0;



        }



        }

    }

    ///



    count_of_zakr = 0;

    for(int x = 0; x < stb_count; x++)

    {

        for(int y = 0; y < target_stb[x].kol_vo; y++)

        {

        int holder = target_stb[x].stroka[y].number;

        int range = target_stb[x].stroka[y].range_lst_ps

        - target_stb[x].stroka[y].range_fst_ps + 1;

        for(int z = target_stb[x].stroka[y].range_fst_ps;

        z <= target_stb[x].stroka[y].range_lst_ps; z++)

        {

        if(z < 0 || z >= max_stb_len)

        return false;

        if(testpnt [z][x] == 'x')

        {

            for(; z <= target_stb[x].stroka[y].range_lst_ps

            && testpnt [z][x] == 'x'; z++)

            count_of_zakr++;

        }

        if(count_of_zakr > holder)

        {

            int wrong_counter = 0;

            for(int h = 0; h < target_stb[x].kol_vo; h++)

                if(count_of_zakr > target_stb[x].stroka[h].number)

                wrong_counter++;

            if(wrong_counter == target_stb[x].kol_vo)

            return false;

            if(range - count_of_zakr < holder)

            {

            return false;

            }

        }

        count_of_zakr = 0;



        }



        }

    }*/

    /*

    ///

    int count_of_zakr = 0;

    for(int x = 0; x < str_count; x++)

    {

        for(int y = 0; y < max_str_len; y++)

        {



        if(testpnt [x][y] == 'x')

        {

        for(; y < max_str_len && testpnt [x][y] == 'x'; y++)

        count_of_zakr++;

        int wrong_counter = 0;

        for(int h = 0; h < target_str[x].kol_vo; h++)

            if(count_of_zakr > target_str[x].stroka[h].number)

               wrong_counter++;

        if(wrong_counter == target_str[x].kol_vo)

        return false;

        count_of_zakr = 0;

        }



       }

    }

    ///

    //int count_of_zakr = 0;

    for(int x = 0; x < stb_count; x++)

    {

        for(int y = 0; y < max_stb_len; y++)

        {



        if(testpnt [y][x] == 'x')

        {

        for(; y < max_stb_len && testpnt [y][x] == 'x'; y++)

        count_of_zakr++;

        int wrong_counter = 0;

        for(int h = 0; h < target_stb[x].kol_vo; h++)

            if(count_of_zakr > target_stb[x].stroka[h].number)

               wrong_counter++;

        if(wrong_counter == target_stb[x].kol_vo)

        return false;

        count_of_zakr = 0;

        }



       }

    }

     */

    return true;

}

/*CheckAll

Проверка правильности решения кроссворда.

Если ВСЕ линии закрыты - то кроссворд решен правильно.

*/

bool CheckAll(column target_str [], column target_stb [], char testpnt [] [30])

{

    /*(for(int x = 0; x < str_count; x++)

    {

       target_str[x].is_locked = LockLineStr(target_str, x, testpnt);

    }

    for(int x = 0; x < stb_count; x++)

    {

       target_stb[x].is_locked = LockLineStr(target_stb, x, testpnt);

    }*/

    for(int x = 0; x < str_count; x++)

    {

        if(target_str[x].is_locked == false)

            return false;

    }



    for(int x = 0; x < stb_count; x++)

    {

        if(target_stb[x].is_locked == false)

            return false;

    }

    return true;

}



/*CheckShag

Проверка "шага" - то есть проверяется, есть ли разница между двумя состояниями поля.

Учитываются изменения диапазонов.

*/

bool CheckShag(char target [] [30], char copy_target [] [30],

               column stroki [], column stroki_copy [], column stolbzi [],

               column stolbzi_copy [])

{

    for(int x = 0; x < str_count; x++)

      {

          for(int y = 0; y < stb_count; y++)

          {

              if(copy_target[x][y] != target [x][y])

              {

              return true;

              }



          }

      }

    for(int x = 0; x < str_count; x++)

    {

        for(int y = 0; y < stroki[x].kol_vo; y++)

        {

             if(stroki[x].stroka[y].range_fst_ps !=

                stroki_copy[x].stroka[y].range_fst_ps)

                    return true;

             if(stroki[x].stroka[y].range_lst_ps !=

                stroki_copy[x].stroka[y].range_lst_ps)

                    return true;

        }

    }



    for(int x = 0; x < stb_count; x++)

    {

        for(int y = 0; y < stolbzi[x].kol_vo; y++)

        {

             if(stolbzi[x].stroka[y].range_fst_ps !=

                stolbzi_copy[x].stroka[y].range_fst_ps)

                    return true;

             if(stolbzi[x].stroka[y].range_lst_ps !=

                stolbzi_copy[x].stroka[y].range_lst_ps)

                    return true;

        }

    }

      return false;

}

/*GetKletka

Выдача неопределенной клетки для rand-цикла в main()

*/

kletka_pack GetKletka(char target [] [30])

{

    kletka_pack temp;

    static int x;

    static int y;

    int counter = 0;

    int help_counter = 0;

    if(x >= str_count)

        x = 0;

    if(y >= stb_count)

        y = 0;

    for(; x < str_count; x++)

      {

          for(; y < stb_count; y++)

          {

              help_counter++;

              if(target [x][y] == '.')

              {

                  counter++;

                  temp.stroka = x;

                  temp.stolbez = y;

                  return temp;

              }

          }

          y = 0;

      }

   if(counter == 0 && help_counter == str_count * stb_count)//Вроде как исключение о том, что в поле больше нет неопределеных клеток

   {

   temp.stolbez = -1;

   temp.stroka = -1;

   return temp;

   }

   x = 0;

   y = 0;

   temp = GetKletka(target);

   return temp;

}

/*RandRecurs

Изначальный вариант rand-цикла

Он провалился, потому что видете ли, система проверки стек-фреймов то ли углядела бесконечную рекурсию,

то ли (и это вроде как скорее всего) выделенная память была забита в результате создания рекурсией (видете ли?!)

слишком большого (примерно 1Mb по весу, как много!) количества копий переменных функции.

*/

void RandRecurs(char testm [] [30], column stroki [], column stolbzi [])

{

      char testm_copy [str_count][30];

      char testm_copy_rand [str_count][30];

      kletka_pack temp;

      column stroki_copy [str_count];

      column stolbzi_copy [stb_count];



      while(1)

      {



      if(!CheckRight(stroki, stolbzi, testm))

      {

      return;

      }



      for(int x = 0; x < str_count; x++)

      {

          for(int y = 0; y < stb_count; y++)

          {

              testm_copy[x][y] = testm [x][y];

          }

      }

      try

      {

      monolithstr(stroki, str_count, testm);

      monolithstb(stolbzi, stb_count, testm);

      CycleStr(stroki, str_count, testm);

      CycleStb(stolbzi, stb_count, testm);

      }

      catch(column::bad_access & wrong)

      {

      return;

      }//catch



      if(!CheckRight(stroki, stolbzi, testm))

      {

      return;

      }//if





      if(!CheckShag(testm, testm_copy, stroki, stroki_copy, stolbzi, stolbzi_copy))

      {

      cout << "GO" << endl;

      for(int x = 0; x < str_count; x++)

      {

          for(int y = 0; y < stb_count; y++)

            t