#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "common.h"
#include "eval.h"

BitBoard passed[2];
BitBoard weaked[2];

static short PawnSq[2][64]={
{
0,0,0,0,0,0,0,0,
5,5,5,-10,-10,5,5,5,
-2,-2,-2,6,6,-2,-2,-2,
0,0,0,25,25,0,0,0,
2,2,12,16,16,12,2,2,
4,8,12,16,16,12,4,4,
4,8,12,16,16,12,4,4,
0,0,0,0,0,0,0,0},
{
0,0,0,0,0,0,0,0,
4,8,12,16,16,12,4,4,
4,8,12,16,16,12,4,4,
2,2,12,16,16,12,2,2,
0,0,0,25,25,0,0,0,
-2,-2,-2,6,6,-2,-2,-2,
5,5,5,-10,-10,5,5,5,
0,0,0,0,0,0,0,0}
};

static const short Passed[2][8] ={ { 0,48,48,96,144,192,240,0},{0,240,192,144,96,48,48,0} };

static const short isolani_normal[8]={-8,-10,-12,-14,-14,-12,-10,-8};
static const short isolani_weaker[8]={-22,-24,-26,-28,-28,-26,-24,-22 };

static const short rank7[2]={ 6,1 };
static const short rank8[2]={ 7,0 };
static const BitBoard d2e2[2]={ 0x0018000000000000ULL,0x0000000000001800ULL };
static const BitBoard brank7[2]={ 0x000000000000FF00ULL,0x00FF000000000000ULL };
static const BitBoard brank8[2] ={ 0x00000000000000FFULL,0xFF00000000000000ULL };
static const BitBoard brank67[2]={ 0x0000000000FFFF00ULL,0x00FFFF0000000000ULL };
static const BitBoard brank58[2]={ 0x00000000FFFFFFFFULL,0xFFFFFFFF00000000ULL };

int ScoreP(short side)
{
short s,sq,i,i1,xside;
short n1,n2,backward;
short nfile[8];
short EnemyKing;
BitBoard c,t,p,blocker,*e;
PawnSlot *ptable;
if(board.b[side][pawn]==NULLBITBOARD) return 0;
xside=1^side;
EnemyKing=board.king[xside];
p=board.b[xside][pawn];
t=board.b[side][pawn];
c=t;
ptable=PawnTab[side];
ptable+=PawnHashKey&PHashMask;
TotalPawnHashCnt++;
if(ptable->phase==phase&&ptable->pkey==KEY(PawnHashKey))
	{
	GoodPawnHashCnt++;
	s=ptable->score;
	passed[side]=ptable->passed;
	weaked[side]=ptable->weaked;
	goto phase2; 
	}
s=0;
passed[side]=NULLBITBOARD;
weaked[side]=NULLBITBOARD;
memset(nfile,0,sizeof(nfile));
while(t)
	{
	sq=leadz(t);
	CLEARBIT(t,sq);
	s+=PawnSq[side][sq]; 
	if((p&PassedPawnMask[side][sq])==NULLBITBOARD)
		{
		if((side==white&&(FromToRay[sq][sq|56]&c)==0)||(side==black&&(FromToRay[sq][sq&7]&c)==0))
			{
			passed[side]|=BitPosArray[sq];
			if(side==white) s+=(Passed[side][RANK(sq)]*phase)/12;
			else if(side==black) s+=(Passed[side][RANK(sq)]*phase)/12;
			}
		}
	backward=false;
	if(side==white) i=sq+8;
	else i=sq-8;
	if(!(PassedPawnMask[xside][i]&~FileBit[ROW(sq)]&c)&&cboard[i]!=pawn)
		{
		n1=nbits(c&MoveArray[ptype[xside]][i]);
		n2=nbits(p&MoveArray[ptype[side]][i]);
		if(n1<n2) backward=true;
		}
	if(!backward&&(BitPosArray[sq]&brank7[xside]))
		{
		i1=1;
		i+=(side==white?8:-8);
		if(!(PassedPawnMask[xside][i]&~FileBit[ROW(i1)]&c))
			{
			n1=nbits(c&MoveArray[ptype[xside]][i]);
			n2=nbits(p&MoveArray[ptype[side]][i]);
			if(n1<n2) backward=true;
			}
		}
	if(backward)
		{
		weaked[side]|=BitPosArray[sq];
		s+=BACKWARDPAWN;
		}
	if((MoveArray[ptype[side]][sq]&p)&&(MoveArray[ptype[side]][sq]&c)) s+=PAWNBASEATAK;
	nfile[ROW(sq)]++;
	}
for(i=0;i<=7;i++)
	{
	if(nfile[i]>1) s+=DOUBLEDPAWN;
	if(nfile[i]&&(!(c&IsolaniMask[i])))
		{
		if(!(FileBit[i]&board.b[xside][pawn])) s+=isolani_weaker[i]*nfile[i];
		else s+=isolani_normal[i]*nfile[i];
		weaked[side]|=(c&FileBit[i]);
		}
	}
if(computerplays==side)
	{
	if(nbits(board.b[computerplays][pawn])==8) s+=EIGHT_PAWNS;
	if(nbits(stonewall[xside]&board.b[xside][pawn])==3) s+=STONEWALL;
	n=0;
	if(side==white) n=nbits((c>>8)&board.b[xside][pawn]&(rings[0]|rings[1]|rings[2]));
	else n=nbits((c<<8)&board.b[xside][pawn]&(rings[0]|rings[1]|rings[2]));
	if(n>1) s+=n*LOCKEDPAWNS;
	}
ptable->pkey=KEY(PawnHashKey);
ptable->passed=passed[side];
ptable->weaked=weaked[side];
ptable->score=s;
ptable->phase=phase;

phase2:
c=board.b[side][pawn];
sq=board.king[xside];
if(side==white&&board.b[side][queen]&&(BitPosArray[C6]|BitPosArray[F6])&c)
	{
	if(c&BitPosArray[F6]&&sq>H6&&distance[sq][G7]==1) s+=PAWNNEARKING;
	if(c&BitPosArray[C6]&&sq>H6&&distance[sq][B7]==1) s+=PAWNNEARKING;
	}
else if(side==black&&board.b[side][queen]&&(BitPosArray[C3]|BitPosArray[F3])&c)
	{
	if(c&BitPosArray[F3]&&sq<A3&&distance[sq][G2]==1) s+=PAWNNEARKING;
	if(c&BitPosArray[C3]&&sq<A3&&distance[sq][B2]==1) s+=PAWNNEARKING;
	}
t=passed[side]&brank67[side];
if(t&&(board.pmaterial[xside]==ValueR||(board.pmaterial[xside]==ValueN&&pieces[xside]==board.b[xside][knight])))
	{
	n1=ROW(board.king[xside]);
	n2=RANK(board.king[xside]);
	for(i=0;i<=6;i++)
		{
		if(t&FileBit[i]&&t&FileBit[i+1]&&(n1<i-1||n1>i+1||(side==white&&n2<4)||(side==black&&n2>3))) s+=CONNECTEDPP;
		}
	}
blocker=board.friends[side]|board.friends[xside];
if(side==white&&(((c&d2e2[white])>>8)&blocker)) s+=BLOCKDEPAWN;
if(side==black&&(((c&d2e2[black])<<8)&blocker)) s+=BLOCKDEPAWN;
if(passed[side]&&board.pmaterial[xside]==0)
	{
	e=board.b[xside];
	i1=board.king[xside];
	p=passed[side];
	while(p)
		{
		sq=leadz(p);
		CLEARBIT(p,sq);
		if(board.side==side)
			{
			if(!(SquarePawnMask[side][sq]&board.b[xside][king])) s+=ValueQ*Passed[side][RANK(sq)]/PFACTOR;
			}
		else if(!(MoveArray[king][i1]&SquarePawnMask[side][sq])) s+=ValueQ*Passed[side][RANK(sq)]/PFACTOR;
		}
	}
c=board.b[side][pawn];
if(abs(ROW(board.king[side])-ROW(board.king[xside]))>=4&&PHASE<6)
	{
	n1=ROW(board.king[xside]);
	p=(IsolaniMask[n1]|FileBit[n1])&c;
	while(p)
		{
		sq=leadz(p);
		CLEARBIT(p,sq);
		s+=10*(5-distance[sq][board.king[xside]]);
		}
	}
return s;
}

static const short Outpost[2][64]=
{
{
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,1,1,1,1,0,0,
0,1,1,1,1,1,1,0,
0,0,1,1,1,1,0,0,
0,0,0,1,1,0,0,0,
0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,
0,0,0,1,1,0,0,0,
0,0,1,1,1,1,0,0,
0,1,1,1,1,1,1,0,
0,0,1,1,1,1,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 }
};


#ifdef __STORM__
__inline int CTL(short sq,short piece,short side)
#else
static inline int CTL(short sq,short piece,short side)
#endif
{
short s,n,EnemyKing,FriendlyKing;
BitBoard controlled;
s=0;
EnemyKing=board.king[1^side];
FriendlyKing=board.king[side];
controlled=AttackXFrom(sq,side);
n=nbits(controlled&(rings[0]|rings[1]));
s+=4*n;
n=nbits(controlled&DistMap[EnemyKing][2]);
s+=n;
n=nbits(controlled&DistMap[FriendlyKing][2]);
s+=n;
n=nbits(controlled);
s+=4*n;
return s;
}

int ScoreN(short side)
{
short s,s1,sq,xside;
short EnemyKing;
BitBoard c,t;
if(board.b[side][knight]==NULLBITBOARD) return 0;
xside=side^1;
s=s1=0;
c=board.b[side][knight];
t=board.b[xside][pawn]; 
EnemyKing=board.king[xside];
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	s1=CTL(sq,knight,side);
	if((BitPosArray[sq] &(FileBit[0]|FileBit[7]|RankBit[0]|RankBit[7]))!=NULLBITBOARD) s1+=KNIGHTONRIM;
	if(Outpost[side][sq]&&!(t&IsolaniMask[ROW(sq)]&PassedPawnMask[side][sq]))
		{
		s1+=OUTPOSTKNIGHT;
		if(MoveArray[ptype[xside]][sq]&board.b[side][pawn]) s1+=OUTPOSTKNIGHT;
		}
	if(MoveArray[knight][sq]&weaked[xside]) s1+=ATAKWEAKPAWN;
	pscore[sq]=s1;
	s+=s1;
	}
return s;
}

int ScoreB(short side)
{
short s,s1,xside,n,sq,EnemyKing;
BitBoard c,t;
if(board.b[side][bishop]==NULLBITBOARD) return 0;
s=s1=0;
c=board.b[side][bishop];
xside=side^1;
EnemyKing=board.king[xside];
n=0;
t=board.b[xside][pawn];
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	n++;
	s1=CTL(sq,bishop,side);
	if(Outpost[side][sq]&&!(t&IsolaniMask[ROW(sq)]&PassedPawnMask[side][sq]))
		{
		s1+=OUTPOSTBISHOP;
		if(MoveArray[ptype[xside]][sq]&board.b[side][pawn]) s1+=OUTPOSTBISHOP;
		}
	if(side==white)
		{
		if(board.king[side]>=F1&&board.king[side]<=H1&&sq==G2) s1+=FIANCHETTO;
		if(board.king[side]>=A1&&board.king[side]<=C1&&sq==B2) s1+=FIANCHETTO;
		}
	else if(side==black)
		{
		if(board.king[side]>=F8&&board.king[side]<=H8&&sq==G7) s1+=FIANCHETTO;
		if(board.king[side]>=A8&&board.king[side]<=C8&&sq==B7) s1+=FIANCHETTO;
		}
	if(BishopAttack(sq)&weaked[xside]) s1+=ATAKWEAKPAWN;
	pscore[sq]=s1;
	s+=s1;
	}
if(n>1) s+=DOUBLEDBISHOPS;
return s;
}

int BishopTrapped(short side)
{
int s=0;
if(side==white)
	{
	if((board.b[white][bishop]&BitPosArray[A7])&&(board.b[black][pawn]&BitPosArray[B6])&&SwapOff(MOVE(A7,B6))<0) s+=BISHOPTRAPPED;
	if((board.b[white][bishop]&BitPosArray[H7])&&(board.b[black][pawn]&BitPosArray[G6])&&SwapOff(MOVE(H7,G6))<0) s+=BISHOPTRAPPED;
	}
else
	{
	if((board.b[black][bishop]&BitPosArray[A2])&&(board.b[white][pawn]&BitPosArray[B3])&&SwapOff(MOVE(A2,B3))<0) s+=BISHOPTRAPPED;
	if((board.b[black][bishop]&BitPosArray[H2])&&(board.b[white][pawn]&BitPosArray[G3])&&SwapOff(MOVE(H2,G3))<0) s+=BISHOPTRAPPED;
	}
return s;
}

int ScoreR(short side)
{
short s,s1,sq,xside,fyle,EnemyKing;
BitBoard c;
if(board.b[side][rook]==NULLBITBOARD) return 0;
s=s1=0;
c=board.b[side][rook];
xside=side^1;
EnemyKing=board.king[xside];
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	s1=CTL(sq,rook,side);
	fyle=ROW(sq);
	if(PHASE<7)
		{
		if(!(board.b[side][pawn]&FileBit[fyle]))
			{
			if(fyle==5&&ROW(board.king[xside])>=E_FILE) s1+=ROOKLIBERATED;
			s1+=ROOKHALFFILE;
			if(!(board.b[xside][pawn]&FileBit[fyle])) s1+=ROOKOPENFILE;
			}
		}
	if(phase>6&&(FileBit[fyle]&passed[white]&brank58[white]))
		{
		if(nbits(Ray[sq][7]&passed[white])==1) s1+=ROOKBEHINDPP;
		else if(Ray[sq][4]&passed[white]) s1+=ROOKINFRONTPP;
		}
	if(FileBit[fyle]&passed[black]&brank58[black])
		{
		if(nbits(Ray[sq][4]&passed[black])==1) s1+=ROOKBEHINDPP;
		else if(Ray[sq][7]&passed[black]) s1+=ROOKINFRONTPP;
		}
	if(RookAttack(sq)&weaked[xside]) s1+=ATAKWEAKPAWN;
	if(RANK(sq)==rank7[side]&&(RANK(EnemyKing)==rank8[side]||board.b[xside][pawn]&RankBit[RANK(sq)])) s1+=ROOK7RANK;
	pscore[sq]=s1;
	s+=s1;
	}
return s;
}

int DoubleQR7(short side)
{
short xside;
xside=1^side;
if(nbits((board.b[side][queen]|board.b[side][rook])&brank7[side])>1&&((board.b[xside][king]&brank8[side])||(board.b[xside][pawn]&brank7[side]))) return ROOKS7RANK;
return 0;
}

int ScoreQ(short side)
{
short s,s1,sq,xside,EnemyKing;
BitBoard c;
if(board.b[side][queen]==NULLBITBOARD) return 0;
s=s1=0;
xside=1^side;
c=board.b[side][queen];
EnemyKing=board.king[xside];
if(side==computer) if(c==NULLBITBOARD) s+=QUEEN_NOT_PRESENT;
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	s1=CTL(sq,queen,side);
	if(distance[sq][EnemyKing]<=2) s1+=QUEENNEARKING;
	if(QueenAttack(sq)&weaked[xside]) s1+=ATAKWEAKPAWN;
	pscore[sq]=s1;
	s+=s1;
	}
return s;
}

static const short KingSq[64]=
{
24,24,24,16,16,0,32,32,
24,20,16,12,12,16,20,24,
16,12,8,4,4,8,12,16,
12,8,4,0,0,4,8,12,
12,8,4,0,0,4,8,12,
16,12,8,4,4,8,12,16,
24,20,16,12,12,16,20,24,
24,24,24,16,16,0,32,32
};

static const short EndingKing[64]=
{
0,6,12,18,18,12,6,0,
6,12,18,24,24,18,12,6,
12,18,24,32,32,24,18,12,
18,24,32,48,48,32,24,18,
18,24,32,48,48,32,24,18,
12,18,24,32,32,24,18,12,
6,12,18,24,24,18,12,6,
0,6,12,18,18,12,6,0
};

static short pawncover[9]={-60,-30,0,5,30,30,30,30,30};
static const short factor[9]={7,8,8,7,6,5,4,2,0};
static const BitBoard Corner[2]={ 0xC3C3000000000000ULL,0x000000000000C3C3ULL};

int ScoreK(short side)
{
short s,sq,sq1,n,n1,n2,xside,file,fsq,rank;
BitBoard b,x;
s=0;
xside=1^side;
sq=board.king[side];
file=ROW(sq);
rank=RANK(sq);
KingSafety[side]=0;
if(!ENDING)
	{ 
	s+=((6-phase)*KingSq[sq]+phase*EndingKing[sq])/6;
	if(side==white) n=nbits(MoveArray[king][sq]&board.b[side][pawn]&RankBit[rank+1]);
	else n=nbits(MoveArray[king][sq]&board.b[side][pawn]&RankBit[rank-1]);
	s+=pawncover[n];
	if(!board.castled[side])
		{
		n=-1;
		if(side==white)
			{
			if(sq==4&&Mvboard[sq]==0)
				{
				if((board.b[side][rook]&BitPosArray[H1])!=NULLBITBOARD&&Mvboard[H1]==0) n=nbits(MoveArray[king][G1]&board.b[side][pawn]&RankBit[rank+1]);
				if((board.b[side][rook]&BitPosArray[A1])!=NULLBITBOARD&&Mvboard[A1]==0) n=nbits(MoveArray[king][C1]&board.b[side][pawn]&RankBit[rank+1]);
				}
			}
		else
			{
			if(sq==60&&Mvboard[sq]==0)
				{
				if((board.b[side][rook]&BitPosArray[H8])!=NULLBITBOARD&&Mvboard[H8]==0)
				n=nbits(MoveArray[king][G8]&board.b[side][pawn]&RankBit[rank-1]);
				if((board.b[side][rook]&BitPosArray[A8])!=NULLBITBOARD&&Mvboard[A8]==0)
				n=nbits(MoveArray[king][C8]&board.b[side][pawn]&RankBit[rank-1]);
				}
			}
		pawncover[3]=30;
		if(n!=-1) s+=pawncover[n];
		}
	if(side==computer&&file>=F_FILE&&!(FileBit[G_FILE]&board.b[side][pawn]))
		{
		if(side==white&&cboard[F2]==pawn) s+=GOPEN;
		else if(side==black&&cboard[F7]==pawn) s+=GOPEN;
		}
	if(!(FileBit[file]&board.b[side][pawn])) s+=KINGOPENFILE;
	if(!(FileBit[file]&board.b[xside][pawn])) s+=KINGOPENFILE1;
	switch(file)
		{
		case A_FILE:
		case E_FILE:
		case F_FILE:
		case G_FILE:
			if(!(FileBit[file+1]&board.b[side][pawn])) s+=KINGOPENFILE;
			if(!(FileBit[file+1]&board.b[xside][pawn])) s+=KINGOPENFILE1;
			break;
		case H_FILE:
		case D_FILE:
		case C_FILE:
		case B_FILE:
			if(!(FileBit[file-1]&board.b[side][pawn])) s+=KINGOPENFILE;
			if(!(FileBit[file-1]&board.b[xside][pawn])) s+=KINGOPENFILE1;
		}
	if(board.castled[side])
		{
		if(side==white)
			{
			if(file>E_FILE)
				{
				if(!(BitPosArray[F2]&board.b[side][pawn])||!(BitPosArray[G2]&board.b[side][pawn])||!(BitPosArray[H2]&board.b[side][pawn])) s+=RUPTURE;
				}
			else if(file<E_FILE)
				{
				if(!(BitPosArray[A2]&board.b[side][pawn])||!(BitPosArray[B2]&board.b[side][pawn])||!(BitPosArray[C2]&board.b[side][pawn])) s+=RUPTURE;
				}
			}
		else
			{
			if(file>E_FILE)
				{
				if(!(BitPosArray[F7]&board.b[side][pawn])||!(BitPosArray[G7]&board.b[side][pawn])||!(BitPosArray[H7]&board.b[side][pawn])) s+=RUPTURE;
				}
			else if(file<E_FILE)
				{
				if(!(BitPosArray[A7]&board.b[side][pawn])||!(BitPosArray[B7]&board.b[side][pawn])||!(BitPosArray[C7]&board.b[side][pawn])) s+=RUPTURE;
				}
			}
		}
	if(side==computer)
		{
		if(file>=E_FILE&&board.b[xside][queen]&&board.b[xside][rook]&&!((board.b[side][pawn]|board.b[xside][pawn])&FileBit[7])) s+=HOPEN;
		if(side==white)
			{
			if(file>E_FILE)
				{
				if(board.b[side][rook]&mask_kr_trapped_w[H_FILE-file]) s+=ROOKTRAPPED;
				}
			else if(file<D_FILE)
				{
				if(board.b[side][rook]&mask_qr_trapped_w[file]) s+=ROOKTRAPPED;
				}
			}
		else
			{
			if(file>E_FILE)
				{
				if(board.b[side][rook]&mask_kr_trapped_b[H_FILE-file]) s+=ROOKTRAPPED;
				}
			else if(file<D_FILE)
				{
				if(board.b[side][rook]&mask_qr_trapped_b[file]) s+=ROOKTRAPPED;
				}
			}
		}
	if(file>E_FILE&&ROW(board.king[xside])<D_FILE)
		{
		if(side==white)
		fsq=G3; else fsq=G6;
		if((BitPosArray[fsq]&board.b[side][pawn])!=NULLBITBOARD) if(((BitPosArray[F4]|BitPosArray[H4]|BitPosArray[F5]|BitPosArray[H5])&board.b[xside][pawn])!=NULLBITBOARD)  s+=FIANCHETTO_TARGET;	
		}
	if(file<E_FILE&&ROW(board.king[xside])>E_FILE)
		{
		if(side==white) fsq=B3;
		else fsq=B6;
		if((BitPosArray[fsq]&board.b[side][pawn])!=NULLBITBOARD) if(((BitPosArray[A4]|BitPosArray[C4]|BitPosArray[A5]|BitPosArray[C5])&board.b[xside][pawn])!=NULLBITBOARD) s+=FIANCHETTO_TARGET;	
		}
	x=boardhalf[side]&boardside[file<=D_FILE];
	n1=nbits(x&(board.friends[xside]));
	if(n1>0)
		{
		n2=nbits(x &(board.friends[side]&~board.b[side][pawn]&~board.b[side][king]));
		if(n1>n2) s+=(n1-n2)*KING_DEFENDER_DEFICIT;
		}
	KingSafety[side]=s;
	s=(s*factor[phase])/8;
	}
else
	{
	s+=EndingKing[sq];
	s+=CTL(sq,king,side);
	b=(board.b[white][pawn]|board.b[black][pawn]);
	while(b)
		{
		sq1=leadz(b);
		CLEARBIT(b,sq1);
		if(BitPosArray[sq1]&board.b[white][pawn]) s-=distance[sq][sq1+8]*10-5;
		else if(BitPosArray[sq1]&board.b[white][pawn]) s-=distance[sq][sq1-8]*10-5;
		else s-=distance[sq][sq1]-5;
		}
	if(MoveArray[king][sq]&weaked[xside]) s+=ATAKWEAKPAWN*2;
	}
if(phase>=4)
	{
	if(side==white)
		{
		if(sq<A2) if(!(MoveArray[king][sq] &(~board.b[side][pawn]&RankBit[1]))) s+=KING_BACK_RANK_WEAK;
		}
	else
		{
		if(sq>H7) if(!(MoveArray[king][sq] &(~board.b[side][pawn]&RankBit[6]))) s+=KING_BACK_RANK_WEAK;
		}
	}
pscore[sq]=s;
return s;
}

int LoneKing(short side,short loser)
{
short s,winer,sq1,sq2;
winer=1^loser;
if(board.material[winer]==ValueB+ValueN&&nbits(board.b[winer][bishop])==1&&nbits(board.b[winer][knight])==1) return(ScoreKBNK(side,loser));
sq1=board.king[winer];
sq2=board.king[loser];
s=150-6*taxicab[sq1][sq2]-EndingKing[sq2];
if(side==loser) s=-s;
s+=MATERIAL;
return s;
}

int KPK(short side)
{
short winer,loser,sq,sqw,sql;
int s;
winer=(board.b[white][pawn]?white:black);
loser=1^winer;
sq =leadz(board.b[winer][pawn]);
sqw=board.king[winer];
sql=board.king[loser];
s=ValueP+(ValueQ*Passed[winer][RANK(sq)]/PFACTOR)+4*(winer==white?RANK(sqw):7-RANK(sqw));
if(~SquarePawnMask[winer][sq]&board.b[loser][king])
	{
	if(!(MoveArray[king][sql]&SquarePawnMask[winer][sq])) return(winer==side?s:-s);
	if(winer==side) return s;
	}
if(ROW(sq)!=0&&ROW(sq)!=7&&((IsolaniMask[ROW(sq)]|FileBit[ROW(sq)])&board.b[winer][king]))
	{
	if(winer==white)
		{
		if(RANK(sqw)==RANK(sq)+2) return winer==side?s:-s;
		if(RANK(sqw)==RANK(sq)+1)
			{
			if(RANK(sqw)==5) return winer==side?s:-s;
			if(sqw<A6) 
				{
				if(sqw+16==sql&&winer==side) return 0;
				else return winer==side?s:-s;
				}
			}
		if(RANK(sqw)==RANK(sq))
			{
			if((RANK(sql)-RANK(sq)<2||RANK(sql)-RANK(sq)>4)&&winer==side) return s;
			if((RANK(sql)-RANK(sq)<1||RANK(sql)-RANK(sq)>5)&&loser==side) return -s;
			if(RANK(sq)==5&&sqw+16!=sql) return winer==side?s:0;
			}
		if(RANK(sq)==6&&RANK(sqw)==5)
			{
			if(sql!=sq+8) return winer==side?s:0;
			if(sql==sq+8&&sql==sqw+16) return winer==side?s:0;
			}
		}
	else
		{
		if(RANK(sqw)==RANK(sq)-2) return winer==side?s:-s;
		if(RANK(sqw)==RANK(sq)-1)
			{
			if(RANK(sqw)==2) return winer==side?s:-s;
			if(sqw>H3)
				{
				if(sqw-16==sql&&winer==side) return 0;
				else return winer==side?s:-s;
				}
			}
		if(RANK(sqw)==RANK(sq))
			{
			if((RANK(sq)-RANK(sql)<2||RANK(sq)-RANK(sql)>4)&&winer==side) return s;
			if((RANK(sq)-RANK(sql)<1||RANK(sq)-RANK(sql)>5)&&loser==side) return -s;
			if(RANK(sq)==5&&sqw+16!=sql) return winer==side?s:0;
			}
		if(RANK(sq)==1&&RANK(sqw)==2)
			{
			if(sql!=sq-8) return winer==side?s:0;
			if(sql==sq-8&&sql==sqw-16) return winer==side?s:0;
			}
		} 
	}  
return 0;
}

short KBNK[64]=
{
0,10,20,30,40,50,60,70,
10,20,30,40,50,60,70,60,
20,30,40,50,60,70,60,50,
30,40,50,60,70,60,50,40,
40,50,60,70,60,50,40,30,
50,60,70,60,50,40,30,20,
60,70,60,50,40,30,20,10,
70,60,50,40,30,20,10,0
};

int ScoreKBNK(short side,short loser)
{
short s,winer,sq1,sq2,sqB;
winer=1^loser;
sqB=board.king[loser];
if(board.b[winer][bishop]&WHITESQUARES)
sqB=RANK(sqB)*8+7-ROW(sqB);
sq1=board.king[winer];
sq2=board.king[loser];
s=300-6*taxicab[sq1][sq2];
s-=KBNK[sqB];
s-=EndingKing[sq2];
s-=taxicab[leadz(board.b[winer][knight])][sq2];
s-=taxicab[leadz(board.b[winer][bishop])][sq2];
if(board.b[winer][king]&0x00003C3C3C3C0000ULL) s+=20;
if(side==loser) s=-s;
s+=MATERIAL;
return s; 
}

static const BitBoard nn[2]={0x4200000000000000ULL,0x0000000000000042ULL};
static const BitBoard bb[2]={0x2400000000000000ULL,0x0000000000000024ULL};
static const BitBoard rr[2]={0x8100000000000000ULL,0x0000000000000081ULL};
static const BitBoard corner=0xC3C300000000C3C3ULL;

int ScoreDev(short side)
{
int s=0;
short sq,xside;
BitBoard c;
xside=1^side;
c=(board.b[side][knight]&nn[side])|(board.b[side][bishop]&bb[side]);
s+=nbits(c)*(-8);
if(board.castled[side]||GameCnt/2+1>=20) return s;
s+=NOTCASTLED;
if(Mvboard[board.king[side]]>0) s+=KINGMOVED;
c=board.b[side][rook];
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	if(Mvboard[sq]>0) s+=ROOKMOVED;
	}
if(board.b[side][queen])
	{
	sq=leadz(board.b[side][queen]);
	if(Mvboard[sq]>0) s+=EARLYQUEENMOVE;
	}
c=board.b[side][knight]|board.b[side][bishop];
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	if(Mvboard[sq]>1)	s+=EARLYMINORREPEAT;
	}
c=board.b[side][pawn]&(FileBit[0]|FileBit[1]|FileBit[6]|FileBit[7]);
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	if(Mvboard[sq]>0) s+=EARLYWINGPAWNMOVE;
	}
c=board.b[side][pawn]&(FileBit[2]|FileBit[3]|FileBit[4]|FileBit[5]);
while(c)
	{
	sq=leadz(c);
	CLEARBIT(c,sq);
	if(Mvboard[sq]>1) s+=EARLYCENTERPREPEAT;
	}
return s;
}

int Evaluate(int alpha,int beta)
{
short side,xside,s,s1,score;
short npiece[2];
BitBoard *b;
side=board.side;
xside=1^side;
if(alpha>MATE-255||beta<-MATE+255) return MATERIAL; 
if(board.material[white]+board.material[black]==ValueP) return KPK(side);  
if(board.material[xside]==0&&board.b[side][pawn]==NULLBITBOARD) return LoneKing(side,xside);
if(board.material[side]==0&&board.b[xside][pawn]==NULLBITBOARD) return LoneKing(side,side);
EvalCall++;
phase=PHASE;
b=board.b[white];
pieces[white]=b[knight]|b[bishop]|b[rook]|b[queen];
npiece[white]=nbits(pieces[white]);
b=board.b[black];
pieces[black]=b[knight]|b[bishop]|b[rook]|b[queen];
npiece[black]=nbits(pieces[black]);
hunged[white]=hunged[black]=0;
memset(pscore,0,sizeof(pscore));
s1=MATERIAL;
if((s1+maxposnscore[side]<alpha||s1-maxposnscore[xside]>beta)&&phase<=6)
	{
	score=s1;
	goto next;
	}
s=0;
s+=ScoreDev(side)-ScoreDev(xside);
s+=ScoreP(side)-ScoreP(xside);
s+=ScoreK(side)-ScoreK(xside);
s+=BishopTrapped(side)-BishopTrapped(xside);
s+=DoubleQR7(side)-DoubleQR7(xside);
s1=s+MATERIAL;
if(s1+lazyscore[side]<alpha||s1-lazyscore[side]>beta) score=s1;
else
	{
	EvalCnt++;
	s1=0;
	s1+=ScoreN(side)-ScoreN(xside);
	s1+=ScoreB(side)-ScoreB(xside);
	s1+=ScoreR(side)-ScoreR(xside);
	s1+=ScoreQ(side)-ScoreQ(xside);
	lazyscore[side]=MAX(s1,lazyscore[side]);
	maxposnscore[side]=MAX(maxposnscore[side],s+s1);
	score=s+s1+MATERIAL;
	}

next:
if(MATERIAL>=200)
	{
	score+=(RootPieces-nbits(pieces[white]|pieces[black]))*TRADEPIECE;
	score-=(RootPawns-nbits(board.b[white][pawn]|board.b[black][pawn]))*TRADEPAWNS;
	}
else if(MATERIAL<=-200)
	{
	score-=(RootPieces-nbits(pieces[white]|pieces[black]))*TRADEPIECE;
	score+=(RootPawns-nbits(board.b[white][pawn]|board.b[black][pawn]))*TRADEPAWNS;
	}
if(ENDING&&pieces[white]==board.b[white][bishop]&&pieces[black]==board.b[black][bishop]&&((pieces[white]&WHITESQUARES&&pieces[black]&BLACKSQUARES)||(pieces[white]&BLACKSQUARES&&pieces[black]&WHITESQUARES))) score/=2;
if(score>0&&!board.b[side][pawn]&&(board.material[side]<ValueR||pieces[side]==board.b[side][knight])) score=0;
if(score<0&&!board.b[xside][pawn]&&(board.material[xside]<ValueR||pieces[xside]==board.b[xside][knight])) score=0;
return score;
}

short EvaluateDraw()
{
BitBoard *w,*b;
short wm,bm,wn,bn;
w=board.b[white];
b=board.b[black];
if(w[pawn]!=0||b[pawn]!=0) return false;
wm=board.material[white];
bm=board.material[black];
wn=nbits(w[knight]);
bn=nbits(b[knight]);
if((wm<ValueR ||(wm==2*ValueN&&wn==2))&&(bm<ValueR ||(bm==2*ValueN&&bn==2))) return true;
if(wm<ValueR)
	{
	if(bm==2*ValueB&&(nbits(board.b[black][bishop]&WHITESQUARES)==2||nbits(board.b[black][bishop]&BLACKSQUARES)==2)) return true;
	}
if(bm<ValueR)
	{
	if(wm==2*ValueB&&(nbits(board.b[white][bishop]&WHITESQUARES)==2||nbits(board.b[white][bishop]&BLACKSQUARES)==2)) return true;
	}
return false;
}
