CPW King

Home * Engines * CPW-Engine * CPW_King

This is a patch to the CPW-Engine, changing its evaluation function. Modifications include:
 * getting rid of lazy eval
 * using eval hash table as default
 * modifying mobility functions, so that they will count number of attacks on squares near enemy king as well as the number of attackers
 * placing those functions in the piece-specific routines, before king safety calculation, so that it can make use of them
 * adding functions to count attacks by queens

Resulting program plays at the roughly the same strength as regular CPW-Engine, but is much more entertaining to watch. To obtain optimal results, piece/square values fo bishops and knights should be raised a tiny bit.

The most obvious drawback of the presented code is that it does not see attackers that are lined up, such as rooks doubled on a file. If You consider making this example into a real program, this is the first thing to change.

We need to add the following function to the eval_init.cpp, in order to define squares which are considered worthwhile to attack:

void setSquaresNearKing { for (int i = 0; i < 128; ++i) for (int j = 0; j < 128; ++j) {

e.sqNearK[WHITE][i][j] = 0; e.sqNearK[BLACK][i][j] = 0;

if ( IS_SQ(i) &&         IS_SQ(j) ) {

// squares constituting the ring around both kings

if (j == i + NORTH || j == i + SOUTH ||             j == i + EAST  || j == i + WEST  ||              j == i + NW    || j == i + NE    ||              j == i + SW    || j == i + SE ) {

e.sqNearK[WHITE][i][j] = 1; e.sqNearK[BLACK][i][j] = 1; }

/* squares in front of the white king ring */

if ( j == i + NORTH + NORTH ||              j == i + NORTH + NE    ||               j == i + NORTH + NW ) e.sqNearK[WHITE] [i] [j] = 1;

// squares in front og the black king ring

if ( j == i + SOUTH + SOUTH ||              j == i + SOUTH + SE    ||               j == i + SOUTH + SW ) e.sqNearK[WHITE] [i] [j] = 1; }

} }

The complete eval.cpp looks as follows:


 * 1) include "stdafx.h"
 * 2) include "0x88_math.h"
 * 3) include "eval.h"
 * 4) include "transposition.h"


 * 1) define use_eval_hash

/* mobility values for various piece kinds */ int bish_mob[16] = { -10, -4, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8 }; int rook_mob[16] = { -4,  -2, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 }; int knight_mob[9] = { -6, -4, 0, 2, 4, 5, 6, 7, 8};

/* adjustements of piece value based on the number of own pawns */ int knight_adj[9] = { -20, -16, -12, -8, -4, 0,  4,  8, 12}; int rook_adj[9] =  {  15,  12,   9,  6,  3,  0, -3, -6, -9};


 * 1) define MINOR_ATT 2
 * 2) define ROOK_ATT 4
 * 3) define QUEEN_ATT 8

/*******************************************************************
 * This struct holds data about certain aspects of evaluation,    *
 * which allows program to print them if desired.                 *

struct eval_vector { int MaterialAdjustement[2]; int Blockages[2]; int PositionalThemes[2]; int Mobility[2]; int KingAttackers[2]; // no. of pieces attacking enemy king int KingPressure[2]; // value of king pressure } v;

/* local lists of pieces and pawns and indexes to them */ U8 pieceList[32]; U8 pieceIndex; U8 pawnList[32]; U8 pawnIndex;

/* global flag used by mobility/attack detection functions to know if a piece examined currently is a king attacker */

int isAttacker = 0;

/*****************************************************************************
 * Fast evaluation (material + pcsq + pawn structure)       *

int fast_eval {

/* fold in incrementally updated values */ int result = p.PieceMaterial[WHITE] + p.PawnMaterial[WHITE] + p.Pcsq[WHITE] - p.PieceMaterial[BLACK] - p.PawnMaterial[BLACK] - p.Pcsq[BLACK];

/* evaluate pawn structure, remembering that a pawn list must be set */ result += getPawnScoreNoList;

/* return score relative to the side to move */ if ( b.stm == BLACK ) return -result; else return result; }

/*****************************************************************************
 * 1. Main evaluation function                              *

int eval( int alpha, int beta ) { int result;

/* probe the evaluatinon hashtable */ int probeval = tteval_probe; if (probeval != INVALID) return probeval;

/* set internal data of the evaluation function */ eval_setPieceLists; eval_clearVector;

/* sum the incrementally counted material and pcsq values */ result = p.PieceMaterial[WHITE] + p.PawnMaterial[WHITE] + p.Pcsq[WHITE] - p.PieceMaterial[BLACK] - p.PawnMaterial[BLACK] - p.Pcsq[BLACK];

/* tempo bonus */ if ( b.stm == WHITE ) result += e.TEMPO; else result -= e.TEMPO;

/* add in pawn structure evaluation */ result += getPawnScore;

/*******************************************************************    *  Low material correction - guarding against an illusory material * * advantage. Program will not not  expect to  win  having  only * * a single minor piece and no pawns. *    *******************************************************************/

if ( ( p.PawnMaterial[WHITE] == 0 )  &&          ( p.PieceMaterial[WHITE] < 400 ) &&          ( result > 0 ) ) return 0;

if ( ( p.PawnMaterial[BLACK] == 0 )  &&          ( p.PieceMaterial[BLACK] < 400 ) &&          ( result < 0 ) ) return 0;

/*******************************************************************    *  Program will not expect to win having only two knights in case  * * neither  side  has pawns. Please note that this code  assumes  * * different values for bishop and knight, and eval_init should  * * take care of that. *    *******************************************************************/

if ( !p.PawnMaterial[WHITE] && !p.PawnMaterial[BLACK] ) { if ( p.PieceMaterial[WHITE] == 2 * e.PIECE_VALUE[KNIGHT] && result > 0 ) result = 0; if ( p.PieceMaterial[BLACK] == 2 * e.PIECE_VALUE[KNIGHT] && result < 0 ) result = 0; }

/*******************************************************************   * Adjusting material value for the various combinations of pieces. *   * Currently it scores bishop, knight and rook pairs. The first one * * gets a bonus, the latter two - a penalty. Please also note that * * adjustements of knight and rook value based on the number of own * * pawns on the board are done within the piece-specific routines. *   *******************************************************************/

if ( p.PieceCount[WHITE][BISHOP] > 1 ) v.MaterialAdjustement[WHITE] += e.BISHOP_PAIR; if ( p.PieceCount[BLACK][BISHOP] > 1 ) v.MaterialAdjustement[BLACK] += e.BISHOP_PAIR; if ( p.PieceCount[WHITE][KNIGHT] > 1 ) v.MaterialAdjustement[WHITE] -= e.P_KNIGHT_PAIR; if ( p.PieceCount[BLACK][KNIGHT] > 1 ) v.MaterialAdjustement[BLACK] -= e.P_KNIGHT_PAIR; if ( p.PieceCount[WHITE] [ROOK] > 1 ) v.MaterialAdjustement[WHITE] -= e.P_ROOK_PAIR; if ( p.PieceCount[BLACK] [ROOK] > 1 ) v.MaterialAdjustement[BLACK] -= e.P_ROOK_PAIR;

// penalty for the lack of pawns - added 28.07.2008 if ( p.PieceCount[WHITE] [PAWN] == 0 ) v.MaterialAdjustement[WHITE] -= 16; if ( p.PieceCount[BLACK] [PAWN] == 0 ) v.MaterialAdjustement[BLACK] -= 16;

/********************************************************************   *   Evaluate piece placement. This giant loop calls piece-specific * *  functions which tend to do four things:                         * *                                                                  *    *   (1) they look for the trapped pieces and blockages              * *  (2) they look for rooks on (half) open files                    * *  (3) they calculate mobility and king safety                     * *  (4) they calculate adjustements of material value based on      * *     the number of pawns                                          * ********************************************************************/

for (int i=0; i < pieceIndex; i++) {

S8 sq = pieceList[i];

switch ( b.color[sq] ) { case WHITE : { switch ( b.pieces[sq] ) { case KNIGHT : wKnightEval(sq); break; case BISHOP : wBishopEval(sq); break; case ROOK  : wRookEval(sq);   break; case QUEEN : wQueenEval(sq);  break; }          }           break; case BLACK : { switch ( b.pieces[sq] ) { case KNIGHT : bKnightEval(sq); break; case BISHOP : bBishopEval(sq); break; case ROOK  : bRookEval(sq);   break; case QUEEN : bQueenEval(sq);  break; }          }           break; }   }

/********************************************************************   *   After  the piece evaluation loop we have the king tropism  data * *  in order, so it is time to do full king evaluation. For details * *  see comments in wKingEval function. *   ********************************************************************/

result += wKingEval( p.KingLoc[WHITE] ); result -= bKingEval( p.KingLoc[BLACK] );

/********************************************************************   *   Pattern evaluation - mainly things interrelated with the pawn   * *  position, not fitting elsewhere. *   ********************************************************************/

blockedCentralPawns; // don't block central pawns on initial squares blockedRooks;       // avoid pseudo-castling which blocks the rook slavMistake;        // don't play c4-c5 against Slav / Stonewall evalFianchetto;

/********************************************************************   *  Fold in data gathered in evaluation vector. *   ********************************************************************/

result += v.MaterialAdjustement[WHITE]; result -= v.MaterialAdjustement[BLACK]; result += v.Blockages[WHITE]; result -= v.Blockages[BLACK]; result += v.PositionalThemes[WHITE]; result -= v.PositionalThemes[BLACK];

/******************************************************************   *  Here mobility score is scaled according to the side to move. *   *  We  give  more weight to opponent's mobility  to  encourage    * * playing for restraint. *   ******************************************************************/

if ( sd.myside == WHITE ) { v.Mobility[BLACK] *= 4; v.Mobility[BLACK] /= 3; } else { v.Mobility[WHITE] *= 4; v.Mobility[WHITE] /= 3; }

result += v.Mobility[WHITE]; result -= v.Mobility[BLACK];

/*******************************************************************   *  Finally return the score relative to the side to move. *   *******************************************************************/

if ( b.stm == BLACK ) result = -result;

// save value in the eval tt   tteval_save(result);

return result; }

/***********************************************************************
 * 2. Preparatory routines                         *

void eval_setPieceLists {

/***********************************************************************
 * Create local  lists  of pieces and pawns. This is  done  to  avoid  *
 * looping through the entire board three times: for pawns, for pieces *
 * and again evaluating mobility if lazy eval does not produce a cutoff.*

pieceIndex = 0; pawnIndex = 0;

for (U8 row=0; row < 8; row++) for (U8 col=0; col < 8; col++) {

S8 sq = row * 16 + col;

if ( b.color[sq] != COLOR_EMPTY ) { if ( b.pieces[sq] == PAWN ) { pawnList[pawnIndex] = sq; ++pawnIndex; }        else { pieceList[pieceIndex] = sq; ++pieceIndex; }     }   } }

/***********************************************************************
 * This is a reduced version of the previous function, and it creates  *
 * only a list of pawns.                                               *

void eval_setPawnLists {

pawnIndex = 0;

for ( U8 row=0; row < 8; row++ ) for ( U8 col=0; col < 8; col++ ) {

S8 sq = row * 16 + col;

if ( b.color[sq] != COLOR_EMPTY &&          b.pieces[sq] == PAWN ) { pawnList[pawnIndex] = sq; ++pawnIndex; }   } }

void eval_clearVector { v.MaterialAdjustement[WHITE] = 0; v.MaterialAdjustement[BLACK] = 0; v.PositionalThemes[WHITE]   = 0; v.PositionalThemes[BLACK]   = 0; v.KingAttackers[WHITE] = 0; v.KingAttackers[BLACK] = 0; v.KingPressure[WHITE] = 0; v.KingPressure[BLACK] = 0; v.Blockages[WHITE]    = 0; v.Blockages[BLACK]    = 0; v.Mobility[WHITE]     = 0; v.Mobility[BLACK]     = 0; }

/************************************************************************
 * 3. King safety evaluation                         *

int wKingEval(S8 sq) { int result = 0;

if ( p.PieceMaterial[WHITE] < e.ENDGAME_MAT ) { result += e.endgame_king[sq]; } else { result += e.PIECESQUARE[KING][WHITE][sq]; result += wKingShield; result -= scaleAttacks( v.KingPressure[BLACK], v.KingAttackers[BLACK] );

/* Scale the middlegame king evaluation against remaining enemy material */ result *= p.PieceMaterial[BLACK]; result /= e.START_MATERIAL; }

return result; }

int bKingEval(S8 sq) { int result = 0;

if ( p.PieceMaterial[BLACK] < e.ENDGAME_MAT ) { result += e.endgame_king[sq]; } else { result += e.PIECESQUARE[KING][BLACK][sq]; result += bKingShield; result -= scaleAttacks( v.KingPressure[WHITE], v.KingAttackers[WHITE] );

/* Scale the middlegame king evaluation against remaining enemy material */ result *= p.PieceMaterial[WHITE]; result /= e.START_MATERIAL; }

return result; }

int scaleAttacks(int attack_value, int n_of_attackers) { int result;

switch ( n_of_attackers ) { case 0 : result = 0; case 1 : result = 0; case 2 : result = attack_value; case 3 : result = ( attack_value * 4 ) / 3; case 4 : result = ( attack_value * 3 ) / 2; default: result = attack_value * 2; }

return result; }

int wKingShield {

int result = 0;

/* king on the kingside */ if ( COL(p.KingLoc[WHITE]) > COL_E ) {

if ( isPiece(WHITE, PAWN, F2) ) result += e.SHIELD_1; else if ( isPiece(WHITE, PAWN, F3) ) result += e.SHIELD_2;

if ( isPiece(WHITE, PAWN, G2) ) result += e.SHIELD_1; else if ( isPiece(WHITE, PAWN, G3) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [WHITE] [ COL_G ] == 0 ) result -= e.P_NO_SHIELD;

if ( isPiece(WHITE, PAWN, H2) ) result += e.SHIELD_1; else if ( isPiece(WHITE, PAWN, H3) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [WHITE] [ COL_H ] == 0 ) result -= e.P_NO_SHIELD; }

/* king on the queenside */ else if ( COL(p.KingLoc[WHITE]) < COL_D ) {

if ( isPiece(WHITE, PAWN, A2) ) result += e.SHIELD_1; else if ( isPiece(WHITE, PAWN, A3) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [WHITE] [ COL_A ] == 0 ) result -= e.P_NO_SHIELD;

if ( isPiece(WHITE, PAWN, B2) ) result += e.SHIELD_1; else if ( isPiece(WHITE, PAWN, B3) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [WHITE] [ COL_B ] == 0 ) result -= e.P_NO_SHIELD;

if ( isPiece(WHITE, PAWN, C2) ) result += e.SHIELD_1; else if ( isPiece(WHITE, PAWN, C3) ) result += e.SHIELD_2; }

return result; }

int bKingShield { int result = 0;

/* king on the kingside */ if ( COL(p.KingLoc[BLACK]) > COL_E ) { if ( isPiece(BLACK, PAWN, F7) ) result += e.SHIELD_1; else if ( isPiece(BLACK, PAWN, F6) ) result += e.SHIELD_2;

if ( isPiece(BLACK, PAWN, G7) ) result += e.SHIELD_1; else if ( isPiece(BLACK, PAWN, G6) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [BLACK] [ COL_G ] == 0 ) result -= e.P_NO_SHIELD;

if ( isPiece(BLACK, PAWN, H7) ) result += e.SHIELD_1; else if ( isPiece(BLACK, PAWN, H6) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [BLACK] [ COL_H ] == 0 ) result -= e.P_NO_SHIELD; }

/* king on the queenside */ else if ( COL(p.KingLoc[BLACK]) < COL_D ) { if ( isPiece(BLACK, PAWN, A7) ) result += e.SHIELD_1; else if ( isPiece(BLACK, PAWN, A6) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [BLACK] [ COL_A ] == 0 ) result -= e.P_NO_SHIELD;

if ( isPiece(BLACK, PAWN, B7) ) result += e.SHIELD_1; else if ( isPiece(BLACK, PAWN, B6) ) result += e.SHIELD_2; else if ( p.PawnsOnFile [BLACK] [ COL_B ] == 0 ) result -= e.P_NO_SHIELD;

if ( isPiece(BLACK, PAWN, C7) ) result += e.SHIELD_1; else if ( isPiece(BLACK, PAWN, C6) ) result += e.SHIELD_2; } return result; }

/*********************************************************************************
 * 4. Pawn structure evaluaton                        *

int getPawnScore { int result;

/*****************************************************************************   *   This function wraps hashing mechanism around evalPawnStructure. Please * *  note  that since we use the pawn hashtable, evalPawnStructure must not * *  take into account the piece position. In a more elaborate program, pawn * *  hashtable would contain only the characteristics of pawn structure,  and * *  scoring them in conjunction with the piece position would have been done * *  elsewhere. *   ******************************************************************************/

int probeval = ttpawn_probe; if (probeval != INVALID) return probeval;

result = evalPawnStructure;

ttpawn_save(result);

return result; }

/* a clone of getPawnScore, used in fastEval, when the pawn list is not set */

int getPawnScoreNoList { int result;

int probeval = ttpawn_probe; if (probeval != INVALID) return probeval;

eval_setPawnLists; result = evalPawnStructure;

ttpawn_save(result);

return result; }

int evalPawnStructure { int result = 0;

/* 1. evaluate pawn center */ result += evalPawnCenter;

/* 2. evaluate doubled/tripled pawns */ for (U8 col=0; col < 8; col++) { result -= e.P_MULTI_PAWN[ p.PawnsOnFile [WHITE] [col] ]; result += e.P_MULTI_PAWN[ p.PawnsOnFile [BLACK] [col] ]; }

/* 3. core procedure: loop through pawn list, evaluating each pawn on the board */ for (U8 i=0; i < pawnIndex; i++) {

S8 sq = pawnList[i];

if (b.color[sq] == WHITE) result += wPawnEval(sq); else result -= bPawnEval(sq); }  return result; }

int evalPawnCenter { int result = 0;

if ( isPiece(WHITE, PAWN, D4) ) { if (isPiece(WHITE, PAWN, E4 ) ) result += e.DUO_D4E4; if (isPiece(WHITE, PAWN, C4 ) ) result += e.DUO_D4C4; if (isPiece(WHITE, PAWN, E3 ) ) result += e.DUO_D4E3; }

if ( isPiece(WHITE, PAWN, E4) ) { if (isPiece(WHITE, PAWN, F4 ) ) result += e.DUO_E4F4; if (isPiece(WHITE, PAWN, D3 ) ) result += e.DUO_E4D3; }

if ( isPiece(BLACK, PAWN, D5) ) { if (isPiece(BLACK, PAWN, E5 ) ) result -= e.DUO_D4E4; if (isPiece(BLACK, PAWN, C5 ) ) result -= e.DUO_D4C4; if (isPiece(BLACK, PAWN, E6 ) ) result -= e.DUO_D4E3; }

if ( isPiece(BLACK, PAWN, E5) ) { if (isPiece(BLACK, PAWN, F5 ) ) result -= e.DUO_E4F4; if (isPiece(BLACK, PAWN, D6 ) ) result -= e.DUO_E4D3; }

return result; }

int wPawnEval(S8 sq) { int result = 0;

/* 1. Evaluate passed pawns, scoring them higher if they are protected by friendly pawns */

if ( isWPFree(sq) ) { if (isWPSupported(sq) ) result += e.w_protected_passer[sq]; else result += e.w_passed_pawn[sq]; }

/* 2. Evaluate weak pawns */

if ( isWPWeak(sq) ) { result += e.w_weak_pawn[sq]; /* weak pawns on half-open files tend to be even weaker */ if ( p.PawnsOnFile[BLACK] [COL( sq) ] == 0 ) result -= 4; }

return result; }

int bPawnEval(S8 sq) { int result = 0;

/* 1. Evaluate passed pawns, scoring them higher if they are protected by friendly pawns */

if ( isBPFree(sq) ) { if ( isBPSupported(sq) ) result += e.b_protected_passer[sq]; else result += e.b_passed_pawn[sq]; }

/* 2. Evaluate weak pawns */

if ( isBPWeak(sq) ) { result += e.b_weak_pawn[sq]; /* weak pawns on half-open files tend to be even weaker */ if ( p.PawnsOnFile[WHITE] [COL( sq) ] == 0 ) result -= 4; }

return result; }

int isWPFree(S8 sq) {

S8 nextSq = sq + NORTH;

while ( IS_SQ(nextSq) ) {

/* either blocked by enemy pawn or doubled */ if ( b.pieces[nextSq] == PAWN ) return 0;

if ( IS_SQ(nextSq + WEST) && isPiece(BLACK, PAWN, nextSq + WEST) ) return 0;

if ( IS_SQ(nextSq + EAST) && isPiece(BLACK, PAWN, nextSq + EAST) ) return 0;

nextSq += NORTH; }

return 1; }

int isBPFree(S8 sq) { S8 nextSq = sq + SOUTH;

while ( IS_SQ(nextSq) ) {

/* either blocked by enemy pawn or doubled */ if ( b.pieces[nextSq] == PAWN ) return 0;

if ( IS_SQ(nextSq + WEST) && isPiece(WHITE, PAWN, nextSq + WEST) ) return 0;

if ( IS_SQ(nextSq + EAST) && isPiece(WHITE, PAWN, nextSq + EAST) ) return 0;

nextSq += SOUTH; }

return 1; }

int isWPWeak(S8 sq) { S8 nextSq = sq;

while ( IS_SQ(nextSq) ) {

if ( IS_SQ(nextSq + WEST) && isPiece(WHITE, PAWN, nextSq + WEST) ) return 0;

if ( IS_SQ(nextSq + EAST) && isPiece(WHITE, PAWN, nextSq + EAST) ) return 0;

nextSq += SOUTH; }

return 1; }

int isBPWeak(S8 sq) { S8 nextSq = sq;

while ( IS_SQ(nextSq) ) {

if ( IS_SQ(nextSq + WEST) && isPiece(BLACK, PAWN, nextSq + WEST) ) return 0;

if ( IS_SQ(nextSq + EAST) && isPiece(BLACK, PAWN, nextSq + EAST) ) return 0;

nextSq += NORTH; }

return 1; }

/****************************************************************
 * The next two procedures are used in passed pawn evaluation, *
 * the assumption being that passed pawns that are defended or *
 * or whose stop square is protected by a friendly pawn tend   *
 * to be stronger.                                             *

int isWPSupported(S8 sq) { if ( IS_SQ(sq+WEST) && isPiece(WHITE,PAWN, sq + WEST) ) return 1; if ( IS_SQ(sq+EAST) && isPiece(WHITE,PAWN, sq + EAST) ) return 1; if ( IS_SQ( sq+SE ) && isPiece(WHITE,PAWN, sq + SE ) ) return 1; if ( IS_SQ( sq+SW ) && isPiece(WHITE,PAWN, sq + SW ) ) return 1;

return 0; }

int isBPSupported(S8 sq) { if ( IS_SQ(sq+WEST) && isPiece(BLACK,PAWN, sq + WEST) ) return 1; if ( IS_SQ(sq+EAST) && isPiece(BLACK,PAWN, sq + EAST) ) return 1; if ( IS_SQ( sq+NE ) && isPiece(BLACK,PAWN, sq + NE ) ) return 1; if ( IS_SQ( sq+NW ) && isPiece(BLACK,PAWN, sq + NW ) ) return 1;

return 0; }

/************************************************************************************
 * 5. Evaluation of pieces                                   *

void wKnightEval(S8 sq) {

/* material value adjustement based on the no. of own pawns */ v.MaterialAdjustement[WHITE] += knight_adj[ p.PieceCount[WHITE] [PAWN] ];

/* mobility and king attacks calculation */ v.Mobility[WHITE] += wKnightMob(sq);

/* trapped or blocking knight */ switch (sq) { case A8 : if (isPiece(BLACK, PAWN, A7) || isPiece(BLACK, PAWN, C7) ) v.Blockages[WHITE] -= e.P_KNIGHT_TRAPPED_A8; break; case H8 : if (isPiece(BLACK, PAWN, H7) || isPiece(BLACK, PAWN, F7) ) v.Blockages[WHITE] -= e.P_KNIGHT_TRAPPED_A8; break; case A7 : if (isPiece(BLACK, PAWN, A6) && isPiece(BLACK, PAWN, B7) ) v.Blockages[WHITE] -= e.P_KNIGHT_TRAPPED_A7; break; case H7 : if (isPiece(BLACK, PAWN, H6) && isPiece(BLACK, PAWN, G7) ) v.Blockages[WHITE] -= e.P_KNIGHT_TRAPPED_A7; break; case C3 : if (isPiece(WHITE, PAWN, C2) && isPiece(WHITE, PAWN, D4) && !isPiece(WHITE, PAWN, E4) ) v.Blockages[WHITE] -= e.P_C3_KNIGHT; break; } }

void bKnightEval(S8 sq) {

/* material value adjustement based on the no. of own pawns */ v.MaterialAdjustement[BLACK] += knight_adj[ p.PieceCount[BLACK] [PAWN] ];

/* mobility and king attack calculation */ v.Mobility[BLACK] += bKnightMob(sq);

/* trapped or blocking knight */ switch (sq) { case A1 : if (isPiece(WHITE, PAWN, A2) || isPiece(WHITE, PAWN, C2) ) v.Blockages[BLACK] -= e.P_KNIGHT_TRAPPED_A8; break; case H1 : if (isPiece(WHITE, PAWN, H2) || isPiece(WHITE, PAWN, F2) ) v.Blockages[BLACK] -= e.P_KNIGHT_TRAPPED_A8; break; case A2 : if (isPiece(WHITE, PAWN, A3) && isPiece(WHITE, PAWN, B2) ) v.Blockages[BLACK] -= e.P_KNIGHT_TRAPPED_A7; break; case H2 : if (isPiece(WHITE, PAWN, H3) && isPiece(WHITE, PAWN, G2) ) v.Blockages[BLACK] -= e.P_KNIGHT_TRAPPED_A7; break; case C6 : if (isPiece(BLACK, PAWN, C7) && isPiece(BLACK, PAWN, D5) && !isPiece(BLACK, PAWN, E5) ) v.Blockages[BLACK] -= e.P_C3_KNIGHT; break; } }

void wBishopEval(S8 sq) {

/* mobility and king attack calculaion */ v.Mobility[WHITE] += wBishopMob(sq);

/* trapped bishop and returning bishop */ switch (sq) { case A7 : if ( isPiece(BLACK, PAWN, B6) ) v.Blockages[WHITE] -= e.P_BISHOP_TRAPPED_A7; break; case H7 : if ( isPiece(BLACK, PAWN, G6) ) v.Blockages[WHITE] -= e.P_BISHOP_TRAPPED_A7; break; case B8 : if ( isPiece(BLACK, PAWN, C7) ) v.Blockages[WHITE] -= e.P_BISHOP_TRAPPED_A7; break; case G8 : if ( isPiece(BLACK, PAWN, F7) ) v.Blockages[WHITE] -= e.P_BISHOP_TRAPPED_A7; break; case A6 : if ( isPiece(BLACK, PAWN, B5) ) v.Blockages[WHITE] -= e.P_BISHOP_TRAPPED_A6; break; case H6 : if ( isPiece(BLACK, PAWN, G5) ) v.Blockages[WHITE] -= e.P_BISHOP_TRAPPED_A6; break; case F1 : if ( isPiece(WHITE, KING, G1) ) v.PositionalThemes[WHITE] += e.RETURNING_BISHOP; break; case C1 : if ( isPiece(WHITE, KING, B1) ) v.PositionalThemes[WHITE] += e.RETURNING_BISHOP; break; } }

void bBishopEval(S8 sq) {

/* mobility and king attack calculation */ v.Mobility[BLACK] += bBishopMob(sq);

/* trapped bishop and returning bishop */ switch (sq) { case A2 : if ( isPiece(WHITE, PAWN, B3) ) v.Blockages[BLACK] -= e.P_BISHOP_TRAPPED_A7; break; case H2 : if ( isPiece(WHITE, PAWN, G3) ) v.Blockages[BLACK] -= e.P_BISHOP_TRAPPED_A7; break; case B1 : if ( isPiece(WHITE, PAWN, C2) ) v.Blockages[BLACK] -= e.P_BISHOP_TRAPPED_A7; break; case G1 : if ( isPiece(WHITE, PAWN, F2) ) v.Blockages[BLACK] -= e.P_BISHOP_TRAPPED_A7; break; case A3 : if ( isPiece(WHITE, PAWN, B4) ) v.Blockages[BLACK] -= e.P_BISHOP_TRAPPED_A6; break; case H3 : if ( isPiece(WHITE, PAWN, G4) ) v.Blockages[BLACK] -= e.P_BISHOP_TRAPPED_A6; break; case F8 : if ( isPiece(BLACK, KING, G8) ) v.PositionalThemes[BLACK] += e.RETURNING_BISHOP; break; case C8 : if ( isPiece(BLACK, KING, B8) ) v.PositionalThemes[BLACK] += e.RETURNING_BISHOP; break; } }

void wRookEval(S8 sq) {

/* material value adjustement based on the no. of own pawns */ v.MaterialAdjustement[WHITE] += rook_adj[ p.PieceCount[WHITE] [PAWN] ];

/* mobility and king attack calculation */ v.Mobility[WHITE] += wRookMob(sq);

/* open and half-open files */ if ( p.PawnsOnFile [WHITE] [ COL(sq) ] == 0 ) {

if ( p.PawnsOnFile [BLACK] [ COL(sq) ] == 0 ) v.PositionalThemes[WHITE] += e.ROOK_OPEN; else v.PositionalThemes[WHITE] += e.ROOK_HALF; } }

void bRookEval(S8 sq) {

/* material value adjustement based on the no. of own pawns */ v.MaterialAdjustement[BLACK] += rook_adj[ p.PieceCount[BLACK] [PAWN] ];

/* mobility and king attack calculation */ v.Mobility[BLACK] += bRookMob(sq);

/* open and half-open files */ if ( p.PawnsOnFile [BLACK] [ COL(sq) ] == 0 ) {

if ( p.PawnsOnFile [WHITE] [ COL(sq) ] == 0 ) v.PositionalThemes[BLACK] += e.ROOK_OPEN; else v.PositionalThemes[BLACK] += e.ROOK_HALF; } }

void wQueenEval(S8 sq) {

/* mobility and king attack calculation */ v.Mobility[WHITE] += wQueenMob(sq);

/* penalize premature developement */ if ( ROW(sq) > ROW_2 ) { if ( isPiece(WHITE, KNIGHT, B1) ) v.PositionalThemes[WHITE] -= 2; if ( isPiece(WHITE, BISHOP, C1) ) v.PositionalThemes[WHITE] -= 2; if ( isPiece(WHITE, BISHOP, F1) ) v.PositionalThemes[WHITE] -= 2; if ( isPiece(WHITE, KNIGHT, G1) ) v.PositionalThemes[WHITE] -= 2; } }

void bQueenEval(S8 sq) {

/* mobility and king attack calculation */ v.Mobility[BLACK] += bQueenMob(sq);

/* penalize premature developement */ if ( ROW(sq) < ROW_7 ) { if ( isPiece(BLACK, KNIGHT, B8) ) v.PositionalThemes[BLACK] -= 2; if ( isPiece(BLACK, BISHOP, C8) ) v.PositionalThemes[BLACK] -= 2; if ( isPiece(BLACK, BISHOP, F8) ) v.PositionalThemes[BLACK] -= 2; if ( isPiece(BLACK, KNIGHT, G8) ) v.PositionalThemes[BLACK] -= 2; } }

/**********************************************************************************
 * 6. Mobility and king attack evaluation                  *

int wKnightMob(S8 sq) {

isAttacker = 0; int localMobility = leaperMobility(WHITE, sq, KNIGHT, MINOR_ATT); if ( isAttacker ) ++v.KingAttackers[WHITE];

return knight_mob[localMobility]; }

int bKnightMob(S8 sq) {

isAttacker = 0; int localMobility = leaperMobility(BLACK, sq, KNIGHT, MINOR_ATT); if ( isAttacker ) ++v.KingAttackers[BLACK];

return knight_mob[localMobility]; }

int wBishopMob(S8 sq) {

isAttacker = 0;

int localMobility = sliderMobility(WHITE, sq, NE, MINOR_ATT ) + sliderMobility(WHITE, sq, NW, MINOR_ATT ) + sliderMobility(WHITE, sq, SE, MINOR_ATT ) + sliderMobility(WHITE, sq, SW, MINOR_ATT );

if ( isAttacker ) ++v.KingAttackers[WHITE];

return bish_mob[localMobility]; }

int bBishopMob(S8 sq) {

isAttacker = 0;

int localMobility = sliderMobility(BLACK, sq, NE, MINOR_ATT ) + sliderMobility(BLACK, sq, NW, MINOR_ATT ) + sliderMobility(BLACK, sq, SE, MINOR_ATT ) + sliderMobility(BLACK, sq, SW, MINOR_ATT );

if ( isAttacker ) ++v.KingAttackers[BLACK];

return bish_mob[localMobility]; }

int wRookMob(S8 sq) {

isAttacker = 0;

int localMobility = sliderMobility(WHITE, sq, NORTH, ROOK_ATT ) + sliderMobility(WHITE, sq, SOUTH, ROOK_ATT ) + sliderMobility(WHITE, sq, EAST, ROOK_ATT ) + sliderMobility(WHITE, sq, WEST, ROOK_ATT );

if ( isAttacker ) ++v.KingAttackers[WHITE];

return rook_mob[localMobility]; }

int bRookMob(S8 sq) {

isAttacker = 0;

int localMobility = sliderMobility(BLACK, sq, NORTH, ROOK_ATT ) + sliderMobility(BLACK, sq, SOUTH, ROOK_ATT ) + sliderMobility(BLACK, sq, EAST, ROOK_ATT ) + sliderMobility(BLACK, sq, WEST, ROOK_ATT );

if ( isAttacker ) ++v.KingAttackers[BLACK];

return rook_mob[localMobility]; }

// with queen, currently we look for king attacks, not for mobility

int wQueenMob(S8 sq) {

isAttacker = 0;

int localMobility = sliderMobility(WHITE, sq, NORTH, QUEEN_ATT ) + sliderMobility(WHITE, sq, SOUTH, QUEEN_ATT ) + sliderMobility(WHITE, sq, EAST, QUEEN_ATT ) + sliderMobility(WHITE, sq, WEST, QUEEN_ATT ) + sliderMobility(WHITE, sq, NE, QUEEN_ATT ) + sliderMobility(WHITE, sq, NW, QUEEN_ATT ) + sliderMobility(WHITE, sq, SE, QUEEN_ATT ) + sliderMobility(WHITE, sq, SW, QUEEN_ATT );

if ( isAttacker ) ++v.KingAttackers[WHITE];

return 0; }

int bQueenMob(S8 sq) {

isAttacker = 0;

int localMobility = sliderMobility(BLACK, sq, NORTH, QUEEN_ATT ) + sliderMobility(BLACK, sq, SOUTH, QUEEN_ATT ) + sliderMobility(BLACK, sq, EAST, QUEEN_ATT ) + sliderMobility(BLACK, sq, WEST, QUEEN_ATT ) + sliderMobility(BLACK, sq, NE, QUEEN_ATT ) + sliderMobility(BLACK, sq, NW, QUEEN_ATT ) + sliderMobility(BLACK, sq, SE, QUEEN_ATT ) + sliderMobility(BLACK, sq, SW, QUEEN_ATT );

if ( isAttacker ) ++v.KingAttackers[BLACK];

return 0; }

int sliderMobility(U8 color, S8 sq, int vect, int attBonus) { int nextSq = sq + vect; int result = 0;

while ( IS_SQ(nextSq) ) {

if ( e.sqNearK[!color] [p.KingLoc[!color] ] [nextSq] ) { isAttacker = 1; v.KingPressure[color] += attBonus; }

if (b.color[nextSq] != COLOR_EMPTY ) { if ( b.color[nextSq] != color ) return result + 1; return result; }

++result;

nextSq = nextSq + vect; }

return result; }

int leaperMobility(U8 color, S8 sq, char byPiece, int attBonus) { S8 nextSq; int result = 0;

for (U8 dir=0;dir<8;dir++) { nextSq = sq + vector[byPiece][dir];

if ( IS_SQ(nextSq) && b.color[nextSq] != color ) {

/* king attack */ if ( e.sqNearK[!color] [p.KingLoc[!color] ] [nextSq] ) { isAttacker = 1; v.KingPressure[color] += attBonus; }          ++result; }   }

return result; }

/***************************************************************************************
 * 7. Pattern detection                                       *

void blockedCentralPawns { if ( isPiece(WHITE,PAWN,D2) && b.color[D3] != COLOR_EMPTY ) v.Blockages[WHITE] -= e.P_BLOCK_CENTRAL_PAWN; if ( isPiece(WHITE,PAWN,E2) && b.color[E3] != COLOR_EMPTY ) v.Blockages[WHITE] -= e.P_BLOCK_CENTRAL_PAWN; if ( isPiece(BLACK,PAWN,D7) && b.color[D6] != COLOR_EMPTY ) v.Blockages[BLACK] -= e.P_BLOCK_CENTRAL_PAWN; if ( isPiece(BLACK,PAWN,E7) && b.color[E6] != COLOR_EMPTY ) v.Blockages[BLACK] -= e.P_BLOCK_CENTRAL_PAWN; }

void blockedRooks {

if ( ( isPiece(WHITE, KING, F1) || isPiece(WHITE, KING, G1 ) )&&        ( isPiece(WHITE, ROOK, H1) || isPiece(WHITE, ROOK, G1 ) )       ) v.Blockages[WHITE] -= e.P_KING_BLOCKS_ROOK;

if ( ( isPiece(WHITE, KING, C1) || isPiece(WHITE, KING, B1 ) )&&        ( isPiece(WHITE, ROOK, A1) || isPiece(WHITE, ROOK, B1 ) )       ) v.Blockages[WHITE] -= e.P_KING_BLOCKS_ROOK;

if ( ( isPiece(BLACK, KING, F8) || isPiece(BLACK, KING, G8 ) )&&        ( isPiece(BLACK, ROOK, H8) || isPiece(BLACK, ROOK, G8 ) )       ) v.Blockages[BLACK] -= e.P_KING_BLOCKS_ROOK;

if ( ( isPiece(BLACK, KING, C8) || isPiece(BLACK, KING, B8 ) )&&        ( isPiece(BLACK, ROOK, A8) || isPiece(BLACK, ROOK, B8 ) )       ) v.Blockages[BLACK] -= e.P_KING_BLOCKS_ROOK; }

void slavMistake { if ( isPiece(WHITE, PAWN, D4) &&         isPiece(WHITE, PAWN, C5) &&          isPiece(BLACK, PAWN, D5) &&          isPiece(BLACK, PAWN, C6) ) v.PositionalThemes[WHITE] -= e.P_SLAV_MISTAKE;

if ( isPiece(BLACK, PAWN, D5) &&         isPiece(BLACK, PAWN, C4) &&          isPiece(WHITE, PAWN, D4) &&          isPiece(WHITE, PAWN, C3) ) v.PositionalThemes[BLACK] -= e.P_SLAV_MISTAKE; }

void evalFianchetto {

if ( isPiece(WHITE, PAWN, G3) ) { if ( isPiece(WHITE, BISHOP, G2 ) ) v.PositionalThemes[WHITE] += e.FIANCHETTO; else { if ( !isPiece(WHITE, BISHOP, F3 ) &&               !isPiece(WHITE, BISHOP, H1 ) &&                !isPiece(WHITE, BISHOP, H3 ) ) v.PositionalThemes[WHITE] -= e.P_NO_FIANCHETTO; }   }

if ( isPiece(WHITE, PAWN, B3) ) { if ( isPiece(WHITE, BISHOP, B2 ) ) v.PositionalThemes[WHITE] += e.FIANCHETTO; else { if ( !isPiece(WHITE, BISHOP, C3 ) &&               !isPiece(WHITE, BISHOP, A1 ) &&                !isPiece(WHITE, BISHOP, A3 ) )

v.PositionalThemes[WHITE] -= e.P_NO_FIANCHETTO; }   }

if ( isPiece(BLACK, PAWN, G6) ) { if ( isPiece(BLACK, BISHOP, G7 ) ) v.PositionalThemes[BLACK] += e.FIANCHETTO; else { if ( !isPiece(BLACK, BISHOP, F6 ) &&               !isPiece(BLACK, BISHOP, H8 ) &&                !isPiece(BLACK, BISHOP, H6 ) ) v.PositionalThemes[BLACK] -= e.P_NO_FIANCHETTO; }   }

if ( isPiece(BLACK, PAWN, B6) ) { if ( isPiece(BLACK, BISHOP, B7 ) ) v.PositionalThemes[BLACK] += e.P_NO_FIANCHETTO; else { if ( !isPiece(BLACK, BISHOP, C6 ) &&               !isPiece(BLACK, BISHOP, A8 ) &&                !isPiece(BLACK, BISHOP, A6 ) ) v.PositionalThemes[BLACK] -= e.P_NO_FIANCHETTO; }   } }

/* determine if two squares lie on the same or neighbouring columns */ int isNearCol(S8 sq1, S8 sq2) { U8 c1 = COL(sq1); U8 c2 = COL(sq2); U8 hor_dist = (U8) abs(c1 - c2);

if ( hor_dist < 2 ) return 1; else return 0; }

int isPiece(U8 color, U8 piece, S8 sq) { return ( (b.pieces[sq] == piece) && (b.color[sq] == color) ); }

/***************************************************************************************
 * 8. Printing eval results                                   *

void printEval { eval(-30000,30000); printf("--\n"); printf("Total value (for side to move): %d \n", eval(-INFINITY,INFINITY) ); printf("Material balance   : %d \n", p.PieceMaterial[WHITE] + p.PawnMaterial[WHITE] - p.PieceMaterial[BLACK] - p.PawnMaterial[BLACK] ); printf("Material adjustement: %d \n", v.MaterialAdjustement[WHITE] - v.MaterialAdjustement[BLACK]); printf("Piece/square tables : %d \n", p.Pcsq[WHITE] - p.Pcsq[BLACK]); printf("Pawn structure     : %d \n", evalPawnStructure ); printf("Blockages          : %d \n", v.Blockages[WHITE] - v.Blockages[BLACK] ); printf("Positional themes  : %d \n", v.PositionalThemes[WHITE] - v.PositionalThemes[BLACK] ); printf("Mobility: white %d, black %d, total %d \n", v.Mobility[WHITE], v.Mobility[BLACK], v.Mobility[WHITE] - v.Mobility[BLACK] ); printf("King pressure: white %d, black %d \n", v.KingPressure[WHITE], v.KingPressure[BLACK] ); printf("King attackers: white %d, black %d \n", v.KingAttackers[WHITE], v.KingAttackers[BLACK] ); printf("Kings: white %d, black %d, total: %d \n", wKingEval(p.KingLoc[WHITE]), bKingEval(p.KingLoc[BLACK] ), wKingEval(p.KingLoc[WHITE])-bKingEval(p.KingLoc[BLACK]) ); printf("Tempo: "); if ( b.stm == WHITE ) printf("%d", e.TEMPO); else printf("%d", -e.TEMPO); printf("\n"); printf("--\n"); }

Up one Level