/******************************************
* Needle - a bitboard based chess engine. *
* (C) 2004 Mikko Nummelin                 *
******************************************/

#include "needle.h"

#define _EVALUATE_C

#define OPEN_LONG_DIAGONAL	5
#define TWO_BISHOPS		10
#define BISHOP_TRAP_RISK	15
#define ROOK_ON_SEMI_OPEN_BONUS	9
#define QUEEN_ON_SEMI_OPEN_BONUS	5
#define ANOTHER_ROOK_BONUS	5
#define ATTACKING_ROOK_BONUS	12
#define SUPPORTING_QUEEN_BONUS	3
#define OPPONENTS_PAWN_PENALTY	6
#define OPPONENTS_MINOR_PENALTY	4
#define SHORT_CASTLING_RIGHT_BONUS	8
#define LONG_CASTLING_RIGHT_BONUS	7
#define NEAR_BISHOP_PENALTY	3
#define ATTACKING_KNIGHT_PENALTY	10
#define ATTACKING_PAWN_PENALTY	10
#define GOOD_COVER_BONUS	3
#define H3_PAWN_COVER_PENALTY	1
#define MISSING_H_PENALTY	6
#define SHATTERED_CASTLING_PENALTY	10
#define THREAT_INTO_KPOS_PENALTY	3
#define PASSED_PAWN_BONUS	17
#define SUPPORTED_PAWN_BONUS	5
#define DOUBLE_PAWN_PENALTY	12
#define ISOLATED_PAWN_PENALTY	7
#define OPP_LONE_KING_BONUS 150

#define MIDGAME_LIMIT	2500
#define ENDGAME_LIMIT	1000

#define RIGHT_BISHOP_TRAP_AREA	0x0000030303030000
#define LEFT_BISHOP_TRAP_AREA	0x0000c0c0c0c00000

/* White king in middlegame */
const int Km[] = {
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-10,-10,-20,-20,-20,-20,-10,-10,
	 15, 20, 25,-20,  0,-20, 30, 20
};

/* White king in endgame */
const int Ke[] = {
	-24,-20,-16,-15,-15,-16,-20,-24,
	-20,-10, -5, -3, -3, -5,-10,-20,
	-16, -5,  0,  4,  4,  0, -5,-16,
	-15, -3,  4,  8,  8,  4, -3,-15,
	-15, -3,  4,  8,  8,  4, -3,-15,
	-16, -5,  0,  4,  4,  0, -5,-16,
	-20,-10, -5, -3, -3, -5,-10,-20,
	-24,-20,-16,-15,-15,-16,-20,-24
};

/* Black king in middlegame */
const int km[] = {
	 15, 20, 25,-20,  0,-20, 30, 20,
	-10,-10,-20,-20,-20,-20,-10,-10,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25,
	-25,-25,-25,-25,-25,-25,-25,-25
};

/* Black king in endgame */
const int ke[] = {
	-24,-20,-16,-15,-15,-16,-20,-24,
	-20,-10, -5, -3, -3, -5,-10,-20,
	-16, -5,  0,  4,  4,  0, -5,-16,
	-15, -3,  4,  8,  8,  4, -3,-15,
	-15, -3,  4,  8,  8,  4, -3,-15,
	-16, -5,  0,  4,  4,  0, -5,-16,
	-20,-10, -5, -3, -3, -5,-10,-20,
	-24,-20,-16,-15,-15,-16,-20,-24
};

/* White pawns in middlegame */
const int Pm[] = {
	  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,  8, 12, 12,  0,  0,  0,
	  0,  0, 10, 15, 15,  0,  0,  0,
	  0,  0,  3,  5,  5,  0,  0,  0,
	  3,  3,-10,-25,-25,  5,  3,  3,
	  0,  0,  0,  0,  0,  0,  0,  0
};

/* White pawns in endgame */
const int Pe[] = {
	  0,  0,  0,  0,  0,  0,  0,  0,
	 10, 14, 16, 20, 20, 16, 14, 10,
	  5, 10, 12, 15, 15, 12, 10,  5,
	  2,  3,  8, 11, 11,  8,  3,  2,
	  1,  2,  3,  5,  5,  3,  2,  1,
	 -5, -5, -5, -5, -5, -5, -5, -5,
	  0,  0,-10,-10,-10,-10,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0
};

/* Black pawns in middlegame */
const int pm[] = {
	  0,  0,  0,  0,  0,  0,  0,  0,
	  3,  3,-10,-25,-25,  5,  3,  3,
	  0,  0,  3,  5,  5,  0,  0,  0,
	  0,  0, 10, 15, 15,  0,  0,  0,
	  0,  0,  8, 12, 12,  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
};

/* Black pawns in endgame */
const int pe[] = {
	  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,-10,-10,-10,-10,  0,  0,
	 -5, -5, -5, -5, -5, -5, -5, -5,
	  1,  2,  3,  5,  5,  3,  2,  1,
	  2,  3,  8, 11, 11,  8,  3,  2,
	  5, 10, 12, 15, 15, 12, 10,  5,
	 10, 14, 16, 20, 20, 16, 14, 10,
	  0,  0,  0,  0,  0,  0,  0,  0
};

/* White knights */
const int Nm[] = {
	 -5, -5, -5, -5, -5, -5, -5, -5,
	 -5, -1,  0,  0,  0,  0, -1, -5,
	 -5,  0,  5,  5,  5,  5,  0, -5,
	 -5,  0,  5,  7,  7,  5,  0, -5,
	 -5,  0,  5,  7,  7,  5,  0, -5,
	 -5,  0,  5,  5,  5,  6,  0, -5,
	 -5, -1,  0,  0,  0,  0, -1, -5,
	 -5,-20, -5, -5, -5, -5,-20, -5
};

/* Black knights */
const int nm[] = {
	 -5,-20, -5, -5, -5, -5,-20, -5,
	 -5, -1,  0,  0,  0,  0, -1, -5,
	 -5,  0,  5,  5,  5,  6,  0, -5,
	 -5,  0,  5,  7,  7,  5,  0, -5,
	 -5,  0,  5,  7,  7,  5,  0, -5,
	 -5,  0,  5,  5,  5,  5,  0, -5,
	 -5, -1,  0,  0,  0,  0, -1, -5,
	 -5, -5, -5, -5, -5, -5, -5, -5
};

/* White bishops in middlegame */
const int Bm[] = {
	 -3, -3, -3, -3, -3, -3, -3, -3,
	 -3,  0,  0,  0,  0,  0,  0, -3,
	 -3,  0,  3,  3,  3,  3,  0, -3,
	 -3,  0,  3,  5,  5,  3,  0, -3,
	 -3,  0,  3,  5,  5,  3,  0, -3,
	 -3,  0,  3,  3,  3,  3,  0, -3,
	 -3,  0,  0,  0,  0,  0,  0, -3,
	 -3, -3,-10, -3, -3,-10, -3, -3
};

/* Black bishops in middlegame */
const int bm[] = {
	 -3, -3,-10, -3, -3,-10, -3, -3,
	 -3,  0,  0,  0,  0,  0,  0, -3,
	 -3,  0,  3,  3,  3,  3,  0, -3,
	 -3,  0,  3,  5,  5,  3,  0, -3,
	 -3,  0,  3,  5,  5,  3,  0, -3,
	 -3,  0,  3,  3,  3,  3,  0, -3,
	 -3,  0,  0,  0,  0,  0,  0, -3,
	 -3, -3, -3, -3, -3, -3, -3, -3
};

/* White rooks in middlegame */
const int Rm[] = {
	  5,  5,  5,  5,  5,  5,  5,  5,
	  8,  8,  9,  9,  9,  9,  8,  8,
	  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,  3,  3,  3,  3,  0,  0,
	  0,  0,  3,  3,  3,  3,  0,  0
};

/* Black rooks in middlegame */
const int rm[] = {
	  0,  0,  3,  3,  3,  3,  0,  0,
	  0,  0,  3,  3,  3,  3,  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,
	  8,  8,  9,  9,  9,  9,  8,  8,
	  5,  5,  5,  5,  5,  5,  5,  5
};

/* White queen(s) in middlegame */
const int Qm[] = {
	  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  0,  2,  2,  2,  2,  0,  0,
	 -5, -5, -5,  5,  2, -5, -5, -5
};

/* Black queen(s) in middlegame */
const int qm[] = {
	 -5, -5, -5,  5,  2, -5, -5, -5,
	  0,  0,  2,  2,  2,  2,  0,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  2,  2,  2,  2,  2,  2,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0
};

const unsigned long long adjacent_file_masks[] = {
	0x0303030303030303,
	0x0707070707070707,
	0xe0e0e0e0e0e0e0e0,
	0x1c1c1c1c1c1c1c1c,
	0x3838383838383838,
	0x7070707070707070,
	0xe0e0e0e0e0e0e0e0,
	0xc0c0c0c0c0c0c0c0
};

const unsigned long long strict_adj_file_masks[] = {
	0x0202020202020202,
	0x0505050505050505,
	0x0a0a0a0a0a0a0a0a,
	0x1414141414141414,
	0x2828282828282828,
	0x5050505050505050,
	0xa0a0a0a0a0a0a0a0,
	0x4040404040404040
};

const unsigned long long file_masks[] = {
	0x0101010101010101,
	0x0202020202020202,
	0x0404040404040404,
	0x0808080808080808,
	0x1010101010101010,
	0x2020202020202020,
	0x4040404040404040,
	0x8080808080808080
};

const unsigned long long white_passed_pawn_masks[] = {
	0xffffffffffffff00,
	0xffffffffffff0000,
	0xffffffffff000000,
	0xffffffff00000000,
	0xffffff0000000000,
	0xffff000000000000,
	0xff00000000000000,
	0x0000000000000000
};

const unsigned long long black_passed_pawn_masks[] = {
	0x0000000000000000,
	0x00000000000000ff,
	0x000000000000ffff,
	0x0000000000ffffff,
	0x00000000ffffffff,
	0x000000ffffffffff,
	0x0000ffffffffffff,
	0x00ffffffffffffff
};

const unsigned char supporting_pawn_masks[] = {
	0x2,0x5,0xa,0x14,0x28,0x50,0xa0,0x4
};

int evaluate_and_pick_material(Board *brd, Piececalc *pc) {
	int bitno,value;
	Bitboard tmp_bitboard;

	bitno=value=0;
	zero_piececalc(pc);

	/* White king */
	bitno=my_bsf(brd->K.whole);
	pc->Ksq=bitno;

	/* White queen(s) */
	tmp_bitboard.whole=brd->Q.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->Qsq[pc->Q]=bitno;
		pc->Q++;
		value+=QUEEN_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* White bishop(s) */
	tmp_bitboard.whole=brd->B.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->Bsq[pc->B]=bitno;
		pc->B++;
		value+=BISHOP_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* White knight(s) */
	tmp_bitboard.whole=brd->N.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->Nsq[pc->N]=bitno;
		pc->N++;
		value+=KNIGHT_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* White rook(s) */
	tmp_bitboard.whole=brd->R.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->Rsq[pc->R]=bitno;
		pc->R++;
		value+=ROOK_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* White pawn(s) */
	tmp_bitboard.whole=brd->P.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->Psq[pc->P]=bitno;
		pc->P++;
		value+=PAWN_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* Black king */
	bitno=my_bsf(brd->k.whole);
	pc->ksq=bitno;

	/* Black queen(s) */
	tmp_bitboard.whole=brd->q.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->qsq[pc->q]=bitno;
		pc->q++;
		value-=QUEEN_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* Black bishop(s) */
	tmp_bitboard.whole=brd->b.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->bsq[pc->b]=bitno;
		pc->b++;
		value-=BISHOP_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* Black knight(s) */
	tmp_bitboard.whole=brd->n.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->nsq[pc->n]=bitno;
		pc->n++;
		value-=KNIGHT_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* Black rook(s) */
	tmp_bitboard.whole=brd->r.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->rsq[pc->r]=bitno;
		pc->r++;
		value-=ROOK_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	/* Black pawn(s) */
	tmp_bitboard.whole=brd->p.whole;
	while(tmp_bitboard.whole!=BITBOARD_ZERO) {
		bitno=my_bsf(tmp_bitboard.whole);
		pc->psq[pc->p]=bitno;
		pc->p++;
		value-=PAWN_VALUE;
		tmp_bitboard.whole &= ~bpow(bitno);
	}

	return value;
}

/* Evaluates development and mobility */
int evaluate_dm(Board *brd, Piececalc *pc) {

	unsigned char occ;
	int bitno,fileno,rankno,diano,diamask,i,value=0;

	/* White bishop(s) */
	if((brd->B.whole & WHITE_SQUARES_MASK)&&
		(brd->B.whole & BLACK_SQUARES_MASK)){
		value+=TWO_BISHOPS;
	}
	for(i=0;i<pc->B;i++){
		bitno=pc->Bsq[i];
		value+=Bm[077-bitno];
		diano=nw_diano_for_bit(bitno);
		diamask=nw_mask_for_bit(bitno);
		occ=brd->Pnw.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value+=OPEN_LONG_DIAGONAL;
		}
		diano=ne_diano_for_bit(bitno);
		diamask=ne_mask_for_bit(bitno);
		occ=brd->Pne.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value+=OPEN_LONG_DIAGONAL;
		}
		if(bpow(bitno) & LEFT_BISHOP_TRAP_AREA)	{
			if(bpow(bitno-9) & all_white_pieces(brd)) {
				value-=BISHOP_TRAP_RISK;
			}
		}
		if(bpow(bitno) & RIGHT_BISHOP_TRAP_AREA)	{
			if(bpow(bitno-7) & all_white_pieces(brd)) {
				value-=BISHOP_TRAP_RISK;
			}
		}
	}

	/* White knight(s) */
	for(i=0;i<pc->N;i++){
		value+=Nm[077-pc->Nsq[i]];
	}

	/* White rook(s) */
	for(i=0;i<pc->R;i++){
		bitno=pc->Rsq[i];
		value+=Rm[077-bitno];
		fileno=fileno_for_bit(bitno);
		rankno=rankno_for_bit(bitno);
		occ=brd->Kr.rows[fileno]|brd->Br.rows[fileno]|
			brd->Nr.rows[fileno]|brd->Pr.rows[fileno];
		if(occ==0x00) { /* File is at least semi-open */
			value+=ROOK_ON_SEMI_OPEN_BONUS;
			if(brd->Rr.rows[fileno]&~bpow(fileno)){
				value+=ANOTHER_ROOK_BONUS;
			}
			if(brd->Qr.rows[fileno]){
				value+=SUPPORTING_QUEEN_BONUS;
			}
			if(brd->pr.rows[fileno]){
				value-=OPPONENTS_PAWN_PENALTY;
			}
			if(brd->br.rows[fileno]|brd->nr.rows[fileno]){
				value-=OPPONENTS_MINOR_PENALTY;
			}
			if(brd->k.whole & adjacent_file_masks[7-fileno]){
				value+=ATTACKING_ROOK_BONUS;
			}
		}
	}

	/* White queen(s) */
	for(i=0;i<pc->Q;i++){
		bitno=pc->Qsq[i];
		value+=Qm[077-bitno];
		fileno=fileno_for_bit(bitno);
		rankno=rankno_for_bit(bitno);
		occ=brd->Kr.rows[fileno]|brd->Br.rows[fileno]|
			brd->Nr.rows[fileno]|brd->Pr.rows[fileno];
		if(occ==0x00) { /* File is at least semi-open */
			value+=QUEEN_ON_SEMI_OPEN_BONUS;
			if(brd->pr.rows[fileno]){
				value-=OPPONENTS_PAWN_PENALTY;
			}
			if(brd->br.rows[fileno]|brd->nr.rows[fileno]){
				value-=OPPONENTS_MINOR_PENALTY;
			}
		}
		diano=nw_diano_for_bit(bitno);
		diamask=nw_mask_for_bit(bitno);
		occ=brd->Pnw.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value+=OPEN_LONG_DIAGONAL;
		}
		diano=ne_diano_for_bit(bitno);
		diamask=ne_mask_for_bit(bitno);
		occ=brd->Pne.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value+=OPEN_LONG_DIAGONAL;
		}
	}

	/* Black bishop(s) */
	if((brd->b.whole & WHITE_SQUARES_MASK)&&
		(brd->b.whole & BLACK_SQUARES_MASK)){
		value-=TWO_BISHOPS;
	}
	for(i=0;i<pc->b;i++){
		bitno=pc->bsq[i];
		value-=bm[077-bitno];
		diano=nw_diano_for_bit(bitno);
		diamask=nw_mask_for_bit(bitno);
		occ=brd->pnw.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value-=OPEN_LONG_DIAGONAL;
		}
		diano=ne_diano_for_bit(bitno);
		diamask=ne_mask_for_bit(bitno);
		occ=brd->pne.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value-=OPEN_LONG_DIAGONAL;
		}
		if(bpow(bitno) & LEFT_BISHOP_TRAP_AREA)	{
			if(bpow(bitno+7) & all_black_pieces(brd)) {
				value+=BISHOP_TRAP_RISK;
			}
		}
		if(bpow(bitno) & RIGHT_BISHOP_TRAP_AREA)	{
			if(bpow(bitno+9) & all_black_pieces(brd)) {
				value+=BISHOP_TRAP_RISK;
			}
		}
	}

	/* Black knight(s) */
	for(i=0;i<pc->n;i++){
		value-=nm[077-pc->nsq[i]];
	}

	/* Black rook(s) */
	for(i=0;i<pc->r;i++){
		bitno=pc->rsq[i];
		value-=rm[077-bitno];
		fileno=fileno_for_bit(bitno);
		rankno=rankno_for_bit(bitno);
		occ=brd->kr.rows[fileno]|brd->br.rows[fileno]|
			brd->nr.rows[fileno]|brd->pr.rows[fileno];
		if(occ==0x00) { /* File is at least semi-open */
			value-=ROOK_ON_SEMI_OPEN_BONUS;
			if(brd->rr.rows[fileno]&~bpow(fileno)){
				value-=ANOTHER_ROOK_BONUS;
			}
			if(brd->qr.rows[fileno]){
				value-=SUPPORTING_QUEEN_BONUS;
			}
			if(brd->Pr.rows[fileno]){
				value+=OPPONENTS_PAWN_PENALTY;
			}
			if(brd->Br.rows[fileno]|brd->Nr.rows[fileno]){
				value+=OPPONENTS_MINOR_PENALTY;
			}
			if(brd->K.whole & adjacent_file_masks[7-fileno]){
				value-=ATTACKING_ROOK_BONUS;
			}
		}
	}

	/* Black queen(s) */
	for(i=0;i<pc->q;i++){
		bitno=pc->qsq[i];
		value-=qm[077-bitno];
		fileno=fileno_for_bit(bitno);
		rankno=rankno_for_bit(bitno);
		occ=brd->kr.rows[fileno]|brd->br.rows[fileno]|
			brd->nr.rows[fileno]|brd->pr.rows[fileno];
		if(occ==0x00) { /* File is at least semi-open */
			value-=QUEEN_ON_SEMI_OPEN_BONUS;
			if(brd->Pr.rows[fileno]){
				value+=OPPONENTS_PAWN_PENALTY;
			}
			if(brd->Br.rows[fileno]|brd->Nr.rows[fileno]){
				value+=OPPONENTS_MINOR_PENALTY;
			}
		}
		diano=nw_diano_for_bit(bitno);
		diamask=nw_mask_for_bit(bitno);
		occ=brd->pnw.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value-=OPEN_LONG_DIAGONAL;
		}
		diano=ne_diano_for_bit(bitno);
		diamask=ne_mask_for_bit(bitno);
		occ=brd->pne.rows[diano];
		occ &= diamask;
		if((diamask&0x18)&&(occ==0x00)) {
			value-=OPEN_LONG_DIAGONAL;
		}
	}

	return value;
}

int evaluate_king_safety(Board *brd, Piececalc *pc) {
	int bitno,value=0;
	Bitboard safety_mask;

	/* White king */
	value+=Km[077-pc->Ksq];

	if(brd->castling_flags&0x1){
		value+=SHORT_CASTLING_RIGHT_BONUS;
	}
	if(brd->castling_flags&0x2){
		value+=LONG_CASTLING_RIGHT_BONUS;
	}

	bitno=pc->Ksq;
	safety_mask.whole=smask_for_bit(bitno);
	if(safety_mask.whole & brd->b.whole){
		value-=NEAR_BISHOP_PENALTY;
	}
	if(safety_mask.whole & brd->n.whole){
		value-=ATTACKING_KNIGHT_PENALTY;
	}
	if(safety_mask.whole & brd->p.whole){
		value-=ATTACKING_PAWN_PENALTY;
	}
	if((bitno>=0)&&(bitno<=2)){ /* King side castled king */
		if((brd->P.rows[1]&0x7)==0x7){
			value+=GOOD_COVER_BONUS;
			if(is_threat(brd,'b',8)||is_threat(brd,'b',9)){
				value-=THREAT_INTO_KPOS_PENALTY;
			}
		} else if((brd->P.rows[1]&0x7)==0x6){
			if(brd->P.rows[2]&0x1){
				value-=H3_PAWN_COVER_PENALTY;
			} else {
				value-=MISSING_H_PENALTY;
			}
		} else if(((brd->P.rows[1]&0x7)==0x5)&&
			(brd->P.rows[2]&0x2)&&
			(brd->B.rows[1]&0x2)) {
			value+=GOOD_COVER_BONUS;
		} else {
			value-=SHATTERED_CASTLING_PENALTY;
		}
	}
	if((bitno>5)&&(bitno<=7)){ /* Queen side castled king */
		if((brd->P.rows[1]&0xc0)==0xc0){
			value+=GOOD_COVER_BONUS;
		} else if((brd->P.rows[1]&0x40)==0x40){
			if(brd->P.rows[2]&0x80){
				value-=H3_PAWN_COVER_PENALTY;
			} else {
				value-=MISSING_H_PENALTY;
			}
		} else if(((brd->P.rows[1]&0xa0)==0xa0)&&
			(brd->P.rows[2]&0x40)&&
			(brd->B.rows[1]&0x40)) {
			value+=GOOD_COVER_BONUS;
		} else {
			value-=SHATTERED_CASTLING_PENALTY;
		}
	}

	/* Black king */
	value-=km[077-pc->ksq];

	if(brd->castling_flags&0x4){
		value-=SHORT_CASTLING_RIGHT_BONUS;
	}
	if(brd->castling_flags&0x8){
		value-=LONG_CASTLING_RIGHT_BONUS;
	}

	bitno=pc->ksq;
	safety_mask.whole=smask_for_bit(bitno);
	if(safety_mask.whole & brd->B.whole){
		value+=NEAR_BISHOP_PENALTY;
	}
	if(safety_mask.whole & brd->N.whole){
		value+=ATTACKING_KNIGHT_PENALTY;
	}
	if(safety_mask.whole & brd->P.whole){
		value+=ATTACKING_PAWN_PENALTY;
	}
	if((bitno>=070)&&(bitno<=072)){ /* King side castled king */
		if((brd->p.rows[6]&0x7)==0x7){
			value-=GOOD_COVER_BONUS;
			if(is_threat(brd,'w',060)||is_threat(brd,'w',061)){
				value+=THREAT_INTO_KPOS_PENALTY;
			}
		} else if((brd->p.rows[6]&0x7)==0x6){
			if(brd->p.rows[5]&0x1){
				value+=H3_PAWN_COVER_PENALTY;
			} else {
				value+=MISSING_H_PENALTY;
			}
		} else if(((brd->p.rows[6]&0x7)==0x5)&&
			(brd->p.rows[5]&0x2)&&
			(brd->b.rows[6]&0x2)) {
			value-=GOOD_COVER_BONUS;
		} else {
			value+=SHATTERED_CASTLING_PENALTY;
		}
	}
	if((bitno>075)&&(bitno<=077)){ /* Queen side castled king */
		if((brd->p.rows[6]&0xc0)==0xc0){
			value-=GOOD_COVER_BONUS;
		} else if((brd->p.rows[6]&0x40)==0x40){
			if(brd->p.rows[5]&0x80){
				value+=H3_PAWN_COVER_PENALTY;
			} else {
				value+=MISSING_H_PENALTY;
			}
		} else if(((brd->p.rows[6]&0xa0)==0xa0)&&
			(brd->p.rows[5]&0x40)&&
			(brd->b.rows[6]&0x40)) {
			value-=GOOD_COVER_BONUS;
		} else {
			value+=SHATTERED_CASTLING_PENALTY;
		}
	}

	return value;
}

int evaluate_pawn_structure(Board *brd, Piececalc *pc) {
	int i,fileno,rankno,value=0;

	/* White pawns */
	for(i=0;i<pc->P;i++){
		value+=Pm[077-pc->Psq[i]];
		fileno=fileno_for_bit(pc->Psq[i]);
		rankno=rankno_for_bit(pc->Psq[i]);
		if((adjacent_file_masks[7-fileno] &
			white_passed_pawn_masks[rankno] &
			(brd->P.whole | brd->p.whole))==BITBOARD_ZERO) {
			value+=PASSED_PAWN_BONUS;
		}
		if(brd->P.rows[rankno-1] & supporting_pawn_masks[7-fileno]){
			value+=SUPPORTED_PAWN_BONUS;
		}
		if(file_masks[7-fileno] &
			white_passed_pawn_masks[rankno] &
			brd->P.whole) {
			value-=DOUBLE_PAWN_PENALTY;
		}
		if((strict_adj_file_masks[7-fileno] &
			brd->P.whole)==BITBOARD_ZERO) {
			value-=ISOLATED_PAWN_PENALTY;
		}
	}

	/* Black pawns */
	for(i=0;i<pc->p;i++){
		value-=pm[077-pc->psq[i]];
		fileno=fileno_for_bit(pc->psq[i]);
		rankno=rankno_for_bit(pc->psq[i]);
		if((adjacent_file_masks[7-fileno] &
			black_passed_pawn_masks[rankno] &
			(brd->P.whole | brd->p.whole))==BITBOARD_ZERO) {
			value-=PASSED_PAWN_BONUS;
		}
		if(brd->p.rows[rankno+1] & supporting_pawn_masks[7-fileno]){
			value-=SUPPORTED_PAWN_BONUS;
		}
		if(file_masks[7-fileno] &
			black_passed_pawn_masks[rankno] &
			brd->p.whole) {
			value+=DOUBLE_PAWN_PENALTY;
		}
		if((strict_adj_file_masks[7-fileno] &
			brd->p.whole)==BITBOARD_ZERO) {
			value+=ISOLATED_PAWN_PENALTY;
		}
	}

	return value;
}

int evaluate_eg_king_safety(Board *brd, Piececalc *pc) {
	int white_king_rankno,white_king_fileno,black_king_rankno,black_king_fileno;
	int rook_rankno,rook_fileno,ccorner_rankno,ccorner_fileno;
	int dist,value=0;

	white_king_rankno=rankno_for_bit(pc->Ksq);
	white_king_fileno=fileno_for_bit(pc->Ksq);
	black_king_rankno=rankno_for_bit(pc->ksq);
	black_king_fileno=fileno_for_bit(pc->ksq);

	/* White king */
	value+=Ke[077-pc->Ksq];
	if((black_piecevalues(pc)==0)&&
		(pc->p==0)) {
		/* Black king is alone */
		value+=OPP_LONE_KING_BONUS;
		dist=(white_king_rankno-black_king_rankno)*
		(white_king_rankno-black_king_rankno)+
		(white_king_fileno-black_king_fileno)*
		(white_king_fileno-black_king_fileno);
		value-=dist;
		if(pc->R==1) {
			/* This assists in krk, but supposedly does no harm even otherwise */
			rook_rankno=rankno_for_bit(pc->Rsq[0]);
			rook_fileno=fileno_for_bit(pc->Rsq[0]);
			ccorner_rankno=8;ccorner_fileno=8; /* Dummy values */
			if(black_king_rankno<rook_rankno){
				ccorner_rankno=0;
			} else if(black_king_rankno>rook_rankno){
				ccorner_rankno=7;
			}
			if(black_king_fileno<rook_fileno){
				ccorner_fileno=0;
			} else if(black_king_fileno>rook_fileno){
				ccorner_fileno=7;
			}
			if((ccorner_rankno<8)&&(ccorner_fileno<8)){
				value-=abs(ccorner_rankno-rook_rankno)*
					abs(ccorner_fileno-rook_fileno);
			} else {
				value-=50;
			}
		}
	}

	/* Black king */
	value-=ke[077-pc->ksq];
	if((white_piecevalues(pc)==0)&&
		(pc->P==0)) {
		/* White king is alone */
		value-=OPP_LONE_KING_BONUS;
		dist=(white_king_rankno-black_king_rankno)*
		(white_king_rankno-black_king_rankno)+
		(white_king_fileno-black_king_fileno)*
		(white_king_fileno-black_king_fileno);
		value+=dist;
		if(pc->r==1) {
			/* This assists in krk, but supposedly does no harm even otherwise */
			rook_rankno=rankno_for_bit(pc->rsq[0]);
			rook_fileno=fileno_for_bit(pc->rsq[0]);
			ccorner_rankno=8;ccorner_fileno=8; /* Dummy values */
			if(white_king_rankno<rook_rankno){
				ccorner_rankno=0;
			} else if(white_king_rankno>rook_rankno){
				ccorner_rankno=7;
			}
			if(white_king_fileno<rook_fileno){
				ccorner_fileno=0;
			} else if(white_king_fileno>rook_fileno){
				ccorner_fileno=7;
			}
			if((ccorner_rankno<8)&&(ccorner_fileno<8)){
				value+=abs(ccorner_rankno-rook_rankno)*
					abs(ccorner_fileno-rook_fileno);
			} else {
				value+=50;
			}
		}
	}
	return value;
}

int evaluate_eg_pawn_structure(Board *brd, Piececalc *pc) {
	int i,fileno,rankno,value=0;

	/* White pawns */
	for(i=0;i<pc->P;i++){
		value+=Pe[077-pc->Psq[i]];
		fileno=fileno_for_bit(pc->Psq[i]);
		rankno=rankno_for_bit(pc->Psq[i]);
		if((adjacent_file_masks[7-fileno] &
			white_passed_pawn_masks[rankno] &
			(brd->P.whole | brd->p.whole))==BITBOARD_ZERO) {
			value+=PASSED_PAWN_BONUS*7/5;
		}
		if(brd->P.rows[rankno-1] & supporting_pawn_masks[7-fileno]){
			value+=SUPPORTED_PAWN_BONUS;
		}
		if(file_masks[7-fileno] &
			white_passed_pawn_masks[rankno] &
			brd->P.whole) {
			value-=DOUBLE_PAWN_PENALTY;
		}
	}

	/* Black pawns */
	for(i=0;i<pc->p;i++){
		value-=pe[077-pc->psq[i]];
		fileno=fileno_for_bit(pc->psq[i]);
		rankno=rankno_for_bit(pc->psq[i]);
		if((adjacent_file_masks[7-fileno] &
			black_passed_pawn_masks[rankno] &
			(brd->P.whole | brd->p.whole))==BITBOARD_ZERO) {
			value-=PASSED_PAWN_BONUS*7/5;
		}
		if(brd->p.rows[rankno+1] & supporting_pawn_masks[7-fileno]){
			value-=SUPPORTED_PAWN_BONUS;
		}
		if(file_masks[7-fileno] &
			black_passed_pawn_masks[rankno] &
			brd->p.whole) {
			value+=DOUBLE_PAWN_PENALTY;
		}
	}

	return value;
}

int evaluate_for_midgame(Board *brd, Piececalc *pc) {
	int value=0;
	value+=evaluate_dm(brd,pc);
	value+=evaluate_king_safety(brd,pc);
	value+=evaluate_pawn_structure(brd,pc);
	return value;
}

int evaluate_for_endgame(Board *brd, Piececalc *pc) {
	int value=0;
	value+=evaluate_eg_king_safety(brd,pc);
	value+=evaluate_eg_pawn_structure(brd,pc);
	return value;
}

int evaluate(Board *brd) {
	int max_piecevalues=0,midgame_value,endgame_value,value=0;
	Piececalc pc;

	/* First calculate two different values,
	 * one for midgame, one for endgame */
	value=evaluate_and_pick_material(brd,&pc);
	midgame_value=value+evaluate_for_midgame(brd,&pc);
	endgame_value=value+evaluate_for_endgame(brd,&pc);

	if(white_piecevalues(&pc)>black_piecevalues(&pc)){
		max_piecevalues=white_piecevalues(&pc);
	} else {
		max_piecevalues=black_piecevalues(&pc);
	}

	/* Then take weighted average of these values */
	if(max_piecevalues>=MIDGAME_LIMIT) {
		value=midgame_value;
	} else if(max_piecevalues<=ENDGAME_LIMIT) {
		value=endgame_value;
	} else {
		value=(midgame_value-endgame_value)*
			(max_piecevalues-ENDGAME_LIMIT)/
			(MIDGAME_LIMIT-ENDGAME_LIMIT)+
			endgame_value;
	}

	return value;
}

int evaluate_for_color(Board *brd){
	return (brd->whosmove=='w') ? evaluate(brd) : -evaluate(brd);
}

void zero_piececalc(Piececalc *aop) {
	aop->Q=0;aop->R=0;aop->B=0;aop->N=0;aop->P=0;
	aop->q=0;aop->r=0;aop->b=0;aop->n=0;aop->p=0;
}

int white_piecevalues(Piececalc *aop) {
	return(QUEEN_VALUE*aop->Q+
		ROOK_VALUE*aop->R+
		BISHOP_VALUE*aop->B+
		KNIGHT_VALUE*aop->N);
}

int black_piecevalues(Piececalc *aop) {
	return(QUEEN_VALUE*aop->q+
		ROOK_VALUE*aop->r+
		BISHOP_VALUE*aop->b+
		KNIGHT_VALUE*aop->n);
}
