#include "a_structure.h"
//-----------------------------------------------------------------------------------
/*
 * перебор позиций
 *
 * АВТОР ChessTerminator75
 * ПОСЛЕДНЕЕ ИЗМЕНЕНИЕ 23.02.2009 20.12.2009
*/
//---------------------------------------------------------------------------

// Задаем различные режимы компиляции перебора. Здесь мы можем легко
// включить отключить любой метод
//switch
#define SAVE_LINE 1 // при отключении(0) остается только генератор. даже останавливать движок приходится через Ctrl + Alt + Delete
           // сейчас еще придется отключать проверку на мат в модуле c_Iterative_Deepening т.е. отключать фрагмент && (flag_mate == 0)

#define FORCED 1 // включаем-выключаем(1-0) режим форсировки на взятиях

//----------------------------------
#define ALPHA_BETA_ON 1 // включаем-выключаем(1-0) режим альфа-бета отсечения
// нижеследующие три метода дают эффект только при включенном альфа-бета

#define HASH 1 // включаем-выключаем(1-0) хеш-таблицу
#define HASH_SCORE 1 // включаем-выключаем(1-0) использование оценки из хеш-таблицы
#define HASH_TEST 0 // включаем-выключаем(1-0) экстренное завершение работы движка
                    // в случае ошибки использования хода из хеш таблицы
#define HASH_TEST_SCORE 0 // включаем-выключаем(1-0) экстренное завершение работы движка
                    // в случае ошибки использования оценки из хеш таблицы.
                    // обязательно HASH_SCORE 1

#define KILLER 1 // включаем-выключаем(1-0) киллеров

#define REPETITION 1 // включаем-выключаем(1-0) детектор повторов позиций

#define EXTENSION_CHEK 1 // включаем-выключаем(1-0) продление на шахах

// внимание! для нулевого хода и futility должно быть EXTENSION_CHEK 1
#define NULL_MOVE 1 // включаем-выключаем(1-0) режим нулевого хода
#define LMR 1 // включаем-выключаем(1-0) режим Late Move Reductions


// работа этих эвристик под вопросом.---------------------------------------------

// по моему не совсем корректно продлевать размены только в главном варианте
// непонятно насколько это искажает альфа бета поиск.
 #define EXTENSION_CAPTURES 1 // включаем-выключаем(1-0) продление на разменах




 #define FUTILITY_PRUNING 0 // включаем-выключаем(1-0) режим futility pruning
                            // наряду с дельта прунингом он бессмысленен
                            // оставляю только потому что буду переделывать по разоринг
//--------------------------------------------------------------------------------


#define TEST_L 0  // включаем-выключаем(1-0) режим вывода в файл тестовой информации
#define TEST_PRINT_ALL_LINE 0  // включаем-выключаем(1-0) режим вывода при игре тестовой информации
                      // в графическую оболочку т.е. либо лучшая линия либо все линии первого уровня.


/*******************************************

 класс FULLSEARCH
 включает в себя данные и методы основного перебора

 в нем реализованы:
 (все описания с точки зрения белых)
 часто я сам до конца не понимаю для чего что то сделал
 поэтому описания дополню глупыми вопросами самому себе :)
 -------------------

 ALPHA - BETA
 об этой эвристике написано столько что добавить мне больше нечего :)
 идея выглядит примерно так:

 альфа бета с амортизацией отказов
 int AlphaBeta (pos, depth, alpha, beta) {
	if (depth == 0) return Evaluate(pos);
	best = -INFINITY;
	succ = Successors(pos);
	while (!Empty(succ)) {
		pos = RemoveOne(succ);
		value = -AlphaBeta(pos, depth - 1, -beta, -alpha);
		if (value > best) best = value;
	    if (value > alpha) alpha = value;
        if (alpha >= beta) return alpha;
	}
	return best;
 }
 --------------------------------------------------------------

 NULL MOVE
 если до дна не меньше двух полу ходов если ход не взятие и не шах и если не главный вариант
 и если мы не в нулевом ходе т.е. не допускаем вызов нулевого в нулевом 
 то 
 мы пропускаем свой ход и если даже при такой форе противник не может улучшить оценку
 найденную в поиске до этого то эту ветку можно подрезать
 ?
 --------------------------------------------------------------

 LMR
 применяем эвристику если до дна не меньше трех полу ходов если не шах и если не в главном варианте
 четыре первых хода: хеш-ход, лучшее взятие, два киллера не редуцируются
 все взятия не редуцируются
 все остальные ходы редукция на один полу ход
 ?
 --------------------------------------------------------------

 FUTILITY PRUNING
 если не взятие не шах и не в главной линии и не в нулевом поиске то
 на предпоследней глубине т.е. depth_max - depth == FUTILITY_DEPTH(равна 1)
 если 
 оценка - FUTILITY_MARGIN(равна 100) >= beta return beta
 т.е. если позицию не спасает даже фора в пешку то мы просто возвращаем бету
 таким образом перебор сокращаем на полу ход и не проводим форсированный поиск.
 ?
 
 --------------------------------------------------------------

 ---------------------
 класс самый сложный и запутанный 
 не вызывает сомнений то что он перегружен
 его надо упрощать и разбивать но пока не ясно как это сделать

********************************************/
class FULLSEARCH{

  int audit;// задержка опроса команды экстренного выхода
  int depth_max_rem;//
  int lmr_reduction;//
  bool flag_stop_search;// переменная для отсечки перебора при экстренном выходе
  __int64 nodes;// количество узлов
  char string_in2[65536];//
  int from;// откуда ходит фигура
  int to;// куда ходит фигура
  bool flag_stop_null_move;// останавливаем использование нулевого хода
  //int return_hash_score;
//////////////////////////////////////////////////////////////////////////////////////////
public:


double deep_time_terminate; // передаем на глубину время остановки счета 

//---------------------------------------------------------------------------
// 
void ini_global_loop(int depth_max//
					 );


//---------------------------------------------------------------------------
// возвращаем флаг остановки поиска. так если в глубине поиска получили команду
// на остановку то передаем ее наружу
bool get_stop_search();

//---------------------------------------------------------------------------
// возвращаем лучший вариант
struct T_PV * get_pv_best();

//---------------------------------------------------------------------------
// возвращаем количество рассмотренных узлов
__int64  get_nodes();

//---------------------------------------------------------------------------
//обнуляем количество рассмотренных узлов
 void set_nodes_in_0();

//---------------------------------------------------------------------------
// возвращаем откуда делается ход
int get_from();

//---------------------------------------------------------------------------
// возвращаем куда делается ход
int get_to();

//---------------------------------------------------------------------------
// Поиск на нулевом уровне за белых
int White_root(struct T_Bitboard * const p_bitboard,// представление доски
               struct T_list_surplus_moves & list_surplus_moves,// список возможных ходов (всевозможные ходы из данного узла)
			   int alpha,//
			   const int beta,// 
			   const int depth_max// максимальная глубина
			   );

//---------------------------------------------------------------------------
// Поиск на нулевом уровне за черных
int Black_root(struct T_Bitboard * const p_bitboard,// представление доски
               struct T_list_surplus_moves & list_surplus_moves,// список возможных ходов (всевозможные ходы из данного узла)
			   const int alpha,//
			   int beta,// 
			   const int depth_max// максимальная глубина
			   );

//////////////////////////////////////////////////////////////////////////////////////////
private:

//---------------------------------------------------------------------------
// поиск за белых
int White(struct T_Bitboard * const p_bitboard,// представление доски
		  int alpha,//
		  const int beta,//
		  const int depth_max,// максимальная глубина
		  const int depth,// глубина
		  const int description_move,// тип хода который привел к данной позиции
		  const bool flag_pv_f,// основной ли это вариант (pv)
		  bool flag_check,//флаг шаха
		  const bool flag_null_m// флаг нулевого хода
		  );

//---------------------------------------------------------------------------
// поиск за черных 
int Black(struct T_Bitboard * const p_bitboard,// представление доски
		  const int alpha,//
		  int beta,//
		  const int depth_max,// максимальная глубина
		  const int depth,// глубина
		  const int description_move,// тип хода который привел к данной позиции
		  const bool flag_pv_f,// основной ли это вариант (pv)
		  bool flag_check,//флаг шаха
		  const bool flag_null_m// флаг нулевого хода
		  );

//---------------------------------------------------------------------------
// производим расчеты на максимальной глубине. для белых
inline int Max_depth_white(struct T_Bitboard * const p_bitboard,// представление доски
						   const int alpha,//
						   const int beta,//
		                   const bool flag_pv_f,// основной ли это вариант (pv)
						   const int depth// глубина
						   );

//---------------------------------------------------------------------------
// производим расчеты на максимальной глубине. для черных
inline int Max_depth_black(struct T_Bitboard * const p_bitboard,// представление доски
						   const int alpha,//
						   const int beta,//
		                   const bool flag_pv_f,// основной ли это вариант (pv)
						   const int depth// глубина
						   );

//---------------------------------------------------------------------------
// продление на шахах. для белых
inline void Extension_for_chek_white(const struct T_Bitboard * const p_bitboard,// представление доски
									 const int depth_max,// максимальная глубина
									 int & depth_max_new,// новая максимальная глубина
									 bool & flag_check// флаг шаха
									 );

//---------------------------------------------------------------------------
// продление на шахах. для черных
inline void Extension_for_chek_black(const struct T_Bitboard * const p_bitboard,// представление доски
									 const int depth_max,// максимальная глубина
									 int & depth_max_new,// новая максимальная глубина
									 bool & flag_check// флаг шаха
									 );

//---------------------------------------------------------------------------
// реализуем продление на взятиях
inline void Extension_for_captures(const int description_move,// тип хода
								   const int description_move_up,// тип хода на предыдущей глубине
								   const int depth_max,// максимальная глубина
								   int & depth_max_new// новая максимальная глубина
								   );

//---------------------------------------------------------------------------
// полная сортировка
inline void Sorting_moves(struct T_list_surplus_moves * const p_list_surplus_moves// список ходов
						  );

//---------------------------------------------------------------------------
// полная сортировка корневого списка
inline void Sorting_white_moves_root(struct T_list_surplus_moves * const p_list_surplus_moves// список ходов
						  );

//---------------------------------------------------------------------------
// полная сортировка корневого списка
inline void Sorting_black_moves_root(struct T_list_surplus_moves * const p_list_surplus_moves// список ходов
						  );

//---------------------------------------------------------------------------
// использую для теста
void Print_name_from_coord(const struct T_Bitboard * const p_bitboard// представление доски
						   );

//---------------------------------------------------------------------------
// выводим вариант который обдумываем
void Print_currmove(const struct T_list_surplus_moves * const p_list_surplus_moves,//список ходов
				  const int nodes_0,// количество ходов на нулевой глубине
				  const int i,// номер хода по списку
				  const int Depth_Max// максимальная глубина
				  );

// выводим текущий вариант в оболочку
void Print_pv_line(const bool colour_move,// цвет печатающей стороны
				const struct T_list_surplus_moves * const p_list_surplus_moves,// список ходов
				const struct T_PV * const p_PV_best_point,// лучший вариант
				const __int64 print_nodes,// количество узлов
				const int i,// номер хода в списке
				const int Depth_Max,// максимальная глубина
				const int value// оценка позиции
				//,const double time_nodes// время расчета варианта
				);

//---------------------------------------------------------------------------
// использую для теста. 
inline void Save_test_bitboard(const struct T_Bitboard * const p_bitboard,// представление доски
                               struct T_Bitboard * p_test_bitboard// представление доски
						       );

//---------------------------------------------------------------------------
// использую для теста. сравниваем доски
inline void Compare_test_bitboard(const struct T_Bitboard * const p_bitboard,// представление доски
                                  struct T_Bitboard * p_test_bitboard// представление доски
						          );

//---------------------------------------------------------------------------
//TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
// печатаем список
// глубина перебора, список
#if TEST_L
void List_Print(int Depth,// текущая глубина
                struct T_list_surplus_moves * p_list_surplus_moves// список ходов
				);
#endif
//---------------------------------------------------------------------------

};//class FULLSEARCH
