#ifndef HEAD_H_INCLUDED

#define HEAD_H_INCLUDED

#include <iostream>

#include <array>

#include <stdexcept>

#include <fstream>

#include <cstdlib>





using std::cout;

using std::endl;

using std::ifstream;

using std::ofstream;

using std::cin;



//Заголовочный файл с вроде-как-классом и основными функциями.

//Много friends потому что предпочитаю функции типа Func(Obj, y),

//a не Obj.Func(y); Считайте личной причудой.



class column //Представляет ОДНУ колонку чисел в кроссворде.

//Колонка это как бы строка и столбец: тут нет разницы.

{

private:

    struct chislo //Представляет ОДНО число из колонки.

    {

    int number;//Само число.

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

    //if(?) -> Алгоритм-функции -> SetRange (Stb / Str).

    int range_lst_ps;//Последняя границы диапазона числа.

    //За пояснениями туда же.

    };

    chislo stroka [40];//Размер массива проставлен от балды.

    bool is_locked = 0;//Флаг "закрыта ли колонка?".

    //За пояснениями в алгоритм-функции -> LockLine (Stb / Str).

    bool is_full = 0;//Флаг "заполнена ли колонка?".

    //Введен в экспериментальных целях, значения не имеет

    bool monolith_check = 0;//Флаг "есть ли в колонке монолит-число?".

    //Как оказалось - он не нужен. За пояслениями про монолит -> алгоритм-функции

    //-> monolith(stb / str).

    int kol_vo;//Количество чисел в колонке.

    column(chislo * stroka_, int kol_vo_);

    //Приватный конструктор для приема первичных данных

public:

    column() {}

    column(const column & target);

    //column(column && target);

    friend column GetInfoColumn(ifstream &);

    friend void SetRangeStr(column target [], int max_size, char [] [30]);

    friend void SetRangeStb(column target [], int max_size, char [] [30]);

    friend bool monolithstr(column target [], int max_size, char [] [30]);

    friend bool monolithstb(column target [], int max_size, char [] [30]);

    friend void CycleStr(column target [], int max_size, char  [] [30]);

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

    friend void RazvertStr(column target [], int strk, int strk_pos, int, char [] [30]);

    friend void RazvertStb(column target [], int strk, int strk_pos, int, char [] [30]);

    friend void DoOpredStr(column target [], int strk, int strk_pos, int lst_pos,

            int neo_holder_pos, char [] [30]);

    friend void DoOpredStb(column target [], int strk, int strk_pos, int lst_pos,

            int neo_holder_pos, char [] [30]);

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

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

    friend void DeleteRangeStr(column target [], int fst_ps, int lst_pos,

                            int index, int strk, char testpnt [] [30]);

    friend void DeleteRangeStb(column target [], int fst_ps, int lst_pos,

                            int index, int strk, char testpnt [] [30]);

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

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

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

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

    friend void RandRecurs(char testm [] [30], column stroki [], column stolbzi [], int sc);

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

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

                column stolbzi_copy []);

    column operator=(const column &);

    void show() const;

    ~column();

    ///

    class bad_access//Класс-исключение "неверный индекс доступа к массиву"

    {

     private:

        int bad_number;

     public:

        explicit bad_access(int t_) : bad_number(t_) {}

        void show() const {cout << "Bad access index: " << bad_number << endl; }

    };

    ///

    class bad_no_kletka//Класс-исключение "неопределенных клеток больше нет"

    //(неопределенной называется клетка БЕЗ состояния, то есть ВОЗМОЖНО не пустая ИЛИ ВОЗМОЖНО не закрашеная)

    {

      private:

        int bad_num;

      public:

        explicit bad_no_kletka(int bd) : bad_num(bd) {}

    };

};



struct kletka_pack//Структура для упаковки координат клетки в функции GetKletka()

{

    int stroka;

    int stolbez;

};





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

column GetInfoColumn(ifstream &);

//Константы. Взаимно перепутаны нафиг.

const int max_str_len = 30;//ширина

const int max_stb_len = 30;//высота

const int str_count = 30;

const int stb_count = 30;

//Объявления алгоритм-функций

void SetRangeStr(column target [], int max_size, char [] [30]);

void SetRangeStb(column target [], int max_size, char [] [30]);

bool monolithstr(column target [], int max_size, char [] [30]);

bool monolithstb(column target [], int max_size, char [] [30]);

void CycleStr(column target [], int max_size, char [] [30]);

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

void RazvertStr(column target [], int strk, int strk_pos, int lst_pos, char [] [30]);

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

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

            int neo_holder_pos, char [] [30]);

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

            int neo_holder_pos, char [] [30]);

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

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

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

                 char testpnt [] [30]);

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

                 char testpnt [] [30]);

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

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

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

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

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

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

               column stolbzi_copy []);

kletka_pack GetKletka(char target [] [30]);

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



class pack//Пакет состояния поля кроссворда

//То есть все его данные: строки, столбцы, само поле...

{

    public:

    column str [30];

    column stb [30];

    char testm_copy_rand [30][30];

    kletka_pack wcords;

    pack() {}

    pack operator=(const pack & target);

    pack(const pack &);

};









#endif // HEAD_H_INCLUDED

