#include "a_structure.h"

//-----------------------------------------------------------------------------------
/*
 * реализуем хеш-таблицу
 *
 * АВТОР ChessTerminator75
 * ПОСЛЕДНЕЕ ИЗМЕНЕНИЕ  9.03.2009 20.12.2009
 *
*/
//---------------------------------------------------------------------------

#define TEST_H 0 // включаем-выключаем(1-0) режим вывода в файл тестовой информации

#define U64(u) (u##ui64)

/*******************************************
класс HASHM

работаем с хеш-таблицей и памятью под нее

********************************************/
class HASHM{

// максимальное количество элементов в хеш-таблице
unsigned __int64 max_index_hash;

// указатель на хеш-таблицу(это еще Си стиль)
struct T_hash_moves * p_hash_moves;

// в начале нам нужно заполнить вспомогательный массив случайных чисел 
// связанных с расположением фигуры на доске в нем все фигуры на всех полях
// это трехмерный массив координаты которого цвет, имя, координата фигуры
// массив этот глобальный и содержит случайные числа
// в дальнейшем складывая эти числа мы получим случайный ключ тем не менее
// однозначно связанный с данной позицией
// [цвет фигуры][имя фигуры][координата фигуры]
// 2*6*64= 768 
unsigned __int64 random_piese_key[2][7][64];

// массив для запоминания хеш-ключей позиций при погружении на глубину
// т.е. у нас записываются не только ходы в pv_current но и ключи позиций
// другими словами запоминаем ветку ключей позиций
unsigned __int64 hash_three_moves[120];

// массив для запоминания хеш-ключей позиций
// при анализе входящей строки от оболочки
// другими словами запоминаем ветку ключей позиций
unsigned __int64 hash_string_moves[1000];

int save_cnt_move; // запоминаем количество ходов в строке

int age; // возраст элемента таблицы. нужен что бы перезаписывать элементы от прошлых позиций

//TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
#if TEST_H
 int hash_save;
#endif 
//TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

//////////////////////////////////////////////////////////////////////////////////////////
public:

// РАБОТА С ХЕШ - ТАБЛИЦЕЙ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// смотрим не встречалась ли нам такая позиция если встречалась то применяем сохраненную оценку
// функцию используем для отсечки по оценке
int Look_hash_score_white(
			   const unsigned __int64 key,// хеш - ключ
			   const int depth,// глубина
               const int depth_max,// максимальная глубина
			   const int alpha,//
		       const int beta,//
               int & hash_alpha,//
		       int & hash_beta,//
               int & test_flag_hash_moves,// флаг хода (1- улучшили альфу(бету); 3-просто локальный максимум(минимум); 2-отсечка по бете(альфе))
               int & hash_depth,// максимальная глубина
               int & hash_depth_max// максимальная глубина
			   );

//---------------------------------------------------------------------------
// смотрим не встречалась ли нам такая позиция если встречалась то применяем сохраненную оценку
// функцию используем для отсечки по оценке
int Look_hash_score_black(
			   unsigned __int64 key,// хеш - ключ
			   const int depth,// глубина
               const int depth_max,// максимальная глубина
			   const int alpha,//
		       const int beta,//
               int & hash_alpha,//
		       int & hash_beta,//
               int & test_flag_hash_moves,// флаг хода (1- улучшили альфу(бету); 3-просто локальный максимум(минимум); 2-отсечка по бете(альфе))
               int & hash_depth,// максимальная глубина
               int & hash_depth_max// максимальная глубина
			   );

//---------------------------------------------------------------------------
// смотрим не встречалась ли нам такая позиция если встречалась то ее ход смотрим первым
void Look_hash_move(struct T_list_surplus_moves * p_list_surplus_moves,// список ходов
			   const unsigned __int64 key,// хеш - ключ
			   const int depth,// глубина
			   int  & flag_insert_hash_move//флаг того что удалось найти хеш-ход и поднять на первую позицию
			   );

//---------------------------------------------------------------------------
// кэшируем лучший на данный момент ход
// если ход более изучен и глубина варианта больше тогда перезаписываем
void Save_best_hash_key(int i,// номер хода по списку
						unsigned __int64 key,// хеш-ключ
						struct T_list_surplus_moves * p_list_surplus_moves,// список ходов
						int score_move,// оценка хода
						int flag_hash_moves,// флаг хода (1- улучшили альфу(бету); 3-просто локальный максимум(минимум); 2-отсечка по альфе(бете))
						int depth,// глубина записи хода
						int depth_max,// максимальная глубина расчета
					    int alpha,//
		                int beta//
						);

//---------------------------------------------------------------------------
// освобождаем память из под хеш-таблицы
void Hash_size_free();

//---------------------------------------------------------------------------
// выделяем память под хеш-таблицу. размер задается в мегабайтах
void Hash_size_ini_default(int hash_size// размер хеш-таблицы в мегабайтах
						   );

//---------------------------------------------------------------------------
// инициализируем все ключи в хеш-таблице 0
void Ini_hash_moves();

//---------------------------------------------------------------------------
// освобождаем память из под хеш-таблицы и по новой выделяем память под хеш-таблицу. размер задается в мегабайтах
void Hash_size_resize(int hash_size// размер хеш-таблицы в мегабайтах
				   );

//---------------------------------------------------------------------------
// тестируем хеш-таблицу. печатаем полное количество элементов сколько использовали а сколько пустых
void TEST_Hash_index();

//---------------------------------------------------------------------------
// обнуляем возраст позиции
void Set_age_0();

//---------------------------------------------------------------------------
// следующий век :)
// увеличиваем возраст позиции
void Aging();



// РАБОТА С ХЕШ - КЛЮЧОМ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// меняем ключ во время хода
void Modification_random_key(bool  colour_figure,// цвет ходящей стороны
							 int i,// номер хода по списку
							 struct T_list_surplus_moves * p_list_surplus_moves,// список ходов
							 struct T_Bitboard * p_bitboard,// представление доски
                             struct T_undo undo[]//информация для отката хода
							 );

//---------------------------------------------------------------------------
// инициализируем ключ начальной позиции
void Start_position_random_key(struct T_Bitboard * p_bitboard// представление доски
							   );

//---------------------------------------------------------------------------
// каждой возможной позиции каждой возможной фигуры 
// присваиваем случайное число
void Ini_random_piese_key();



// ПОВТОРЫ ПОЗИЦИЙ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// возвращаем количество ходов в строке игры переданной из оболочки
int get_save_cnt_move();

//---------------------------------------------------------------------------
// запоминаем хеш-ключ на текущей глубине
// нужно для детектора повторов в линии варианта
void Save_hash_three(unsigned __int64 key,// хеш-ключ
					 int depth // глубина
					 );

//---------------------------------------------------------------------------
// запоминаем хеш-ключ для текущего хода
// нужно для детектора повторов в линии партии переданной оболочкой
void Save_hash_string_moves(unsigned __int64 key,// хеш-ключ
					 int cnt_move // счетчик ходов
					 );

//---------------------------------------------------------------------------
// анализируем линию ключей полученную из строки партии. если видим совпадение то возвращаем 1 иначе 0
// конечно совпадение не должно быть трехкратным ведь тогда это уже ничья
bool Analysis_hash_string_moves(
                                int depth // глубина
						        );

//---------------------------------------------------------------------------
// инициализируем хеш-массив повторов возрастающими числами что бы исключить ложное срабатывание
void HASHM::Ini_hash_three();

//---------------------------------------------------------------------------
// инициализируем хеш-массив повторов возрастающими числами что бы исключить ложное срабатывание
void HASHM::Ini_hash_string_moves();


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

// РАБОТА С ХЕШ - ТАБЛИЦЕЙ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// кэшируем ход т.е. записываем ход в хеш-таблицу
void Save_hash_key(int i,// номер хода по списку
				   unsigned __int64 key,// хеш - ключ
				   struct T_list_surplus_moves * p_list_surplus_moves,// список ходов
				   int score_move,// оценка хода
				   int flag_hash_moves,// флаг хода (1- улучшили альфу(бету); 3-просто локальный максимум(минимум); 2-отсечка по бете(альфе))
				   int depth,// глубина записи хода
				   int depth_max,// максимальная глубина расчета
				   int alpha,//
		           int beta//
				   );

//---------------------------------------------------------------------------
// поднимаем хеш-ход на первую позицию в списке ходов насчитанных для данной позиции
void Insert_hash_moves(struct T_list_surplus_moves * p_list_surplus_moves,// список ходов
					   unsigned __int64 key,// хеш - ключ
					   int depth ,// глубина
					   int  & flag_insert_hash_move//флаг того что удалось найти хеш-ход и поднять на первую позицию
					   );

//---------------------------------------------------------------------------


// РАБОТА С ХЕШ - КЛЮЧОМ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// генерируем случайный 64 битный ключ
unsigned __int64 rand_64();


// ПОВТОРЫ ПОЗИЦИЙ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// устарела
void Print_hash_moves();

};//class HASHM



