How do engines evaluate a position (actual algorithm)? How do chess engines actually evaluate a position? I am looking for a technical answer, not a general summary of how minimax works, I already know how minimax and alpha-beta, etc, work, so please do not reiterate generalities. I am interested specifically in the evaluation function.

My understanding is that the evaluation of a position is the same as evaluation of the leaf of the decision tree given best play by both sides. So, the problem then is how is each leaf evaluated? Obviously, whatever algorithm is used must be very fast because millions of leafs are evaluated. So, if this is right, then evaluation simply reduces to how a leaf position is evaluated.

The two methods for leaf evaluation that I know of are material balance and king safety. However, I suspect that it must be more complicated than this, otherwise evaluations would not have such fractional values. For example, there are many positions where both sides have the same material and perfectly safe kings. So, in those cases we would expect an evaluation of "0.00". However, in actuality the engine I use (Rybka) never has such an evaluation (unless it is a draw). It's evaluation of such positions is always something like "0.13" or "-0.05" or "0.07". So, obviously it is doing something more than just material+king safety. How does it come up with the number?
Chess algorithms are complicated, but I'm sure static evaluation gets applied before reaching the leaf nodes. For example, it's very common to reduce or even eliminate a branch if it loses materials.


The best way to learn positional evaluation in chess is the Stockfish source code. There's simply nothing better than that. https://github.com/official-stockfish/Stockfish/blob/master/src/evaluate.cpp.
If you don't like reading C++ code. There's a page here: https://hxim.github.io/Stockfish-Evaluation-Guide/.



function middle_game_evaluation(pos) {
  var v = 0;
  v += piece_value_mg(pos) - piece_value_mg(colorflip(pos));
  v += psqt_mg(pos) - psqt_mg(colorflip(pos));
  v += imbalance_total(pos);
  v += pawns_mg(pos) - pawns_mg(colorflip(pos));
  v += pieces_mg(pos) - pieces_mg(colorflip(pos));
  v += mobility_mg(pos) - mobility_mg(colorflip(pos));
  v += threats_mg(pos) - threats_mg(colorflip(pos));
  v += passed_mg(pos) - passed_mg(colorflip(pos));
  v += space(pos) - space(colorflip(pos));
  v += king_mg(pos) - king_mg(colorflip(pos));
  return v;
}


Stockfish evaluates a position by linearly add each individual term. That includes piece values, square values, pawn structures, mobility, passed pawns etc. Nothing special here.


How to get those values, known as parameter tuning? Nobody knows for sure, we have to adjust the parameters, play many games, look at the results. Sounds dumb? Yes, it is, but that's what all chess programmers do. Google's AlphaZero is no exception.