bmove=0    // the moving player 0=white 16=black
inhand=0   // piece in hand (ie, during move)
going=0    // DEV: denotes auto play, or not. 
player=0   // human colour (0=white, 16=black)
moveno=0   // no of moves  
ep=0       //en passant state (points to square behind takable pawn, ie, where the taking pawn ends up.
Bt=1999    
Al=-Bt
ss=0       //used in display.js
s0=3;
mate=0;   //1 for stale-, 2 for check-
d=document;
lttrs="abcdefghijkl" // 4 more letters
pawns=[[],[]];
dirs=[14,-14];
BE=168; // we need a 12*14 field
//kp=[25,95]
boardheap=[]  // history of board state, for undo.
pieces=[]
board=[]  
moves=[0,0,[1,14],[29,27,16,12],[15,13],[13,26,15,30],[15,13],[1,14,15,13],[1,14,15,13],0]       //in order _,p,r,n,b,e,v,q,k
pv=[0,1,5,3,3,3,2,9,63,0] // value of piece, might need to be fine tuned, added e with 3 and v with 2
weight=[]           
for(z=0;z<10;z++){ 
    pv[z+16] = pv[z]<<=4;
    mz=moves[z]
    if(mz){ 
	s=mz.length 
	for(x=0;x<s;){
	    mz[s+x]=-mz[x++]
	}
    }
}
//alert(pv);
x='w000000000000w'
y='wwwwwwwwwwwwww'
bstring=y+y+"w234567865432ww111111111111w"+x+x+x+x+"whhhhhhhhhhhhwwijklmnomlkjiw"+y+y
wstring=x+x+x+"000001111000000000123321000000012355321000" // value of position, might need to be fine tuned
weights=[]
pw='000012346900';
b_pweights=[];
b_weights=[];    // central weighting for ordinary pieces.
for(y=0;y<12;y++){
    for(x=0;x<14;x++){
	z=(y*14)+x;
	b_pweights[z]=parseInt(pw.charAt(y));    //also need to add main weight set at start.
	b_weights[z]=parseInt(wstring.charAt((z<84)?z:167-z),35)&7; // for all the ordinary pieces
	board[z]=parseInt(bstring.charAt(z),35);
    }
}
board[BE]=0;

// **************some display stuff.

A=E=d.all;
if (!E)event=0; //else errors in onmouseover.
DOM=d.getElementsByTagName || null;
if (DOM||E){
  d.write("<img src=0.gif id=pih name=pih width=32 height=32>");
  A= (E||d.getElementsByTagName("img"));
  itch=A["pih"].style;
}

///////////////////////////treeclimb begins

var comp=new Function('a','b','return b[0]-a[0]'); //comparison function for treeclimb integer sort (descending)
/****treeclimber */
function treeclimber(count, bm, sc, s, e, alpha, beta, EP){
    var z=-1;
    sc=-sc;
    var nbm=16-bm;
    if (sc <-400)return [sc,s,e];      //if king taken, no deepening.
    var b=Al;     //best move starts at -infinity
    var S,E=board[e];
    board[e]=S=board[s];
    board[s]=0;
    if(S)pieces[nbm][pieces[nbm].length]=[S,e];

    //now some stuff to handle queening
    if(S&15==1 && board[e+dirs[bm>>4]]>31){
    	board[e]+=6-queener; //queener is choice for pawn queening
    }

    var movelist=parse(bm,EP,sc);
    var movecount=movelist.length;
    var mv;
    if (movecount) {
	if(count){	
	    //BRANCH NODES
	    var t;
	    var cmp=comp;
	    movelist.sort(cmp); //descending order
	    count--;
	    best=movelist[0];
	    var bs=best[1];
	    var be=best[2];
	    b=-treeclimber(count, nbm, best[0], bs, be, -beta, -alpha, best[3])[0];
	    for(z=1;z<movecount;z++){		
		if (b>alpha)alpha=b;  //b is best
		mv = movelist[z];	
		t= -treeclimber(count, nbm, mv[0], mv[1], mv[2], -alpha-1, -alpha, mv[3])[0];
		if ((t>alpha) && (t<beta)){
		    t= -treeclimber(count, nbm, mv[0],mv[1],mv[2],-beta,-t, mv[3])[0];
		}		
		if (t>b){
		    b=t;
		    bs=mv[1];
		    be=mv[2];
		    if(t>alpha)alpha=t;
		    if (b>beta){
			break;
		    }
		}
	    }
	}	
	else{
	    b=Al;
	    //LEAF NODES
	    while(--movecount &&  beta>b){
		if(movelist[movecount][0]>b){
		    b=movelist[movecount][0];
		}
	    }
	}
    }else{debug('no movelist')};
    board[s]=S;
    board[e]=E;
    pieces[nbm].length--;

    return [b,bs,be];
}


function safetywrapper(count,bm,s,e,ep){
    var E=board[e],S=board[e]=board[s];
    board[s]=0;
    prepare();
    bm=treeclimber(count,bm,0,BE,BE,Al,Bt,ep);
    board[s]=S;
    board[e]=E;
    return bm[0];
}


// ************************************* findmove();

function findmove(){
    level=d.fred.hep.selectedIndex+1;
    var t=treeclimber(level,bmove,0,BE,BE,Al,Bt,ep);
    return move(t[1],t[2],0);
}

// **************************************** move();
function move(s,e,queener){

    var E=board[e];
    var S=board[s];
    var a=S&15;
    var bmx=bmove>>4;
    var ch=0;

    //test if this move is legal
    var t=0;
    var z=0;
    if (bmove==player){
	prepare();
	var p=parse(bmove,ep,0);
	for (;z<p.length;z++){
	    t=t||(s==p[z][1]&&e==p[z][2]);
	}
	if (!t) {
	    going=0;
	    debug ('no such move!',p,'\ns e',s,e,'\n',S,E);
	    return 0;
	}
	// get best other player's move
	// if it's check, squawk
	t=safetywrapper(0,16-bmove,s,e,ep);
	if (t>400){
	    debug('in check',t);
	    return 0;
	}	
    }
    display2(s,e,E,ch);
    t=safetywrapper(0,bmove,s,e,ep);
    if (t>400){
	debug('check!',t);
	ch=1;
    }
    // and if it isn't check before opposition's best move, its stalemate.
    t=safetywrapper(1,16-bmove,s,e,ep);
    if(t<-400){	
	going=0;
	finish(ch);
	//	if(!ch)return 0; //dont do stale mate move.
    }
    if(E&15==8){finish(1)}

    //put board on heap.
    boardheap[moveno]=[board.toString(),ep];
    ep=0;
    var x=s%14;
    var gap=e-s;
    var dir=dirs[bmx];
    if(a==1){ // pawns
	if(board[e+dir]>31)board[s]+=6-queener;
	if(gap==2*dir && (board[e-1]&1||board[e+1]&1))ep=s+dir;
	if(!E&& gap%14)shift(e,e-dir);
    }
    shift(s,e);
    prepare();   // get stuff ready for next move
    moveno++;
    bmove=16-bmove;
    return 1;
}

function finish(ch){
    dfbv(ch?'checkmate!':'stalemate!');
    mate=ch++;
    going=0;    
}


////////////////////////////////////parse

function prepare(){
    var z=139,Q;
    //    alert('in prepare');
    s0=(moveno<32)?4-(moveno>>3):(moveno>64);
    pieces[0]=[];
    pieces[16]=[];
    kweights=[];
    pweights=[[],[]];

    for(;z>28;z--){
	a=board[z];
	if(a&15){
	    pieces[a&16][pieces[a&16].length]=[a,z]; 	    
	}
	weights[z]=b_weights[z]*s0;
	kweights[z]=(moveno>40)||(10-2*b_weights[z])*s0;// while moveno <= 40, weight to edge.
	Q=pweights[1][167-z]=pweights[0][z]=b_pweights[z];//centralising for first 8 moves, then forwards only.
	if (moveno<7 && z>56){
	    pweights[0][z]=pweights[1][167-z]=Q+(Math.random()*weights[z])|1;	    
	    weights[34]=weights[132]=19;//hold queens at home
	}
    }
    //    debug("moveno s0",moveno,s0);
}


function parse(bm,EP,tpn) {
    //	var bord=board

    
    var yx,tyx;    //start and end position
    var h;         //for pawn taking moves
    var E,a;       //E=piece at end place, a= piece moving
    var cx;     // loop for move direction
    var mv;     // list of move direction
    var k=-1;   // length of movelist (mvl)
    var bmx=bm>>4; //0 for white, 1 for black
    var nbm=bm^16;  //not bm (bm is the players colour)
    var nx=nbm>>4; //not bmx (ie 1 for white, 0 for black)
    var dir=dirs[bmx]; //dir= 14 for white, -14 for black
    var mvl=[];        // movelist (built up with found moves
    var m;             // current value in mv[cx]
    var wate;          // initial weighting of pieces position
    var pweight=pweights[bmx];//=pweights[bmx]
    var weight;       //=weight localised weight
    var z;//loop counter.
    var ak;              //flags piece moving is king.
    var mlen;            //mv length in inner loop
    var pbm=pieces[bm];  //list of pieces that can move

//      debug("pieces", bm, pieces[bm]);
    
    if (! pbm) alert('no pbm');
    var pbl=pbm.length;   //marginal time saving
    var B=board;          //local ref to board
    for (z=0;z<pbl;z++){
	yx=pbm[z][1];
	a=B[yx];
	if (pbm[z][0]==a){
	    a&=15;
	    if(a>1){    //non-pawns

		ak=a==8;
		weight=ak?kweights:weights //different weight tables for king/knight
		wate=tpn-weight[yx];
		mv=moves[a];
		if(a==3||ak||a==5){
		    for(cx=0;cx<8;){     //knights,kings,elephant
			tyx=yx+mv[cx++];    
			E=B[tyx];
			if(!E||(E&48)==nbm){ 
			mvl[++k]=[wate+pv[E]+weight[tyx],yx,tyx];
			}
		    }	    
		}
		else if(a==6){
		    for(cx=0;cx<4;){     //vezir
			tyx=yx+mv[cx++];
			E=B[tyx];
			if(!E||(E&48)==nbm){
			mvl[++k]=[wate+pv[E]+weight[tyx],yx,tyx];
			
			}
		    }	    
		}
		else{//rook, bishop, queen
		    mlen=mv.length;
		    for(cx=0;cx<mlen;){     //goeth thru list of moves
			E=0;
			m=mv[cx++];
			tyx=yx;
			while(!E){   //while on board && no piece
			    tyx+=m;
			    E=B[tyx];
			    if(!E||(E&48)==nbm){
				mvl[++k]=[wate+pv[E]+weight[tyx],yx,tyx];
			    }
			}
		    }
		}
	    }
	    else{    //pawns
		
		wate=tpn-pweight[yx];
		tyx=yx+dir;
		if(!B[tyx]){
		    mvl[++k]=[wate+pweight[tyx],yx,tyx];
		    if(! pweight[yx] && (!B[tyx+dir])){  //2 squares at start - start flagged by 0 pweights weighting
			mvl[++k]=[wate+pweight[tyx+dir],yx,tyx+dir,tyx];    //ep points to the takeable spot
		    }
		}
		if(EP&&(EP==tyx+1||EP==tyx-1)){
		    mvl[++k]=[wate+pweight[tyx],yx,EP];
		}		
		for(h=tyx-1;h<tyx+2;h+=2){                        //h=-1,1 --for pawn capturing
		    E=B[h]+bm; 
		    if(E&15&&E&16){
			mvl[++k]=[wate+pv[E]+pweight[h],yx,h];
		    }
		}
	    }
	}
    }

    
    return mvl;
}
//////////////////////display


// *************************************** macro-control

function B(it){ //it is clicked square
    var a=board[it],p='pih';
    if (mate)return;
    if (ss==it && inhand){   //ss is global, for starting place of moving piece.
	Bim(p,0);         //this bit replaces a piece if you click on the square it came from
	Bim(ss,inhand,1);
	inhand=0;
	return;
    }
    if (a&&(bmove==(a&16))){     //ie, if one picked up of right colour, it becomes start
        if (inhand) Bim(ss,inhand,1); //put back old piece, if any
	inhand=a;
        ss=it;
        Bim(ss,0,1);     //not real shift, but blank start
        Bim(p,a);     //dragging piece
        if(E)drag();      //puts in right place
        d.onmousemove=drag;  //link in hand image to mouse
    	return;
    }
    if (inhand){
	if(move(ss,it,d.fred.hob.selectedIndex,y)){
	    Bim(p,0); //blank moving
	    d.onmousemove=null;         //and switch off mousemove.
	    if(A) itch.top=itch.left='0px';
	    inhand=0;
	    B2();
	}
    }
}


//////////////////////////////to go:

//B1 is auto
Btime=0;
function B1(){
    if(!mate && findmove()){          //do other colour
	Btime=setTimeout("B2()",500)
    }
    else{ going=0}
}
function B2(){
	if (going || player!=bmove){
		clearTimeout(Btime);
		B1();
	}
}

// *******************************shift & display

function shift(s,e){
    var z=0,a=board[s];
    board[e]=a;
    board[s]=0;
    Bim(s,0,1);
    Bim(e,a,1);
}

function display2(s,e,b,c){
    var x=s%14,tx=e%14,mn=1+(moveno>>1);
    dfbv("\n"+(bmove?'     ':(mn<10?" ":"")+mn+".  ")+lttrs.charAt(x-1)+((s-x)/14-1)+(b?'x':'-')+lttrs.charAt(tx-1)+((e-tx)/14-1)+(c?'+':' '));
}

function dfbv(x){
    d.fred.bib.value+=x;
}


// *******************************************redraw screen from board

function refresh(bw){
    player=bw;
    for (var z=0;z<BE;z++){
	if(board[z]<32)Bim(z,board[z],1);
    }
    //    if (player!=bmove)B2();
}


function goback(){
    if (!moveno)return;
    moveno-=2;
    var b=boardheap[moveno];
    board=eval("["+b[0]+"]");
    dfbv('\n --undo--');
    ep=b[2];
    bmove=moveno%2;
    refresh(bmove);
    prepare();
}

// *********************************************drag piece
var px="px";
function drag(e) {
    e=e||event;
    itch.left=(e.clientX+1)+px;
    itch.top=(e.clientY-4)+px;
}

function Bim(img,src,swap){
    if (A || img!='pih'){
	if (swap){
	    img="i"+(player?167-img:img);
	}
	d.images[img].src=src+'.gif';
    }
}


// *********************************************final write,etc
    // can be merged with weighters;

html='<table cellpadding=4>'
for (y=126;y>14;y-=14){
	html+="<tr>"
    for(x=0;x<13;x++){
        z=y+x
        if(x&&x<14){
            html+=('<td class=' + ((x+(y/14))&1?'b':'w') + '><a href="#" onclick="B(player?167-'+z+':'+z+');return false"><img src=0.gif width=6 height=46 border=0><img src=0.gif width=42 height=46 name=i'+z+' border=0><img src=0.gif width=6 height=46 border></a></td>\n')
        }
    }
    html+='</tr>\n'
}
html+='</table>'


d.write(html);
refresh(0);
