#include "bitboard.h"
#include "bitsearch.h"
#include "biteval.h"
#include "bitpsq.h"
#include <stdlib.h>
#include <memory.h>

#define USE_SKILL

#define USE_NEWATTM

#ifdef USE_NEWATTM
#include "bitmagic.h"
#endif

#include "bitkpk.h"
#include "bitpersonality.h"

// use this to use pure material eval
//#define DISABLE_KNOWLEDGE

//#define DEBUG_TOUCHMATE

// use this to disable passed pawn bonuses
//#define DISABLE_PASSED_PAWNS

// scale scores according to non-pawn material left. gives very low score to KRKQ and so on
// seems to have 0 effect on performance, so I removed this (well scored 53% in 40 games, but still...)
// in second test, it only scored 35% in 10 games so I finally removed it. there seems to be a bug anyway...(?)
#define SCALE_SCORES

i32 lazyEvalMargin = 200;

i32 kingSafetyScale = 100;
i32 pawnShelterScale = 100;
i32 mobilityScale = 100;
i32 bishopPair = 2*250;

enum
{
	kingShieldMask = 1
};

// old (1.02) passed pawn bonuses
#define OLD_EVAL_PASSERS
// old->new eval blend
#define NEW_EVAL_LERP(o,n) ((((o)*0+(n)*256))/256)
// use "real" king->passed pawn dist (speculative => removed!)
//#define USE_REALDIST

// new rook behind passed pawn: no double bonus!
#define NEW_ROOKPASS

// use new evaluator
#define USE_NEW_EVAL
// hybrid_eval_pawn shield
#define PAWN_SHIELD_V2

// passed pawn dist eg shift (originally 2)
#define PASS_SH 0
// passed pawn opening scale
#define PASS_OP 0

#define TBSCALE 1

// debug eval cache collisions
//#define DEBUG_EVALCOLLISIONS
//#define DEBUG_EVALCACHE
//#define DEBUG_HASH U64C(0x7048be267b53c7d4)
#define DEBUG_HASH U64C(0x61d6897112c2ce51)

// ~unsafe
#define NUNSAFE		U64C(0xffffffffffffffff)
#define NUNSAFE_MOB U64C(0xffffffffffffffff)

enum
{
	useLazyEval		=	1
};

enum opening_pawn_value_penalty
{
    OPVAL = 0*75		// opening pawn value penalty
};

enum
{
	kpkWin		=		64000,			// orig. 64000
	rqWin		=		125000,			// orig. 125000
	touchMate	=		250000,			// orig. 125000
};

// material keys
static const u64 matBishopEndgameMask = 
	(U64C(63) << MATSHIFT( white, queen )) | (U64C(63) << MATSHIFT( black, queen )) |
	(U64C(63) << MATSHIFT( white, rook )) | (U64C(63) << MATSHIFT( black, rook )) |
	(U64C(63) << MATSHIFT( white, knight )) | (U64C(63) << MATSHIFT( black, knight ));
static const u64 matKPk = (U64C(1) << MATSHIFT( white, pawn ));
static const u64 matKkp = (U64C(1) << MATSHIFT( black, pawn ));
static const u64 matKNBk = (U64C(1) << MATSHIFT( white, knight )) | (U64C(1) << MATSHIFT( white, bishop ));
static const u64 matKknb = (U64C(1) << MATSHIFT( black, knight )) | (U64C(1) << MATSHIFT( black, bishop ));
static const u64 matKNNk = (U64C(2) << MATSHIFT( white, knight ));
static const u64 matKknn = (U64C(2) << MATSHIFT( black, knight ));
static const u64 matKPRkr = (U64C(1) << MATSHIFT( black, rook )) | (U64C(1) << MATSHIFT( white, rook )) | (U64C(1) << MATSHIFT( white, pawn ));
static const u64 matKRkpr = (U64C(1) << MATSHIFT( white, rook )) | (U64C(1) << MATSHIFT( black, rook )) | (U64C(1) << MATSHIFT( black, pawn ));
static const u64 matKnightOrBetterWhite =
	(U64C(63) << MATSHIFT( white, knight )) | (U64C(63) << MATSHIFT( white, bishop )) |
	(U64C(63) << MATSHIFT( white, rook )) | (U64C(63) << MATSHIFT( white, queen ));
static const u64 matKnightOrBetterBlack =
	(U64C(63) << MATSHIFT( black, knight )) | (U64C(63) << MATSHIFT( black, bishop )) |
	(U64C(63) << MATSHIFT( black, rook )) | (U64C(63) << MATSHIFT( black, queen ));
static const u64 matRookOrBetterWhite = (U64C(63) << MATSHIFT( white, rook )) | (U64C(63) << MATSHIFT( white, queen ));
static const u64 matRookOrBetterBlack =	(U64C(63) << MATSHIFT( black, rook )) | (U64C(63) << MATSHIFT( black, queen ));
static const u64 matLoneKingWhiteMask = (U64C(63) << MATSHIFT( white, pawn )) | 
	(U64C(63) << MATSHIFT( white, knight )) | (U64C(63) << MATSHIFT( white, bishop )) |
	(U64C(63) << MATSHIFT( white, rook )) | (U64C(63) << MATSHIFT( white, queen ));
static const u64 matLoneKingBlackMask = (U64C(63) << MATSHIFT( black, pawn )) | 
	(U64C(63) << MATSHIFT( black, knight )) | (U64C(63) << MATSHIFT( black, bishop )) |
	(U64C(63) << MATSHIFT( black, rook )) | (U64C(63) << MATSHIFT( black, queen ));

/*
	PAWN TABLES
*/

i32 bwdOpening		=		NEW_EVAL_LERP(20, 20);
i32 bwdEndgame		=		NEW_EVAL_LERP(25, 25);
i32 isoOpening		=		NEW_EVAL_LERP(80, 37);			// orig. 80, 37 best so far
i32 isoEndgame		=		NEW_EVAL_LERP(100, 76);			// orig. 100, 76 best so far
i32 dblOpening		=		NEW_EVAL_LERP(200, 78);			// orig. 200, 78 best so far
i32 dblEndgame		=		NEW_EVAL_LERP(150, 150);			// orig. 150, 150 best so far (*results varied a lot here, a different value might be better)

static const i32 kingMateTab[8] = {
    0, 0, 200, 150, 100, 50, -100, -200,
};

static const i32 kingCenterTab[ 64 ] = {
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 1, 1, 1, 1, 1, 1, 0,
    0, 1, 2, 2, 2, 2, 1, 0,
    0, 1, 2, 3, 3, 2, 1, 0,
    0, 1, 2, 3, 3, 2, 1, 0,
    0, 1, 2, 2, 2, 2, 1, 0,
    0, 1, 1, 1, 1, 1, 1, 0,
    0, 0, 0, 0, 0, 0, 0, 0
};

static const i32 knbTable[64] = {
    +999, +500, +250, +100, -100, -250, -500, -999,
    +500, +400, +250, +100, -100, -250, -400, -500,
    +250, +250, +150, + 80, - 80, -150, -250, -250,
    +100, +100, + 80, + 50, - 50, - 80, -100, -100,
    -100, -100, - 80, - 50, + 50, + 80, +100, +100,
    -250, -250, -150, - 80, + 80, +150, +250, +250,
    -500, -400, -250, -100, +100, +250, +400, +500,
    -999, -500, -250, -100, +100, +250, +500, +999
};

#define USE_EVAL_CACHE

#ifdef USE_EVAL_CACHE
enum eval_maximum
{
    evalMax = 1048576
};

#ifndef USE_NEW_EVAL
static u64 evalHash[ evalMax ] = { 0 };
static i16 evalVal[ evalMax ] = { 0 };
static u8 evalFlags[ evalMax ] = { 0 };
#endif

#ifdef DEBUG_EVALCOLLISIONS
static BitBoard evalBoard[ evalMax ];
#endif

#endif

static u64 growBits( const u64 &m )
{
    // FIXME: stupid?!
    return
        m |
        ((m << 1) & L1MASK) |
        ((m >> 1) & R1MASK) |
        (m << 8) |
        (m >> 8) |
        ((m << 9) & L1MASK) |
        ((m << 7) & R1MASK) |
        ((m >> 9) & R1MASK) |
        ((m >> 7) & L1MASK);
}

// real distance to passed pawn
i32 BitEval::realDist( i8 turn, u8 kp, u8 pp, const u64 &blocked )
{
////	i8 dmat[64];		// distance matrix
    u64 processed = 0;
    const u64 &ppm = ONESHL( pp );

    if ( !levBuilt[ turn ] )
    {
        u64 k = ONESHL( kp );
        processed = levels[ turn ][ 0 ] = growBits( k ) & ~blocked;
        i8 lev = 0;
        while ( lev < 9 && !(processed & ppm) )
        {
            // iterate...
            ++lev;
            levels[ turn ][ lev ] = growBits( levels[ turn ][lev-1] ) & ~blocked;
            if ( !levels[ turn ][lev] || levels[ turn ][lev] == levels[ turn ][lev-1] )
            {
                for (;lev < 10; lev++)
                {
                    levels[ turn ][ lev ] = 0;
                }
                break;
            }
            processed |= levels[ turn ][ lev ];
        }
        levBuilt[ turn ] = 1;
    }

    i8 i;
    for (i=0; i<10; i++)
    {
        if ( levels[ turn ][ i ] & ppm )
        {
            break;
        }
    }
    return 1+i;
}

i32 BitSearch::eval( const BitBoard &cb, i32 alpha, i32 beta )
{
    // TODO/FIXME: implement!
    evals++;
#ifdef USE_NEW_EVAL
    i32 res = evaluator->eval( cb, alpha, beta );
//	res = (res+4)/5*5;
//	res = res * (101-cb.flags().fiftyCounter) / 101;

    return res;
#else
#error old eval no longer supported
#endif
}

// NEW_EVALUATOR_CODE

// BitEval

// unfortunately lazy eval really doesn't work for me
// well... seems equal in one test after 100 games. So I think it could work but needs MUCH more testing! so keeping...
// hmmm with LE scores 296 vs 295 without... so keeping
// NO! seems like a disaster against TCB!
BitEval::BitEval( i32 evalCacheSizeBytes ) : evalCacheSize(0), evalHash(0), evalScore(0), debugFlag(0),
        pawnHash(0), pawnHashSize(0), kpkEval(0),
        skill(100)
{
    kpkEval = new BitKPK;
////	kpkEval->generate();	// new: integrated into code!
    memset( &tphash, 0, sizeof(tphash) );
    pawns = &tphash;
    bonusTable = &bonusTablePSQ;	//gbonusTable;
    pawnHashSize = evalCacheSizeBytes/2 / sizeof(BitPawnHash);
    evalCacheSize = evalCacheSizeBytes/2 / 14;
    if ( evalCacheSize < 0 )
        evalCacheSize = 0;
    if ( pawnHashSize < 0 )
        pawnHashSize = 0;
    if ( evalCacheSize )
    {
        evalHash = new u64[ evalCacheSize ];
        if ( !evalHash )
        {
            evalCacheSize = 0;
        }
        else
        {
	    memset( evalHash, 0, evalCacheSize * sizeof(u64) );
            evalScore = new i16[ 3*evalCacheSize ];
            if ( !evalScore )
            {
                delete[] evalHash;
                evalHash = 0;
                evalCacheSize = 0;
            } else memset( evalScore, 0, evalCacheSize*3*sizeof(i16) );
        }
    }
    if ( pawnHashSize )
    {
        pawnHash = new BitPawnHash[ pawnHashSize ];
        if ( !pawnHash )
        {
            pawnHashSize = 0;
        }
        else
        {
            memset( pawnHash, 0, pawnHashSize * sizeof( BitPawnHash ) );
        }
    }
}

BitEval::~BitEval()
{
    if ( evalHash )
    {
        delete[] evalHash;
    }
    if ( evalScore )
    {
        delete[] evalScore;
    }
    if ( pawnHash )
    {
        delete[] pawnHash;
    }
    delete kpkEval;
}

#if defined(DEBUG) || defined(_DEBUG)
#define DEBUG_FLAG_STAGE( str ) if ( debugFlag )	\
{	\
	logFmt("score %s [0]=%d [1]=%d\n", str, score[0], score[1] );	\
}
#else
#define DEBUG_FLAG_STAGE( str )
#endif

const u64 AFILE =
    (U64C(1) << A1) |
    (U64C(1) << A2) |
    (U64C(1) << A3) |
    (U64C(1) << A4) |
    (U64C(1) << A5) |
    (U64C(1) << A6) |
    (U64C(1) << A7) |
    (U64C(1) << A8);

const u64 HFILE =
    (U64C(1) << H1) |
    (U64C(1) << H2) |
    (U64C(1) << H3) |
    (U64C(1) << H4) |
    (U64C(1) << H5) |
    (U64C(1) << H6) |
    (U64C(1) << H7) |
    (U64C(1) << H8);

i32 pawnSafetyWgt		=		NEW_EVAL_LERP(2, 7);		// originally 2	(7 = best so far) (* >8 might be better)
i32	knightSafetyWgt		=		NEW_EVAL_LERP(3, 7);		// originally 3	(7 = best so far) (* >8 might be better)
i32	bishopSafetyWgt		=		NEW_EVAL_LERP(3, 8);		// originally 3	(8 = best so far)
i32	rookSafetyWgt		=		NEW_EVAL_LERP(4, 12);		// originally 4 (12 = best so far)
i32	queenSafetyWgt		=		NEW_EVAL_LERP(5, 10);		// originally 5 (10 = best so far)

i32 BitEval::eval( const BitBoard &b, i32 alpha, i32 beta )
{
/*	{
		board = &b;
        i32 matEval =
            board->mat().dmat;
		{
			i32 score[2] = { matEval*10, matEval*10 };
			u64 all = board->bits[wall];
			while( all )
			{
				i8 pos = popLSB(all);
				i8 piece = board->pieces[ pos ] & 127;
				score[0] += bonusTablePSQ[0][ white ][ piece ][ pos ]; score[1] += bonusTablePSQ[1][ white ][ piece ][ pos ];
			}
			all = board->bits[ball];
			while( all )
			{
				i8 pos = popLSB(all);
				i8 piece = board->pieces[ pos ] & 127;
				score[0] -= bonusTablePSQ[0][ black ][ piece ][ pos ]; score[1] -= bonusTablePSQ[1][ black ][ piece ][ pos ];
			}
			const BitMat &bm = board->mat();
			i32 scale = 256 * (bm.tmat - 2200) / (6550 - 2200);
			if ( scale < 0 )
				scale = 0;
			else if ( scale > 256 )
				scale = 256;

			matEval = (score[1] + (scale * (score[0] - score[1]) >> 8))/10;
		}
        if ( board->flags().turn == black )
        {
            matEval = -matEval;
        }
		return matEval;
	}*/
    // probe cache first
    i32 hi = evalCacheSize ? (i32)((u32)b.bits[ bhash ] % evalCacheSize) : -1;
    u64 *ecHash = hi >= 0 ? evalHash + hi : 0;
    i16 *ecScore = hi >= 0 ? evalScore + hi*3 : 0;

    if ( !debugFlag && hi >= 0 && b.bits[ bhash ] == *ecHash )
    {
        safetyEval[0] = ecScore[1];
        safetyEval[1] = ecScore[2];
        return *ecScore;
    }

    board = &b;
    const BitMat &bm = b.mat();
    const BitFlags &bf = b.flags();
    turn = bf.turn;
    check = bf.check;
    i32 sc = bm.dmat;

#ifdef DISABLE_KNOWLEDGE
    return (turn == black ? -sc : sc) / 10;
#endif

    if ( useLazyEval )
    {
		i32 stage = board->stage();
		if ( /*!check &&*/ stage < 2 )
        {
            if ( turn == white )
            {
                if ( sc + lazyEvalMargin < alpha || sc - lazyEvalMargin > beta )
                {
                    return sc;
                }
            }
            else
            {
                if ( -sc + lazyEvalMargin < alpha || -sc - lazyEvalMargin > beta )
                {
                    return -sc;
                }
            }
            /*			if ( sc + lazyEvalMargin < 10*alpha || sc - lazyEvalMargin > 10*beta )
            			{
            				return (turn == black ? -sc : sc) / 10;
            			}*/
        }
    }

    sc *= 10;

    u8 whpair = bm.pair[ white ];			// white has a bishop pair (FIXME: assume on different colors, which is ok as long as there's no underpromotion)
    u8 blpair = bm.pair[ black ];			// black has a bishop pair (FIXME: assume on different colors)

    // new: bishop pair really seems to be stronger!
    if ( whpair & bpair )
    {
        sc += bishopPair;
    }
    if ( blpair & bpair )
    {
        sc -= bishopPair;
    }

    // probe pawn cache
    i32 phi = pawnHashSize ? (i32)((u32)b.bits[ bpawnhash ] % pawnHashSize) : -1;
    pawns = phi >= 0 ? pawnHash + phi : &tphash;
    tphash.hash = 0;

    score[0] = score[1] = sc;

    const BitFlags &f = board->flags();

#if defined(DEBUG) || defined(_DEBUG)
	{
		int i;
		for (i=pawn; i<king; i++)
		{
			ASSERT( ((board->bits[ bmathash ] >> MATSHIFT( white, i )) & 63) == bitCount( board->bits[ INDEX( white, i ) ] ) );
			ASSERT( ((board->bits[ bmathash ] >> MATSHIFT( black, i )) & 63) == bitCount( board->bits[ INDEX( black, i ) ] ) );
		}
	}
#endif

	ASSERT( kpkEval );
	const u64 &matHash = board->bits[ bmathash ];
	// potential_kpk...
	if ( matHash == matKkp )
	{
		// kkp
		i32 sc = kpkEval->probe( b ) * kpkWin;
		if ( sc == 0 )
		{
			if ( hi >= 0 )
			{
				*ecHash = b.bits[ bhash ];
				*ecScore = 0;
				ecScore[1] = ecScore[2] = 0;
			}
			return 0;
		}
		if ( turn == black )
			sc = -sc;
		score[0] += sc;
		score[1] += sc;

	}
	else if ( matHash == matKPk )
	{
		// kpk
		i32 sc = kpkEval->probe( b ) * kpkWin;
		if ( sc == 0 )
		{
			if ( hi >= 0 )
			{
				*ecHash = b.bits[ bhash ];
				*ecScore = 0;
				ecScore[1] = ecScore[2] = 0;
			}
			return 0;
		}
		if ( turn == black )
			sc = -sc;
		score[0] += sc;
		score[1] += sc;
	}

    tmat[ white ] = bm.wtmat;
    ASSERT( bm.wtmat ==
            tmatTab[ knight ] * bitCount( board->bits[ wknight ] ) +
            tmatTab[ bishop ] * bitCount( board->bits[ wbishop ] ) +
            tmatTab[ rook ] * bitCount( board->bits[ wrook ] ) +
            tmatTab[ queen ] * bitCount( board->bits[ wqueen ] ) );
    tmat[ black ] = bm.tmat - tmat[ white ];

    kingMask[ white ] = ONESHL( f.kingPos[white] );
    kingMask[ black ] = ONESHL( f.kingPos[black] );

    levBuilt[ white ] = levBuilt[ black ] = 0;

    all = board->bits[wall] | board->bits[ball];

    memset( attackMask, 0, sizeof(attackMask) );
    passedPawnMask[0] = passedPawnMask[1] = 0;

    safetyEval[0] = safetyEval[1] = 0;

    attackerCount[0] = attackerCount[1] = 0;
    attackerScale[0] = attackerScale[1] = 0;

    cantIntercept[0] = cantIntercept[1] = 0;

    allAttackMask[ white ] = attackMask[ white ][ king ] = safetyMask[ white ] = kingMov[ f.kingPos[white] ];
    safetyMask[ white ] |= safetyMask[white] >> 8;

    allAttackMask[ black ] = attackMask[ black ][ king ] = safetyMask[ black ] = kingMov[ f.kingPos[black] ];
    safetyMask[ black ] |= safetyMask[black] << 8;

    // white pawns' attack mask:
    {
        u64 b = board->bits[ wpawn ];
        if ( b )
        {
            u64 atm = ((b >> 9) & R1MASK) | ((b >> 7) & L1MASK);
            attackMask[ white ][ pawn ] = atm;
            allAttackMask[ white ] |= atm;

            i32 ac = bitCount( atm & safetyMask[ black ] );
            if ( ac )
            {
                attackerCount[ black ] += ac;
                attackerScale[ black ] += 2 * ac;
            }

            ac = bitCount( (b >> 8) & ~all );
            {
                // pawn_can_advance bonus
                score[0] += ac*10;
                score[1] += ac*15;
            }
        }
    }

    // white pawns' attack mask:
    {
        u64 b = board->bits[ bpawn ];
        if ( b )
        {
            u64 atm = ((b << 9) & L1MASK) | ((b << 7) & R1MASK);
            attackMask[ black ][ pawn ] = atm;
            allAttackMask[ black ] |= atm;

            i32 ac = bitCount( atm & safetyMask[ white ] );
            if ( ac )
            {
                attackerCount[ white ] += ac;
                attackerScale[ white ] += 2 * ac;
            }
            ac = bitCount( (b << 8) & ~all );
            {
                // pawn_can_advance bonus
                score[0] -= ac*10;
                score[1] -= ac*15;
            }
        }
    }

    rookOrBetter[ white ] = board->bits[ wrook ] | board->bits[ wqueen ];
	knightOrBetter[ white ] = rookOrBetter[ white ] | board->bits[ wknight ] | board->bits[ wbishop ];
	rookOrBetter[ black ] = board->bits[ brook ] | board->bits[ bqueen ];
	knightOrBetter[ black ] = rookOrBetter[ black ] | board->bits[ bknight ] | board->bits[ bbishop ];

//	rookOrBetter[ white ] = matHash & matRookOrBetterWhite;
	ASSERT( (rookOrBetter[white]!=0) == ((board->bits[ wrook ] | board->bits[ wqueen ])!=0) );
//    rookOrBetter[ black ] = matHash & matRookOrBetterBlack;
	ASSERT( (rookOrBetter[black]!=0) == ((board->bits[ brook ] | board->bits[ bqueen ])!=0) );
//    knightOrBetter[ white ] = matHash & matKnightOrBetterWhite;
	ASSERT( (knightOrBetter[white]!=0) == ((rookOrBetter[ white ] | board->bits[ wknight ] | board->bits[ wbishop ])!=0) );
//    knightOrBetter[ black ] = matHash & matKnightOrBetterBlack;
	ASSERT( (knightOrBetter[black]!=0) == ((rookOrBetter[ black ] | board->bits[ bknight ] | board->bits[ bbishop ])!=0) );

    loneKing[white] = !(matHash & matLoneKingWhiteMask);
	ASSERT( loneKing[white] == (!tmat[white] && !board->bits[ wpawn ]) );
    loneKing[black] = !(matHash & matLoneKingBlackMask);
	ASSERT( loneKing[black] == (!tmat[black] && !board->bits[ bpawn ]) );

//	u8 pos[64];
//	i32 npos;
//	i32 i;
    u64 _m;

    DEBUG_FLAG_STAGE( "before evalPawns" );

    const u64 &ph = board->bits[ bpawnhash ];
    if ( pawns->hash == ph )
    {
        score[0] += pawns->score[0];
        score[1] += pawns->score[1];
        passedPawnMask[ white ] = board->bits[ wpawn ] & pawns->passed;
        passedPawnMask[ black ] = board->bits[ bpawn ] & pawns->passed;
    }
    else
    {
        pawns->hash = ph;
        pawns->score[0] = score[0];
        pawns->score[1] = score[1];

        // slow eval pawns
        _m = board->bits[wpawn];
        while ( _m )
        {
            whitePawnHashed( popLSB( _m ) );
        }
        _m = board->bits[bpawn];
        while ( _m )
        {
            blackPawnHashed( popLSB( _m ) );
        }
        // convert to relative score
        pawns->score[0] = score[0] - pawns->score[0];
        pawns->score[1] = score[1] - pawns->score[1];
        pawns->passed = passedPawnMask[ white ] | passedPawnMask[ black ];
    }

    // eval pawns
    _m = passedPawnMask[ white ];
    /*	i32 cpassers = bitCount( _m & ((_m >> 1) & R1MASK) );
    	score[0] += cpassers * 750;
    	score[1] += cpassers * 1500;*/
    while ( _m )
    {
        whitePassedPawn( popLSB( _m ) );
    }
    _m = passedPawnMask[ black ];
    /*	cpassers = bitCount( _m & ((_m >> 1) & R1MASK) );
    	score[0] -= cpassers * 750;
    	score[1] -= cpassers * 1500;*/
    while ( _m )
    {
        blackPassedPawn( popLSB( _m ) );
    }
    DEBUG_FLAG_STAGE( "before evalKnights" );

    // eval knights
    _m = board->bits[wknight];
    while ( _m )
    {
        whiteKnight( popLSB( _m ) );
    }

    DEBUG_FLAG_STAGE( "afeter evalWhiteKnight" );

    _m = board->bits[bknight];
    while ( _m )
    {
        blackKnight( popLSB( _m ) );
    }

    DEBUG_FLAG_STAGE( "before evalBishops" );

    // eval bishops
    _m = board->bits[wbishop];
    while ( _m )
    {
        whiteBishop( popLSB( _m ) );
    }
    _m = board->bits[bbishop];
    while ( _m )
    {
        blackBishop( popLSB( _m ) );
    }

    _m = board->bits[wrook];
    while ( _m )
    {
        whiteRook( popLSB( _m ) );
    }
    _m = board->bits[brook];
    while ( _m )
    {
        blackRook( popLSB( _m ) );
    }

    _m = board->bits[wqueen];
    while ( _m )
    {
        whiteQueen( popLSB( _m ) );
    }
    _m = board->bits[bqueen];
    while ( _m )
    {
        blackQueen( popLSB( _m ) );
    }

    whiteKing( f.kingPos[ white ] );
    blackKing( f.kingPos[ black ] );

	if ( !(tmat[white] | tmat[black] ) )
	{
		// pawn ending, the side with a pawn up usually wins. used to avoid to enter lost pawn endgames
		i32 bcw = bitCount( board->bits[wpawn] );
		i32 bcb = bitCount( board->bits[bpawn] );
		if ( bcw != bcb )
		{
			if ( bcw > bcb )
				score[1] += 1000;
			else 
				score[1] -= 1000;
		}
	}

    customEval();

#ifdef SCALE_SCORES
    {
		u8 pawnLess[2] = { !board->bits[ wpawn ], !board->bits[ bpawn ] };
		u8 noPawns = pawnLess[ white ] & pawnLess[ black ];
        if ( pawnLess[white] | pawnLess[black] )
        {
            if ( abs( tmat[ white ] - tmat[ black ] ) <= tmatTab[ bishop ]
            && !(board->bits[ wqueen ] | board->bits[ bqueen ]))
            {
				if ( noPawns || (score[1] < 0 && pawnLess[black]) || (score[1] > 0 && pawnLess[white] ) )
				{
					// most likely a draw
					score[0] >>= 5;
					score[1] >>= 5;
				}
            }
            /*			else
            			{
            				if ( tmat[white] + tmat[black] <= 2 * tmatTab[ queen ] )
            				{
            					// try lessen score for KQKR endgame...
            					if ( board->bits[ wqueen ] && board->bits[ brook ] )
            					{
            						score[0] >>= 4;
            						score[1] >>= 4;
            					}
            					else
            					if ( board->bits[ bqueen ] && board->bits[ wrook ] )
            					{
            						score[0] >>= 4;
            						score[1] >>= 4;
            					}
            				}
            			}*/
        }
    }
#endif

    i32 scale = 256 * (bm.tmat - 2200) / (6550 - 2200);
    if ( scale < 0 )
        scale = 0;
    else if ( scale > 256 )
        scale = 256;

    sc = score[1] + (scale * (score[0] - score[1]) >> 8);

    // do_special_eval
    if ( !loneKing[white] || !loneKing[black] )
    {
        if ( bm.dmat < 0 && loneKing[white] )
        {
            // bonus for king_proximity to enemy king
            sc -= kingMateTab[ kdistTab[ f.kingPos[white] ][ f.kingPos[black] ] ];
            sc += kingCenterTab[ f.kingPos[white] ] * 100;
#if 1
            if ( rookOrBetter[black] && !(board->bits[ ball ] & (
                                              kingMov[ f.kingPos[white] ] & ~kingMov[ f.kingPos[black] ]) ) )
            {
                // this is a position we can win
                /*				u64 t = kingMov[ f.kingPos[white] ];
                				t &= ~allAttackMask[ black ];
                				if ( t )*/
                {
                    sc -= rqWin;
                }
            }
            /*			else
            			{
            				u64 t;
            				if ( (t = board->bits[ bpawn ]) != 0 )
            				{
            					if ( !((t << 8) & ~all) )
            					{
            						// pawns can't advance!
            						if ( !rookOrBetter[ black ] && tmat[ black ] <= tmatTab[ bishop ] )
            						{
            							sc = 0;
            						}
            					}
            				}
            			}*/
#endif
        }
        if ( bm.dmat > 0 && loneKing[black] )
        {
            // bonus for king_proximity to enemy king
            sc += kingMateTab[ kdistTab[ f.kingPos[white] ][ f.kingPos[black] ] ];
            sc -= kingCenterTab[ f.kingPos[black] ] * 100;
#if 1
            u8 kp, ekp;
            if ( rookOrBetter[white] && !(board->bits[ wall ] & (
                                              kingMov[ f.kingPos[black] ] &~ kingMov[ f.kingPos[white] ]) ) )
            {
                /*				u64 t = kingMov[ f.kingPos[black] ];
                				t &= ~allAttackMask[ white ];
                				if ( t )*/
                {
                    // this is a position we can win
                    sc += rqWin;
                    /*					BitBoard tb(*board);
                    					tb.dump();*/
                }
            }
            /*			else
            			{
            				u64 t;
            				if ( (t = board->bits[ wpawn ]) != 0 )
            				{
            					if ( !((t >> 8) & ~all) )
            					{
            						// pawns can't advance!
            						if ( !rookOrBetter[ white ] && tmat[ white ] <= tmatTab[ bishop ] )
            						{
            							sc = 0;
            						}
            					}
            				}
            			}*/
#endif
        }
    }

	if ( bm.dmat > 0 )
	{
		// white
		if ( matHash == matKNNk )
		{
             sc = 0;
		}
		else if ( matHash == matKNBk )
		{
			// must deliver mate in the corner of the same color as white's bishop
			bool blackCorner = !(board->bits[ wbishop ] & WSQUARES);
			sc += knbTable[ f.kingPos[black] ] * (blackCorner ? -2 : +2);
		}
		else if ( matHash == matKPRkr )
		{
			// krkrp ending
			u8 ppos = getLSB( board->bits[ wpawn ] );
			u8 dkp = f.kingPos[ black ];
			if ( (dkp >> 3) < (ppos >> 3) )
			{
				// king in front of pawn => potential draw
				if ( sideCoverMask[black][dkp] & board->bits[ wpawn ] )
				{
					sc >>= 5;
				}
			}
		}
	}
	else
	{
		// black
		if ( matHash == matKknn )
		{
			sc = 0;
		}
		else if ( matHash == matKknb )
		{
			bool blackCorner = !(board->bits[ bbishop ] & WSQUARES);
			sc -= knbTable[ f.kingPos[white] ] * (blackCorner ? -2 : +2);
		}
		else if ( matHash == matKRkpr )
		{
			// krkrp ending
			u8 ppos = getLSB( board->bits[ bpawn ] );
			u8 dkp = f.kingPos[ white ];
			if ( (dkp >> 3) > (ppos >> 3) )
			{
				// king in front of pawn => potential draw
				if ( sideCoverMask[white][dkp] & board->bits[ bpawn ] )
				{
					sc >>= 5;
				}
			}
		}
	}
#if 0
    if ( (loneKing[white] || loneKing[black]) && (bm.tmat <= tmatTab[ knight ] + tmatTab[ bishop ]) )
    {
        // eval knbk endgame
        // knight count for each side
        i8 knightCount[2] = { bitCount( board->bits[ wknight ] ), bitCount( board->bits[ bknight ] ) };
        // bishop count for each side
        i8 bishopCount[2] = { bitCount( board->bits[ wbishop ] ), bitCount( board->bits[ bbishop ] ) };
        if ( loneKing[black] )
        {
            // black is a lone king
            if ( knightCount[ white ] == 2 && !board->bits[ wpawn ] )
            {
                // white has knnk => assume draw (checkmate cannot be forced)
				ASSERT( matHash == matKNNk );
                sc = 0;
            }
            else
                if ( bishopCount[ white ] == 1 && knightCount[ white ] == 1 )
                {
					ASSERT( matHash == matKNBk );
                    // must deliver mate in the corner of the same color as white's bishop
                    bool blackCorner = !(board->bits[ wbishop ] & WSQUARES);
                    sc += knbTable[ f.kingPos[black] ] * (blackCorner ? -2 : +2);
                }
        }
        else
            if ( loneKing[white] )
            {
                // white is a lone king
                if ( knightCount[ black ] == 2 && !board->bits[ bpawn ] )
                {
                    // black has knnk => assume draw (checkmate cannot be forced)
					ASSERT( matHash == matKknn );
                    sc = 0;
                }
                else
                    if ( bishopCount[ black ] == 1 && knightCount[ black ] == 1 )
                    {
                        // must deliver mate in the corner of the same color as black's bishop
						ASSERT( matHash == matKknb );
                        bool blackCorner = !(board->bits[ bbishop ] & WSQUARES);
                        sc -= knbTable[ f.kingPos[white] ] * (blackCorner ? -2 : +2);
                    }
            }
    }
#endif

#ifndef SCALE_SCORES
    // endgame => final eval better for me?
    // lone king, king + bishop, king + knight
    // note: see stamma's mate (wiki) (?! ok ?!)
    if ( bm.tmat <= tmatTab[ knight ] )
    {
        if ( !board->bits[ wpawn ] && sc > 0 )
        {
            // white has no pawns and because of low material conditions can't win!
            sc = -100;
        }
        if ( !board->bits[ bpawn ] && sc < 0 )
        {
            // black has no pawns and because of low material conditions can't win!
            sc = +100;
        }
    }
#endif

    // new blind bishop check
    if ( loneKing[ black ] )
    {
		if ( turn == black && !board->flags().check )
		{
			u8 kp = board->flags().kingPos[ black ];
			u8 ekp = board->flags().kingPos[ white ];
			u64 t = kingMov[ kp ];
			t &= ~kingMov[ekp];
			t &= ~allAttackMask[ white ];
			if ( !t )
			{
				sc = 0;
			}
		}
        if ( tmat[ white ] <= tmatTab[ bishop ] )
        {
            const u64 &mybishops = board->bits[ wbishop ];

            if ( mybishops )
            {
                const u64 &mypawns = board->bits[ wpawn ];
                // white has a bishop
                bool whiteBishop = (mybishops & WSQUARES) != 0;
                if ( whiteBishop )
                {
                    if ( !(mypawns & ~HFILE) && (mypawns & HFILE ) )
                    {
                        sc = 0;			// blind bishop
                        // FIXME: what if king is out of range?!
                    }
                }
                else
                {
                    if ( !(mypawns & ~AFILE) && (mypawns & AFILE ) )
                    {
                        sc = 0;			// blind bishop
                        // FIXME: what if king is out of range?!
                    }
                }
            }
        }
    }
    else if ( loneKing[ white ] )
    {
		if ( turn == white && !board->flags().check )
		{
			u8 kp = board->flags().kingPos[ white ];
			u8 ekp = board->flags().kingPos[ black ];
			u64 t = kingMov[ kp ];
			t &= ~kingMov[ekp];
			t &= ~allAttackMask[ black ];
			if ( !t )
			{
				sc = 0;
			}
		}
        if ( tmat[ black ] <= tmatTab[ bishop ] )
        {
            const u64 &mybishops = board->bits[ bbishop ];

            if ( mybishops )
            {
                const u64 &mypawns = board->bits[ bpawn ];
                // white has a bishop
                bool whiteBishop = (mybishops & WSQUARES) != 0;
                if ( whiteBishop )
                {
                    if ( !(mypawns & ~AFILE) && (mypawns & AFILE ) )
                    {
                        sc = 0;			// blind bishop
                        // FIXME: what if king is out of range?!
                    }
                }
                else
                {
                    if ( !(mypawns & ~HFILE) && (mypawns & HFILE ) )
                    {
                        sc = 0;			// blind bishop
                        // FIXME: what if king is out of range?!
                    }
                }
            }
        }
    }

#if 0
	// new: bishop endgame with opposite bishops
	if ( !(matHash & matBishopEndgameMask) )
	{
		const u64 &wb = board->bits[ wbishop ];
		const u64 &bb = board->bits[ bbishop ];
		if ( wb && bb )
		{
			if ( wb & WSQUARES )
			{
				if ( !(bb & WSQUARES) )
				{
					sc >>= 1;
				}
			}
			else
			{
				if ( !(bb & BSQUARES) )
				{
					sc >>= 1;
				}
			}
		}
	}
#endif

    i32 result = turn == white ? sc/10 : -(sc/10);

#ifdef USE_SKILL
    if ( skill < 100 )
    {
        result += (rand()%201 - 100)*(100 - skill);
    }
#endif

    if ( result >= bmate - 1000 )
    {
        result = bmate - 1001;
    } else if ( result <= -bmate + 1000 )
    {
        result = -bmate + 1001;
    }

    if ( hi >= 0 )
    {
        *ecHash = b.bits[ bhash ];
        *ecScore = result;
        ecScore[1] = safetyEval[0];
        ecScore[2] = safetyEval[1];
    }

    return result;
}

#define SCORE_PSQ_WHITE( piece ) if (1) { score[0] += (*bonusTable)[0][ white ][ piece ][ pos ]; score[1] += (*bonusTable)[1][ white ][ piece ][ pos ]; }
#define SCORE_PSQ_BLACK( piece ) if (1) { score[0] -= (*bonusTable)[0][ black ][ piece ][ pos ]; score[1] -= (*bonusTable)[1][ black ][ piece ][ pos ]; }

static u64 knightAttm( u8 pos )
{
    return knightMov[ pos ];
}

#ifndef USE_NEWATTM
// mask: blockmask
// NOTE! pieces in blockmask are also included!
static u64 bishopAttm( u8 pos, const u64 &mask )
{
    u64 targ = 0;
    i32 j;
    for (j=1; j<8; j+=2)
    {
        u64 dm = diagMask[ j ][ pos ];
        u64 dma = dm & mask;
        if ( !dma )
        {
            // add_dm!
            targ |= dm;
            continue;
        }
        i8 bit = (j<4) ? getMSB(dma) : getLSB(dma);
        if ( bit < 0 )
            continue;
        // extract targets...
        targ |= betweenMask[ pos ][ bit ] | ONESHL( bit );
    }
    return targ;
}

// mask: blockmask
// NOTE! pieces in blockmask are also included!
static u64 rookAttm( u8 pos, const u64 &mask )
{
    u64 targ = 0;
    i32 j;
    for (j=0; j<8; j+=2)
    {
        u64 dm = diagMask[ j ][ pos ];
        u64 dma = dm & mask;
        if ( !dma )
        {
            // add_dm!
            targ |= dm;
            continue;
        }
        i8 bit = (j<4) ? getMSB(dma) : getLSB(dma);
        if ( bit < 0 )
            continue;
        // extract targets...
        targ |= betweenMask[ pos ][ bit ] | ONESHL( bit );
    }
    return targ;
}

// mask: blockmask
// NOTE! pieces in blockmask are also included!
static u64 queenAttm( u8 pos, const u64 &mask )
{
    u64 targ = 0;
    i32 j;
    for (j=0; j<8; j++)
    {
        u64 dm = diagMask[ j ][ pos ];
        u64 dma = dm & mask;
        if ( !dma )
        {
            // add_dm!
            targ |= dm;
            continue;
        }
        i8 bit = (j<4) ? getMSB(dma) : getLSB(dma);
        if ( bit < 0 )
            continue;
        // extract targets...
        targ |= betweenMask[ pos ][ bit ] | ONESHL( bit );
    }
    return targ;
}
#endif

// originally: 1*, 1*
// 2*: 50928.500 (best so far)
// 3*/2: 50916.500 (worse)
// 3*: worse
// 4*: much worse
#define PT(x) (NEW_EVAL_LERP(1,2)*(x))
#define PPT(x) (NEW_EVAL_LERP(1,2)*(x))

// passed pawn distance bonus
static i32 passTab[] = {
	PT(0), PT(35/4), PT(30/4), PT(25/4), PT(20/4), PT(15/4), PT(10/4), PT(5/4), PT(0)
};

// passed pawn penalty
static i32 passPenTab[] = {
	PPT(0), PPT(13/1), PPT(25/1), PPT(38/1), PPT(50/1), PPT(63/1), PPT(75/1), PPT(88/1), PPT(100/1)
};

i32	ppOpBase		=		50;			// orig. 50
i32	ppOpScale		=		0;			// orig. 0, 10 best so far
i32	ppEndBase		=		100;		// orig. 100
i32	ppEndScale		=		45;			// orig. 45 (88 best so far)

void BitEval::whitePawnHashed( u8 pos )
{
	SCORE_PSQ_WHITE( pawn );

	score[0] -= OPVAL;				// opening pawn value

	const u64 &t = ONESHL(pos);

	u64 cm = ((t << 9) & L1MASK) | ((t << 7) & R1MASK);
	// passed pawn?
	bool passed = ( board->bits[ bpawn ] & passPawnMask[ white ][ pos ] ) == 0;

	i32 pd = pos >> 3;		// promotion_distance

	// covered by friendly pawn?
	bool covered = ( board->bits[ wpawn ] & cm ) != 0;
	// isolated pawn?
	bool isolated = !(isoPawnMask[ pos ] & board->bits[ wpawn]);
	u64 nm = ((t << 1) & L1MASK) | ((t >> 1) & R1MASK);
	// chained pawn?
	bool chained = covered || (board->bits[ wpawn ] & nm);
	// doubled pawn?
	bool doubled = (frontMask[ white ][ pos ] & board->bits[ wpawn ]) != 0;
	// backward pawn?
	bool backward = !chained && !isolated && !passed;

	// candidate passed pawn
	bool candidate = 0;
	if ( !passed && !isolated && !doubled && !(frontMask[ white ][ pos ] & board->bits[ bpawn ]) )
	{
		if ( bitCount( passPawnMask[ white ][ pos ] & board->bits[ bpawn ] ) < 2 )
		{
			candidate = 1;
			score[0] += (ppOpBase + (6 - pd)*(6 - pd)*ppOpScale)/10;
			score[1] += (ppEndBase + (6 - pd)*(6 - pd)*ppEndScale)/10;
		}
	}

	u8 file = pos & 7;
	if ( chained )
	{
		score[0] += 10;
		score[1] += 20;
	}
	if ( backward )
	{
		score[0] -= bwdOpening;
		score[1] -= bwdEndgame;
	}
	if ( !doubled && passed )
	{
		// set passed pawn mask!
		passedPawnMask[ white ] |= t;
		score[0] += ppOpBase + (6 - pd)*(6 - pd)*ppOpScale;
		score[1] += ppEndBase + (6 - pd)*(6 - pd)*ppEndScale;
	}
	if ( covered )
	{
		score[0] += 10;
		score[1] += 20;
	}
	if ( isolated )
	{
		// penalize isolated pawns
		score[0] -= isoOpening;
		score[1] -= isoEndgame;
	}
	if ( doubled )
	{
		// penalize doubled pawns
		score[0] -= dblOpening;
		score[1] -= dblEndgame;
	}
}

void BitEval::whitePassedPawn( u8 pos )
{
	i32 pd = pos >> 3;		// promotion_distance

	// set passed pawn mask!
	const BitFlags &f = board->flags();

	i32 scale = 256 * (3275 - tmat[ black ]) / 3275;

	// bonus (distance to own passed pawn)
	i32 d = kdistTab[ f.kingPos[ white ] ][ pos ];
	if ( f.turn != white )
		d++;
	score[0] += (passTab[ d ] * scale * PASS_OP) >> 8;
	score[1] += ((passTab[ d ] << PASS_SH) * scale) >> 8;

	// penalty (distance to enemy passed pawn)
	d = kdistTab[ f.kingPos[ black ] ][ pos ];
	if ( f.turn == white )
		d++;

	score[0] += (passPenTab[ d ] * scale * PASS_OP) >> 8;
	score[1] += ((passPenTab[ d ] << PASS_SH) * scale) >> 8;

#ifdef USE_REALDIST
	if ( !board->mat().tmat )
	{
		d = realDist( black, f.kingPos[ black ], pos, attackMask[ white ][ pawn ] );
		if ( f.turn == white )
			d++;
	}
#endif
#ifdef DISABLE_PASSED_PAWNS
	return;
#endif
	if ( d > pd + 1 )		// IMPORTANT! +1 => forgot the ability to capture just_promoted pawn!
	{
		if ( 1/*!(frontMask[ white ][ pos ] & all)*/ )
		{
			if ( !cantIntercept[ white ] || cantIntercept[ white ] > pd )
			{
				cantIntercept[ white ] = pd;
			}
		}
	}
}

void BitEval::blackPawnHashed( u8 pos )
{
	SCORE_PSQ_BLACK( pawn );

	score[0] += OPVAL;				// opening pawn value

	const u64 &t = ONESHL(pos);

	u64 cm = ((t >> 9) & R1MASK) | ((t >> 7) & L1MASK);
	// passed pawn?
	bool passed = ( board->bits[ wpawn ] & passPawnMask[ black ][ pos ] ) == 0;

	i32 pd = 7 - (pos >> 3);		// promotion_distance

	u64 nm = ((t << 1) & L1MASK) | ((t >> 1) & R1MASK);
	// covered by friendly pawn?
	bool covered = ( board->bits[ bpawn ] & cm ) != 0;
	// isolated pawn?
	bool isolated = !(isoPawnMask[ pos ] & board->bits[ bpawn]);
	// chained pawn?
	bool chained = covered || (board->bits[ bpawn ] & nm);
	// backward pawn?
	bool backward = !chained && !isolated && !passed;
	// doubled pawn?
	bool doubled = (frontMask[ black ][ pos ] & board->bits[ bpawn ]) != 0;

	// candidate passed pawn
	bool candidate = 0;
	if ( !passed && !isolated && !doubled && !(frontMask[ black ][ pos ] & board->bits[ wpawn ]) )
	{
		if ( bitCount( passPawnMask[ black ][ pos ] & board->bits[ wpawn ] ) < 2 )
		{
			candidate = 1;
			score[0] -= (ppOpBase + (6 - pd)*(6 - pd)*ppOpScale)/10;
			score[1] -= (ppEndBase + (6 - pd)*(6 - pd)*ppEndScale)/10;
		}
	}

	u8 file = pos & 7;
	if ( chained )
	{
		score[0] -= 10;
		score[1] -= 20;
	}
	if ( backward )
	{
		score[0] += bwdOpening;
		score[1] += bwdEndgame;
	}
	if ( !doubled && passed )
	{
		// set passed pawn mask!
		passedPawnMask[ black ] |= t;
		score[0] -= ppOpBase + (6 - pd)*(6 - pd)*ppOpScale;
		score[1] -= ppEndBase + (6 - pd)*(6 - pd)*ppEndScale;
	}
	if ( covered )
	{
		score[0] -= 10;
		score[1] -= 20;
	}
	if ( isolated )
	{
		// penalize isolated pawns
		score[0] += isoOpening;
		score[1] += isoEndgame;
	}
	if ( doubled )
	{
		// penalize doubled pawns
		score[0] += dblOpening;
		score[1] += dblEndgame;
	}
}

void BitEval::blackPassedPawn( u8 pos )
{
	i32 pd = 7 - (pos >> 3);		// promotion_distance

	const BitFlags &f = board->flags();

	i32 scale = 256 * (3275 - tmat[ white ]) / 3275;

	// bonus (distance to own passed pawn)
	i32 d = kdistTab[ f.kingPos[ black ] ][ pos ];
	if ( f.turn != black )
		d++;
	score[0] -= (passTab[ d ] * scale * PASS_OP) >> 8;
	score[1] -= ((passTab[ d ] << PASS_SH) * scale) >> 8;

	// penalty (distance to enemy passed pawn)
	d = kdistTab[ f.kingPos[ white ] ][ pos ];
	if ( f.turn == black )
		d++;

	score[0] -= (passPenTab[ d ] * scale * PASS_OP) >> 8;
	score[1] -= ((passPenTab[ d ] << PASS_SH) * scale) >> 8;

#ifdef USE_REALDIST
	if ( !board->mat().tmat )
	{
		d = realDist( white, f.kingPos[ white ], pos, attackMask[ black ][ pawn ] );
		if ( f.turn == black )
			d++;
	}
#endif
#ifdef DISABLE_PASSED_PAWNS
	return;
#endif
	if ( d > pd + 1 )		// IMPORTANT! +1 => forgot the ability to capture just_promoted pawn!
	{
		if ( 1/*!(frontMask[ black ][ pos ] & all )*/ )
		{
			if ( !cantIntercept[ black ] || cantIntercept[ black ] > pd )
			{
				cantIntercept[ black ] = pd;
			}
		}
	}
}

#define M(x) ( ((x) * 100 + 128) / 256 * mobilityScale / 100 )

// opening/midgame knight mobility scores
static i32 knightMobility[9] =
{
	M(-38), M(-25), M(-12), M(0), M(+12), M(+25), M(+31), M(+38), M(+38)
};

// endgame knight mobility scores
static i32 knightMobilityEnd[9] =
{
	M(-33), M(-23), M(-13), M(-3), M(+7), M(+17), M(+22), M(+27), M(+27)
};

void BitEval::whiteKnight( u8 pos )
{
	SCORE_PSQ_WHITE( knight );
	u64 atm = knightAttm( pos );
	attackMask[ white ][ knight ] |= atm;
	allAttackMask[ white ] |= atm;

	u64 unsafe = attackMask[ black ][ pawn ] & ~knightOrBetter[ black ];

	i32 ac = bitCount( atm & safetyMask[ black ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ black ] += ac;
		attackerScale[ black ] += knightSafetyWgt * ac;
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ wall ] );

	// for mobility calculation, exclude squares attacked by enemy pawns
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	ASSERT( mobility <= 8 );

/*	if ( debugFlag )
	{
		char sq[3] = {'a' + (pos & 7), '8' - (pos>>3), 0 };
		logFmt("white_knight_mobility at %s: %d\n", sq, mobility );
	}*/

	score[0] += knightMobility[ mobility ];
	score[1] += knightMobilityEnd[ mobility ];
	if ( attackMask[ black ][ pawn ] & ONESHL( pos ) )
	{
		score[0] -= 20;
		score[1] -= 20;
	}
	if ( (attackMask[ white ][ pawn ] & ONESHL( pos )) && !(attackMask[ black ][ pawn ] & ONESHL( pos )) )
	{
		// knight outpost bonus
		score[0] += 10;
		score[1] += 10;
	}
}

void BitEval::blackKnight( u8 pos )
{
	SCORE_PSQ_BLACK( knight );
	u64 atm = knightAttm( pos );
	attackMask[ black ][ knight ] |= atm;
	allAttackMask[ black ] |= atm;

	u64 unsafe = attackMask[ white ][ pawn ] & ~knightOrBetter[ white ];

	i32 ac = bitCount( atm & safetyMask[ white ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ white ] += ac;
		attackerScale[ white ] += knightSafetyWgt * ac;
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ ball ] );

	// for mobility calculation, exclude squares attacked by enemy pawns
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	ASSERT( mobility <= 8 );

/*	if ( debugFlag )
	{
		char sq[3] = {'a' + (pos & 7), '8' - (pos>>3), 0 };
		logFmt("black_knight_mobility at %s: %d\n", sq, mobility );
	}*/

	score[0] -= knightMobility[ mobility ];
	score[1] -= knightMobilityEnd[ mobility ];

	if ( attackMask[ white ][ pawn ] & ONESHL( pos ) )
	{
		score[0] += 20;
		score[1] += 20;
	}
	if ( (attackMask[ black ][ pawn ] & ONESHL( pos )) && !(attackMask[ white ][ pawn ] & ONESHL( pos )) )
	{
		// knight outpost bonus
		score[0] -= 10;
		score[1] -= 10;
	}
}

// opening/midgame bishop mobility scores
static i32 bishopMobility[15] =
{
	M(-25), M(-11), M(3), M(17), M(31), M(+45), M(+57), M(+65), M(+71), M(+74), M(+76), M(+78), M(+79), M(+80), M(+81)
};

// endgame bishop mobility scores
static i32 bishopMobilityEnd[15] =
{
	M(-30), M(-16), M(-2), M(12), M(26), M(+40), M(+52), M(+60), M(+65), M(+69), M(+71), M(+73), M(+74), M(+75), M(+75)
};

void BitEval::whiteBishop( u8 pos )
{
	SCORE_PSQ_WHITE( bishop );
	// attack through friendly bishops and queens!
	u64 atm = bishopAttm( pos, all & ~( board->bits[ wbishop ] | board->bits[ wqueen ] ) );
	attackMask[ white ][ bishop ] |= atm;
	allAttackMask[ white ] |= atm;

	u64 unsafe = attackMask[ black ][ pawn ] & ~knightOrBetter[ black ];

	i32 ac = bitCount( atm & safetyMask[ black ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ black ] += ac;
		attackerScale[ black ] += bishopSafetyWgt * ac;
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ wall ] );

	// for mobility calculation, exclude squares attacked by enemy pawns
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	ASSERT( mobility <= 14 );
	score[0] += bishopMobility[ mobility ];
	score[1] += bishopMobilityEnd[ mobility ];

	if ( attackMask[ black ][ pawn ] & ONESHL( pos ) )
	{
		score[0] -= 20;
		score[1] -= 20;
	}
	if ( pos == A7 )
	{
		const u64 &b6 = ONESHL( B6 );
		if ( board->bits[ bpawn ] & b6 )
		{
			// try to eval trapped bishop on a7
			BitMove m;
			m.clear();
			m.from = A7;
			m.to = B6;
			if ( board->see(m, 1) < 0 )
			{
				m.to = B8;
				if ( board->see(m, 1) < 0 )
				{
					// trapped!
					score[0] -= TBSCALE*1000;
					score[1] -= TBSCALE*1000;
				}
			}
		}
	}
	else if ( pos == H7 )
	{
		const u64 &g6 = ONESHL( G6 );
		if ( board->bits[ bpawn ] & g6 )
		{
			// try to eval trapped bishop on h7
			BitMove m;
			m.clear();
			m.from = H7;
			m.to = G6;
			if ( board->see(m, 1) < 0 )
			{
				m.to = G8;
				if ( board->see(m, 1) < 0 )
				{
					// trapped!
					score[0] -= TBSCALE*1000;
					score[1] -= TBSCALE*1000;
				}
			}
		}
	}
	if ( (attackMask[ white ][ pawn ] & ONESHL( pos )) && !(attackMask[ black ][ pawn ] & ONESHL( pos )) )
	{
		// bishop outpost bonus
		score[0] += 10;
		score[1] += 10;
	}
}

void BitEval::blackBishop( u8 pos )
{
	SCORE_PSQ_BLACK( bishop );
	// attack through friendly bishops and queens!
	u64 atm = bishopAttm( pos, all & ~( board->bits[ bbishop ] | board->bits[ bqueen ] ) );
	attackMask[ black ][ bishop ] |= atm;
	allAttackMask[ black ] |= atm;

	u64 unsafe = attackMask[ white ][ pawn ] & ~knightOrBetter[ white ];

	i32 ac = bitCount( atm & safetyMask[ white ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ white ] += ac;
		attackerScale[ white ] += bishopSafetyWgt * ac;
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ ball ] );

	// for mobility calculation, exclude squares attacked by enemy pawns
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	ASSERT( mobility <= 14 );
	score[0] -= bishopMobility[ mobility ];
	score[1] -= bishopMobilityEnd[ mobility ];

	if ( attackMask[ white ][ pawn ] & ONESHL( pos ) )
	{
		score[0] += 20;
		score[1] += 20;
	}
	if ( pos == A2 )
	{
		const u64 &b3 = ONESHL( B3 );
		if ( board->bits[ wpawn ] & b3 )
		{
			// try to eval trapped bishop on a2
			BitMove m;
			m.clear();
			m.from = A2;
			m.to = B3;
			if ( board->see(m, 1) < 0 )
			{
				m.to = B1;
				if ( board->see(m, 1) < 0 )
				{
					// trapped!
					score[0] += TBSCALE*1000;
					score[1] += TBSCALE*1000;
				}
			}
		}
	}
	else if ( pos == H2 )
	{
		const u64 &g3 = ONESHL( G3 );
		if ( board->bits[ wpawn ] & g3 )
		{
			// try to eval trapped bishop on h2
			BitMove m;
			m.clear();
			m.from = H2;
			m.to = G3;
			if ( board->see(m, 1) < 0 )
			{
				m.to = G1;
				if ( board->see(m, 1) < 0 )
				{
					// trapped!
					score[0] += TBSCALE*1000;
					score[1] += TBSCALE*1000;
				}
			}
		}
	}
	if ( (attackMask[ black ][ pawn ] & ONESHL( pos )) && !(attackMask[ white ][ pawn ] & ONESHL( pos )) )
	{
		// bishop outpost bonus
		score[0] -= 10;
		score[1] -= 10;
	}
}

// opening/midgame rook mobility scores
static i32 rookMobility[15] =
{
	M(-20), M(-14), M(-8), M(-2), M(4), M(+10), M(+14), M(+19), M(+23), M(+26), M(+27), M(+28), M(+29), M(+30), M(+31)
};

// endgame rook mobility scores
static i32 rookMobilityEnd[15] =
{
	M(-36), M(-19), M(-3), M(13), M(29), M(+46), M(+62), M(+79), M(+95), M(+106), M(+111), M(+114), M(+116), M(+117), M(+118)
};

i32	rook7thOpening		=		NEW_EVAL_LERP(50, 146);		// orig. 50, 146 best so far
i32	rook7thEndgame		=		NEW_EVAL_LERP(100, 100);	// orig. 100, 100 best so far
i32	rookPassOpening		=		NEW_EVAL_LERP(150, 35);		// orig. 150, 35 best so far
i32	rookPassEndgame		=		NEW_EVAL_LERP(200, 75);		// orig. 200, 75 best so far (*need more testing later?)
i32	rookOnOpenOpening	=		NEW_EVAL_LERP(35, 250);		// orig. 35, 500 best so far
i32	rookOnOpenEndgame	=		NEW_EVAL_LERP(45, 45);		// orig. 45
i32	rookOnSemiOpening	=		NEW_EVAL_LERP(15, 15);		// orig. 15
i32	rookOnSemiEndgame	=		NEW_EVAL_LERP(25, 25);		// orig. 25

void BitEval::whiteRook( u8 pos )
{
	SCORE_PSQ_WHITE( rook );
	// attack through friendly rooks and queens!
	u64 atm = rookAttm( pos, all & ~( board->bits[ wrook ] | board->bits[ wqueen ] ) );
	attackMask[ white ][ rook ] |= atm;
	allAttackMask[ white ] |= atm;

	u64 unsafe = attackMask[ black ][ pawn ] | attackMask[ black ][ knight ] | attackMask[ black ][ bishop ];
	unsafe &= ~rookOrBetter[ black ];

	i32 ac = bitCount( atm & safetyMask[ black ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ black ] += ac;
		attackerScale[ black ] += rookSafetyWgt * ac;
	}

	const u64 &fm = fileMask[ pos & 7 ];
	i32 bc = bitCount( (board->bits[ wpawn ] | board->bits[ bpawn ]) & fm );

	if ( bc == 0 )
	{
		// rook on open file bonus
		score[0] += rookOnOpenOpening;
		score[1] += rookOnOpenEndgame;
	}
	else
	if ( bc == 1 )
	{
		// rook on semi-open file bonus
		score[0] += rookOnSemiOpening;
		score[1] += rookOnSemiEndgame;
	}

	// rook behind passed pawn!
	if ( (atm & passedPawnMask[ white ]) && (frontMask[ white ][ pos ] & passedPawnMask[ white ])
#ifdef NEW_ROOKPASS
		&& !(frontMask[ white ][ pos ] & board->bits[ wrook ])
#endif
		)
	{
		// rook behind friendly passed pawn bonus!
		score[0] += rookPassOpening;
		score[1] += rookPassEndgame;
	}

	if ( (pos >> 3) == 1 )
	{
		// rook on 7th bonus -- only if king is trapped or there're enemy pawns on 7th as well
		if ( (board->flags().kingPos[ black ] >> 3) == 0 || ((u16)board->bits[ bpawn ] & 0xff00 ) )
		{
			score[0] += rook7thOpening;
			score[1] += rook7thEndgame;
		}
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ wall ] );

	// for mobility calculation, exclude squares attacked by enemy pawns, bishops and knights
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	ASSERT( mobility <= 14 );
	score[0] += rookMobility[ mobility ];
	score[1] += rookMobilityEnd[ mobility ];

	if ( attackMask[ black ][ pawn ] & ONESHL( pos ) )
	{
		score[0] -= 63;
		score[1] -= 63;
	}

	// now evaluate trapped rooks!
	const BitFlags &f = board->flags();
	if ( mobility <= 5 && !f.castRights[ white ] )
	{
		u8 kp = f.kingPos[ white ];
		if ( (pos >> 3) == 7 && (pos >> 3) == (kp >> 3) )
		{
			u8 kpx = kp & 7;
			u8 px = pos & 7;
			if ( (kpx >= 4 && px > kpx) || (kpx < 4 && px < kpx) )
			{
				score[0] -= 1200;
			}
		}
	}
}

void BitEval::blackRook( u8 pos )
{
	SCORE_PSQ_BLACK( rook );
	// attack through friendly rooks and queens!
	u64 atm = rookAttm( pos, all & ~( board->bits[ brook ] | board->bits[ bqueen ] ) );
	attackMask[ black ][ rook ] |= atm;
	allAttackMask[ black ] |= atm;

	u64 unsafe = attackMask[ white ][ pawn ] | attackMask[ white ][ knight ] | attackMask[ white ][ bishop ];
	unsafe &= ~rookOrBetter[ white ];

	i32 ac = bitCount( atm & safetyMask[ white ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ white ] += ac;
		attackerScale[ white ] += rookSafetyWgt * ac;
	}

	const u64 &fm = fileMask[ pos & 7 ];
	i32 bc = bitCount( (board->bits[ wpawn ] | board->bits[ bpawn ]) & fm );

	if ( bc == 0 )
	{
		// rook on open file bonus
		score[0] -= rookOnOpenOpening;
		score[1] -= rookOnOpenEndgame;
	}
	else
	if ( bc == 1 )
	{
		// rook on semi-open file bonus
		score[0] -= rookOnSemiOpening;
		score[1] -= rookOnSemiEndgame;
	}

	// rook behind passed pawn!
	if ( (atm & passedPawnMask[ black ]) && (frontMask[ black ][ pos ] & passedPawnMask[ black ])
#ifdef NEW_ROOKPASS
		&& !(frontMask[ black ][ pos ] & board->bits[ brook ])
#endif
		)
	{
		// rook behind friendly passed pawn bonus!
		score[0] -= rookPassOpening;
		score[1] -= rookPassEndgame;
	}

	if ( (pos >> 3) == 6 )
	{
		// rook on 7th bonus -- only if king is trapped or there're enemy pawns on 7th as well
		if ( (board->flags().kingPos[ white ] >> 3) == 7 || (board->bits[ wpawn ] & U64C(0x00ff000000000000) ) )
		{
			score[0] -= rook7thOpening;
			score[1] -= rook7thEndgame;
		}
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ ball ] );

	// for mobility calculation, exclude squares attacked by enemy pawns, bishops and knights
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	ASSERT( mobility <= 14 );
	score[0] -= rookMobility[ mobility ];
	score[1] -= rookMobilityEnd[ mobility ];

	if ( attackMask[ white ][ pawn ] & ONESHL( pos ) )
	{
		score[0] += 63;
		score[1] += 63;
	}

	// now evaluate trapped rooks!
	const BitFlags &f = board->flags();
	if ( mobility <= 5 && !f.castRights[ black ] )
	{
		u8 kp = f.kingPos[ black ];
		if ( (pos >> 3) == 0 && (pos >> 3) == (kp >> 3) )
		{
			u8 kpx = kp & 7;
			u8 px = pos & 7;
			if ( (kpx >= 4 && px > kpx) || (kpx < 4 && px < kpx) )
			{
				score[0] += 1200;
			}
		}
	}
}

// opening/midgame queen mobility scores
static i32 queenMobility[16] =
{
	M(-10), M(-8), M(-6), M(-3), M(-1), M(+1), M(+3), M(+5), M(+8), M(+10), M(+12), M(+15), M(+16), M(+17), M(+18), M(+20)
};

// endgame queen mobility scores
static i32 queenMobilityEnd[16] =
{
	M(-18), M(-13), M(-7), M(-2), M(3), M(+8), M(+13), M(+19), M(+23), M(+27), M(+32), M(+34), M(+35), M(+35), M(+35), M(+35)
};

void BitEval::whiteQueen( u8 pos )
{
	SCORE_PSQ_WHITE( queen );
	// attack through friendly bishops, rooks and queens!
	u64 atm = queenAttm( pos, all & ~( board->bits[ wbishop ] | board->bits[ wrook ] | board->bits[ wqueen ] ) );
	attackMask[ white ][ queen ] |= atm;
	allAttackMask[ white ] |= atm;

	u64 unsafe = attackMask[ black ][ pawn ] | attackMask[ black ][ knight ] | attackMask[ black ][ bishop ] | attackMask[ black ][ rook ];
	unsafe &= ~board->bits[ bqueen ];

	i32 ac = bitCount( atm & safetyMask[ black ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ black ] += ac;
		attackerScale[ black ] += queenSafetyWgt * ac;
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ wall ] );

	// for mobility calculation, exclude squares attacked by enemy pawns, bishops, knights and rooks
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	if ( mobility > 15 )
		mobility = 15;
	score[0] += queenMobility[ mobility ];
	score[1] += queenMobilityEnd[ mobility ];

	if ( attackMask[ black ][ pawn ] & ONESHL( pos ) )
	{
		score[0] -= 30;
		score[1] -= 30;
	}
}

void BitEval::blackQueen( u8 pos )
{
	SCORE_PSQ_BLACK( queen );
	// attack through friendly bishops, rooks and queens!
	u64 atm = queenAttm( pos, all & ~( board->bits[ bbishop ] | board->bits[ brook ] | board->bits[ bqueen ] ) );
	attackMask[ black ][ queen ] |= atm;
	allAttackMask[ black ] |= atm;

	u64 unsafe = attackMask[ white ][ pawn ] | attackMask[ white ][ knight ] | attackMask[ white ][ bishop ] | attackMask[ white ][ rook ];
	unsafe &= ~board->bits[ wqueen ];

	i32 ac = bitCount( atm & safetyMask[ white ] & NUNSAFE );
	if ( ac )
	{
		attackerCount[ white ] += ac;
		attackerScale[ white ] += queenSafetyWgt * ac;
	}

	// exclude friendly pieces
	atm &= ~( board->bits[ ball ] );

	// for mobility calculation, exclude squares attacked by enemy pawns, bishops, knights and rooks
	i32 mobility = bitCount( atm & NUNSAFE_MOB );
	if ( mobility > 15 )
		mobility = 15;
	score[0] -= queenMobility[ mobility ];
	score[1] -= queenMobilityEnd[ mobility ];

	if ( attackMask[ white ][ pawn ] & ONESHL( pos ) )
	{
		score[0] += 30;
		score[1] += 30;
	}
}

i32	shelterFront1	=	NEW_EVAL_LERP(60, 104);			// orig: 60	(104 seems best, but around 68 might need more investigation)
i32	shelterFront2	=	NEW_EVAL_LERP(30, 59);			// orig: 30 (59 best so far)

i32 KING_SHIELD = kingShieldMask * NEW_EVAL_LERP(300, 480/*544*/);			// 544 seems best
i32 pawnStorm = 50;

#define SAFESCL 1

void BitEval::whiteKing( u8 pos )
{
	SCORE_PSQ_WHITE( king );

	// new: pawn storm
	u64 storm = sideCoverMask[ white ][ pos ] & board->bits[ bpawn ];
	while ( storm )
	{
		i8 bit = popLSB( storm );
		i8 idist = 7 - abs( (pos >> 3) - (bit >> 3) );
		// penalize according to idist
		score[0] -= idist * pawnStorm;
	}

	if ( bitCount( sideCoverMaskFixed[ white ][ pos ] & board->bits[ wpawn ] ) >= 2 )
	{
		// pawn shield bonus (FIXME: better!)
		score[0] += KING_SHIELD;
		score[1] += 0;
	}
#ifdef PAWN_SHIELD_V2
	{
		// pawn shield eval #2
		u64 t = ONESHL( pos );
		t |= ((t << 1) & L1MASK) | ((t >> 1) & R1MASK);
		u64 tmp = t;
		t |= (t >> 8);
		i32 front1 = bitCount( t & board->bits[ wpawn ] );
		score[0] += front1 * shelterFront1 * pawnShelterScale / 100;
		tmp >>= 16;
		i32 front2 = bitCount( t & board->bits[ wpawn ] );
		score[0] += front2 * shelterFront2 * pawnShelterScale / 100;
/*		tmp >>= 8;
		i32 front3 = bitCount( t & board->bits[ wpawn ] );
		score[0] += front3 * 5;*/
	}
#endif

/*	i32 undef = bitCount( allAttackMask[black] & ~attackMask[ white ][ pawn ]
				& ~attackMask[ white ][ knight ] & ~attackMask[ white ][ bishop ]
				& ~attackMask[ white ][ rook ] & ~attackMask[ white ][ queen ]
				& kingMov[ pos ] );*/

	// now apply king safety!
	i32 safety = attackerScale[ white ] * attackerCount[ white ];// + 50*undef;
	safety = safety * SAFESCL * 2125/1000 * kingSafetyScale / 100;

/*	if ( safety )
	{
		static i32 maxSfty = 0;
		if ( safety > maxSfty )
		{
			maxSfty = safety;
			logFmt("max_safety: %d\n", safety );
		}
		logFmt("");
	}*/

	if ( safety )
	{
/*		if ( safety > 1000 )	// doesn't seem to have any effect...
			safety = 1000;*/

		i32 scale = 256 * (tmat[ black ] - 500) / (3275 - 500);

		if ( scale < 0 )
			scale = 0;
		else if ( scale > 256 )
			scale = 256;

		safety = (scale * safety) >> 8;
		safetyEval[ white ] = safety;

/*		static i32 maxsf = -0x80000000;
		if ( safety > maxsf )
		{
			logFmt("white_maxsfty = %d\n", maxsf = safety );
		}*/

		// safety scaled by enemy_tmat, not total tmat!
		score[0] -= safety;
		score[1] -= safety;
	}

	if ( cantIntercept[ white ] )
	{
		if ( !cantIntercept[ black ] || cantIntercept[ black ] > cantIntercept[ white ] )
		{
			// can't intercept!
/*			score[0] += 600;
			score[1] += 600;*/
			if ( !knightOrBetter[ black ] )
			{
				// no minor/major piece to prevent passed pawn from promoting
				score[0] += board->matTab[ queen ] - board->matTab[ pawn ];
				score[1] += board->matTab[ queen ] - board->matTab[ pawn ];
			}
		}
	}

#if 0
	// DUMB: eval_attacks!
	{
		// unsafe enemies (not defended by pawns but attacked by us)
		u64 unsafe = board->bits[ ball ] & ~attackMask[ black ][ pawn ] & allAttackMask[ white ];
		if ( unsafe )
		{
			i32 i;
			for ( i=knight; i<king; i++ )
			{
				u64 tmp = unsafe & attackMask[ white ][ i ];
				if ( tmp )
				{
					i32 j;
					for ( j=pawn; j<king; j++ )
					{
						if ( tmp & board->bits[ INDEX( black, j ) ] )
						{
							i32 sc = attackBonus[ i ][ j ];
							score[0] += sc;
							score[1] += sc;
						}
					}
				}
			}
		}
	}
#endif
}

void BitEval::blackKing( u8 pos )
{
	SCORE_PSQ_BLACK( king );

	// new: pawn storm
	u64 storm = sideCoverMask[ black ][ pos ] & board->bits[ wpawn ];
	while ( storm )
	{
		i8 bit = popLSB( storm );
		i8 idist = 7 - abs( (pos >> 3) - (bit >> 3) );
		// penalize according to idist
		score[0] += idist * pawnStorm;
	}

	if ( bitCount( sideCoverMaskFixed[ black ][ pos ] & board->bits[ bpawn ] ) >= 2 )
	{
		// pawn shield bonus (FIXME: better!)
		score[0] -= KING_SHIELD;
		score[1] -= 0;
	}
#ifdef PAWN_SHIELD_V2
	{
		// pawn shield eval #2
		u64 t = ONESHL( pos );
		t |= ((t << 1) & L1MASK) | ((t >> 1) & R1MASK);
		u64 tmp = t;
		t |= (t << 8);
		i32 front1 = bitCount( t & board->bits[ bpawn ] );
		score[0] -= front1 * shelterFront1 * pawnShelterScale / 100;
		tmp <<= 16;
		i32 front2 = bitCount( t & board->bits[ bpawn ] );
		score[0] -= front2 * shelterFront2 * pawnShelterScale / 100;
/*		tmp <<= 8;
		i32 front3 = bitCount( t & board->bits[ bpawn ] );
		score[0] -= front3 * 5;*/
	}
#endif

/*	i32 undef = bitCount( allAttackMask[white] & ~attackMask[ black ][ pawn ]
				& ~attackMask[ black ][ knight ] & ~attackMask[ black ][ bishop ]
				& ~attackMask[ black ][ rook ] & ~attackMask[ black ][ queen ]
				& kingMov[ pos ] );*/

	// now apply king safety!
	i32 safety = attackerScale[ black ] * attackerCount[ black ];// + 50*undef;
	safety = safety * SAFESCL * 2125/1000 * kingSafetyScale / 100;

	if ( safety )
	{
/*		if ( safety > 1000 )	// doesn't seem to have any effect...
			safety = 1000;*/

		i32 scale = 256 * (tmat[ white ] - 500) / (3275 - 500);

		if ( scale < 0 )
			scale = 0;
		else if ( scale > 256 )
			scale = 256;

		safety = (scale * safety) >> 8;
		safetyEval[ black ] = safety;

		// safety scaled by enemy_tmat, not total tmat!
		score[0] += safety;
		score[1] += safety;
	}

	if ( cantIntercept[ black ] )
	{
		if ( !cantIntercept[ white ] || cantIntercept[ white ] > cantIntercept[ black ] )
		{
			// can't intercept!
/*			score[0] -= 600;
			score[1] -= 600;*/
			if ( !knightOrBetter[ white ] )
			{
				// no minor/major piece to prevent passed pawn from promoting
				score[0] -= board->matTab[ queen ] - board->matTab[ pawn ];
				score[1] -= board->matTab[ queen ] - board->matTab[ pawn ];
			}
		}
	}

#if 0
	// DUMB: eval_attacks!
	{
		// unsafe enemies (not defended by pawns but attacked by us)
		u64 unsafe = board->bits[ wall ] & ~attackMask[ white ][ pawn ] & allAttackMask[ black ];
		if ( unsafe )
		{
			i32 i;
			for ( i=knight; i<king; i++ )
			{
				u64 tmp = unsafe & attackMask[ black ][ i ];
				if ( tmp )
				{
					i32 j;
					for ( j=pawn; j<king; j++ )
					{
						if ( tmp & board->bits[ INDEX( white, j ) ] )
						{
							i32 sc = attackBonus[ i ][ j ];
							score[0] -= sc;
							score[1] -= sc;
						}
					}
				}
			}
		}
	}
#endif
}

void BitEval::clearCache()
{
	if ( evalCacheSize > 0 && evalHash )
	{
		memset( evalHash, 0, evalCacheSize * sizeof(u64) );
	}
}

i32 BitEval::setDebugFlag( i32 df )
{
	i32 res = debugFlag;
	debugFlag = df;
	return res;
}

// orig. 500 (550 best so far)
i32 imbalWgt = NEW_EVAL_LERP(500, 550);

void BitEval::customEval()
{
	u64 _m;
/*	i32 dmat = board->mat().dmat;

	i32 dsc = dmat / 15;

	score[0] += dsc;
	score[1] += dsc;*/

	// evaluate safe center square
	static u64 csquares = 
		(U64C(1) << C2) | (U64C(1) << D2) | (U64C(1) << E2) | (U64C(1) << F2) |
		(U64C(1) << C3) | (U64C(1) << D3) | (U64C(1) << E3) | (U64C(1) << F3) |
		(U64C(1) << C4) | (U64C(1) << D4) | (U64C(1) << E4) | (U64C(1) << F4) |
		(U64C(1) << C5) | (U64C(1) << D5) | (U64C(1) << E5) | (U64C(1) << F5) |
		(U64C(1) << C6) | (U64C(1) << D6) | (U64C(1) << E6) | (U64C(1) << F6) |
		(U64C(1) << C7) | (U64C(1) << D7) | (U64C(1) << E7) | (U64C(1) << F7)
	;

/*	// tempo
	if ( board->flags().turn == white )
	{
		score[0] += 100;
		score[1] += 100;
	}
	else
	{
		score[0] -= 100;
		score[1] -= 100;
	}*/

	{
		// white
		u64 p = board->bits[ wpawn ];
		u64 center = csquares & ~p & ~attackMask[ black ][ pawn ];
		center &= ~( allAttackMask[ black ] & ~allAttackMask[ white ] );
		p |= p << 8;
		p |= p << 16;
		score[0] += 10 * (bitCount( center ) + bitCount( center & p ));
	}
	{
		// black
		u64 p = board->bits[ bpawn ];
		u64 center = csquares & ~p & ~attackMask[ white ][ pawn ];
		center &= ~( allAttackMask[ white ] & ~allAttackMask[ black ] );
		p |= p >> 8;
		p |= p >> 16;
		score[0] -= 10 * (bitCount( center ) + bitCount( center & p ));
	}
#if 1
#if 0
	{
		i32 maj = bitCount( board->bits[ wrook ] ) + 2*bitCount( board->bits[ wqueen ] )
		- bitCount( board->bits[ brook ] ) - 2*bitCount( board->bits[ bqueen ] );
		if ( maj > 0 )
		{
			score[0] += imbalWgt;
			score[1] += imbalWgt;
		}
		else if ( maj < 0 )
		{
			score[0] -= imbalWgt;
			score[1] -= imbalWgt;
		}
	}

#else
	if ( rookOrBetter[ white ] && !rookOrBetter[ black ] )
	{
		score[0] += imbalWgt;
		score[1] += imbalWgt;
	}
	else
	if ( rookOrBetter[ black ] && !rookOrBetter[ white ] )
	{
		score[0] -= imbalWgt;
		score[1] -= imbalWgt;
	}
#endif
#endif
	if ( !check )
	{
		bool foundMate = 0;
		// try to evaluate mate in one
		if ( turn == white )
		{
			// white to move
			if ( board->bits[ wqueen ] )
			{
				u8 kp = board->flags().kingPos[ white ];
				u8 ekp = board->flags().kingPos[ black ];
				u64 km = kingMov[ ekp ];
				u64 m = km;
				u64 unsafe = attackMask[ black ][ pawn ] |
					attackMask[ black ][ knight ] |
					attackMask[ black ][ bishop ] |
					attackMask[ black ][ rook ] |
					attackMask[ black ][ queen ];
				m &= ~(unsafe | board->bits[ wall ] );
				u64 safe = attackMask[ white ][ pawn ] |
					attackMask[ white ][ knight ] |
					attackMask[ white ][ bishop ] |
					attackMask[ white ][ rook ] |
					attackMask[ white ][ king ];
				m &= safe;
				// now iterate m and try to find contact checkmate square
				// get wqueen pos
//				u8 qp[64];
//				i32 nqp = getPos( board->bits[ wqueen ], qp );
//				i32 i;
				_m = board->bits[ wqueen ];
				km &= ~(board->bits[ ball ] | safe);
//				for (i=0; i<nqp; i++)
				while( _m )
				{
					u8 qp = popLSB( _m );
					u8 df = diagFlags[ qp ][ kp ];
					if ( df < 8 )
					{
						u64 qam = queenAttm( qp, all );
						if ( qam & ONESHL( kp ) )
						{
							qam &= diagMask[ df ][ kp ];
							if ( df & 1 )
							{
								// check for enemy bishop/queen pin
								if ( qam & (board->bits[ bbishop ] | board->bits[ bqueen ] ) )
								{
									// pinned => ignore
/*									BitBoard tb(*board);
									tb.dump();*/
									continue;
								}
							}
							else
							{
								// check for enemy rook/queen pin
								if ( qam & (board->bits[ brook ] | board->bits[ bqueen ] ) )
								{
									// pinned => ignore
/*									BitBoard tb(*board);
									tb.dump();*/
									continue;
								}
							}
						}
					}
					// for each queen
					// get attack mask
					u64 qatm = queenAttm( qp, all );
					if ( (qatm &= m) != 0 )
					{
//						u8 p[64];
//						i32 np = getPos( qatm, p );
//						i32 j;
//						for (j=0; j<np; j++)
						while( qatm )
						{
							u8 qtp;
							if ( !(km & ~queenAttm( qtp = popLSB(qatm)/*p[j]*/, all )) )
							{
								// found_touchmate!
								foundMate = 1;
								score[0] = score[1] = touchMate;
#ifdef DEBUG_TOUCHMATE
								{
									BitMove m[256];
									i32 vm = board->moves( m );
									i32 i;
									for (i=0; i<vm; i++)
									{
										if ( m[i].from == qp && m[i].to == qtp )
											break;
									}
									if ( i >= vm )
									{
										printf("BUG_FOUND!\n");
									}
								}
#endif
								/*							BitBoard tb(*board);
								tb.dump();*/
//								i = nqp;
								_m = 0;
								break;
							}
						}
					}
				}
			}
		}
		else
		{
			// black to move
			if ( board->bits[ bqueen ] )
			{
				u8 kp = board->flags().kingPos[ black ];
				u8 ekp = board->flags().kingPos[ white ];
				u64 km = kingMov[ ekp ];
				u64 m = km;
				u64 unsafe = attackMask[ white ][ pawn ] |
					attackMask[ white ][ knight ] |
					attackMask[ white ][ bishop ] |
					attackMask[ white ][ rook ] |
					attackMask[ white ][ queen ];
				m &= ~(unsafe | board->bits[ ball ] );
				u64 safe = attackMask[ black ][ pawn ] |
					attackMask[ black ][ knight ] |
					attackMask[ black ][ bishop ] |
					attackMask[ black ][ rook ] |
					attackMask[ black ][ king ];
				m &= safe;
				// now iterate m and try to find contact checkmate square
				// get bqueen pos
//				u8 qp[64];
//				i32 nqp = getPos( board->bits[ bqueen ], qp );
//				i32 i;
				_m = board->bits[ bqueen ];
				km &= ~(board->bits[ wall ] | safe);
//				for (i=0; i<nqp; i++)
				while( _m )
				{
					u8 qp = popLSB( _m );
					u8 df = diagFlags[ qp ][ kp ];
					if ( df < 8 )
					{
						u64 qam = queenAttm( qp, all );
						if ( qam & ONESHL( kp ) )
						{
							qam &= diagMask[ df ][ kp ];
							if ( df & 1 )
							{
								// check for enemy bishop/queen pin
								if ( qam & (board->bits[ wbishop ] | board->bits[ wqueen ] ) )
								{
									// pinned => ignore
/*									BitBoard tb(*board);
									tb.dump();*/
									continue;
								}
							}
							else
							{
								// check for enemy rook/queen pin
								if ( qam & (board->bits[ wrook ] | board->bits[ wqueen ] ) )
								{
									// pinned => ignore
/*									BitBoard tb(*board);
									tb.dump();*/
									continue;
								}
							}
						}
					}
					// for each queen
					// get attack mask
					u64 qatm = queenAttm( qp, all );
					if ( (qatm &= m) != 0 )
					{
//						u8 p[64];
//						i32 np = getPos( qatm, p );
//						i32 j;
//						for (j=0; j<np; j++)
						while( qatm )
						{
							u8 qtp;
							if ( !(km & ~queenAttm( qtp = popLSB(qatm), all )) )
							{
								// found_touchmate!
								foundMate = 1;
								score[0] = score[1] = -touchMate;
#ifdef DEBUG_TOUCHMATE
								{
									BitMove m[256];
									i32 vm = board->moves( m );
									i32 i;
									for (i=0; i<vm; i++)
									{
										if ( m[i].from == qp && m[i].to == qtp )
											break;
									}
									if ( i >= vm )
									{
										printf("BUG_FOUND!\n");
									}
								}
#endif
								/*							BitBoard tb(*board);
								tb.dump();*/
//								i = nqp;
								_m = 0;
								break;
							}
						}
					}
				}
			}
		}
	}
}

// Personality parameters

extern i32 gmatTab[];

static AutoBitParameter _ppars[] =
{
	AutoBitParameter("PawnValueCP", &gmatTab[pawn], 0, 2000 ),
	AutoBitParameter("KnightValueCP", &gmatTab[knight], 0, 2000 ),
	AutoBitParameter("BishopValueCP", &gmatTab[bishop], 0, 2000 ),
	AutoBitParameter("RookValueCP", &gmatTab[rook], 0, 2000 ),
	AutoBitParameter("QueenValueCP", &gmatTab[queen], 0, 2000 ),
	AutoBitParameter("KingSafetyPercent", &kingSafetyScale, 0, 1000 ),
	AutoBitParameter("PawnShelterPercent", &pawnShelterScale, 0, 1000 ),
	AutoBitParameter("MobilityPercent", &mobilityScale, 0, 1000 ),
	AutoBitParameter("KingShieldMP", &KING_SHIELD, 0, 10000 ),
	AutoBitParameter("PawnShelterFront1MP", &shelterFront1, 0, 10000 ),
	AutoBitParameter("PawnShelterFront2MP", &shelterFront2, 0, 10000 ),
	AutoBitParameter("PawnStormMP", &pawnStorm, 0, 10000 ),
	AutoBitParameter("BishopPairMP", &bishopPair, 0, 10000 ),
	AutoBitParameter("ImbalanceMP", &imbalWgt, 0, 10000 ),
	AutoBitParameter("PawnAttackWeightMP", &pawnSafetyWgt, 0, 10000 ),
	AutoBitParameter("KnightAttackWeightMP", &knightSafetyWgt, 0, 10000 ),
	AutoBitParameter("BishopAttackWeightMP", &bishopSafetyWgt, 0, 10000 ),
	AutoBitParameter("RookAttackWeightMP", &rookSafetyWgt, 0, 10000 ),
	AutoBitParameter("QueenAttackWeightMP", &queenSafetyWgt, 0, 10000 ),
	AutoBitParameter("RookOn7thOpeningMP", &rook7thOpening, 0, 10000 ),
	AutoBitParameter("RookOn7thEndgameMP", &rook7thEndgame, 0, 10000 ),
	AutoBitParameter("RookBehindPasserOpeningMP", &rookPassOpening, 0, 10000 ),
	AutoBitParameter("RookBehindPasserEndgameMP", &rookPassEndgame, 0, 10000 ),
	AutoBitParameter("RookOnOpenOpeningMP", &rookOnOpenOpening, 0, 10000 ),
	AutoBitParameter("RookOnOpenEndgameMP", &rookOnOpenEndgame, 0, 10000 ),
	AutoBitParameter("RookOnSemiOpenOpeningMP", &rookOnSemiOpening, 0, 10000 ),
	AutoBitParameter("RookOnSemiOpenEndgameMP", &rookOnSemiEndgame, 0, 10000 ),
	AutoBitParameter("PasserOpeningBaseMP", &ppOpBase, 0, 10000 ),
	AutoBitParameter("PasserOpeningScaleMP", &ppOpScale, 0, 10000 ),
	AutoBitParameter("PasserEndgameBaseMP", &ppEndBase, 0, 10000 ),
	AutoBitParameter("PasserEndgameScaleMP", &ppEndScale, 0, 10000 ),
	AutoBitParameter("DoubledPawnOpeningMP", &dblOpening, 0, 10000 ),
	AutoBitParameter("DoubledPawnEndgameMP", &dblEndgame, 0, 10000 ),
	AutoBitParameter("IsolatedPawnOpeningMP", &isoOpening, 0, 10000 ),
	AutoBitParameter("IsolatedPawnEndgameMP", &isoEndgame, 0, 10000 ),
	AutoBitParameter("BackwardPawnOpeningMP", &bwdOpening, 0, 10000 ),
	AutoBitParameter("BackwardPawnEndgameMP", &bwdEndgame, 0, 10000 ),
	AutoBitParameter("LazyEvalMarginCP", &lazyEvalMargin, 0, 10000 )
};
