Difference between revisions of "CPW King"
GerdIsenberg (talk | contribs) |
GerdIsenberg (talk | contribs) |
||
Line 66: | Line 66: | ||
/* mobility values for various piece kinds */ | /* mobility values for various piece kinds */ | ||
− | int bish_mob[16] | + | int bish_mob[16] = { -10, -4, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8 }; |
− | int rook_mob[16] | + | 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}; | + | int knight_mob[9] = { -6, -4, 0, 2, 4, 5, 6, 7, 8 }; |
/* adjustements of piece value based on the number of own pawns */ | /* 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 knight_adj[9] = { -20, -16, -12, -8, -4, 0, 4, 8, 12 }; |
− | int rook_adj[9] = | + | int rook_adj[9] = { 15, 12, 9, 6, 3, 0, -3, -6, -9 }; |
#define MINOR_ATT 2 | #define MINOR_ATT 2 | ||
Line 84: | Line 84: | ||
struct eval_vector { | struct eval_vector { | ||
− | int MaterialAdjustement[2]; | + | int MaterialAdjustement[2]; |
− | int Blockages[2]; | + | int Blockages[2]; |
− | int PositionalThemes[2]; | + | int PositionalThemes[2]; |
− | int Mobility[2]; | + | int Mobility[2]; |
− | int KingAttackers[2]; // no. of pieces attacking enemy king | + | int KingAttackers[2]; // no. of pieces attacking enemy king |
− | int KingPressure[2]; // value of king pressure | + | int KingPressure[2]; // value of king pressure |
} v; | } v; | ||
Line 99: | Line 99: | ||
/* global flag used by mobility/attack detection functions to know | /* global flag used by mobility/attack detection functions to know | ||
− | + | if a piece examined currently is a king attacker */ | |
int isAttacker = 0; | int isAttacker = 0; | ||
Line 109: | Line 109: | ||
int fast_eval() { | 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; | |
} | } | ||
Line 128: | Line 128: | ||
*****************************************************************************/ | *****************************************************************************/ | ||
− | int eval( int alpha, int beta ) { | + | 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; | |
} | } | ||
Line 306: | Line 307: | ||
void eval_setPieceLists() { | void eval_setPieceLists() { | ||
− | /*********************************************************************** | + | /*********************************************************************** |
− | * Create local lists of pieces and pawns. This is done to avoid * | + | * Create local lists of pieces and pawns. This is done to avoid * |
− | * looping through the entire board three times: for pawns, for pieces * | + | * looping through the entire board three times: for pawns, for pieces * |
− | * and again evaluating mobility if lazy eval does not produce a cutoff.* | + | * 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; | S8 sq = row * 16 + col; | ||
− | if ( b.color[sq] != COLOR_EMPTY ) { | + | if (b.color[sq] != COLOR_EMPTY) { |
− | + | if (b.pieces[sq] == PAWN) { | |
− | + | pawnList[pawnIndex] = sq; | |
− | + | ++pawnIndex; | |
− | + | } | |
− | + | else { | |
− | + | pieceList[pieceIndex] = sq; | |
− | + | ++pieceIndex; | |
− | + | } | |
} | } | ||
− | + | } | |
} | } | ||
Line 340: | Line 341: | ||
void eval_setPawnLists() { | void eval_setPawnLists() { | ||
− | + | pawnIndex = 0; | |
− | + | for (U8 row = 0; row < 8; row++) | |
− | for ( U8 col=0; col < 8; col++ ) { | + | for (U8 col = 0; col < 8; col++) { |
S8 sq = row * 16 + col; | S8 sq = row * 16 + col; | ||
− | if ( b.color[sq] != COLOR_EMPTY && | + | if (b.color[sq] != COLOR_EMPTY && |
− | + | b.pieces[sq] == PAWN) { | |
− | + | pawnList[pawnIndex] = sq; | |
− | + | ++pawnIndex; | |
− | + | } | |
} | } | ||
} | } | ||
Line 357: | Line 358: | ||
void eval_clearVector() { | 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; | |
} | } | ||
Line 376: | Line 377: | ||
int wKingEval(S8 sq) { | 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 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 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 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; | + | return result; |
} | } | ||
int bKingShield() { | 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; | return result; | ||
Line 501: | Line 504: | ||
int getPawnScore() { | 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; | |
} | } | ||
Line 526: | Line 529: | ||
int getPawnScoreNoList() { | 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 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 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 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 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) { | 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) { | 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) { | 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) { | 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; | |
} | } | ||
Line 728: | Line 731: | ||
int isWPSupported(S8 sq) { | 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) { | 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; | |
} | } | ||
Line 751: | Line 754: | ||
void wKnightEval(S8 sq) { | 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) { | 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) { | 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) { | 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) { | 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) { | 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) { | 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) { | 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; | |
− | + | } | |
} | } | ||
Line 891: | Line 894: | ||
int wKnightMob(S8 sq) { | 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) { | 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) { | 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) { | 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) { | 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) { | 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]; | |
} | } | ||
Line 973: | Line 976: | ||
int wQueenMob(S8 sq) { | 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) { | 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 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] ) { | + | 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) { | 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; | |
} | } | ||
Line 1,060: | Line 1,063: | ||
void blockedCentralPawns() { | 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() { | 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() { | 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() { | 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 */ | /* determine if two squares lie on the same or neighbouring columns */ | ||
int isNearCol(S8 sq1, S8 sq2) { | 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) { | int isPiece(U8 color, U8 piece, S8 sq) { | ||
− | + | return ((b.pieces[sq] == piece) && (b.color[sq] == color)); | |
} | } | ||
Line 1,176: | Line 1,179: | ||
void printEval() { | 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"); | |
} | } | ||
</pre> | </pre> | ||
'''[[CPW-Engine|Up one Level]]''' | '''[[CPW-Engine|Up one Level]]''' |
Latest revision as of 15:46, 18 December 2018
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 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"); }