#define EI(col,name)		(endgame += ((name)*sign[col]))
#define EPRI(col,sq,pcnt)	(endgame += PawnRank[RANK_COL(sq, colour)]*(pcnt)/100)

// RookEndgame() // TUNE ME

int Board::RookEndgame(Personality *p, PawnEntry *p_ent) {

	// material table collision
	if(piece[BISHOP] | piece[KNIGHT] | piece[QUEEN])			
		return (((PHASE_NB/2)*endgame + (PHASE_NB/2)*opening) / PHASE_NB);

	const int phase = 20; // PHASE_NB - 2*RookNb
	const int ALL_PAWNS_LEFT = 0, ALL_PAWNS_RIGHT = 1,
		SINGLE_PASSER_LEFT = 2, SINGLE_PASSER_RIGHT = 3,
		PAWN_EVERYWHERE = 4;
	const int intEighthRank[] = {RANK_8, RANK_1},
			  intSeventhRank[] = {RANK_7, RANK_2};
	const int KingDefenceBonus[] = {75, 75, 50, 50, 40};

	BitBoard wp = piece[PAWN] & Occupied(WHITE),	bp = piece[PAWN] & Occupied(BLACK),
			wr = piece[ROOK] & Occupied(WHITE),		br = piece[ROOK] & Occupied(BLACK),
			wk = piece[KING] & Occupied(WHITE),		bk = piece[KING] & Occupied(BLACK);

	// type of position
	int type;
	if((wp|bp) & RightSide == 0)						type = ALL_PAWNS_LEFT;
	else if((wp|bp) & LeftSide == 0)					type = ALL_PAWNS_RIGHT;
	else if(CountBits((wp|bp) & LeftSide) == 1)			type = SINGLE_PASSER_LEFT;
	else if(CountBits((wp|bp) & RightSide) == 1)		type = SINGLE_PASSER_RIGHT;
	else	type = PAWN_EVERYWHERE;

	BitBoard movers, forward, backward;
	int colour, sq, rsq, opp_rsq, qsq, pawn_rank, tmp, pass_nb[2], opp_ksq;
	pass_nb[WHITE] = pass_nb[BLACK] = 0;
	// passed pawns
	for(colour = WHITE; colour <= BLACK; colour++) {
		opp_ksq = ksq[colour^1];
		movers = p_ent->passed_pawns & Occupied(colour);
		rsq = FindFirstBit(piece[ROOK] & Occupied(colour));
		opp_rsq = FindFirstBit(piece[ROOK] & Occupied(colour^1));		
		while(movers) {
			pass_nb[colour] += 1;
			sq = ExtractFirstBit(movers);
			pawn_rank = RANK_COL(sq, colour); 
			forward = HalfOpenFileMask[colour][sq];
			backward = HalfOpenFileMask[colour^1][sq];			
			qsq = LastRankSquare[colour][File(sq)]; // queening square	

			// isolated king
			if(type != PAWN_EVERYWHERE) {
				// opp's king
				if((File(sq) < File(rsq) < File(opp_ksq))
				|| (File(sq) > File(rsq) > File(opp_ksq)))								EI(colour, 20);
				// friendly king
				if((File(sq) < File(opp_rsq) < File(ksq[colour]))
				|| (File(sq) > File(opp_rsq) > File(ksq[colour])))						EI(colour, -20);
			} 
			// isolated king (8th rank)
			if(Rank(opp_ksq) == intEighthRank[colour] 
			&& Rank(rsq) == intSeventhRank[colour])										EI(colour, 20);					
			// passed chain
			if(ChainPawnMask[colour][sq] & p_ent->passed_pawns & Occupied(colour)) {
				MTI(colour, OP_PASSED_CHAIN, EG_PASSED_CHAIN, RANK_COL(sq, colour));
				EPRI(colour, sq, 50);
				EI(colour, 30);
			}
			// our rook behind
			if(backward & piece[ROOK] & Occupied(colour))								EPRI(colour, sq, 40);
			// enemy rook behind
			if(backward & piece[ROOK] & Occupied(colour^1))								EPRI(colour, sq, -40);
			// friendly rook on 7th rank 
			if(Rank(rsq) == RANK_7 && pawn_rank == Rank(rsq))							EI(colour, 40);			
			// our king blocks pawn move
			if(forward & piece[KING] & Occupied(colour))								EPRI(colour, sq, -20);
			// friendly rook on 8th rank 
			if(pawn_rank == RANK_7 
			&& (forward & piece[ROOK] & Occupied(colour))
			&& (ATT_RANK(rsq, occupied) & ROOK_ATT(opp_ksq) & ~King[opp_ksq]) == 0)		EI(colour, -50);			
			// 'a' or 'h' file
			if(BIT(sq) & (FileA|FileH))													EPRI(colour, sq, -20);
			// active king
			if(pawn_rank >= RANK_4
			&& (BIT(ksq[colour]) & (CONTACT_FILES_BB(sq)|FILE_BB(sq)))
			&& SQUARE_DIST(qsq, ksq[colour]) < SQUARE_DIST(qsq, opp_ksq)-1)				EPRI(colour, sq, KingDefenceBonus[type]);
			// attacker - opponents king (further king => bigger our bonus) 
			tmp = sq + 8*sign[colour];
			ETIC(colour, EG_PASSED_PAWN_ATTACKER, RANK_COL(sq, colour), SQUARE_DIST(tmp, opp_ksq));
			ETIC(colour, EG_PASSED_PAWN_DEFENDER, RANK_COL(sq, colour), -SQUARE_DIST(tmp, ksq[colour]));				
		}
		// mobility
		tmp = CountFirstBits(ROOK_ATT(rsq));
		EI(colour, 3*tmp);	
		// rook attacks undefended pawns
		if(ROOK_ATT(rsq) & p_ent->weak_pawns & Occupied(colour^1))						EI(colour, 10);	
	}	

	// discounts
	// other side is empty
	if(type == ALL_PAWNS_LEFT || type == ALL_PAWNS_RIGHT)
		endgame = endgame * 80/100;
	// counter-attack
	if((pass_nb[WHITE] != 0 && pass_nb[BLACK] != 0))
		endgame = endgame * 70/100;
	// more pawns
	if(type == SINGLE_PASSER_LEFT || type == SINGLE_PASSER_RIGHT) {
		tmp = 100 + 2*CountBits(wp|bp);
		endgame = endgame * tmp/100;
	} // more blocked pawns
	if(type == SINGLE_PASSER_LEFT || type == SINGLE_PASSER_RIGHT) {
		tmp = 100 + 6*CountBits(BIT_UP(wp) & bp);
		endgame = endgame * tmp/100;
	} 	
	// 'h' & 'g' files
	if((type == ALL_PAWNS_LEFT || type == ALL_PAWNS_RIGHT)
	&& ((wp|bp) & (FileA|FileC|FileF|FileH)) == (wp|bp)) // hack 'a'+'c' and 'f'+'g' 
		endgame = endgame * 80/100;
	// bonuses
	// friendly king close to opponent's pawns
	if(type == SINGLE_PASSER_LEFT) {
		if((LeftSide & wp) 
		&& (RightSide & (wp|bp))
		&& (File(ksq[WHITE] > File(ksq[BLACK]))))		EI(WHITE, 30);
		else if((LeftSide & bp) 
		&& (RightSide & (wp|bp))
		&& (File(ksq[BLACK] > File(ksq[WHITE]))))		EI(BLACK, 30);
	} else if(type == SINGLE_PASSER_RIGHT) {
		if((RightSide & wp) 
		&& (LeftSide & (wp|bp))
		&& (File(ksq[WHITE] < File(ksq[BLACK]))))		EI(WHITE, 30);
		else if((RightSide & bp) 
		&& (LeftSide & (wp|bp))
		&& (File(ksq[BLACK] < File(ksq[WHITE]))))		EI(BLACK, 30);
	}
	// king zone
	if(wp & KingZone[BLACK][ ksq[BLACK] ])				EI(WHITE, -10);	
	if(bp & KingZone[WHITE][ ksq[WHITE] ])				EI(BLACK, -10);
		
	// we already have material and pawn values in 'opening' & 'endgame'	
	return ((phase * endgame + (PHASE_NB - phase) * opening) / PHASE_NB);	
}


// PawnEndgame() // TUNE ME

int Board::PawnEndgame(Personality *p, PawnEntry *p_ent) {

	// material table collision
	if(piece[BISHOP] | piece[KNIGHT] | piece[ROOK] | piece[QUEEN])			
		return (((PHASE_NB/2)*endgame + (PHASE_NB/2)*opening) / PHASE_NB);

	// init
	int colour, sq, rank, tmp;
	BitBoard wp = piece[PAWN] & Occupied(WHITE),	bp = piece[PAWN] & Occupied(BLACK),			
			 wk = piece[KING] & Occupied(WHITE),	bk = piece[KING] & Occupied(BLACK);
	BitBoard movers, mob, blocker, pawn_att[2] = {0, 0};	
	
	// passed pawns (squares)
	// hack: all to '0' = a1
	int passed_pair[2] = {0, 0},
		passed_chain[2] = {0, 0},
		super_chain[2] = {0, 0},
		unstop_passer[2] = {0, 0}, // rank (!)
		score[2] = {0, 0};

	// King zone penalty
	pawn_att[WHITE] = mob = BIT_UP_LEFT(wp) | BIT_UP_RIGHT(wp);
	if(((wp | mob) ^ mob) & KingZone[BLACK][ ksq[BLACK] ])			ESI(WHITE, EG_KING_ZONE_PENALTY);
	// tempo for black
	if(BIT_DOWN(bp) & ~(mob|wp|bp))									EI(BLACK, 15);
	// black pawns into the enemy king area
	pawn_att[BLACK] = mob = BIT_DOWN_LEFT(bp) | BIT_DOWN_RIGHT(bp);
	if(((bp | mob) ^ mob) & KingZone[WHITE][ ksq[WHITE] ])			ESI(BLACK, EG_KING_ZONE_PENALTY);
	// tempo for white
	if(BIT_UP(wp) & ~(mob|wp|bp))									EI(WHITE, 15);

	// KPK draw
	if(CountFirstBits(wp|bp) == 1) {
		if(wp) {
			if(BIT_TWO_UP(wk) & bk) { // opposition
				if((BIT_UP(wk) & wp)
				&& (stm == BLACK || (wp & ~SeventhRank[WHITE])))	return endgame = 0;				
				if(((BIT_LEFT(wk) & wp) || (BIT_RIGHT(wk) & wp))
				&& (stm == WHITE || (wp & ~SeventhRank[WHITE])))	return endgame = 0;
			} if((BIT_DOWN_LEFT(wp) & wk) && (BIT_UP(wp) & bk)) {
				if(stm == WHITE || (wp & ~SeventhRank[WHITE]))		return endgame = 0;
			} if((BIT_DOWN_RIGHT(wp) & wk) && (BIT_UP(wp) & bk)) {
				if(stm == WHITE || (wp & ~SeventhRank[WHITE]))		return endgame = 0;
			}			
		} else if(bp) {
			if(BIT_TWO_DOWN(bk) & wk) {
				if((BIT_DOWN(bk) & bp)
				&& (stm == WHITE || (bp & ~SeventhRank[BLACK])))	return endgame = 0;				
				if(((BIT_LEFT(bk) & bp) || (BIT_RIGHT(bk) & bp))
				&& (stm == BLACK || (bp & ~SeventhRank[BLACK])))	return endgame = 0;
			} if((BIT_UP_LEFT(bp) & bk) && (BIT_DOWN(bp) & wk)) {
				if(stm == BLACK || (bp & ~SeventhRank[BLACK]))		return endgame = 0;
			} if((BIT_UP_RIGHT(bp) & bk) && (BIT_DOWN(bp) & wk)) {
				if(stm == BLACK || (bp & ~SeventhRank[BLACK]))		return endgame = 0;
			}	
		}
	}
	
	// passed pawns
	bool passed_flag = false;
	for(colour = WHITE; colour <= BLACK; colour++) {		
		movers = p_ent->passed_pawns & Occupied(colour);
		while(movers) {			
			tmp = sq = ExtractFirstBit(movers);
			mob = HalfOpenFileMask[colour][sq];
			// opponent has no pieces (pawns only)
			if(mob & piece[KING])				tmp -= 8*sign[colour]; // blocker
			if(colour == stm)					tmp += 8*sign[colour]; // our tempo 
			if(RANK_COL(sq,colour) == RANK_2)	tmp += 8*sign[colour]; // a2-a4 instead of a2-a3
			if((UnstoppablePassed[colour][tmp] & piece[KING] & Occupied(colour^1))
			|| (KingAssist[colour][sq] & piece[KING] & Occupied(colour))) 
				unstop_passer[colour] = MAX(unstop_passer[colour], RANK_COL(tmp, colour) * 2); // *2 - moves to plies format
			else {
				tmp -= 8*sign[colour];
				blocker = (piece[PAWN] & Occupied(colour^1)) | KING_ATT(ksq[colour]) | (pawn_att[colour] & ~Pawn[colour][sq]);
				if((BIT(sq + 8*sign[colour]) & ~Occupied(colour^1)) 
				&& !(KING_ATT(ksq[colour^1]) & ~UnstoppablePassed[colour][tmp] & ~blocker)) {
					tmp += 8*sign[colour];					
					unstop_passer[colour] = MAX(unstop_passer[colour], RANK_COL(tmp, colour) * 2); // *2 - moves to plies format					
				}
			}

			// blockers
			if(!(mob & Occupied(colour)))							ETI(colour, EG_PASSED_PAWN_WO_OUR_BLOCKER, RANK_COL(sq, colour));
			if(!(mob & Occupied(colour^1)))							ETI(colour, EG_PASSED_PAWN_WO_OPP_BLOCKER, RANK_COL(sq, colour));
			
			// king assistance
			tmp = sq + 8*sign[colour];
			// attacker - opponents king (further king => bigger our bonus) 
			ETIC(colour, EG_PASSED_PAWN_ATTACKER, RANK_COL(sq, colour), SQUARE_DIST(tmp, ksq[colour^1]));
			ETIC(colour, EG_PASSED_PAWN_DEFENDER, RANK_COL(sq, colour), -SQUARE_DIST(tmp, ksq[colour]));

			// remote passer
			if((BIT(sq) & (FileA|FileB)) 
			&& !(((wp|bp) ^ BIT(sq)) & ~WingBB[KINGSIDE]))			EI(colour, 20);
			else if((BIT(sq) & FileA) 
			&& !(((wp|bp) ^ BIT(sq)) & ~RightSide))					EI(colour, 25);
			
			if((BIT(sq) & (FileH|FileG)) 
			&& !(((wp|bp) ^ BIT(sq)) & ~WingBB[QUEENSIDE]))			EI(colour, 20);
			else if((BIT(sq) & FileH) 
			&& !(((wp|bp) ^ BIT(sq)) & ~LeftSide))					EI(colour, 25);

			// passed chain
			if(ChainPawnMask[colour][sq] & movers) {
				passed_flag = true;
				// super chain (3 or more pawns) ?
				if((L_CONTACT_FILES_BB(sq) & King[sq] & p_ent->passed_pawns & Occupied(colour))
				&& (R_CONTACT_FILES_BB(sq) & King[sq] & p_ent->passed_pawns & Occupied(colour))) {					
					tmp = RANK_COL(sq, colour);
					if(tmp > RANK_COL(super_chain[colour], colour)
					|| !super_chain[colour])
						super_chain[colour] = sq;
				// passed chain (2 pawns)
				} else {
					tmp = RANK_COL(sq, colour);
					if(tmp > RANK_COL(passed_chain[colour], colour)
					|| !passed_chain[colour])
						passed_chain[colour] = sq;
				}
			}
			// passed pair (two passed pawns always win)
			if(PassedPair[colour][sq] & p_ent->passed_pawns & Occupied(colour)) {
				passed_flag = true;
				tmp = RANK_COL(sq, colour);
				if(tmp > RANK_COL(passed_pair[colour], colour)
				|| !passed_pair[colour])
					passed_pair[colour] = sq;
			}
		}
		// remote king
		if((piece[KING] & Occupied(colour) & WingBB[QUEENSIDE]) 
		&& !((wp|bp) & ~WingBB[KINGSIDE]))							EI(colour, 20);		
	}
	// pawn endings more valiable
	endgame = endgame * 160/100;

	// Scores:
	const int Unstoppable = 5;
	const int PassedPair = 5;
	const int SuperChain = 4;
	const int PassedChain = 2;
	const int SuperChainKingBonus = 2;
	const int ChainAbove5KingBonus = 3;
	const int SuperChainAbove5Bonus = 2;

	// unstoppable passer
	if(unstop_passer[WHITE] - unstop_passer[BLACK] + sign[stm ^ 1] >= 3)		score[WHITE] = Unstoppable + unstop_passer[WHITE]/2;
	else if(unstop_passer[BLACK] - unstop_passer[WHITE] + sign[stm] >= 3)		score[BLACK] = Unstoppable + unstop_passer[BLACK]/2;

	int chain_nb = 0;	
	for(colour = WHITE; (colour <= BLACK) && passed_flag; colour++) {	
		// superchain
		if(super_chain[colour]) { 
			rank = RANK_COL(super_chain[colour], colour);
			tmp = SuperChain + rank;
			if(rank > 5)														tmp += SuperChainAbove5Bonus;
			if(SQUARE_DIST(ksq[colour], super_chain[colour]) <= 1)				tmp += SuperChainKingBonus;
			score[colour] = MAX(score[colour], tmp);
		} // passed pair
		if(passed_pair[colour]) {
			rank = RANK_COL(passed_pair[colour], colour);
			tmp = PassedPair + rank;			
			score[colour] = MAX(score[colour], tmp);
		} // chain
		if(passed_chain[colour]) {
			rank = RANK_COL(passed_chain[colour], colour);
			tmp = PassedChain + rank;
			if((rank > 5) 
			&& (SQUARE_DIST(ksq[colour], passed_chain[colour]) <= 1))			tmp += ChainAbove5KingBonus;
			if(tmp > score[colour]) {
				score[colour] = tmp;
				chain_nb += 1;
			}
		}
	}
	// compute passed pawns info
	tmp = 10 * (MATH_SQUARE(score[WHITE]) - MATH_SQUARE(score[BLACK]));
	if(tmp > 400)	tmp = 400;
	if(tmp < -400)	tmp = -400;
	endgame += tmp;

	// two chains - draw
	if(chain_nb == 2
	&& (RANK_COL(ksq[WHITE], WHITE) <= RANK_3)
	&& (RANK_COL(ksq[BLACK], BLACK) <= RANK_3))	
		endgame = endgame * 20/100;
	else if(chain_nb == 2
	&& (RANK_COL(ksq[WHITE], WHITE) <= RANK_4)
	&& (RANK_COL(ksq[BLACK], BLACK) <= RANK_4))	
		endgame = endgame * 65/100;

	// combination
	if(wp & (A5|B5|C5) == (A5|B5|C5))									EI(WHITE, 30);
	if(wp & (F5|G5|H5) == (F5|G5|H5))									EI(WHITE, 30);
	if(bp & (A4|B4|C4) == (A4|B4|C4))									EI(BLACK, 30);
	if(bp & (F4|G4|H4) == (F4|G4|H4))									EI(BLACK, 30);
	
	return endgame;
}