Home Previous Bottom Next

Writing a chess program in 99 steps


13  The evaluation function

Before the search algorithm is implemented, we need to have an evaluation function for the leaf nodes, or else there will be nothing to search! As was explained in the introduction, winglet will provide you with a basis for experimenting and improving evaluation. The evaluation is implemented as a member function of the Board structure. It is rudimentary, but will beat most human players unless they survive until some elementary endgame - it basically doesn't know how to play endgames.  The evaluation takes following components into account:

  • Material value (the most important component). If material is unbalanced, then the winning side gets a bonus for exchanging pieces.

  • Pawn position and structure (giving a bonus for passed pawns and penalizing doubled, isolated or backward pawns)

  • Knight position

  • Bishop position, and giving a bonus for having the bishop pair.

  • Rook position (with a bonus for being on an open file or behind a passed pawn)

  • Queen position

  • King position, the king should be protected by his own pawns in the opening and midgame, and not close to enemy pieces.
    During the endgame the king position must be central and near his own pawns.

The evaluation calculates scores from white's perspective, in centipawns, and finally returns the score from the perspective of the side to move (for reasons I will explain in the next section about the search algorithm), so:

if (board.nextMove) return -score;
else return score;

There are two compiler directives added: WINGLET_VERBOSE_EVAL will activate detailed output for every scoring component that is calculated in eval(). The intended use is to tune evaluation by reading, or manually setting up a position, and visually check all static evaluation components. 
WINGLET_DEBUG_EVAL
activates an evaluation symmetry test, where the board position is mirrored, and the evaluation function is called again to see if the score is the same as before. 
This test is also added in perft, so this is a fast way of checking for any unintended asymmetries in the evaluation function.  Both directives can be used independently.

 

A number of new bitboards are introduced, specifically designed to make the evaluation faster. Here you'll see another important reason for using bitboards.

 

Scoring parameters are supplied in globals.h.   The scoring arrays need to be color-symmetrical (i.e. leading to the same results for white and black).  To make scoring data entry easier, eliminate typos, and guarantee symmetry, these arrays are only initialized for white, and then calculated for black, this is done in dataInit()

Some scoring arrays are supplied mirrored, i.e. starting with the last rank. They will transformed back in the right order in dataInit(). This is again done to make scoring data entry easier, because you can enter the data as if you're  looking at a chess board from White's perspective (i.e. with square a1 in the lower left corner instead of the upper left corner).

 

step 44: eval.cpp

#include <iostream>
#include "defines.h"
#include "protos.h"
#include "extglobals.h"
#include "board.h"
 
int Board::eval()
{
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// This is winglet's evaluation function
// The score is calculated from White's perspective (in centipawns)
// and returned from the perspective of the side to move.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       int score, square;
       int whitepawns, whiteknights, whitebishops, whiterooks, whitequeens;
       int blackpawns, blackknights, blackbishops, blackrooks, blackqueens;
       int whitekingsquare, blackkingsquare;
       int whitetotalmat, blacktotalmat;
       int whitetotal, blacktotal;
       BOOLTYPE endgame;
       BitMap temp, whitepassedpawns, blackpassedpawns;
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Material
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       score = board.Material;
       #ifdef WINGLET_VERBOSE_EVAL
              std::cout << "EVAL> MATERIAL>                       " << board.Material << std::endl;
       #endif
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Remember where the kings are
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       whitekingsquare = firstOne(board.whiteKing);
       #ifdef WINGLET_VERBOSE_EVAL
              std::cout << "EVAL> WHITE KING POSITION>            " << SQUARENAME[whitekingsquare] << std::endl;
       #endif
       blackkingsquare = firstOne(board.blackKing);
       #ifdef WINGLET_VERBOSE_EVAL
              std::cout << "EVAL> BLACK KING POSITION>            " << SQUARENAME[blackkingsquare] << std::endl;
       #endif
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Piece counts, note that we could have done this incrementally in (un)makeMove
// because it's basically the same thing as keeping board.Material up to date..
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       whitepawns = bitCnt(board.whitePawns);
       whiteknights = bitCnt(board.whiteKnights);
       whitebishops = bitCnt(board.whiteBishops);
       whiterooks = bitCnt(board.whiteRooks);
       whitequeens = bitCnt(board.whiteQueens);
       whitetotalmat = 3 * whiteknights + 3 * whitebishops + 5 * whiterooks + 10 * whitequeens;
       whitetotal = whitepawns + whiteknights + whitebishops + whiterooks + whitequeens;
       blackpawns = bitCnt(board.blackPawns);
       blackknights = bitCnt(board.blackKnights);
       blackbishops = bitCnt(board.blackBishops);
       blackrooks = bitCnt(board.blackRooks);
       blackqueens = bitCnt(board.blackQueens);
       blacktotalmat = 3 * blackknights + 3 * blackbishops + 5 * blackrooks + 10 * blackqueens;
       blacktotal = blackpawns + blackknights + blackbishops + blackrooks + blackqueens;
       #ifdef WINGLET_VERBOSE_EVAL
              std::cout << "EVAL> WHITE TOTAL MAT>                " << whitetotalmat << std::endl;
              std::cout << "EVAL> BLACK TOTAL MAT>                " << blacktotalmat << std::endl;
              std::cout << "EVAL> WHITE TOTAL>                    " << whitetotal << std::endl;
              std::cout << "EVAL> BLACK TOTAL>                    " << blacktotal << std::endl;
       #endif
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Check if we are in the endgame
// Anything less than a queen (=10) + rook (=5) is considered endgame
// (pawns excluded in this count)
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       endgame = (whitetotalmat < 15 || blacktotalmat < 15);
       #ifdef WINGLET_VERBOSE_EVAL
              std::cout << "EVAL> ENDGAME>                        " << endgame << std::endl;
       #endif
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate for draws due to insufficient material:
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       if (!whitepawns && !blackpawns)
       {
              // king versus king:
              if ((whitetotalmat == 0) && (blacktotalmat == 0)) return 0;
 
              // king and knight versus king:
              if (((whitetotalmat == 3) && (whiteknights == 1) && (blacktotalmat == 0)) ||
                     ((blacktotalmat == 3) && (blackknights == 1) && (whitetotalmat == 0))) return 0;
 
              // 2 kings with one or more bishops, and all bishops on the same colour:
              if ((whitebishops + blackbishops) > 0)
              {
                     if ((whiteknights == 0) && (whiterooks == 0) && (whitequeens == 0) &&
                           (blackknights == 0) && (blackrooks == 0) && (blackqueens == 0))
                     {
                           if (!((board.whiteBishops | board.blackBishops) & WHITE_SQUARES) ||
                    !((board.whiteBishops | board.blackBishops) & BLACK_SQUARES)) return 0;
                     }
              }
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate MATERIAL
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Have the winning side prefer to exchange pieces
// Every exchange with unequal material adds 3 centipawns to the score
// Loosing a piece (from balanced material) becomes more
// severe in the endgame
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       #ifdef WINGLET_VERBOSE_EVAL
              int iexch = 0;
              int iwhitepos = 0;
              int iwhitepawns = 0;
              int iwhiteking = 0;
              int iblackpos = 0;
              int iblackpawns = 0;
              int iblackking = 0;
       #endif
 
       if (whitetotalmat + whitepawns > blacktotalmat + blackpawns)
       {
              score += 45 + 3 * whitetotal - 6 * blacktotal;
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> EXCHANGE WHITE>                 " << (45 + 3 * whitetotal - 6 * blacktotal) << std::endl;
                     iexch = (45 + 3 * whitetotal - 6 * blacktotal);
              #endif
       }
       else
       {
              if (whitetotalmat + whitepawns < blacktotalmat + blackpawns)
              {
                     score += -45 - 3 * blacktotal + 6 * whitetotal;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL> EXCHANGE BLACK>                 " << (-45 - 3 * blacktotal + 6 * whitetotal) << std::endl;
                           iexch = (-45 - 3 * blacktotal + 6 * whitetotal);
                     #endif
              }
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate WHITE PIECES
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate white pawns
// - position on the board
// - distance from opponent king
// - distance from own king
// - passed, doubled, isolated or backward pawns
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       whitepassedpawns = 0;
       temp = board.whitePawns;
       while (temp)
       {
              square = firstOne(temp);
 
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> WHITE PAWN ON                   " << SQUARENAME[square] << std::endl;
              #endif
 
              score += PAWNPOS_W[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << PAWNPOS_W[square] << std::endl;
                     iwhitepos += PAWNPOS_W[square];
                     iwhitepawns += PAWNPOS_W[square];
              #endif
 
              score += PAWN_OPPONENT_DISTANCE[DISTANCE[square][blackkingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << PAWN_OPPONENT_DISTANCE[DISTANCE[square][blackkingsquare]] << std::endl;
                     iwhitepos += PAWN_OPPONENT_DISTANCE[DISTANCE[square][blackkingsquare]];
                     iwhitepawns += PAWN_OPPONENT_DISTANCE[DISTANCE[square][blackkingsquare]];
              #endif
 
              if (endgame)
              {
                     score += PAWN_OWN_DISTANCE[DISTANCE[square][whitekingsquare]];
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  DISTANCE TO OWN KING SCORE     " << PAWN_OWN_DISTANCE[DISTANCE[square][blackkingsquare]] << std::endl;
                           iwhitepos += PAWN_OWN_DISTANCE[DISTANCE[square][whitekingsquare]];
                           iwhitepawns += PAWN_OWN_DISTANCE[DISTANCE[square][whitekingsquare]];
                     #endif
              }
 
              if (!(PASSED_WHITE[square] & board.blackPawns))
              {
                     score += BONUS_PASSED_PAWN;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  IS PASSED, BONUS IS            " << BONUS_PASSED_PAWN << std::endl;
                           iwhitepos += BONUS_PASSED_PAWN;
                           iwhitepawns += BONUS_PASSED_PAWN;
                     #endif
 
                     // remember its location, we need it later when evaluating the white rooks:
                     whitepassedpawns ^= BITSET[square];
              }
 
              if ((board.whitePawns ^ BITSET[square]) & FILEMASK[square])
              {
                     score -= PENALTY_DOUBLED_PAWN;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  IS DOUBLED, PENALTY IS         " << PENALTY_DOUBLED_PAWN << std::endl;
                           iwhitepos -= PENALTY_DOUBLED_PAWN;
                            iwhitepawns -= PENALTY_DOUBLED_PAWN;
                     #endif
              }
 
              if (!(ISOLATED_WHITE[square] & board.whitePawns))
              {
                     score -= PENALTY_ISOLATED_PAWN;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  IS ISOLATED, PENALTY IS        " << PENALTY_ISOLATED_PAWN << std::endl;
                           iwhitepos -= PENALTY_ISOLATED_PAWN;
                           iwhitepawns -= PENALTY_ISOLATED_PAWN;
                     #endif
              }
              else
              {
                     // If it is not isolated, then it might be backward. Two conditions must be true:
                     //  1) if the next square is controlled by an enemy pawn - we use the PAWN_ATTACKS bitmaps to check this
                     //  2) if there are no pawns left that could defend this pawn
                     if ((WHITE_PAWN_ATTACKS[square + 8] & board.blackPawns))
                     {
                           if (!(BACKWARD_WHITE[square] & board.whitePawns))
                           {
                                  score -= PENALTY_BACKWARD_PAWN;
                                  #ifdef WINGLET_VERBOSE_EVAL
                                         std::cout << "EVAL>  IS BACKWARD, PENALTY IS        " << PENALTY_BACKWARD_PAWN << std::endl;
                                         iwhitepos -= PENALTY_BACKWARD_PAWN;
                                         iwhitepawns -= PENALTY_BACKWARD_PAWN;
                                  #endif
                           }
                     }
              }
 
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate white knights
// - position on the board
// - distance from opponent king
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       temp = board.whiteKnights;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> WHITE KNIGHT ON                 " << SQUARENAME[square] << std::endl;
              #endif
 
              score += KNIGHTPOS_W[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << KNIGHTPOS_W[square] << std::endl;
                     iwhitepos += KNIGHTPOS_W[square];
              #endif
 
              score += KNIGHT_DISTANCE[DISTANCE[square][blackkingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << KNIGHT_DISTANCE[DISTANCE[square][blackkingsquare]] << std::endl;
                     iwhitepos += KNIGHT_DISTANCE[DISTANCE[square][blackkingsquare]];
              #endif
 
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate white bishops
// - having the pair
// - position on the board
// - distance from opponent king
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       if (board.whiteBishops)
       {
              if (board.whiteBishops & (board.whiteBishops - 1))
              {
                     score += BONUS_BISHOP_PAIR;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL> WHITE BISHOP PAIR BONUS         " << BONUS_BISHOP_PAIR << std::endl;
                           iwhitepos += BONUS_BISHOP_PAIR;
                     #endif              
              }
       }
 
       temp = board.whiteBishops;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> WHITE BISHOP ON                 " << SQUARENAME[square] << std::endl;
              #endif
 
              score += BISHOPPOS_W[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << BISHOPPOS_W[square] << std::endl;
                     iwhitepos += BISHOPPOS_W[square];
              #endif
 
              score += BISHOP_DISTANCE[DISTANCE[square][blackkingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << BISHOP_DISTANCE[DISTANCE[square][blackkingsquare]] << std::endl;
                     iwhitepos += BISHOP_DISTANCE[DISTANCE[square][blackkingsquare]];
              #endif
 
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate white rooks
// - position on the board
// - distance from opponent king
// - on the same file as a passed pawn
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       temp = board.whiteRooks;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> WHITE ROOK ON                   " << SQUARENAME[square] << std::endl;
              #endif
 
              score += ROOKPOS_W[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << ROOKPOS_W[square] << std::endl;
                     iwhitepos += ROOKPOS_W[square];
              #endif
 
              score += ROOK_DISTANCE[DISTANCE[square][blackkingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << ROOK_DISTANCE[DISTANCE[square][blackkingsquare]] << std::endl;
                     iwhitepos += ROOK_DISTANCE[DISTANCE[square][blackkingsquare]];
              #endif
 
              if (FILEMASK[square] & whitepassedpawns)
              {
                     if ((unsigned int) square < lastOne(FILEMASK[square] & whitepassedpawns))
                     {
                           score += BONUS_ROOK_BEHIND_PASSED_PAWN;
                           #ifdef WINGLET_VERBOSE_EVAL
                                  std::cout << "EVAL>  BEHIND PASSED PAWN BONUS       " << BONUS_ROOK_BEHIND_PASSED_PAWN << std::endl;
                                  iwhitepos += BONUS_ROOK_BEHIND_PASSED_PAWN;
                           #endif
                     }
              }
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate white queens
// - position on the board
// - distance from opponent king
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       temp = board.whiteQueens;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> WHITE QUEEN ON                  " << SQUARENAME[square] << std::endl;
              #endif
 
              score += QUEENPOS_W[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << QUEENPOS_W[square] << std::endl;
                     iwhitepos += QUEENPOS_W[square];
              #endif
 
              score += QUEEN_DISTANCE[DISTANCE[square][blackkingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << QUEEN_DISTANCE[DISTANCE[square][blackkingsquare]] << std::endl;
                     iwhitepos += QUEEN_DISTANCE[DISTANCE[square][blackkingsquare]];
              #endif
 
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate the white king
// - position on the board
// - proximity to the pawns
// - pawn shield (not in the endgame)
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       if (endgame)
       {
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> WHITE KING ON (endgame)         " << SQUARENAME[whitekingsquare] << std::endl;
              #endif
 
              score += KINGPOS_ENDGAME_W[whitekingsquare];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << KINGPOS_ENDGAME_W[whitekingsquare] << std::endl;
                     iwhitepos += KINGPOS_ENDGAME_W[whitekingsquare];
                     iwhiteking += KINGPOS_ENDGAME_W[whitekingsquare];
              #endif
 
       }
       else
       {
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> WHITE KING ON (no endgame)      " << SQUARENAME[whitekingsquare] << std::endl;
              #endif
 
              score += KINGPOS_W[whitekingsquare];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << KINGPOS_W[whitekingsquare] << std::endl;
                     iwhitepos += KINGPOS_W[whitekingsquare];
                     iwhiteking += KINGPOS_W[whitekingsquare];
              #endif
 
              // add pawn shield bonus if we're not in the endgame:
              // strong pawn shield bonus if the pawns are near the king:
              score += BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_W[whitekingsquare] & board.whitePawns);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  STRONG PAWN SHIELD SCORE IS    " << BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_W[whitekingsquare] & board.whitePawns) << std::endl;
                     iwhitepos += BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_W[whitekingsquare] & board.whitePawns);
                     iwhiteking += BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_W[whitekingsquare] & board.whitePawns);
              #endif
 
              // weaker pawn shield bonus if the pawns are not so near the king:
              score += BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_W[whitekingsquare] & board.whitePawns);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  WEAK PAWN SHIELD SCORE IS      " << BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_W[whitekingsquare] & board.whitePawns) << std::endl;
                     iwhitepos += BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_W[whitekingsquare] & board.whitePawns);
                     iwhiteking += BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_W[whitekingsquare] & board.whitePawns);
              #endif
 
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate BLACK PIECES
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate black pawns
// - position on the board
// - distance from opponent king
// - distance from own king
// - passed, doubled, isolated or backward pawns
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       blackpassedpawns = 0;
       temp = board.blackPawns;
       while (temp)
       {
              square = firstOne(temp);
 
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> BLACK PAWN ON                   " << SQUARENAME[square] << std::endl;
              #endif
 
              score -= PAWNPOS_B[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << PAWNPOS_B[square] << std::endl;
                     iblackpos -= PAWNPOS_B[square];
                     iblackpawns -= PAWNPOS_B[square];
              #endif
 
              score -= PAWN_OPPONENT_DISTANCE[DISTANCE[square][whitekingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << PAWN_OPPONENT_DISTANCE[DISTANCE[square][whitekingsquare]] << std::endl;
                     iblackpos -= PAWN_OPPONENT_DISTANCE[DISTANCE[square][whitekingsquare]];
                     iblackpawns -= PAWN_OPPONENT_DISTANCE[DISTANCE[square][whitekingsquare]];
              #endif
 
              if (endgame)
              {
                     score -= PAWN_OWN_DISTANCE[DISTANCE[square][blackkingsquare]];
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  DISTANCE TO OWN KING SCORE     " << PAWN_OWN_DISTANCE[DISTANCE[square][blackkingsquare]] << std::endl;
                           iblackpos -= PAWN_OWN_DISTANCE[DISTANCE[square][blackkingsquare]];
                           iblackpawns -= PAWN_OWN_DISTANCE[DISTANCE[square][blackkingsquare]];
                     #endif
              }
 
              if (!(PASSED_BLACK[square] & board.whitePawns))
              {
                     score -= BONUS_PASSED_PAWN;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  IS PASSED, BONUS IS            " << BONUS_PASSED_PAWN << std::endl;
                           iblackpos -= BONUS_PASSED_PAWN;
                           iblackpawns -= BONUS_PASSED_PAWN;
                     #endif
 
                     // remember its location, we need it later when evaluating the black rooks:
                     blackpassedpawns ^= BITSET[square];
 
              }
 
              if ((board.blackPawns ^ BITSET[square]) & FILEMASK[square])
              {
                     score += PENALTY_DOUBLED_PAWN;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  IS DOUBLED, PENALTY IS         " << PENALTY_DOUBLED_PAWN << std::endl;
                           iblackpos += PENALTY_DOUBLED_PAWN;
                           iblackpawns += PENALTY_DOUBLED_PAWN;
                     #endif
              }
 
              if (!(ISOLATED_BLACK[square] & board.blackPawns))
              {
                     score += PENALTY_ISOLATED_PAWN;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL>  IS ISOLATED, PENALTY IS        " << PENALTY_ISOLATED_PAWN << std::endl;
                           iblackpos += PENALTY_ISOLATED_PAWN;
                            iblackpawns += PENALTY_ISOLATED_PAWN;
                     #endif
              }
              else
              {
                     // If it is not isolated, then it might be backward. Two conditions must be true:
                     //  1) if the next square is controlled by an enemy pawn - we use the PAWN_ATTACKS bitmaps to check this
                     //  2) if there are no pawns left that could defend this pawn
                     if ((BLACK_PAWN_ATTACKS[square - 8] & board.whitePawns))
                     {
                           if (!(BACKWARD_BLACK[square] & board.blackPawns))
                           {
                                  score += PENALTY_BACKWARD_PAWN;
                                  #ifdef WINGLET_VERBOSE_EVAL
                                         std::cout << "EVAL>  IS BACKWARD, PENALTY IS        " << PENALTY_BACKWARD_PAWN << std::endl;
                                         iwhitepos += PENALTY_BACKWARD_PAWN;
                                         iwhitepawns += PENALTY_BACKWARD_PAWN;
                                  #endif
                           }
                     }
              }
 
              temp ^= BITSET[square];
 
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate black knights
// - position on the board
// - distance from opponent king
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       temp = board.blackKnights;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> BLACK KNIGHT ON                 " << SQUARENAME[square] << std::endl;
              #endif
 
              score -= KNIGHTPOS_B[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << KNIGHTPOS_B[square] << std::endl;
                     iblackpos -= KNIGHTPOS_B[square];
              #endif
 
              score -= KNIGHT_DISTANCE[DISTANCE[square][whitekingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << KNIGHT_DISTANCE[DISTANCE[square][whitekingsquare]] << std::endl;
                     iblackpos -= KNIGHT_DISTANCE[DISTANCE[square][whitekingsquare]];
              #endif
 
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate black bishops
// - having the pair
// - position on the board
// - distance from opponent king
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       if (board.blackBishops)
       {
              if (board.blackBishops & (board.blackBishops - 1))
              {
                     score -= BONUS_BISHOP_PAIR;
                     #ifdef WINGLET_VERBOSE_EVAL
                           std::cout << "EVAL> BLACK BISHOP PAIR BONUS         " << BONUS_BISHOP_PAIR << std::endl;
                           iblackpos -= BONUS_BISHOP_PAIR;
                     #endif              
              }
       }
 
       temp = board.blackBishops;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> BLACK BISHOP ON                 " << SQUARENAME[square] << std::endl;
              #endif
 
              score -= BISHOPPOS_B[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << BISHOPPOS_B[square] << std::endl;
                     iblackpos -= BISHOPPOS_B[square];
              #endif
 
              score -= BISHOP_DISTANCE[DISTANCE[square][whitekingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << BISHOP_DISTANCE[DISTANCE[square][whitekingsquare]] << std::endl;
                     iblackpos -= BISHOP_DISTANCE[DISTANCE[square][whitekingsquare]];
              #endif
 
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate black rooks
// - position on the board
// - distance from opponent king
// - on the same file as a passed pawn
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       temp = board.blackRooks;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> BLACK ROOK ON                   " << SQUARENAME[square] << std::endl;
              #endif
 
              score -= ROOKPOS_B[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << ROOKPOS_B[square] << std::endl;
                     iblackpos -= ROOKPOS_B[square];
              #endif
 
              score -= ROOK_DISTANCE[DISTANCE[square][whitekingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << ROOK_DISTANCE[DISTANCE[square][whitekingsquare]] << std::endl;
                     iblackpos -= ROOK_DISTANCE[DISTANCE[square][whitekingsquare]];
              #endif
 
              if (FILEMASK[square] & blackpassedpawns)
              {
                     if ((unsigned int) square > firstOne(FILEMASK[square] & blackpassedpawns))
                     {
                           score -= BONUS_ROOK_BEHIND_PASSED_PAWN;
                           #ifdef WINGLET_VERBOSE_EVAL
                                  std::cout << "EVAL>  BEHIND PASSED PAWN BONUS       " << BONUS_ROOK_BEHIND_PASSED_PAWN << std::endl;
                                  iblackpos -= BONUS_ROOK_BEHIND_PASSED_PAWN;
                           #endif
                     }
              }
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate black queens
// - position on the board
// - distance from opponent king
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       temp = board.blackQueens;
       while (temp)
       {
              square = firstOne(temp);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> BLACK QUEEN ON                  " << SQUARENAME[square] << std::endl;
              #endif
 
              score -= QUEENPOS_B[square];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << QUEENPOS_B[square] << std::endl;
                     iblackpos -= QUEENPOS_B[square];
              #endif
 
              score -= QUEEN_DISTANCE[DISTANCE[square][whitekingsquare]];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  DISTANCE TO OPPONNT KING SCORE " << QUEEN_DISTANCE[DISTANCE[square][whitekingsquare]] << std::endl;
                     iblackpos -= QUEEN_DISTANCE[DISTANCE[square][whitekingsquare]];
              #endif
 
              temp ^= BITSET[square];
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Evaluate the black king
// - position on the board
// - proximity to the pawns
// - pawn shield (not in the endgame)
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       if (endgame)
       {
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> BLACK KING ON (endgame)         " << SQUARENAME[blackkingsquare] << std::endl;
              #endif
 
              score -= KINGPOS_ENDGAME_B[blackkingsquare];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << KINGPOS_ENDGAME_B[blackkingsquare] << std::endl;
                     iblackpos -= KINGPOS_ENDGAME_B[blackkingsquare];
                     iblackking -= KINGPOS_ENDGAME_B[blackkingsquare];
              #endif
       }
       else
       {
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> BLACK KING ON (no endgame)      " << SQUARENAME[blackkingsquare] << std::endl;
              #endif
 
              score -= KINGPOS_B[blackkingsquare];
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  POSITION SCORE IS              " << KINGPOS_B[blackkingsquare] << std::endl;
                     iblackpos -= KINGPOS_B[blackkingsquare];
                     iblackking -= KINGPOS_B[blackkingsquare];
              #endif
 
              // add pawn shield bonus if we're not in the endgame:
              // strong pawn shield bonus if the pawns are near the king:
              score -= BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_B[blackkingsquare] & board.blackPawns);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  STRONG PAWN SHIELD SCORE IS    " << BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_B[blackkingsquare] & board.blackPawns) << std::endl;
                     iblackpos -= BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_B[blackkingsquare] & board.blackPawns);
                     iblackking -= BONUS_PAWN_SHIELD_STRONG * bitCnt(KINGSHIELD_STRONG_B[blackkingsquare] & board.blackPawns);
              #endif
 
              // weaker pawn shield bonus if the pawns are not so near the king:
              score -= BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_B[blackkingsquare] & board.blackPawns);
              #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL>  WEAK PAWN SHIELD SCORE IS      " << BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_B[blackkingsquare] & board.blackPawns) << std::endl;
                     iblackpos -= BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_B[blackkingsquare] & board.blackPawns);
                     iblackking -= BONUS_PAWN_SHIELD_WEAK * bitCnt(KINGSHIELD_WEAK_B[blackkingsquare] & board.blackPawns);
              #endif
 
       }
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Return the score
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
       #ifdef WINGLET_VERBOSE_EVAL
                     std::cout << "EVAL> SUMMARY:" << std::endl;
                     std::cout << "EVAL>  MATERIAL                :" << board.Material << std::endl;
                     std::cout << "EVAL>  UNEVEN MATERIAL BONUS   :" << iexch << std::endl;
                     std::cout << "EVAL>  WHITE POSITIONAL BONUS  :" << iwhitepos << std::endl;
                     std::cout << "EVAL>     WHITE PAWNS BONUS    :" << iwhitepawns << std::endl;
                     std::cout << "EVAL>     WHITE KING POS/SAF   :" << iwhiteking << std::endl;
                     std::cout << "EVAL>  BLACK POSITIONAL BONUS  :" << iblackpos << std::endl;
                     std::cout << "EVAL>     BLACK PAWNS BONUS    :" << iblackpawns << std::endl;
                     std::cout << "EVAL>     BLACK KING POS/SAF   :" << iblackking << std::endl;
       #endif
 
       if (board.nextMove) return -score;
       else return score;
 
}

 


Home Previous Top Next

last update: Thursday 16 June 2011