home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / ARASAN_S.ZIP / SCORING.CPP < prev    next >
C/C++ Source or Header  |  1994-08-07  |  31KB  |  1,087 lines

  1. // Copyright 1994 by Jon Dart.  All Rights Reserved.
  2.  
  3. #include "scoring.h"
  4. #include "bearing.h"
  5. #include "constant.h"
  6. #include "util.h"
  7.  
  8. static int RookCenterTable[] =
  9.     {0, 0, 0, 27, 28, 0, 0, 0,
  10.      0, 0, 0, 27, 28, 0, 0, 0,
  11.      0, 0, 0, 27, 28, 0, 0, 0,
  12.      27, 27, 27, 27, 28, 28, 28, 28,
  13.      35, 35, 35, 35, 36, 36, 36, 36,
  14.      0, 0, 0, 35, 36, 0, 0, 0,
  15.      0, 0, 0, 35, 36, 0, 0, 0,
  16.      0, 0, 0, 35, 36, 0, 0, 0};
  17.  
  18. static int RookCenterDirs[] =
  19.     {0, 0, 0, 8, 8, 0, 0, 0,
  20.      0, 0, 0, 8, 8, 0, 0, 0,
  21.      0, 0, 0, 8, 8, 0, 0, 0,
  22.      1, 1, 1, 0, 0, -1, -1, -1,
  23.      1, 1, 1, 0, 0, -1, -1, -1,
  24.      0, 0, 0, -8, -8, 0, 0, 0,
  25.      0, 0, 0, -8, -8, 0, 0, 0,
  26.      0, 0, 0, -8, -8, 0, 0, 0};
  27.  
  28. static int BishopCenterTable[] =
  29.     {27, 28, 0, 0, 0, 0, 27, 28,
  30.      35, 27, 28, 0, 0, 27, 28, 36,
  31.      0, 35, 27, 28, 27, 28, 36, 0,
  32.      0, 0, 35, 27, 28, 36, 0, 0,
  33.      0, 0, 27, 28, 36, 28, 0, 0,
  34.      0, 27, 35, 36, 35, 36, 28, 0,
  35.      27, 35, 36, 0, 0, 35, 36, 28,
  36.      35, 36, 0, 0, 0, 0, 35, 36};
  37.  
  38. static int BishopCenterDirs[] =
  39.     {9, 9, 0, 0, 0, 0, 7, 7,
  40.      9, 9, 9, 0, 0, 7, 7, 7,
  41.      0, 9, 9, 9, 7, 7, 7, 0,
  42.      0, 0, 9, 0, 0, 7, 0, 0,
  43.      0, 0, -7, 0, 0, -9, 0, 0,
  44.      0, -7, -7, -7, -9, -9, -9, 0,
  45.      -7, -7, -7, 0, 0, -9, -9, -9,
  46.      -7, -7, 0, 0, 0, 0, -9, -9};
  47.  
  48. static int KnightCenterScores[] =
  49.     {0, 0, 0, 0, 0, 0, 0, 0,
  50.      0, 0, 2, 2, 2, 2, 0, 0,
  51.      0, 2, 0, 0, 0, 0, 2, 0,
  52.      0, 2, 0, 5, 5, 0, 2, 0,
  53.      0, 2, 0, 5, 5, 0, 2, 0,
  54.      0, 2, 0, 0, 0, 0, 2, 0,
  55.      0, 0, 2, 2, 2, 2, 0, 0,
  56.      0, 0, 0, 0, 0, 0, 0, 0};
  57.  
  58. static int PawnCenterScores[] =
  59.     {0, 0, 0, 0, 0, 0, 0, 0,
  60.      0, 0, 0, 0, 0, 0, 0, 0,
  61.      0, 0, 0, 0, 0, 0, 0, 0,
  62.      0, 0, 0, 5, 5, 0, 0, 0,
  63.      0, 0, 4, 6, 6, 4, 0, 0,
  64.      0, 0, 3, 4, 4, 3, 0, 0,
  65.      0, 0, -1, -2, -2, -1, 0, 0,
  66.      0, 0, 0, 0, 0, 0, 0, 0};
  67.  
  68. static int KingCenterScores[] =
  69.     {0, 0, 1, 1, 1, 1, 0, 0,
  70.      0, 1, 2, 3, 3, 2, 1, 0,
  71.      1, 2, 6, 7, 7, 6, 2, 1,
  72.      1, 3, 7, 9, 9, 7, 3, 1,
  73.      1, 3, 7, 9, 9, 7, 3, 1,
  74.      1, 2, 6, 7, 7, 6, 2, 1,
  75.      0, 1, 2, 3, 3, 2, 1, 0,
  76.      0, 0, 1, 1, 1, 1, 0, 0};
  77.  
  78. const int KBNKScores[] =
  79.     {-12, -8, -2, 3, 7, 10, 15, 20,
  80.      -8, -6, 1, 0, 5, 9, 12, 15,
  81.      -2, 1, 0, 0, 5, 8, 9, 10,
  82.      3, 2, 0, 0, 0, 5, 5, 7,
  83.      7, 5, 5, 0, 0, 0, 0, 3,
  84.      10, 9, 8, 5, 0, 0, 1, -2,
  85.      15, 12, 9, 5, 2, 1, -6, -8,
  86.      20, 15, 10, 7, 3, -2, -8, -12};
  87.  
  88. Boolean Scoring::pawn_threats = False;
  89. int Scoring::en_prise = 0;
  90. int Scoring::trapped = 0;
  91.  
  92. static Boolean endgame;
  93.  
  94. static int distance( const Square sq1, const Square sq2 )
  95. {
  96.     int file_dist = Util::Abs(sq1.File() - sq2.File());
  97.     int rank_dist = Util::Abs(sq1.Rank(White) - sq2.Rank(White));
  98.     return file_dist + rank_dist;
  99. }
  100.  
  101. // Weights for positional scoring components.  A plus value means that
  102. // the item being scored is valuable to the player; a minus value means
  103. // that a penalty is extracted.  In most cases, scoring components are
  104. // simply summed together to get a total score, but some are folded
  105. // in, in a more complex way.
  106.  
  107. // material terms
  108. const int TWO_BISHOPS = 8;
  109. // development terms
  110. const int CENTER1 = 2; // center control by sliding piece
  111. const int BLOCKED_BISHOP = -4;
  112. const int LOW_BISHOP_MOBILITY = -2;
  113. const int BMOBLTHRESH = 3; // threshold before awarding bishop mobility bonus
  114. const int BISHOP_MOBILITY = 2;
  115. const int BISHOP_BACK = -6;
  116. const int CENTER_PAWN_BLOCK = -5;  // e or d pawn blocked by piece
  117. const int LONG_DIAG = 3; // bishop on long diagonal
  118. const int KNIGHT_BACK = -5;
  119. const int KNIGHT_ON_RIM = -2;
  120. const int LOW_ROOK_MOBILITY = -1;
  121. const int KNIGHT_MOBILITY = 1;
  122. const int ROOK_ON_7TH_RANK = 5;
  123. const int QUEEN_DEVELOP = 2;
  124. const int QUEEN_OUT = -6; // premature development of queen
  125. const int DOUBLED_ROOKS = 6; // on open file
  126. const int ROOK_ON_HALF_OPEN_FILE = 2;
  127. const int ROOK_ON_OPEN_FILE = 2;
  128. // castling terms
  129. const int KCASTLE = 9;
  130. const int QCASTLE = 6;
  131. const int CAN_CASTLE = -2;
  132. const int CANT_CASTLE = -12;
  133. const int CANT_CASTLE_K_SIDE = -6;
  134. const int CANT_CASTLE_Q_SIDE = -4;
  135. const int ATTACK_PREVENTS_CASTLING = -3;
  136. // pawn structure terms
  137. const int PAWN_ON_7TH_RANK = 4;
  138. const int BACKWARD_PAWN = -6;
  139. const int CENTRAL_ISOLANI = -8;
  140. const int ISOLANI = -6;
  141. const int DOUBLED_PAWNS = -18;
  142. const int TRIPLED_PAWNS = -24;
  143. const int PASSED_PAWN[8] = { 0, 12, 13, 17, 25, 41, 73, 0}; // score by rank
  144. const int RIM_PASSED_PAWN = -3; // pawn on h-file or a-file
  145. const int PAWN_DUO = 4; // a la Kmoch
  146. const int ROOK_BEHIND_PP = 3; // rook or queen behind passed pawn
  147. const int UNSUPPORTED_PAWN = -1; // an advanced but unsupported pawn
  148. const int OPP_KING_DISTANCE_FROM_PP = 2; // opposing king distance from passed
  149.                      // pawn
  150. const int OPP_KING_AHEAD_OF_PP = -7;
  151. // king safety terms
  152. const int CHECK = -5;  // being in check
  153. const int ATTACK_NEAR_KING = -3; // square near king attacked
  154. const int KING_OFF_BACK_RANK = -3;
  155. const int KING_PAWN_COVER = 2;
  156. const int KING_NEAR_OPEN_FILE = -1;
  157. const int DANGER_ON_FILE = -2; // rook or queen on file near king
  158. // king position terms - valid only in endgame
  159. const int ADVANCED_KING = 4;
  160. const int KING_NEAR_PAWN = 1;
  161. const int OPPOSITION = 12;
  162. const int KING_DISTANCE = 4; // bringing our king closer to bare king
  163. const int KING_CAN_MOVE = -3; // for each square opposing bare king can move
  164. const int KING_ON_EDGE = 4;   // opposing king on edge
  165. const int KING_IN_CORNER = 4; // opposing king in corner
  166. // piece safety terms
  167. const int EN_PRISE = -6; // piece apparently hung
  168. const int PIECE_TRAPPED = -6; // piece apparently trapped
  169. const int TWO_EN_PRISE = -10; // >1 piece apparently hung
  170. // general endgame terms
  171. const int KING_PAWN_DISTANCE = -10; // distance from opposing king
  172. const int OPP_KING_AHEAD_OF_PAWN = 8;
  173. // KP vs. K endgame
  174. const int UNCATCHABLE_PAWN = 450;
  175. const int KING_AHEAD_OF_PAWN = 32;
  176. const int KING_SAME_FILE = 32;
  177. const int DISTANCE_FROM_PAWN = -8;
  178.  
  179. static int MaterialScore( const Board &board, const ColorType side )
  180. {
  181.   // Computes material score, from the perspective of 'side'.
  182.   // Algorithm is based on that used by Chess 4.5.
  183.   unsigned long ourmat, oppmat, totmat;
  184.   int mdiff;
  185.   
  186.   ourmat = board.getMaterial(side).value();
  187.   oppmat = board.getMaterial(OppositeColor(side)).value();
  188.   mdiff =  (int)(ourmat - oppmat);
  189.   if (Util::Abs(mdiff) > 2*Constants::PawnValue)
  190.   {
  191.      totmat = ourmat + oppmat;
  192.      return mdiff + (Util::Sign(mdiff)*( (10240L - totmat) / 
  193.          Constants::PawnValue ));
  194.   }
  195.   else
  196.      return mdiff;
  197. }
  198.  
  199. static Boolean in_endgame( const Board &board, const ColorType side )
  200. {
  201.     return Boolean((board.getMaterial(side).value()
  202.         <= Piece::Value(Piece::King) +
  203.             Piece::Value(Piece::Queen)) &&
  204.        (board.getMaterial(OppositeColor(side)).value() <= 
  205.         Piece::Value(Piece::King) + Piece::Value(Piece::Queen) +
  206.         2*Piece::Value(Piece::Pawn)));
  207. }
  208.  
  209. static Boolean mopping_up( const Board &board, const ColorType side )
  210. {
  211.     // Returns "true" if "side" has great material advantage (probably
  212.     // enough to mate by force)
  213.     
  214.     const Material &my_mat = board.getMaterial(side);
  215.     const Material &opp_mat = board.getMaterial(OppositeColor(side));
  216.  
  217.     if (opp_mat.king_only() && !endgame)
  218.         return True;
  219.     else if (my_mat.value() - opp_mat.value() < 570)
  220.         return False;
  221.     else
  222.         return (my_mat.value() + opp_mat.value() < 5000);
  223. }
  224.  
  225. int Center( const Board &board, const ColorType side)
  226. {
  227.    if (endgame)
  228.    {
  229.       if (mopping_up(board,OppositeColor(side)))
  230.          return KingCenterScores[board.KingPos(side)];
  231.       else
  232.          return 0;
  233.    }
  234.    int score = 0;
  235.    Square target;
  236.    for (int i = 0; i < 16; i++)
  237.    {
  238.       Square sq(board.PiecePos(side,i));
  239.       if (!sq.IsInvalid())
  240.       {
  241.           Piece piece = board[sq];
  242.           switch (piece.Type())
  243.       {
  244.       case Piece::Pawn:
  245.          if (side == White)
  246.             score += PawnCenterScores[sq];
  247.              else
  248.             score += PawnCenterScores[63-(int)sq];
  249.          break;
  250.           case Piece::Knight:
  251.          score += KnightCenterScores[sq];
  252.          break;
  253.       case Piece::Bishop:
  254.          target = Square(BishopCenterTable[sq]);
  255.          if (target)
  256.          {
  257.              int dir = BishopCenterDirs[sq];
  258.         if (dir)
  259.         {
  260.             for (;;)
  261.             {
  262.                sq += dir;
  263.                if (sq == target)
  264.                {
  265.                       score += CENTER1;
  266.                break;
  267.                }
  268.                else if (!board[sq].IsEmpty())
  269.                    break;
  270.             }
  271.         }
  272.         else
  273.           score += CENTER1;
  274.          }
  275.          break;
  276.           case Piece::Rook:
  277.          target = Square(RookCenterTable[sq]);
  278.          if (target)
  279.          {
  280.              int dir = RookCenterDirs[sq];
  281.         if (dir)
  282.         {
  283.             for (;;)
  284.             {
  285.                sq += dir;
  286.                if (sq == target)
  287.                {
  288.                       score += CENTER1;
  289.                break;
  290.                }
  291.                else if (!board[sq].IsEmpty())
  292.                    break;
  293.             }
  294.         }
  295.         else
  296.           score += CENTER1;
  297.          }
  298.          break;
  299.       case Piece::Queen:
  300.          target = Square(BishopCenterTable[sq]);
  301.          if (target)
  302.          {
  303.              int dir = BishopCenterDirs[sq];
  304.         if (dir)
  305.         {
  306.             for (;;)
  307.             {
  308.                sq += dir;
  309.                if (sq == target)
  310.                {
  311.                       score += CENTER1;
  312.                break;
  313.                }
  314.                else if (!board[sq].IsEmpty())
  315.                    break;
  316.             }
  317.         }
  318.         else
  319.           score += CENTER1;
  320.          }
  321.  
  322.          target = Square(RookCenterTable[sq]);
  323.          if (target)
  324.          {
  325.              int dir = RookCenterDirs[sq];
  326.         if (dir)
  327.         {
  328.             for (;;)
  329.             {
  330.                sq += dir;
  331.                if (sq == target)
  332.                {
  333.                       score += CENTER1;
  334.                break;
  335.                }
  336.                else if (!board[sq].IsEmpty())
  337.                    break;
  338.             }
  339.         }
  340.         else
  341.           score += CENTER1;
  342.          }
  343.          break;
  344.       default:
  345.          break;
  346.       }
  347.       }
  348.    }
  349.    return score;
  350. }
  351.  
  352. int Development( const Board &board, const ColorType side)
  353. // development of pieces
  354. {
  355.    int score = 0;
  356.    int score2 = 0;
  357.    int mobl = 0;
  358.    Boolean have_queen = False;
  359.    Boolean queen_back = False;
  360.    const ColorType oside = OppositeColor(side);
  361.    const Material &my_mat = board.getMaterial(side);
  362.    if (my_mat.count(Piece::Bishop) >= 2)
  363.       score += TWO_BISHOPS;
  364.    for (int i = 0; i < 16; i++)
  365.    {
  366.       Square sq(board.PiecePos(side,i));
  367.       if (!sq.IsInvalid())
  368.       {
  369.          Piece piece = board[sq];
  370.          if (piece.Type() != Piece::Pawn)
  371.          {
  372.             const int rank = sq.Rank(side);
  373.         const int file = sq.File();
  374.         Boolean back = Boolean(rank == 1);
  375.         if (!endgame)
  376.         {
  377.                 if ((rank == 3 || rank == 4) &&
  378.             (file == 4 || file == 5))
  379.             {
  380.             int incr = 8*Direction[side];
  381.             if (board[sq-incr].Type() == Piece::Pawn ||
  382.             board[sq-2*incr].Type() == Piece::Pawn)
  383.             score += CENTER_PAWN_BLOCK;
  384.                 }
  385.         }
  386.             switch(piece.Type())
  387.         {
  388.            case Piece::Bishop:
  389.               {
  390.           {
  391.               for (int j = 0; j < 4; j++)
  392.               {
  393.                   const byte *data = BishopSquares[sq] + (j*8);
  394.               for (;;)
  395.               {
  396.                   byte b = *data;
  397.                   if (b == 255)
  398.                       break;
  399.                   data++;
  400.                   Piece piece = board[b];
  401.                   if (piece.IsEmpty())
  402.                      mobl++;
  403.                   else 
  404.                      break;
  405.                    }
  406.               }
  407.           }
  408.           if (mobl==0)
  409.              score2 += BLOCKED_BISHOP;
  410.           else if (mobl == 1)
  411.              score2 += LOW_BISHOP_MOBILITY;
  412.           else if (mobl > BMOBLTHRESH)
  413.              score2 += (mobl / BMOBLTHRESH)*BISHOP_MOBILITY;
  414.                   if (rank == file)
  415.              score2 += LONG_DIAG;
  416.           if (back && !endgame)
  417.              score += BISHOP_BACK;
  418.                   }
  419.           break;
  420.            case Piece::Knight:
  421.               if (back && !endgame)
  422.              score += KNIGHT_BACK;
  423.           if (file == 1 || file == 8)
  424.              score2 += KNIGHT_ON_RIM;
  425.               if (!endgame)
  426.           {
  427.              const byte *data = KnightSquares[(int)sq];
  428.              int j = 0;
  429.              while (j < 8 && data[j] != 255)
  430.              {
  431.                 Square dest(data[j]);
  432.                 if (board[dest].IsEmpty() && 
  433.                 board.pawn_attacks(dest,oside) ==0)
  434.                 score += KNIGHT_MOBILITY;
  435.                 ++j;
  436.              }
  437.           }
  438.           break;
  439.            case Piece::Queen:
  440.               have_queen = True;
  441.           queen_back = back;
  442.           break;
  443.            case Piece::Rook:
  444.               if (back && !endgame)
  445.           {
  446.              mobl = 0;
  447.              Square sq2(sq);
  448.              while (sq2.File() < 8)
  449.              {
  450.                  ++sq2;
  451.              if (board[sq2].IsEmpty())
  452.                 mobl++;
  453.              else
  454.                 break;
  455.              }
  456.              sq2 = sq;
  457.              while (sq2.File() > 1)
  458.              {
  459.                  --sq2;
  460.              if (board[sq2].IsEmpty())
  461.                 mobl++;
  462.              else
  463.                 break;
  464.              }
  465.              if (mobl < 3)
  466.                 score2 += LOW_ROOK_MOBILITY;
  467.           }
  468.           if (rank == 7)
  469.               score2 += ROOK_ON_7TH_RANK;
  470.                   if (board.PFileCount(file-1,side)==0)
  471.                       score2 += ROOK_ON_HALF_OPEN_FILE;
  472.                   if (board.PFileCount(file-1,oside)==0)
  473.                   {
  474.                       score2 += ROOK_ON_OPEN_FILE;
  475.               const int rr = board.RFileCount(file-1,side);
  476.                       if (rr>=2)
  477.                          score2 += DOUBLED_ROOKS/2;
  478.               }
  479.            default:
  480.               break;
  481.         }
  482.          }
  483.       }
  484.    }
  485.    if (!endgame && have_queen && !queen_back)
  486.    {
  487.       if (score == 0 && 
  488.      (board.CastleStatus(side) == Board::CastledKSide ||
  489.       board.CastleStatus(side) == Board::CastledQSide))
  490.        score += QUEEN_DEVELOP;
  491.       else // premature development of queen
  492.           score += QUEEN_OUT;
  493.    }
  494.    if (endgame)
  495.    {
  496.        Square kp(board.KingPos(side));
  497.        if (board.Side() != side)
  498.        {
  499.           for (int j = 0; j < 4; j++)
  500.           {
  501.           const byte *data = RookSquares[kp] + (j*8);
  502.               if (*data == 255)
  503.               continue;
  504.           else
  505.                   data++;
  506.               if (*data != 255 && board[*data].Type() == Piece::King)
  507.               {
  508.                   score += OPPOSITION;
  509.               break;
  510.               }
  511.           }
  512.        }
  513.        if (mopping_up(board,side))
  514.        {
  515.        // Encourage bringing our king close to opposing king:
  516.        Square oppkp(board.KingPos(oside));
  517.        const int opprank = oppkp.Rank(White);
  518.        const int oppfile = oppkp.File();
  519.        const int ourrank = kp.Rank(White);
  520.        const int ourfile = kp.File();
  521.        int dist = Util::Abs(oppfile - ourfile) +
  522.                  Util::Abs(ourrank - opprank);
  523.        score += (5-dist)*KING_DISTANCE;
  524.        if ((unsigned)board.getMaterial(side).infobits() == 0x8048)
  525.        {
  526.            // KBNK endgame, special case.  This code is currently
  527.            // insufficient to allow the stronger side to win, but
  528.            // it does help the weaker side put up a good defense.
  529.            ColorType bishopColor;
  530.            for (int i = 0; i < 16; i++)
  531.            {
  532.                Square sq(board.PiecePos(board.Side(),i));
  533.                if ( sq != Square::Invalid())
  534.               if (board[sq].Type() == Piece::Bishop)
  535.               {
  536.                  bishopColor = sq.Color();
  537.              break;
  538.               }
  539.            }
  540.            // encourage getting the king to the "right" corner:
  541.            Square evalsq;
  542.            if (bishopColor == White)
  543.            {
  544.                evalsq = Square(9-opprank, oppfile, White);
  545.            }
  546.            else
  547.            {
  548.                evalsq = oppkp;
  549.            }
  550.                score += KBNKScores[evalsq];
  551.        }
  552.        else
  553.        {
  554.            // Encourage putting the king on the edge of the board:
  555.            if (oppkp.OnEdge())
  556.               score += KING_ON_EDGE;
  557.            if (oppfile == 1 || oppfile == 8)
  558.            {
  559.               if (opprank == 1 || opprank == 8)
  560.                  score += KING_IN_CORNER;
  561.            }
  562.            // Encourage restricting opposing king's mobility:
  563.            const byte *data = KingSquares[(int)oppkp];
  564.            score -= 8*KING_CAN_MOVE;
  565.            for (i = 0; i <8 && *data != 255 ;i++)
  566.                {
  567.                   Square sq(*data++);
  568.               if (board.num_attacks(sq,side) == 0)
  569.                   score += KING_CAN_MOVE;
  570.            }
  571.            }
  572.        }
  573.        else if ((unsigned)board.getMaterial(side).infobits() == 0x8001 &&
  574.                (unsigned)board.getMaterial(oside).king_only())
  575.        {
  576.            // KPK endgame
  577.        Square pawnpos;
  578.        for (int i = 0; i < 16; i++)
  579.        {
  580.            Square sq(board.PiecePos(side,i));
  581.            if (!sq.IsInvalid() && board[sq].Type() == Piece::Pawn)
  582.            {
  583.               pawnpos = sq;
  584.           break;
  585.            }
  586.        }
  587.        Square oppkp(board.KingPos(oside));
  588.        Square kp(board.KingPos(side));
  589.        Boolean uncatchable = False;
  590.        if (board.Side() == side)
  591.        {
  592.            uncatchable =
  593.                (pawnpos.Rank(side) >= oppkp.Rank(side) &&
  594.               Util::Abs(pawnpos.File() - oppkp.File()) >= 
  595.               8 - pawnpos.Rank(side));
  596.        }
  597.        else
  598.        {
  599.            uncatchable =
  600.                (pawnpos.Rank(side) >= oppkp.Rank(side) + 1 &&
  601.               Util::Abs(pawnpos.File() - oppkp.File()) >= 
  602.               9 - pawnpos.Rank(side));
  603.        }
  604.        if (uncatchable)
  605.            score += UNCATCHABLE_PAWN;
  606.        else
  607.        {
  608.            // we can't just push the pawn.
  609.            int rank = pawnpos.Rank(side);
  610.            int file_dist = Util::Abs(pawnpos.File() - kp.File());
  611.            if (kp.Rank(side) > rank && file_dist <= 1)
  612.            {
  613.            score += KING_AHEAD_OF_PAWN;
  614.            if (rank < 6 && file_dist == 0)
  615.               score += KING_SAME_FILE;
  616.            }
  617.            else
  618.                score -= PASSED_PAWN[rank-1]/2;
  619.            // also encourage staying near pawn
  620.            score += 10 + DISTANCE_FROM_PAWN*distance(kp,pawnpos);
  621.        }
  622.        }
  623.        else
  624.        {
  625.        // This code is VERY crude .. it helps (a little) in king and
  626.        // pawn endgames, but is pretty useless otherwise ... Lots more
  627.        // work to do here.
  628.            score += KingCenterScores[kp];
  629.            if (kp.Rank(side) > 4)
  630.               score += ADVANCED_KING;
  631.            // bonus for king near pawns
  632.            const byte *data = KingSquares[(int)kp];
  633.        const Boolean king_only 
  634.            = (unsigned)board.getMaterial(side).king_only();
  635.            for (i = 0; i <8 && *data != 255 ;i++)
  636.            {
  637.                Square sq(*data++);
  638.            if (board[sq].Type() == Piece::Pawn)
  639.            {
  640.               score += KING_NEAR_PAWN;
  641.               if (king_only)
  642.               {
  643.                  int file_dist = Util::Abs(kp.File() - sq.File());
  644.                  int rank_dist = Util::Abs(kp.Rank(side) - sq.Rank(side));
  645.                  score += 20 + KING_PAWN_DISTANCE*(file_dist + rank_dist);
  646.              if (kp.Rank(oside) > 
  647.                   sq.Rank(oside))
  648.                score += OPP_KING_AHEAD_OF_PAWN;
  649.               }
  650.            }
  651.            }
  652.        }
  653.  
  654.    }
  655.    return score + score2;
  656. }
  657.  
  658. Boolean search( const Board &board, const Square &sq,
  659.   const int start, const int limit, const ColorType side_to_search,
  660.   const ColorType side )
  661. {
  662. // search rows adjacent to "sq" for presence of a pawn of color 
  663. // 'side_to_search'.
  664. // search covers ranks "start" to "limit" (from the perspective of
  665. // 'side').  The function value is set True if a pawn is found.
  666.  
  667.     const Piece apawn(Piece::Pawn,side_to_search);
  668.  
  669.     int dir, incr;
  670.     if (limit > start)
  671.     {
  672.        dir = 1;
  673.        incr = RankIncr;
  674.     }
  675.     else
  676.     {
  677.         dir = -1;
  678.     incr = -RankIncr;
  679.     }
  680.     if (side == White) incr = -incr;
  681.  
  682.     const int file = sq.File();
  683.     Square sq2(file,start,side);
  684.  
  685.     for (int rank = start; rank != limit; rank += dir)
  686.     {
  687.     if (((file != 8) && board[sq2 + 1] == apawn) ||
  688.         ((file != 1) && board[sq2 - 1] == apawn))
  689.        return True;
  690.     sq2 += incr;
  691.     }
  692.     return False;
  693. }
  694.  
  695. int PawnStructure( const Board &board, const ColorType side )
  696. {
  697.     int score = 0;
  698.     const Piece our_pawn( Piece::Pawn, side );
  699.     for (int k = 0; k < 16; k++)
  700.     {
  701.         Square sq(board.PiecePos(side,k));
  702.     if (!sq.IsInvalid())
  703.     {
  704.        Piece piece = board[sq];
  705.        if (piece.Type() == Piece::Pawn)
  706.        {
  707.           int rank = sq.Rank(side);
  708.           int file = sq.File();
  709.           Boolean backward = False;
  710.           Boolean passed = False;
  711.           Boolean isolated;
  712.           if (rank == 7)
  713.              score += PAWN_ON_7TH_RANK;
  714.           if (board.PFileCount(file-1,OppositeColor(side))==0)
  715.           {
  716.              backward = !search(board,sq,rank,1,side,side);
  717.              passed = !search(board,sq,rank+1,8,OppositeColor(side),side);
  718.           }
  719.           isolated = Boolean(board.PFileCount(file-1,side)==0 &&
  720.                     board.PFileCount(file+1,side)==0);
  721.           if (backward && !isolated)
  722.              score += BACKWARD_PAWN;
  723.             else if (isolated)
  724.           {
  725.              if (file>=3 && file<=6)
  726.                 score += CENTRAL_ISOLANI;
  727.              else
  728.                 score += ISOLANI;
  729.           }
  730.           if (!isolated && rank > 2)
  731.           {
  732.              Square sq2 = sq + ((Direction[side] >0) ? 
  733.                  -RankIncr : +RankIncr);
  734.          if (!(file != 1 && board[sq2 - 1] == our_pawn) &&
  735.              !(file != 8 && board[sq2 + 1] == our_pawn))
  736.             score += UNSUPPORTED_PAWN;
  737.           }
  738.           if (passed)
  739.           {
  740.              score += PASSED_PAWN[rank-1];
  741.              if (file ==1 || file == 8)
  742.                 score += RIM_PASSED_PAWN;
  743.              for (int j=rank+1;j<9;j++)
  744.              {
  745.                     Square sq2(file,j,side);
  746.                  Piece piece2 = board[sq2];
  747.                  if (!piece2.IsEmpty() &&
  748.                    (piece2.Color() == OppositeColor(side)))
  749.              {
  750.                  // blocked passed pawn
  751.                  int hit = PASSED_PAWN[rank-1]/3;
  752.                  // double score if we block the passed pawn
  753.                  // by occupying the square in front of it:
  754.                  if (j==rank+1)
  755.                     score -= 2*hit;
  756.                  else
  757.                     score -= hit;
  758.                  break;
  759.              }
  760.              }
  761.          if (endgame)
  762.          {
  763.              Square oppkp(board.KingPos(OppositeColor(side)));
  764.              score += OPP_KING_DISTANCE_FROM_PP*
  765.                         distance(oppkp,sq);
  766.              if (oppkp.Rank(side) > sq.Rank(side))
  767.                 score += OPP_KING_AHEAD_OF_PP;
  768.          }
  769.              for (j=rank-1;j>0;j--)
  770.              {
  771.                    Square sq3(file,j,side);
  772.             Piece piece3 = board[sq3];
  773.             if (!piece3.IsEmpty())
  774.             {
  775.                if (piece3.Color() == side)
  776.                {
  777.                   if (piece3.Type() == Piece::Rook || piece3.Type() 
  778.                  == Piece::Queen)
  779.                   {
  780.                   score += ROOK_BEHIND_PP;
  781.                   break;
  782.                   }
  783.                    }
  784.                        else
  785.                    break;
  786.             }
  787.              }
  788.           }
  789.           if (rank >3 && file != 8 && board[sq+1] == piece)
  790.              score += PAWN_DUO;
  791.         }
  792.     }
  793.     }
  794.     for (int i = 0; i < 8; i++)
  795.     {
  796.         const int pr = board.PFileCount(i,side);
  797.     if (pr == 2)
  798.        score += DOUBLED_PAWNS;
  799.         else if (pr > 2)
  800.        score += TRIPLED_PAWNS;
  801.     }
  802.     return score;
  803. }
  804.  
  805. int Castling( const Board &board, const ColorType side )
  806. {
  807.     int score = 0;
  808.     int i;
  809.     int atcks = 0;
  810.     Square kp(board.KingPos(side));
  811.     switch (board.CastleStatus(side))
  812.     {
  813.        case Board::CanCastleEitherSide:
  814.          score += CAN_CASTLE; 
  815.      for (i = -1; i >= -2; --i)
  816.         if (board.num_attacks(kp+i,OppositeColor(side)))
  817.         {
  818.            atcks++;
  819.            break;
  820.         }
  821.      for (i = 1; i <= 2; ++i)
  822.         if (board.num_attacks(kp+i,OppositeColor(side)))
  823.         {
  824.            atcks++;
  825.            break;
  826.         }
  827.      score += (ATTACK_PREVENTS_CASTLING)*atcks;
  828.      break;
  829.        case Board::CanCastleKSide:
  830.          score += CANT_CASTLE_Q_SIDE; 
  831.      for (i = 1; i <= 2; ++i)
  832.         if (board.num_attacks(kp+i,OppositeColor(side)))
  833.         {
  834.            atcks++;
  835.            break;
  836.         }
  837.          if (atcks)
  838.         score += (ATTACK_PREVENTS_CASTLING)*atcks;
  839.      break;
  840.        case Board::CanCastleQSide:
  841.          score += CANT_CASTLE_K_SIDE; 
  842.      for (i = -1; i >= -2; --i)
  843.         if (board.num_attacks(kp+i,OppositeColor(side)))
  844.         {
  845.            atcks++;
  846.            break;
  847.         }
  848.      if (atcks)
  849.         score += ATTACK_PREVENTS_CASTLING;
  850.          break;
  851.        case Board::CastledKSide:
  852.          score += KCASTLE; break;
  853.        case Board::CastledQSide:
  854.          score += QCASTLE; break;
  855.        case Board::CantCastleEitherSide:
  856.          score += CANT_CASTLE; break;
  857.     }
  858.     return score;
  859. }
  860.  
  861. int KingSafety( const Board &board, const ColorType side)
  862. {
  863.     int score = 0;
  864.     if ((side == board.Side()) && board.CheckStatus() == Board::InCheck)
  865.        score += CHECK;
  866.     Square kp(board.KingPos(side));
  867.     if (!endgame || mopping_up(board,OppositeColor(side)))
  868.     {
  869.        const byte *data = KingSquares[(int)kp];
  870.        for (int i = 0; i <8 && *data != 255 ;i++)
  871.        {
  872.           if (board.num_attacks(*data++,OppositeColor(side)) >0)
  873.              score += ATTACK_NEAR_KING;
  874.        }
  875.     }
  876.     if (!endgame)
  877.     {
  878.        if (kp.Rank(side) != 8)
  879.           score += KING_OFF_BACK_RANK;
  880.        int dir = (side == White ? -RankIncr : RankIncr);
  881.        Piece my_pawn(Piece::Pawn,side);
  882.        if (kp.File() != 1)
  883.        {
  884.            Square sq(kp-1);
  885.        Square pawnsq(sq+dir);
  886.            if (pawnsq.OnBoard()  &&
  887.             board[pawnsq] == my_pawn)
  888.                 score += KING_PAWN_COVER;
  889.        else if (board.PFileCount(sq.File()-1,side) == 0 &&
  890.             board.PFileCount(sq.File()-1,OppositeColor(side)) == 0)
  891.             score += KING_NEAR_OPEN_FILE;
  892.        }
  893.        Square pawnsq(kp+dir);
  894.        if (pawnsq.OnBoard() &&
  895.            board[pawnsq] == my_pawn)
  896.            score += KING_PAWN_COVER;
  897.        else if (board.PFileCount(kp.File()-1,side) == 0 &&
  898.             board.PFileCount(kp.File()-1,OppositeColor(side)) == 0)
  899.             score += KING_NEAR_OPEN_FILE;
  900.        if (kp.File() != 8)
  901.        {
  902.            Square sq(kp+1);
  903.        Square pawnsq(sq+dir);
  904.            if (pawnsq.OnBoard() &&
  905.             board[pawnsq] == my_pawn)
  906.                 score += KING_PAWN_COVER;
  907.         else if (board.PFileCount(sq.File()-1,side) == 0 &&
  908.             board.PFileCount(sq.File()-1,OppositeColor(side)) == 0)
  909.             score += KING_NEAR_OPEN_FILE;
  910.        }
  911.        const int kpfile = kp.File();
  912.        for (int j=0;j<16;j++)
  913.        {
  914.          Square sq(board.PiecePos(board.OppositeSide(),j));
  915.      if (!sq.IsInvalid())
  916.      {
  917.         Piece::PieceType p = board[sq].Type();
  918.         if (p==Piece::Rook || p == Piece::Queen)
  919.         {
  920.            if (Util::Abs(kpfile - sq.File()) <= 1)
  921.            {
  922.               score += DANGER_ON_FILE;
  923.           break;
  924.            }
  925.         }
  926.      }
  927.        }
  928.     }
  929.     return score;
  930. }
  931.  
  932. Boolean Scoring::check_en_prise( const Board &board, const Square sq,
  933.   const Piece p)
  934. {
  935.        Boolean en_prise = False;
  936.        if (p.Type() == Piece::Pawn ||
  937.             board.num_attacks(sq,board.OppositeSide()) == 0)
  938.        {
  939.            return False;
  940.        }
  941.        if (board.pawn_attacks(sq,board.OppositeSide()) > 0)
  942.        {
  943.            Scoring::pawn_threats = en_prise = True;
  944.        }
  945.        else if (board.num_attacks(sq,board.Side()) == 0)
  946.            en_prise = True;
  947.        else
  948.        {
  949.            const Attack_Entry &entr = 
  950.          board.get_attacks(sq,board.OppositeSide());
  951.        if (Piece::Value(entr.min_attacker()) < p.Value())
  952.          en_prise = True;
  953.        }
  954.        return en_prise;
  955. }
  956.  
  957. int Scoring::threat_score( const Board &board, const ColorType side )
  958. {
  959.     int score = 0;
  960.     en_prise = 0;
  961.     trapped = False;
  962.     pawn_threats = False;
  963.     for (int i = 0; i < 16; i++)
  964.     {
  965.         Square sq(board.PiecePos(side,i));
  966.     if (!sq.IsInvalid())
  967.     {
  968.         Piece piece(board[sq]);
  969.             if (check_en_prise(board,sq,piece))
  970.         {
  971.               // piece is apparently en prise
  972.               score += EN_PRISE;
  973.           en_prise++;
  974.           if (!trapped)
  975.           {
  976.              trapped = True;
  977.              Piece pinnedByPiece;
  978.              Square pinnedBySquare;
  979.              int dir;
  980.              Boolean pinned =
  981.                Bearing::Pinned(board,sq,pinnedByPiece,
  982.                pinnedBySquare,dir);
  983.              // Treat a pinned piece same as a trapped one:
  984.              if (pinned)
  985.                continue;
  986.              Square squares[Bearing::MaxBearSq];
  987.              unsigned n = Bearing::BearSq(board,sq,squares);
  988.              for (unsigned j = 0; j < n; j++)
  989.              {
  990.                  Square dest(squares[j]);
  991.                  if (!check_en_prise(board,dest,piece))
  992.                  {
  993.                 trapped = False;
  994.                 break;
  995.              }
  996.                  } // for 
  997.           }
  998.         }
  999.     }
  1000.     }
  1001.     if (en_prise > 1)
  1002.       score += TWO_EN_PRISE;
  1003.     if (trapped) 
  1004.       score += PIECE_TRAPPED;
  1005.     return score;
  1006. }
  1007.  
  1008. int Scoring::evalu8( const Board &board )
  1009. {
  1010.     int score = 0;
  1011.     endgame = in_endgame(board,board.Side());
  1012.     score += MaterialScore(board,board.Side())
  1013.          + Center(board,board.Side())
  1014.          - Center(board,board.OppositeSide())
  1015.          + Development(board,board.Side())
  1016.          - Development(board,board.OppositeSide())
  1017.          + Castling(board,board.Side())
  1018.          - Castling(board,board.OppositeSide())
  1019.          + PawnStructure(board,board.Side()) 
  1020.          - PawnStructure(board,board.OppositeSide())
  1021.          + KingSafety(board,board.Side())
  1022.          - KingSafety(board,board.OppositeSide())
  1023.          + threat_score(board,board.Side());
  1024.  
  1025.    return score;
  1026. }
  1027.  
  1028. int Scoring::positional_score( const Board &board )
  1029. // returns a positional score
  1030. {
  1031.     int score = 0;
  1032.     endgame = in_endgame(board,board.Side());
  1033.     score +=   Center(board,board.Side())
  1034.          - Center(board,board.OppositeSide())
  1035.          + Development(board,board.Side())
  1036.          - Development(board,board.OppositeSide())
  1037.          + Castling(board,board.Side())
  1038.          - Castling(board,board.OppositeSide())
  1039.          + PawnStructure(board,board.Side())
  1040.          - PawnStructure(board,board.OppositeSide())
  1041.          + KingSafety(board,board.Side())
  1042.          - KingSafety(board,board.OppositeSide())
  1043.          + threat_score(board,board.Side());
  1044.  
  1045.    return score;
  1046. }
  1047.         
  1048. int Scoring::positional_score( const Board &board, Scores &scores,
  1049.                   Scores &opp_scores )
  1050. // returns a positional score
  1051. {
  1052.     endgame = in_endgame(board,board.Side());
  1053.     scores.center = Center(board,board.Side());
  1054.     opp_scores.center = Center(board,board.OppositeSide());
  1055.     scores.development =
  1056.            Development(board,board.Side());
  1057.     opp_scores.development =
  1058.            Development(board,board.OppositeSide());
  1059.     scores.castling =
  1060.            Castling(board,board.Side());
  1061.     opp_scores.castling =
  1062.            Castling(board,board.OppositeSide());
  1063.     scores.pawn_structure =
  1064.            PawnStructure(board,board.Side());
  1065.     opp_scores.pawn_structure =
  1066.            PawnStructure(board,board.OppositeSide());
  1067.     scores.king_safety = 
  1068.            KingSafety(board,board.Side());
  1069.     opp_scores.king_safety =
  1070.            KingSafety(board,board.OppositeSide());
  1071.     scores.threats = 
  1072.            threat_score(board,board.Side());
  1073.     opp_scores.threats = 0;
  1074.  
  1075.     return scores.center + scores.development + scores.castling +
  1076.            scores.pawn_structure + scores.king_safety + scores.threats
  1077.        -  (opp_scores.center + opp_scores.development + 
  1078.           opp_scores.castling + opp_scores.pawn_structure + 
  1079.           opp_scores.king_safety + opp_scores.threats);
  1080. }
  1081.         
  1082. int Scoring::material_score( const Board &board )
  1083. // returns a material score
  1084. {
  1085.     return MaterialScore(board,board.Side());
  1086. }
  1087.