#include "helper.h"
#include "gen.h"

UI64 _tick(){

#ifdef _WIN32 
	return 1000 * clock() / CLOCKS_PER_SEC;

#else
	struct timeb timebuffer;
	ftime(&timebuffer);
	return timebuffer.time * 1000 + timebuffer.millitm;
#endif
}

/* Bioskey checks for input waiting in stdin.
 * Credit here goes to Dr Oliver Brausch for the code from his
 * program Olithink. Some rewriting has been done by CMF, but not much
 * as I have absolutely no idea whatsoever what this does.
 * I think the original code is from Crafty by Prof. Robert Hyatt. */

#ifndef _WIN32 
/* Non-windows version */
int Bioskey(void) {
	fd_set readfds;
	struct timeval timeout;

	FD_ZERO(&readfds);
	FD_SET(fileno(stdin), &readfds);
	/* Set to timeout immediately */
	timeout.tv_sec = 0;
	timeout.tv_usec = 0;
	select(16, &readfds, 0, 0, &timeout);

	return (FD_ISSET(fileno(stdin), &readfds));
}

#else
/* Windows-version */
#include <windows.h>
#include <conio.h>
int Bioskey(void) {
	static int init = 0, pipe;
	static HANDLE inh;
	DWORD dw;
	/* If we're running under XBoard then we can't use _kbhit() as the input commands
	 * are sent to us directly over the internal pipe */

	if (!console) {
#if defined(FILE_CNT)
		if (stdin->_cnt > 0) return stdin->_cnt;
#endif
		if (!init) {
			init = 1;
			inh = GetStdHandle(STD_INPUT_HANDLE);
			pipe = !GetConsoleMode(inh, &dw);
			if (!pipe) {
				SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
				FlushConsoleInputBuffer(inh);
			}
		}
		if (pipe) {
			if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL)) return 1;
			return dw;
		}
		else {
			GetNumberOfConsoleInputEvents(inh, &dw);
			return dw <= 1 ? 0 : dw;
		}
	}
	else

		return _kbhit();
}
#endif

/*
   Current board position [and key] is stored upon execution of move.
   The 'Move History Stack' is incremented to point to the next available slot in the stack. 
   'fifty' is the number of reversible moves. Hence,

   mhs-fifty 

   is '1st' repeatable position [ie., we CAN get there from here]

   finding current key in stack twice constitutes a true 3rep
   finding current key in stack once in search tree == artificial/theoretical 3rep

   Current will be, but not yet, stored at mhs. 
   mhs-4 is most recent possible recurrence of current pos [mhs-1o mhs-2o mhs-3i mhs-4i]
   */

int rep(){

	sHISTDATA * h;
	sHISTDATA * f;
	f = mhs-fifty-1; 

	if(f < move_history-1) f = move_history-1;
	assert(f >= move_history-1); 
	for(h = mhs-4; h > f; h -= 2){ 
		if(h->key == key){

			return 1;
		}
	}
	return 0;
}
/*
   save pos at mhs -> do move -> ++mhs ++fifty

*/
int rep2(){

	sHISTDATA * h;
	sHISTDATA * f;
	f = mhs-fifty-1; 


	if(f < move_history-1) f = move_history-1;

	assert(f >= move_history-1); 

	for(h = mhs-4; h > f; h -= 2){ 

		if(h->key == key){
			/*
			   'root' position is at mhs-ply+1
			   so, > mhs-ply == root or search tree position
			   */





			return 1; 
		}
	}

	return 0;
}

/*
   mhs b4 fifty ply mhs-ply r move mhs aft

   10 6 8 2 1
   11 7 9 2 1 * 12
   12 8 10 2 1 out 13
   13 9 11 2 1 out 14
   14 10 12 2 1 in 15
   15 11 13 2 2 in 16 2nd position discovered w/ mhs poised to store
   16
   */

int rep3(){
	int r = 0;
	sHISTDATA * h;
	sHISTDATA * f;
	f = mhs-fifty-1; 



	if(f < move_history-1) f = move_history-1;
	assert(f >= move_history-1); 

	for(h = mhs-4; h > f; h -= 2){ 

		if(h->key == key){



			++r;
			if(r > 1)
			{


				return 1; 
			}
		}
	}

	return 0;
}

int tagpv(sMOVES *m, int targ, int score){

	for(; m < last_move[ply]; ++m){
		if(m->move.asint == targ){
			m->score = score; 

			return 1;
		}
	}
	return 0;
}

int next(sMOVES *m, int targ){
	sMOVES * i = m;
	sMOVES t;

	if(i->move.asint == targ){

		return 1;
	}
	++i;
	while(i < last_move[ply]){
		if(i->move.asint == targ){
			t = *m;
			*m = *i;
			*i = t;

			return 1;
		}
		++i;
	};
	/*
	   while(i >= m){
	   if(i->move.asint == targ){
	   t = *m;
	 *m = *i;
	 *i = t;
	 m->score = 9000000; 
	 return 1;
	 }
	 --i;
	 };
	 */
	return 0;
}



void sortmvs(sMOVES * fm){
	sMOVES *m = fm+1;
	sMOVES *bm = fm;
	sMOVES *lm = last_move[ply];
	sMOVES t;

	while(m < lm){
		if(m->score > bm->score) bm = m;
		++m;
	}

	/*
	if(bm != fm){
		t = *bm;
		while(--bm >= fm) *(bm+1) = *bm;
		*fm = t;
	}
	//*/

	//*
	 if(bm != fm){
		t = *fm;
		*fm = *bm;
		*bm = t;
	}
	 //*/



}


/*
   int seescore(uMOVE * m)
   {
   int s;
   s = see(m);
   return CAPBASE - (s<0) * (CAPBASE-LOSERS) + s;
   }
   */ 

void sorthmvs(sMOVES * fm){
	sMOVES *m = fm+1;
	sMOVES *bm = fm;
	sMOVES *lm = last_move[ply];
	sMOVES t;
	int s, bs = fm->score;

	//bs += (fm->move.data.type > CAQ) * hget(&fm->move);

	while(m < lm)
	{
		s = m->score;

		//s += (m->move.data.type > CAQ) * hget(&m->move);

		if(s > bs)
		{
			bm = m;
			bs = s;
		}
		++m;
	}

	if(bm != fm){
		t = *fm;
		*fm = *bm;
		*bm = t;
		/*
		 t = *bm;
		m = bm;
		while (m > fm) {
			*m = *(m-1);
			--m;
		}
		*fm = t;
		 //*/
	}


	assert(bm->score <= 11000000); 
}



sMOVES * find_move(int l, int sm){
	sMOVES * i;


	for(i = last_move[l-1]; i < last_move[l]; ++i){
		if(i->move.asint == sm) return i; 




	}
	return 0;
}

int move_in_list(int m){
	sMOVES * i;
	for(i = last_move[ply-1]; i < last_move[ply]; ++i)
		if(i->move.asint == m) return 1;
	return 0;
}

void bubblemvs(){
	int f;
	sMOVES *i;
	sMOVES * l = last_move[ply] - 1;
	sMOVES t;
	do{
		f = 0;
		for(i = last_move[ply-1]; i < l; ++i){
			if(i->score < (i+1)->score){
				t = *(i+1);
				*(i+1) = *i;
				*i = t;
				f = 1;
			}
		}
		--l;
	}while(f);
}

int tally_exchanges(){
	sHISTDATA * g = mhs - ply + 1; 
	int s = 0, m = -1;

	while(g < mhs-1){ 
		m = -m;
		s += m * mval[g->victim];
		++g;
	}
	return s;
}
/*
   Moves NOT extended, but otherwise very 'tactical'/'volatile'

   Moves with higher potential to change SE

   Caps && promotions & otherwise extended moves already excepted

   Some moves 'neutralize' opponent, while others have winning potential

   1. Material
   attack defender(removal), pinned, undefended, or larger piece <--- NOT doing these
   forks, skewers
   2. King safety
   Are we attacking king?
   3. Passed pawns
   To 7th
   To 6th in ending?
   King or piece move in ending?
   4. Any pawn move

 *note: captures are excepted. [NOT reduced]
 **note: move has been executed on internal board so, stm = snm

*/

int danger_move(const uMOVE * m){

	int pt = m->data.piece;
	int dest = m->data.dest;

	int phase = (force[stm^1] > 15) - (force[stm] < 5);
	int f = dest&7;

	int kf = kingsq[stm]&7;




	if(pt >= BQ) return 1;

	if(phase > 0)
	{
		/*if((pt&14) == BQ)
		  {
		  if(distance[128 + m->data.dest - kingsq[stm]] < 3) return 1;
		  }

		  else */
		{
			if(distance[128 + m->data.dest - kingsq[stm]] < 2) return 1;
			if(pt == BP)
			{

				if(abs(f-kf)<3) return 1; 
				if(IS_WHITE(board[dest+15]) && board[dest+15] != WP) return 1; 
				if(IS_WHITE(board[dest+17]) && board[dest+17] != WP) return 1; 

			}
			else if(pt == WP)
			{
				if(m->data.type > CAQ) return 1; 
				if(abs(f-kf)<3) return 1; 
				if(IS_BLACK(board[dest-15]) && board[dest-15] != BP) return 1; 
				if(IS_BLACK(board[dest-17]) && board[dest-17] != BP) return 1; 

			}
		}

	}






	return 0;
}

int passer_move(uMOVE *m)
{
	int pt = m->data.piece & 14;

	if(pt == BP)
	{ 
		if(rank7[m->data.dest]) 
			return 1;

		
		   if(/*force[stm] < 15 &&*/ rank67[stm^1][m->data.dest] 
		   && board[m->data.dest-16+32*stm] != BP+stm
		   && board[m->data.dest-15+32*stm] != BP+stm
		   && board[m->data.dest-17+32*stm] != BP+stm
		   ) return 1;
		   
	}
	return 0;
}

int big_potential_caps(uMOVE *m) {
	if((mhs-1)->victim > WR) return 1; 
	if(m->data.type == PRO) return 1; 
	if((mhs-1)->victim > WP && types[WP-stm] && force[stm]==0) return 1;

	if((mhs-1)->victim == (BP|stm) && RANK(m->data.dest) == (6 - 5 * stm))
		return 1; 
	if(m->data.piece > WR && distance[128 + m->data.dest - kingsq[stm]] < 2)
		return 1; 
	if((m->data.piece & 14) == BK) return 1;
	if(passer_move(m)) return 1;
	return 0;
}

int big_potential_move(uMOVE *m) {
	if(m->data.piece > WR && distance[128 + m->data.dest - kingsq[stm]] < 2)
		return 1; 
	if((m->data.piece & 14) == BK) return 1; 
	if(passer_move(m)) return 1;
	return 0;
}



int val_move(uMOVE *m)
{
	int r;
	r = mval[board[m->data.dest]] 
		+ (m->data.type == ENP) * 100
		+ (m->data.type == PRO) * (mval[m->data.piece]-100);

	return r;
}

int passer_on_7th(int c) {
	int i;
	if(c) {
		for(i = A2; i <= H2; ++i)
			if(board[i] == WP) return 1;
		return 0;
	}
	else {
		for(i = A7; i <= H7; ++i)
			if(board[i] == BP) return 1;
		return 0;
	}
}
/*
 * Calc highest possible gain by 2 moves. first is quiet. 2nd is 
 * capture of nme piece or
 * Assumes capture loses pawn
 * Include promotion to Queen and capture of passers on 7th
 * Include two pawn moves [pawn to fifth then sixth rank]
 * cap of 500
 */
int opti_cap(int c) {
	int t = c^1;
	if(types[BQ|t]) return 875; //  captures queen
	if(types[BP|c] && passer_on_7th(c)) return 875; // promote to Q
	if(types[BR|t]) return 400; // captures rook
	if(types[BP|t]) {
	       if(passer_on_7th(t)) return 300;
	       return 200;
	}
	//return 200;
	if(types[BB|t] || types[BN|t]) return 200; // captures minor
	if(types[BP|c]) return 200;
	if(force[c] > 3) return 200;
	return 50; // basically two very quiet moves
}

