/***************************************************************************
*            move.c
*
*  Fri Apr  1 14:14:30 2005
*  Copyright  2005  DBW
*  opraus@yahoo.com
****************************************************************************/
#include "move.h"

static const int cmask[192] = {
	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,0,0,

	13, 15, 15, 15, 12, 15, 15, 14,  0,0,0,0,0,0,0,0,
	15, 15, 15, 15, 15, 15, 15, 15,  0,0,0,0,0,0,0,0,
	15, 15, 15, 15, 15, 15, 15, 15,  0,0,0,0,0,0,0,0,
	15, 15, 15, 15, 15, 15, 15, 15,  0,0,0,0,0,0,0,0,
	15, 15, 15, 15, 15, 15, 15, 15,  0,0,0,0,0,0,0,0,
	15, 15, 15, 15, 15, 15, 15, 15,  0,0,0,0,0,0,0,0,
	15, 15, 15, 15, 15, 15, 15, 15,  0,0,0,0,0,0,0,0,
	7, 15, 15, 15,  3, 15, 15, 11,  0,0,0,0,0,0,0,0};


	/*
	void file_pc(int sq) {
		int i=0;
		while(pieces[stm][i]) ++i;
		pieces[stm][i] = sq;
		indx[sq] = i;
	}
	 */

	void npush(void){
		mhs->move.asint = 0;
		mhs->victim = 0;
		mhs->key = key;
		mhs->fifty = fifty;
		mhs->epsquare = epsquare;
		assert(mhs < move_history+512);
		++mhs;
	}

	void npop(void){
		assert(mhs > move_history);
		--mhs;
		victim = 0;
		key = mhs->key;
		fifty = mhs->fifty;
		epsquare = mhs->epsquare;
	}

	static void push(const uMOVE *m){
		mhs->move = *m;
		mhs->victim = victim;
		mhs->victii = victii;
		mhs->key = key;
		mhs->fifty = fifty;
		mhs->epsquare = epsquare;
		mhs->castle = castle;
		assert(mhs < move_history+512);
		++mhs;
	}

	static void pop(uMOVE *m){
		assert(mhs > move_history);
		--mhs;
		*m = mhs->move;
		victim = mhs->victim;
		victii = mhs->victii;
		key = mhs->key;
		fifty = mhs->fifty;
		epsquare = mhs->epsquare;
		castle = mhs->castle;
	}

	static void move(const uMOVE * m){
		assert(pieces[stm][indx[m->data.from]] == m->data.from);
		indx[m->data.dest] = indx[m->data.from]; /* board array of piece indices */
		pieces[stm][indx[m->data.dest]] = m->data.dest; /* piece list -> board indices */
		indx[m->data.from] = 32;                  
		board[m->data.dest] = m->data.piece;
		board[m->data.from] = MT;
	}

	static void zcap(const uMOVE * m){
		key ^= zobrist[m->data.piece][m->data.from];
		key ^= zobrist[victim][m->data.dest];
		key ^= zobrist[m->data.piece][m->data.dest];
	}

	static void zmove(const uMOVE * m){
		key ^= zobrist[m->data.piece][m->data.from];
		key ^= zobrist[m->data.piece][m->data.dest];
	}

	static void umove(const uMOVE * m){
		assert(pieces[stm][indx[m->data.dest]] == m->data.dest);
		indx[m->data.from] = indx[m->data.dest]; 
		pieces[stm][indx[m->data.from]] = m->data.from; 
		board[m->data.from] = m->data.piece;
		board[m->data.dest] = victim;
		indx[m->data.dest] = 32;       /* what about victii */           
	}

	static void ucrights(const uMOVE * m){
		castle &= (cmask[m->data.from] & cmask[m->data.dest]);
	}

	void domove(const uMOVE * m){

		int t;
		
		assert(!checkmove(m));
		
		/*
		
		*/
		
		assert(!checkboard());
		
		
				
		victim = board[m->data.dest];	
		if(victim) {
			victii = indx[m->data.dest];
			pieces[stm^1][victii] = 0;
		}
		else victii = 32;
		
		
		push(m);
		
		move(m);
		
		

		key ^= zobrist[9][A1|castle];
		key ^= zobrist[8][epsquare];

		switch(m->data.type){
		
		case CAP:
			force[stm^1] -= fval[victim];  
			--types[victim];               
			zcap(m);		
			ucrights(m);	
			epsquare = 0;
			fifty = 0;
			break;
		
		case KAP:
			force[stm^1] -= fval[victim];  
			--types[victim];               
			kingsq[stm] = m->data.dest;
			zcap(m);		
			ucrights(m);	
			epsquare = 0;
			fifty = 0;
			break;
		
		case PRO:
			force[stm^1] -= fval[victim];  
			--types[victim];               
			--types[BP+stm];               
			++types[m->data.piece];        
			force[stm] += fval[m->data.piece];  
			key ^= zobrist[victim][m->data.dest]; 
			key ^= zobrist[BP|stm][m->data.from];
			key ^= zobrist[m->data.piece][m->data.dest];
			ucrights(m);
			epsquare = 0;
			fifty = 0;
			break;
				
		case ENP:
			--types[WP-stm];               
			zmove(m);
			t = epsquare - 16 + (stm << 5);
			victim = board[t];
			victii = indx[t];
			(mhs-1)->victii = victii; 
			pieces[stm^1][victii] = 0;
			key ^= zobrist[victim][t];
			board[t] = MT;
			indx[t] = 32;
			epsquare = 0;
			fifty = 0;
			break;
				
		case CAK:
			zmove(m);
			epsquare = 0;
			fifty = 0;
			if(stm){	
				kingsq[stm] = G8;
				board[F8] = WR;
				board[H8] = MT;
				indx[F8] = indx[H8]; 
				pieces[stm][indx[F8]] = F8; 
				indx[H8] = 32;                  
				key ^= zobrist[WR][F8];
				key ^= zobrist[WR][H8];
				castle &= 3;
			}
			else{	
				kingsq[stm] = G1;
				board[F1] = BR;
				board[H1] = MT;
				indx[F1] = indx[H1]; 
				pieces[stm][indx[F1]] = F1; 
				indx[H1] = 32;                  
				key ^= zobrist[BR][F1];
				key ^= zobrist[BR][H1];
				castle &= 12;
			}
			break;
				
		case CAQ:
			zmove(m);
			epsquare = 0;
			fifty = 0;
			if(stm){	
				kingsq[stm] = C8;
				board[D8] = WR;
				board[A8] = MT;
				indx[D8] = indx[A8]; 
				pieces[stm][indx[D8]] = D8; 
				indx[A8] = 32;                  
				key ^= zobrist[WR][D8];
				key ^= zobrist[WR][A8];
				castle &= 3;
			}
			else{	
				kingsq[stm] = C1;
				board[D1] = BR;
				board[A1] = MT;
				indx[D1] = indx[A1]; 
				pieces[stm][indx[D1]] = D1; 
				indx[A1] = 32;                  
				key ^= zobrist[BR][D1];
				key ^= zobrist[BR][A1];
				castle &= 12;
			}
			break;
				
		case PP2:
			zmove(m);
			epsquare = 0;
			fifty = 0;
			if(stm){	
				if(board[m->data.dest-1] == BP || board[m->data.dest+1] == BP)
					epsquare = m->data.dest+16;
			}
			else{		
				if(board[m->data.dest-1] == WP || board[m->data.dest+1] == WP)
					epsquare = m->data.dest-16;
			}
			break;
				
		case NOM:
			
			zmove(m);
			ucrights(m);
			epsquare = 0;
			if((m->data.piece&14) == BP) fifty = 0;
			else ++fifty;
			break;
				
		case KMV:
			kingsq[stm] = m->data.dest;
			zmove(m);
			ucrights(m);
			epsquare = 0;
			++fifty;
			break;
				
		default:
			printf("\ndomove()-ing: ");
			printmv(m);
			printf("\n");
			fflush(stdout);
			break;
		}

		
		key ^= zobrist[9][A1|castle];
		key ^= zobrist[8][epsquare];

		
		key = ~key;
		stm ^= 1;

		++ply;

		/* printf("\n>>> %d <<<\n", checkboard()); */
		assert(!checkboard());
	}

	void unmove(void){
		
		uMOVE m;

		assert(!checkboard());

		stm ^= 1;
		--ply;

		pop(&m);	

		switch(m.data.type){
		case CAP:
			force[stm^1] += fval[victim];  
			++types[victim];               
			umove(&m);
			pieces[stm^1][victii] = m.data.dest;
			indx[m.data.dest] = victii;
			break;
				
		case KAP:
			kingsq[stm] = m.data.from;
			force[stm^1] += fval[victim];  
			++types[victim];               
			umove(&m);
			pieces[stm^1][victii] = m.data.dest;
			indx[m.data.dest] = victii;
			break;
				
		case PRO:
			force[stm^1] += fval[victim];  /* move down */
			force[stm] -= fval[m.data.piece];  
			++types[victim];                /* move down */
			++types[BP+stm];               
			--types[m.data.piece];        
			board[m.data.from] = BP|stm;
			board[m.data.dest] = victim;
			indx[m.data.from] = indx[m.data.dest];
			pieces[stm][indx[m.data.from]] = m.data.from;
			if(victim) {
				/* to in here */
				pieces[stm^1][victii] = m.data.dest;  
				indx[m.data.dest] = victii;
			}
			else indx[m.data.dest] = 32;
			break;
				
		case ENP:
			++types[WP-stm];               
			board[m.data.from] = BP|stm;
			board[m.data.dest] = MT;
			board[epsquare-16+(stm<<5)] = WP^stm;
			pieces[stm^1][victii] = epsquare-16+(stm<<5);
			indx[m.data.from] = indx[m.data.dest];
			pieces[stm][indx[m.data.from]] = m.data.from;
			indx[m.data.dest] = 32;
			indx[epsquare-16+(stm<<5)] = victii;
			break;
				
		case CAK:
			kingsq[stm] = m.data.from;
			umove(&m);
			if(stm){	
				board[F8] = MT;
				board[H8] = WR;
				indx[H8] = indx[F8]; 
				pieces[stm][indx[H8]] = H8; 
				indx[F8] = 32;                  
			}
			else{	
				board[F1] = MT;
				board[H1] = BR;
				indx[H1] = indx[F1]; 
				pieces[stm][indx[H1]] = H1; 
				indx[F1] = 32;                  
			}
			break;
				
		case CAQ:
			kingsq[stm] = m.data.from;
			umove(&m);
			if(stm){	
				board[D8] = MT;
				board[A8] = WR;
				indx[A8] = indx[D8]; 
				pieces[stm][indx[A8]] = A8; 
				indx[D8] = 32;                  
			}
			else{	
				board[D1] = MT;
				board[A1] = BR;
				indx[A1] = indx[D1]; 
				pieces[stm][indx[A1]] = A1; 
				indx[D1] = 32;                  
			}
			break;
				
		case PP2:
			umove(&m);
			break;
				
		case NOM:
			umove(&m);
			break;
				
		case KMV:
			kingsq[stm] = m.data.from;
			umove(&m);
			break;
				
		default:
			printf("\nunmove()-ing: ");
			printmv(&m);
			printf("\n");
			fflush(stdout);
			break;
		}

		
		assert(!checkboard());
	}
