/*
 * executing and unexecuting generated moves
 */

#include "phalanx.h"


#undef DEBUG_MLIST
#ifdef DEBUG_MLIST
int checklist(tmove *m)
{
	int j;
	int err=0;
	int wp=0, bp=0;
	for( j=WKP; j!=0 && wp<18; j=L[j].next )
	{ wp++; if(color(B[j])!=WHITE) err=1; }
	for( j=A1; j!=H9; j++ ) if( color(B[j])==WHITE ) wp--;

	for( j=BKP; j!=0 && bp<18; j=L[j].next )
	{ bp++; if(color(B[j])!=BLACK) err=1; }
	for( j=A1; j!=H9; j++ ) if( color(B[j])==BLACK ) bp--;

	if( wp!=0 || bp!=0 || err )
	{
		int x=18;
		send_msg("");
		for( j=WKP; j!=0 && x!=0; j=L[j].next )
			{ x--; if(color(B[j])!=WHITE) send_msg("!"); send_msg("%i,",j); }
		send_msg("");
		x=18;
		for( j=BKP; j!=0 && x!=0; j=L[j].next )
			{ x--; if(color(B[j])!=BLACK) send_msg("!"); send_msg("%i,",j); }
		send_msg("");
		printboard(NULL);
		send_msg("wp=%i, bp=%i\n",wp,bp);
		for(j=0;j!=Counter;j++) printm(G[j].m,NULL);
		send_msg(""); if( m!=NULL) printm(*m,NULL);
		getchar();
		return 1;
	}
	return 0;
}
#endif



#define update_hash(p,s) { G[Counter].hashboard ^= H[ HP[p] ][ HS[s] ]; }



void do_move(register tmove * m)
{

G[Counter].m = *m;
Counter++;
G[Counter].castling = G[Counter-1].castling;
G[Counter].rule50 = G[Counter-1].rule50 + 1;
G[Counter].hashboard = HASH_COLOR ^ G[Counter-1].hashboard;
G[Counter].mtrl = G[Counter-1].xmtrl;
G[Counter].xmtrl = G[Counter-1].mtrl;
Ply++;

switch(m->special)
{
  case 0: /* most of the moves */

	update_hash( m->in1, m->from );
	update_hash( m->in2a, m->to );
	if( m->in2 != 0 ) /* capture */
	{
		update_hash( m->in2, m->to );
		G[Counter].mtrl -= Values[ m->in2 >> 4 ];
		G[Counter].rule50 = 0;

		/* remove captured piece from the list */
		L[ L[m->to].prev ].next = L[m->to].next;
		L[ L[m->to].next ].prev = L[m->to].prev;
	} else
	if( piece(m->in1) == PAWN ) G[Counter].rule50 = 0;

	/* update piece list */
	L[m->to] = L[m->from];
	L[ L[m->to].prev ].next = L[ L[m->to].next ].prev = m->to;

	if( m->in2a != m->in1 ) /* pawn promotion */
	G[Counter].xmtrl += Values[ m->in2a >> 4 ] - P_VALUE;

	B[m->from] = 0;
	B[m->to] = m->in2a;

{
	static unsigned char cb_[80] =
	{
		0, WLONG, 0, 0, 0, (WSHORT|WLONG), 0, 0, WSHORT, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, BLONG, 0, 0, 0, (BSHORT|BLONG), 0, 0, BSHORT, 0
	}; static unsigned char * cb = cb_-20;

	G[Counter].castling |= cb[m->from] | cb[m->to];
}

	break;

  case SHORT_CASTLING:
	if( Color == WHITE )
	{
		B[E1]=0; B[F1]=WR; B[G1]=WK; B[H1]=0;
		G[Counter].castling |= ( WSHORT | WLONG );
		update_hash( WK, E1 );
		update_hash( WK, G1 );
		update_hash( WR, H1 );
		update_hash( WR, F1 );
		L[G1] = L[E1]; WKP = L[L[G1].next].prev = G1;
		L[F1] = L[H1]; L[L[F1].prev].next = L[L[F1].next].prev = F1;
	}
	else
	{
		B[E8]=0; B[F8]=BR; B[G8]=BK; B[H8]=0;
		G[Counter].castling |= ( BSHORT | BLONG );
		update_hash( BK, E8 );
		update_hash( BK, G8 );
		update_hash( BR, H8 );
		update_hash( BR, F8 );
		L[G8] = L[E8]; BKP = L[L[G8].next].prev = G8;
		L[F8] = L[H8]; L[L[F8].prev].next = L[L[F8].next].prev = F8;
	}
	break;
  case LONG_CASTLING:
	if( Color == WHITE )
	{
		B[A1]=0; B[C1]=WK; B[D1]=WR; B[E1]=0;
		G[Counter].castling |= ( WSHORT | WLONG );
		update_hash( WK, E1 );
		update_hash( WK, C1 );
		update_hash( WR, A1 );
		update_hash( WR, D1 );
		L[C1] = L[E1]; WKP = L[L[C1].next].prev = C1;
		L[D1] = L[A1]; L[L[D1].prev].next = L[L[D1].next].prev = D1;
	}
	else
	{
		B[A8]=0; B[C8]=BK; B[D8]=BR; B[E8]=0;
		G[Counter].castling |= ( BSHORT | BLONG );
		update_hash( BK, E8 );
		update_hash( BK, C8 );
		update_hash( BR, A8 );
		update_hash( BR, D8 );
		L[C8] = L[E8]; BKP = L[L[C8].next].prev = C8;
		L[D8] = L[A8]; L[L[D8].prev].next = L[L[D8].next].prev = D8;
	}
	break;
  default: /* en passant pawn capture */

	update_hash( m->in1, m->from );
	update_hash( m->in2a, m->to );
	update_hash( B[m->special], m->special );

	B[m->from] = 0;
	B[m->to] = m->in2a;
	B[m->special] = 0; /* captured pawn */

	/* update piece list */
	L[m->to] = L[m->from];
	L[ L[m->to].prev ].next = L[ L[m->to].next ].prev = m->to;
	L[L[m->special].next].prev = L[m->special].prev;
	L[L[m->special].prev].next = L[m->special].next;

	G[Counter].mtrl -= P_VALUE;
	G[Counter].rule50 = 0; /* this is an irreversible move */
}

Color = enemy(Color);
Depth -= m->dch;

#ifdef DEBUG_MLIST
checklist(m);
#endif

}



void undo_move(register tmove * m)
{

Color = enemy(Color);
Depth += m->dch;
Ply--; Counter--;

switch(m->special)
{
  case 0: /* most of the moves */
	B[m->from] = m->in1;
	B[m->to] = m->in2;

	/* update piece list */
	L[m->from] = L[m->to];
	L[ L[m->from].prev ].next = L[ L[m->from].next ].prev = m->from;
	if( m->in2 != 0 ) /* return captured piece to the list */
	{
		if( color(m->in2) == WHITE )
		{
			L[m->to].next = L[WKP].next;
			L[m->to].prev = WKP;
			L[L[WKP].next].prev = m->to;
			L[WKP].next = m->to;
		}
		else
		{
			L[m->to].next = L[BKP].next;
			L[m->to].prev = BKP;
			L[L[BKP].next].prev = m->to;
			L[BKP].next = m->to;
		}
	}
  break;
  case SHORT_CASTLING:
	if( Color == WHITE )
	{
		B[E1]=WK; B[F1]=0; B[G1]=0; B[H1]=WR;
		L[E1] = L[G1]; WKP = L[L[E1].next].prev = E1;
		L[H1] = L[F1]; L[L[H1].prev].next = L[L[H1].next].prev = H1;
	}
	else
	{
		B[E8]=BK; B[F8]=0; B[G8]=0; B[H8]=BR;
		L[E8] = L[G8]; BKP = L[L[E8].next].prev = E8;
		L[H8] = L[F8]; L[L[H8].prev].next = L[L[H8].next].prev = H8;
	}
  break;
  case LONG_CASTLING:
	if( Color == WHITE )
	{
		B[A1]=WR; B[C1]=0; B[D1]=0; B[E1]=WK;
		L[E1] = L[C1]; WKP = L[L[E1].next].prev = E1;
		L[A1] = L[D1]; L[L[A1].prev].next = L[L[A1].next].prev = A1;
	}
	else
	{
		B[A8]=BR; B[C8]=0; B[D8]=0; B[E8]=BK;
		L[E8] = L[C8]; BKP = L[L[E8].next].prev = E8;
		L[A8] = L[D8]; L[L[A8].prev].next = L[L[A8].next].prev = A8;
	}
  break;
  default: /* en passant pawn capture */
	B[m->to] = 0;
	L[m->from] = L[m->to];
	L[ L[m->from].prev ].next = L[ L[m->from].next ].prev = m->from;
	if( Color ==  WHITE )
	{
		B[m->from] = WP;
		B[m->special] = BP; /* captured pawn */
		L[m->special].next = L[BKP].next;
		L[m->special].prev = BKP;
		L[L[BKP].next].prev = m->special;
		L[BKP].next = m->special;
	}
	else
	{
		B[m->from] = BP;
		B[m->special] = WP; /* captured pawn */
		L[m->special].next = L[WKP].next;
		L[m->special].prev = WKP;
		L[L[WKP].next].prev = m->special;
		L[WKP].next = m->special;
	}
}

#ifdef DEBUG_MLIST
checklist(m);
#endif

}



#ifdef ETTC
/**
***   Doing and undoing only hash keys. To be used for ETC
***   (enhanced transpostion cutoffs); see evaluate.c
**/

void do_hash(register tmove * m)
{

Counter++;
G[Counter].hashboard = HASH_COLOR ^ G[Counter-1].hashboard;

switch(m->special)
{
  case 0: /* most of the moves */

	update_hash( m->in1, m->from );
	update_hash( m->in2a, m->to );
	if( m->in2 != 0 ) /* capture */
		update_hash( m->in2, m->to );

	break;

  case SHORT_CASTLING:
	if( Color == WHITE )
	{
		update_hash( WK, E1 );
		update_hash( WK, G1 );
		update_hash( WR, H1 );
		update_hash( WR, F1 );
	}
	else
	{
		update_hash( BK, E8 );
		update_hash( BK, G8 );
		update_hash( BR, H8 );
		update_hash( BR, F8 );
	}
	break;
  case LONG_CASTLING:
	if( Color == WHITE )
	{
		update_hash( WK, E1 );
		update_hash( WK, C1 );
		update_hash( WR, A1 );
		update_hash( WR, D1 );
	}
	else
	{
		update_hash( BK, E8 );
		update_hash( BK, C8 );
		update_hash( BR, A8 );
		update_hash( BR, D8 );
	}
	break;
  default: /* en passant pawn capture */

	update_hash( m->in1, m->from );
	update_hash( m->in2a, m->to );
	update_hash( B[m->special], m->special );
}

Depth -= m->dch;

}



void undo_hash(register tmove * m)
{
Depth += m->dch;
Counter--;
}

#endif /* ETTC */

