# CPW King

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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:

```#include "stdafx.h"
#include "0x88_math.h"
#include "eval.h"
#include "transposition.h"

#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 };

#define MINOR_ATT 2
#define ROOK_ATT  4
#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 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.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.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 */

/* 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 */

/* 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 */

/* 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 */

/* 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("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");
}

```