A link to a message in the main forum

Discussion of chess software programming and technical issues.

Moderator: Ras

Lyudmil Tsvetkov
Posts: 6052
Joined: Tue Jun 12, 2012 12:41 pm

A link to a message in the main forum

Post by Lyudmil Tsvetkov »

Hi, I am just posting a link to the message in the main forum
about my humble evaluation project, as Marco suggested : http://www.talkchess.com/forum/viewtopi ... 12&t=44074

Best regards,
Ludmil
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: A link to a message in the main forum

Post by mcostalba »

Lyudmil Tsvetkov wrote:Hi, I am just posting a link to the message in the main forum
about my humble evaluation project, as Marco suggested : http://www.talkchess.com/forum/viewtopi ... 12&t=44074

Best regards,
Ludmil
This is pawn evaluation in SF (it is a very standard one and very common across engines). It is a loop across each pawn, it means each pawn is individually evaluated to get a score and the score summed to the total value.

Even if you are not a programmer perhaps you reconize somthing similar to your ideas. Remember that the lines starting with '//' are so called comments. They are free text written in natural language by the programmer as a kind of note. They are not instructions and are discarded by the computer that ignores them.

Code: Select all

  const Square* pl = pos.piece_list(Us, PAWN);

  // Loop through all pawns of the current color and score each pawn
  while ((s = *pl++) != SQ_NONE)
  {
      assert(pos.piece_on(s) == make_piece(Us, PAWN));

      f = file_of(s);
      r = rank_of(s);

      // This file cannot be half open
      e->halfOpenFiles[Us] &= ~(1 << f);

      // Our rank plus previous one. Used for chain detection
      b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));

      // Flag the pawn as passed, isolated, doubled or member of a pawn
      // chain (but not the backward one).
      chain    =   ourPawns   & adjacent_files_bb(f) & b;
      isolated = !(ourPawns   & adjacent_files_bb(f));
      doubled  =   ourPawns   & forward_bb(Us, s);
      opposed  =   theirPawns & forward_bb(Us, s);
      passed   = !(theirPawns & passed_pawn_mask(Us, s));

      // Test for backward pawn
      backward = false;

      // If the pawn is passed, isolated, or member of a pawn chain it cannot
      // be backward. If there are friendly pawns behind on adjacent files
      // or if can capture an enemy pawn it cannot be backward either.
      if (   !(passed | isolated | chain)
          && !(ourPawns & attack_span_mask(Them, s))
          && !(pos.attacks_from<PAWN>(s, Us) & theirPawns))
      {
          // We now know that there are no friendly pawns beside or behind this
          // pawn on adjacent files. We now check whether the pawn is
          // backward by looking in the forward direction on the adjacent
          // files, and seeing whether we meet a friendly or an enemy pawn first.
          b = pos.attacks_from<PAWN>(s, Us);

          // Note that we are sure to find something because pawn is not passed
          // nor isolated, so loop is potentially infinite, but it isn't.
          while (!(b & (ourPawns | theirPawns)))
              Us == WHITE ? b <<= 8 : b >>= 8;

          // The friendly pawn needs to be at least two ranks closer than the
          // enemy pawn in order to help the potentially backward pawn advance.
          backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
      }

      assert(opposed | passed | (attack_span_mask(Us, s) & theirPawns));

      // A not passed pawn is a candidate to become passed if it is free to
      // advance and if the number of friendly pawns beside or behind this
      // pawn on adjacent files is higher or equal than the number of
      // enemy pawns in the forward direction on the adjacent files.
      candidate =   !(opposed | passed | backward | isolated)
                 && (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != 0
                 &&  popcount<Max15>(b) >= popcount<Max15>(attack_span_mask(Us, s) & theirPawns);

      // Passed pawns will be properly scored in evaluation because we need
      // full attack info to evaluate passed pawns. Only the frontmost passed
      // pawn on each file is considered a true passed pawn.
      if (passed && !doubled)
          e->passedPawns[Us] |= s;

      // Score this pawn
      if (isolated)
          value -= IsolatedPawnPenalty[opposed][f];

      if (doubled)
          value -= DoubledPawnPenalty[opposed][f];

      if (backward)
          value -= BackwardPawnPenalty[opposed][f];

      if (chain)
          value += ChainBonus[f];

      if (candidate)
          value += CandidateBonus[relative_rank(Us, s)];
  }
The tables (called arrays) DoubledPawnPenalty...CandidateBonus keep the actual stored scores that depends on file number and if file is half-open. Tables are defined like:

Code: Select all

  // Doubled pawn penalty by opposed flag and file
  const Score DoubledPawnPenalty[2][8] = {
  { S(13, 43), S(20, 48), S(23, 48), S(23, 48),
    S(23, 48), S(23, 48), S(20, 48), S(13, 43) },
  { S(13, 43), S(20, 48), S(23, 48), S(23, 48),
    S(23, 48), S(23, 48), S(20, 48), S(13, 43) }};

  // Isolated pawn penalty by opposed flag and file
  const Score IsolatedPawnPenalty[2][8] = {
  { S(37, 45), S(54, 52), S(60, 52), S(60, 52),
    S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
  { S(25, 30), S(36, 35), S(40, 35), S(40, 35),
    S(40, 35), S(40, 35), S(36, 35), S(25, 30) }};

  // Backward pawn penalty by opposed flag and file
  const Score BackwardPawnPenalty[2][8] = {
  { S(30, 42), S(43, 46), S(49, 46), S(49, 46),
    S(49, 46), S(49, 46), S(43, 46), S(30, 42) },
  { S(20, 28), S(29, 31), S(33, 31), S(33, 31),
    S(33, 31), S(33, 31), S(29, 31), S(20, 28) }};

  // Pawn chain membership bonus by file
  const Score ChainBonus[8] = {
    S(11,-1), S(13,-1), S(13,-1), S(14,-1),
    S(14,-1), S(13,-1), S(13,-1), S(11,-1)
  };

  // Candidate passed pawn bonus by rank
  const Score CandidateBonus[8] = {
    S( 0, 0), S( 6, 13), S(6,13), S(14,29),
    S(34,68), S(83,166), S(0, 0), S( 0, 0)
  };
The predefined scores like:

Code: Select all

S(83,166)
stores togheter a value used for midgame (83) and a value used for endgame (166). The final value is then found interpolating across the 2 values according to current game phase (interpolating code is not reported).
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: A link to a message in the main forum

Post by lucasart »

Lyudmil Tsvetkov wrote:Hi, I am just posting a link to the message in the main forum
about my humble evaluation project, as Marco suggested : http://www.talkchess.com/forum/viewtopi ... 12&t=44074

Best regards,
Ludmil
Have you done any testing ?