1

I read about a SEE without move/undo but they didn't share any simple pseudo code. If the next ply isn't calculated, cant see the recursive nature, Any speculators how this would work without move/undo?

int see(int square, int side)
{
   value = 0;
   piece = get_smallest_attacker(square, side);
   /* skip if the square isn't attacked anymore by this side */
   if ( piece )
   {
      make_capture(piece, square);
      /* Do not consider captures if they lose material, therefor max zero */
      value = max (0, piece_just_captured() -see(square, other(side)) );
      undo_capture(piece, square);
   }
   return value;
}
2

The pseudocode you copied from the wiki is just the easiest way to make you understand SEE. It is NOT used in a real chess engine, because building a swap list would be more efficient.

You should check Stockfish. I'll give you some hints here.

  1. Goto position.cpp.
  2. Find the function Value Position::see(Move m) const. This is where SEE is implemented
  3. Check this loop:

    do {
      assert(slIndex < 32);
    
      // Add the new entry to the swap list
      swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured];
    
      // Locate and remove the next least valuable attacker
      captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
      stm = ~stm;
      stmAttackers = attackers & pieces(stm);
      ++slIndex;
    
    } while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture
    

Stockfish doesn't do exactly what your pseudocode does. It loops for all for possible attackers from the least powerful (min_attacker). For each attacker, the engine checks it's value (PieceValues[MG]) and add it to the swap list. The swap list will then be looped over for nega-max:

  // Having built the swap list, we negamax through it to find the best
  // achievable score from the point of view of the side to move.
  while (--slIndex)
      swapList[slIndex - 1] = std::min(-swapList[slIndex], swapList[slIndex - 1]);

Don't be afraid of the while loop, all it does to check if an exchange is good or not. In fact, the wikipedia you stated has the reasoning:

This uses a trick, equivalent to negamax in tree search, where the loss for the current side is the gain for the opposite side. This can be seen in the expression piece_just_captured() - see(square); which is the value of the piece captured (piece_just_captured()) minus the gain that the opponent might make after the move by recapturing. If that term becomes negative, one would better choose standing pat rather than to capture, which can be done by a conditional assignment, or by a max function with zero as second argument.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.