/***************************************************************************
 *            gen.c
 *
 *  Fri Apr  1 09:19:46 2005
 *  Copyright  2005  DBW
 *  opraus@yahoo.com
 ****************************************************************************/

#include "gen.h"

/*
   SPECIAL versions of similar routines for genc [gen caps] to check for King capture
   add_proc
   add_capc
   add_kapc

   promosc ??
   */

int death;
static sMOVES *m;

static void add_proc(int f, int d, int p, int s){
	assert(m < &move_list[4095]);


	m->move.data.type = PRO;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;

	if(s > 2000) death = 1; 

#ifdef SEE
	if((mval[board[d]]) < (mval[BR]))
	{
		s = nsee(f, d);
		if(s < 0) s += (LOSERS-cval[BP]);
		else s += PROBASE;
	}
	else s += PROBASE;
#else
	s += PROBASE;
#endif
	m->score = s;


	++m;
}

static void add_capc(int f, int d, int p, int s){


	int ps = (pst[p][d] - pst[p][f]);
	assert(m < &move_list[4095]);


	m->move.data.type = CAP;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;

	if(s > 2000) death = 1; 

#ifdef SEE
	/*
	 * s begins at nval[victim]-cval[piece], which is always + largest victims first, least attackers form secondary sort order
	 * so, QxR is before PxN
	 */
	if((mval[board[d]]) < (mval[board[f]]))
	{
		s = nsee(f, d);
		if(s < 0) s += (LOSERS-cval[p]);
		else s += CAPBASE;
	}
	else s += CAPBASE;
#else
	s += CAPBASE;
#endif

	s += ps; 


	m->score = s;


	++m;
}

static void add_kapc(/*KAP*/ int f, int d, int p, int s){


	int ps = (pst[p][d] - pst[p][f]);
	assert(m < &move_list[4095]);

	m->move.data.type = KAP;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;

	if(s > 2000) death = 1; 

	s += CAPBASE;

	s += ps; 


	m->score = s;



	++m;
}

static void add_pro(/*PRO*/ int f, int d, int p, int s){
	assert(m < &move_list[4095]);


	m->move.data.type = PRO;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;

#ifdef SEE	
	s = nsee(f, d);

	if(s < 0) s += (LOSERS-cval[BN]);
	else s += PROBASE;
#else
	s += PROBASE;
#endif

	m->score = s;


	++m;
}

static void add_cap(/*CAP*/ int f, int d, int p, int s){


	int ps = (pst[p][d] - pst[p][f]);
	assert(m < &move_list[4095]);

	m->move.data.type = CAP;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;


#ifdef SEE
	if((mval[board[d]]) < (mval[board[f]]))
	{
		s = nsee(f, d);
		if(s < 0) s += (LOSERS-cval[p]);
		else s += CAPBASE;
	}
	else s += CAPBASE;
#else
	s += CAPBASE;
#endif

	s += ps; 


	m->score = s;


	++m;
}

static void add_enp(/*ENP*/ int f, int d, int p){
	assert(m < &move_list[4095]);


	m->move.data.type = ENP;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;
	m->score = CAPBASE + 100 + (pst[p][d] - pst[p][f]);


	++m;
}

static void add_kap(/*KAP*/ int f, int d, int p, int s){


	int ps = (pst[p][d] - pst[p][f]);
	assert(m < &move_list[4095]);

	m->move.data.type = KAP;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;


	s += CAPBASE;

	s += ps; 


	m->score = s;


	++m;
}


static void add_cak(/*CAK*/ int f, int d, int p){
	assert(m < &move_list[4095]);

	m->move.data.type = CAK;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;
	m->score = CASBASE; 



	++m;
}

static void add_caq(/*CAQ*/ int f, int d, int p){
	assert(m < &move_list[4095]);

	m->move.data.type = CAQ;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;
	m->score = CASBASE-1;



	++m;
}

static void add_kmv(/*KMV*/ int f, int d, int p, int s){


	assert(m < &move_list[4095]);
	assert(s >= -32 && s <= 32);

	assert((Ox88to64(f) << 6) + Ox88to64(d) < 64*64);
	assert((Ox88to64(f) << 6) + Ox88to64(d) >= 0);

	assert(history[stm][(Ox88to64(f) << 6) + Ox88to64(d)] < 5000000);


	m->move.data.type = KMV;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;
	m->score = 0 + hget(&m->move);// (p_curve[force[stm^1]])*(pst[p][d] - pst[p][f])/MF;


	++m;
}

static void add_pp2(/*PP2*/ int f, int d, int p){

	assert(m < &move_list[4095]);
	assert((Ox88to64(f) << 6) + Ox88to64(d) < 64*64);
	assert((Ox88to64(f) << 6) + Ox88to64(d) >= 0);
	assert(stm == 0 || stm == 1);
	assert(history[stm][(Ox88to64(f) << 6) + Ox88to64(d)] < 5000000);
	m->move.data.type = PP2;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;
	m->score = PAWNJUMP + hget(&m->move) + pst[p][d] - pst[p][f];	

	++m;
}

static void add_mov(/*NOM*/ int f, int d, int p, int s){


	assert(m < &move_list[4095]);
	assert(s >= -32 && s <= 32);

	assert((Ox88to64(f) << 6) + Ox88to64(d) < 64*64);
	assert((Ox88to64(f) << 6) + Ox88to64(d) >= 0);

	assert(history[stm][(Ox88to64(f) << 6) + Ox88to64(d)] < 5000000);

	m->move.data.type = NOM;
	m->move.data.from = f;
	m->move.data.dest = d;
	m->move.data.piece = p;
	m->score = s + hget(&m->move) + (pst[p][d] - pst[p][f])/1; 


	++m;
}

static void add_promos(int from, int to, int s){
	add_pro(from, to, BQ|stm, s); 
	add_pro(from, to, BR|stm, s-110);
	add_pro(from, to, BB|stm, s-115);
	add_pro(from, to, BN|stm, s-105);
}

static void genBP(int sq){
	int v;
	if(((v=board[sq+15]) & 7) && ((v&1)==1)){
		if(sq > A7-1)
			add_promos(sq, sq+15, nval[v]-cval[BP]);
		else
			add_cap(sq, sq+15, BP, nval[v]-cval[BP]);
	}
	if(((v=board[sq+17]) & 7) && ((v&1)==1)){ 
		if(sq > A7-1)
			add_promos(sq, sq+17, nval[v]-cval[BP]);
		else
			add_cap(sq, sq+17, BP, nval[v]-cval[BP]);
	}
	if(epsquare){
		if((sq+15) == epsquare || (sq+17) == epsquare)
			add_enp(sq, epsquare, BP);
	}
	if(board[sq+16] == MT){
		if(sq > A7-1)
			add_promos(sq, sq+16, 0);
		else{
			if(sq < H2+1){
				if(board[sq+32] == MT)
					add_pp2(sq, sq+32, BP);
			}
			add_mov(sq, sq+16, BP, PAWNPUSH); 
		}
	}
}

static void genWP(int sq){
	int v;
	if(((v=board[sq-15]) & 7) && ((v&1)==0)){ 
		if(sq < H2+1)
			add_promos(sq, sq-15, nval[v]-cval[BP]);
		else
			add_cap(sq, sq-15, WP, nval[v]-cval[BP]);
	}
	if(((v=board[sq-17]) & 7) && ((v&1)==0)){ 
		if(sq < H2+1)
			add_promos(sq, sq-17, nval[v]-cval[BP]);
		else
			add_cap(sq, sq-17, WP, nval[v]-cval[BP]);
	}
	if(epsquare){
		if((sq-15) == epsquare || (sq-17) == epsquare)
			add_enp(sq, epsquare, WP);
	}
	if(board[sq-16] == MT){
		if(sq < H2+1)
			add_promos(sq, sq-16, 0);
		else{
			if(sq > A7-1){
				if(board[sq-32] == MT)
					add_pp2(sq, sq-32, WP);
			}
			add_mov(sq, sq-16, WP, PAWNPUSH); 
		}
	}
}

static void genN(int sq){
	int i, v, d;
	for(i = 0; i < 8; ++i){
		if((v = board[(d = sq + dlta[i])])){
			if(v == OB || (v&1) == stm) continue; 
			add_cap(sq, d, BN|stm, nval[v]-cval[BN]);
		}
		else add_mov(sq, d, BN|stm, KNIGHTHOP);
	}
}

static void genB(int sq){
	int i, v, d, t;
	for(i = 8; i < 12; ++i){
		d = dlta[i];
		t = sq;
		while((v=board[(t += d)]) == MT)
			add_mov(sq, t, BB|stm, 0);      
		if(v == OB || (v&1) == stm) continue;  
		add_cap(sq, t, BB|stm, nval[v]-cval[BB]);
	}
}

static void genR(int sq){
	int i, v, d, t;
	for(i = 12; i < 16; ++i){
		d = dlta[i];
		t = sq;
		while((v=board[(t += d)]) == MT)
			add_mov(sq, t, BR|stm, 0);     
		if(v == OB || (v&1) == stm) continue;   
		add_cap(sq, t, BR|stm, nval[v]-cval[BR]);
	}
}

static void genQ(int sq){
	int i, v, d, t;
	for(i = 8; i < 16; ++i){
		d = dlta[i];
		t = sq;
		while((v=board[(t += d)]) == MT)
			add_mov(sq, t, BQ|stm, 0);     
		if(v == OB || (v&1) == stm) continue;   
		add_cap(sq, t, BQ|stm, nval[v]-cval[BQ]);
	}
}

static void genK(int sq){
	int i, v, d;
	for(i = 8; i < 16; ++i){
		if((v = board[(d = sq + dlta[i])])){
			if(v == OB || (v&1) == stm) continue;
			add_kap(sq, d, BK|stm, nval[v]-cval[BK]);
		}
		else add_kmv(sq, d, BK|stm, 0);
	}

	if(mhs->threat & IN_CHECK) return;
	if(castle){
		if(stm){	
			if(castle & 4){
				if(board[F8] == MT && board[G8] == MT)
					if(/* !attacked_by_black(E8) && */ !attacked_by_black(F8) && !attacked_by_black(G8))
						add_cak(E8, G8, WK);
			}
			if(castle & 8){	
				if(board[B8] == MT && board[C8] == MT && board[D8] == MT)
					if(!attacked_by_black(C8) && !attacked_by_black(D8) /* && !attacked_by_black(E8) */)
						add_caq(E8, C8, WK);
			}
		}
		else{		
			if(castle & 1){
				if(board[F1] == MT && board[G1] == MT)
					if( /* !attacked_by_white(E1) && */ !attacked_by_white(F1) && !attacked_by_white(G1))
						add_cak(E1, G1, BK);
			}
			if(castle & 2){	
				if(board[B1] == MT && board[C1] == MT && board[D1] == MT)
					if(!attacked_by_white(C1) && !attacked_by_white(D1) /* && !attacked_by_white(E1) */)
						add_caq(E1, C1, BK);
			}
		}
	}
}


int move_is_legal(uMOVE * mv)
{

	int f = mv->data.from;
	int d = mv->data.dest;
	int p = mv->data.piece;
	int t = mv->data.type;
	if(t == PRO) p = BP+stm;

	if(mv->asint == 0) return 0;

	if(board[f] != p) return 0;        

	if ((board[f]&1) != stm) return 0;

	m = &move_list[4064]; 

	switch(p)
	{
		case MT:
		case  1:
			return 0;
			break;
		case BP:
			genBP(f);
			break;
		case WP:
			genWP(f);
			break;
		case BN:

		case WN:
			genN(f);
			break;
		case BK:

		case WK:
			genK(f);
			break;
		case OB:


			return 0;
			break;
		case 9:
			return 0;
			break;
		case BB:

		case WB:
			genB(f);
			break;
		case BR:

		case WR:
			genR(f);
			break;
		case BQ:

		case WQ:
			genQ(f);
			break;
		default:
			printf("error in gen(): %d @ %d", board[f], f);
	}

	--m;
	while(m >= &move_list[4064])

	{
		if(m->move.data.dest == d && m->move.data.type == t)
		{
			/* no need. checked later
			   domove(&m->move);
			   if(inCheck(stm^1))
			   {
			   unmove();
			   return 0;
			   }
			   unmove();              */              
			return 1;
		}
		--m;
	}

	return 0;
}

void gen()
{
	int i, sq;
	m = last_move[ply-1];
	if(stm)
	{    
		for(i=0; i<16; ++i)
		{
			sq = pieces[stm][i];
			if(sq == 0) continue;
			switch(board[sq])
			{
				case MT:
				case  1:
					break;
				case BP:
					break;
				case WP:
					genWP(sq);
					break;
				case BN:
					break;
				case WN:
					genN(sq);
					break;
				case BK:
					break;
				case WK:
					genK(sq);
					break;
				case OB:
					break;
				case 9:
					break;
				case BB:
					break;
				case WB:
					genB(sq);
					break;
				case BR:
					break;
				case WR:
					genR(sq);
					break;
				case BQ:
					break;
				case WQ:
					genQ(sq);
					break;
				default:
					printf("error in gen(): %d @ %d", board[sq], sq);
			}
		}
	}
	else
	{   
		for(i=0; i<16; ++i)
		{
			sq = pieces[stm][i];
			if(sq == 0) continue;
			switch(board[sq])
			{
				case MT:
				case  1:
					break;
				case BP:
					genBP(sq);
					break;
				case WP:
					break;
				case BN:
					genN(sq);
					break;
				case WN:
					break;
				case BK:
					genK(sq);
					break;
				case WK:
					break;
				case OB:
					break;
				case 9:
					break;
				case BB:
					genB(sq);
					break;
				case WB:
					break;
				case BR:
					genR(sq);
					break;
				case WR:
					break;
				case BQ:
					genQ(sq);
					break;
				case WQ:
					break;
				default:
					printf("error in gen()");
			}
		}
	}

	last_move[ply] = m;
}

static void gencBP(int sq){
	int v;
	if(((v=board[sq+15]) & 7) && ((v&1)==1)){ 
		if(sq > A7-1)
			add_proc(sq, sq+15, BQ, nval[v] - cval[BP]);
		else
			add_capc(sq, sq+15, BP, nval[v]-cval[BP]);
	}
	if(((v=board[sq+17]) & 7) && ((v&1)==1)){
		if(sq > A7-1)
			add_proc(sq, sq+17, BQ, nval[v] - cval[BP]);
		else
			add_capc(sq, sq+17, BP, nval[v]-cval[BP]);
	}
	if(epsquare){
		if((sq+15) == epsquare || (sq+17) == epsquare)
			add_enp(sq, epsquare, BP);
	}
	if(board[sq+16] == MT){
		if(sq > A7-1)
			add_proc(sq, sq+16, BQ, 0);
		/*
		   else{
		   if(sq > A6-1)
		   add_mov(sq, sq+16, BP, 0);	
		   }*/
	}
}

static void gencWP(int sq){
	int v;
	if(((v=board[sq-15]) & 7) && ((v&1)==0)){ 
		if(sq < H2+1)
			add_proc(sq, sq-15, WQ, nval[v] - cval[BP]);
		else
			add_capc(sq, sq-15, WP, nval[v]-cval[BP]);
	}
	if(((v=board[sq-17]) & 7) && ((v&1)==0)){ 
		if(sq < H2+1)
			add_proc(sq, sq-17, WQ, nval[v] - cval[BP]);
		else
			add_capc(sq, sq-17, WP, nval[v]-cval[BP]);
	}
	if(epsquare){
		if((sq-15) == epsquare || (sq-17) == epsquare)
			add_enp(sq, epsquare, WP);
	}
	if(board[sq-16] == MT){
		if(sq < H2+1)
			add_proc(sq, sq-16, WQ, 0);
		/*
		   else{
		   if(sq < H3+1)
		   add_mov(sq, sq-16, WP, 0);	
		   }*/
	}
}

static void gencN(int sq){
	int i, v, d;
	for(i = 0; i < 8; ++i){
		if((v = board[(d = sq + dlta[i])])){
			if(v == OB || (v&1) == stm) continue; 
			add_capc(sq, d, BN|stm, nval[v]-cval[BN]);
		}

	}
}

static void gencB(int sq){
	int i, v, d, t;
	for(i = 8; i < 12; ++i){
		d = dlta[i];
		t = sq;
		while((v=board[(t += d)]) == MT);

		if(v == OB || (v&1) == stm) continue;   
		add_capc(sq, t, BB|stm, nval[v]-cval[BB]);
	}
}

static void gencR(int sq){
	int i, v, d, t;
	for(i = 12; i < 16; ++i){
		d = dlta[i];
		t = sq;
		while((v=board[(t += d)]) == MT);

		if(v == OB || (v&1) == stm) continue;   
		add_capc(sq, t, BR|stm, nval[v]-cval[BR]);
	}
}

static void gencQ(int sq){
	int i, v, d, t;
	for(i = 8; i < 16; ++i){
		d = dlta[i];
		t = sq;
		while((v=board[(t += d)]) == MT);

		if(v == OB || (v&1) == stm) continue;   
		add_capc(sq, t, BQ|stm, nval[v]-cval[BQ]);
	}
}

static void gencK(int sq)
{
	int i, v, d;
	for(i = 8; i < 16; ++i)
	{
		if((v = board[(d = sq + dlta[i])])){
			if(v == OB || (v&1) == stm) continue;
			add_kapc(sq, d, BK|stm, nval[v]-cval[BK]);
		}

	}


	if(castle){
		if(stm){	
			if(castle & 4){	
				if(board[F8] == MT && board[G8] == MT)
					if(!attacked_by_black(E8) && !attacked_by_black(F8) && !attacked_by_black(G8))
						add_cak(E8, G8, WK);
			}
			if(castle & 8){	
				if(board[B8] == MT && board[C8] == MT && board[D8] == MT)
					if(!attacked_by_black(C8) && !attacked_by_black(D8) && !attacked_by_black(E8))
						add_caq(E8, C8, WK);
			}
		}
		else{		
			if(castle & 1){	
				if(board[F1] == MT && board[G1] == MT)
					if(!attacked_by_white(E1) && !attacked_by_white(F1) && !attacked_by_white(G1))
						add_cak(E1, G1, BK);
			}
			if(castle & 2){	
				if(board[B1] == MT && board[C1] == MT && board[D1] == MT)
					if(!attacked_by_white(C1) && !attacked_by_white(D1) && !attacked_by_white(E1))
						add_caq(E1, C1, BK);
			}
		}
	}

}



int genc(){
	int i, sq;
	death = 0; 
	m = last_move[ply-1];
	if(stm){    
		for(i=0; i<16; ++i) {
			sq = pieces[stm][i];
			if(sq == 0) continue;
			switch(board[sq]){
				case MT:
				case  1:
					break;
				case BP:
					break;
				case WP:
					gencWP(sq);
					break;
				case BN:
					break;
				case WN:
					gencN(sq);
					break;
				case BK:
					break;
				case WK:
					gencK(sq);
					break;
				case OB:
					break;
				case 9:
					break;
				case BB:
					break;
				case WB:
					gencB(sq);
					break;
				case BR:
					break;
				case WR:
					gencR(sq);
					break;
				case BQ:
					break;
				case WQ:
					gencQ(sq);
					break;
				default:
					printf("error in genc()");
			}
			if(death) break;
		}
	}
	else{   
		for(i=0; i<16; ++i) {
			sq = pieces[stm][i];
			if(sq == 0) continue;
			switch(board[sq]){
				case MT:
				case  1:
					break;
				case BP:
					gencBP(sq);
					break;
				case WP:
					break;
				case BN:
					gencN(sq);
					break;
				case WN:
					break;
				case BK:
					gencK(sq);
					break;
				case WK:
					break;
				case OB:
					break;
				case 9:
					break;
				case BB:
					gencB(sq);
					break;
				case WB:
					break;
				case BR:
					gencR(sq);
					break;
				case WR:
					break;
				case BQ:
					gencQ(sq);
					break;
				case WQ:
					break;
				default:
					printf("error in genc()");
			}
			if(death) break;
		}
	}

	last_move[ply] = m;
	return death;
}

