To expand on what heuristic pruning means for an alpha-beta negamax search, which many chess programs use, typically the evaluation function has some kind of depth parameter and the alpha-beta window. What it does is to test each possible move one by one, calling itself on the resulting position with the depth parameter reduced and with the appropriate alpha-beta window passed in. eval(d,α,β) searches to depth d and returns the value of the current position truncated to the interval [α,β]. At the start we call eval(D,−∞,∞) where D is the maximum depth. Note that the alpha-beta window depends on the evaluation results for previously tried moves as follows.
We first set m := α before testing any move. When testing each subsequent move we would call t := −eval(d',−β,−m) and then set m := max(m,t). If m≥β then we can immediately return β. At the end we return m. The reason for calling "eval(d',−β,−m)" is that if the resulting position has true value u outside [−β,−m] then it would have equivalent effect on the true value v of the current position as the truncated value. (If u<−β, then −eval(d',−β,−m) yields β so we return β, which is correct since v>β. If u>−m, then −eval(d',−β,−m) yields m so it does not affect m, which is correct since that move led to true value of −u<m.) Here d' is set by a heuristic (e.g. quiescence search may set d' := d−1 for normal moves but d' := d−1/2 for check and d' := d for captures).
To understand how heuristic pruning helps, one must first understand how alpha-beta helps. When the move-ordering is optimal (it always tests an optimal move first), then alpha-beta eliminates all the other moves at every alternate recursion level in most of the cases. To intuitively see why, consider the first move. To find an optimal first move X, we really have to check all possible first moves. But after we test an optimal one first, m would be set to that value, and we call eval(,−∞,−m) for every other tested first move X'. But since we first test an optimal opponent response Y to X', we will find that it results in a value at least −m (since X' is not better than X), and hence immediately return (discarding all other opponent responses because the first one already confirms that X' is not better than X). This happens throughout the search tree, and so the branching factor is more or less reduced to 1 at every alternate level in the search tree. This effectively doubles the search-depth possible with the same resources.
Mathematically, it is impossible to do better than alpha-beta search if we want to prove that a move is optimal. However, in many games such as chess we can perform better on average by using heuristic pruning. Instead of testing all the moves required by the alpha-beta search, we discard many of the moves! Heuristics inform this process. For example, if d>4 then we could for each possible move X, perform X then set t[X] := −eval(4,−β,−α) then undo X. After that, t[X] represents a depth-4 evaluation of those moves truncated to [α,β]. We might then choose to discard any move X if t[X]+3≤m; Informally, if move X causes a depth-4 evaluation that is at least a 'bishop' worse than the current best, we assume that it is poor enough that ignoring it will not affect the evaluation result.
Heuristic pruning (beyond alpha-beta) can hence reduce the effective branching factor (not just at every alternate level). That is why it is used in many modern chess programs today. The example heuristic I gave above is just for illustrative purposes; actual chess programs use a whole variety of complex heuristics to prune (e.g. null-move heuristic), as well as heuristics to not prune (e.g. the killer/history heuristic).
Now looking at the situation you have here, it is easy for many heuristics to prune off the best move Bf6
unless the depth-0 evaluation gives high enough weight to king danger, because Bf6
drops the bishop for a pawn and it takes quite a lot of quiet moves to see any benefits besides increased Black king danger. I am not sure, but the best line appears to be:
[Title ""]
[FEN "r1b2r2/pp1p1ppk/2n1p3/6B1/2P5/5N2/PQ3PPP/R4RK1 w Q - 0 1"]
1. Bf6 gxf6 2. Qxf6 Rg8 3. Ng5+ Rxg5 4. Qxg5
This line takes 2 quiet moves, 1 check and 4 captures. However, a pruning heuristic will very likely prune based on the first few moves of the following line:
[Title ""]
[FEN "r1b2r2/pp1p1ppk/2n1p3/6B1/2P5/5N2/PQ3PPP/R4RK1 w Q - 0 1"]
1. Bf6 gxf6 2. Qxf6 Kg8 3. Ng5 Nd8 4. Rad1 e5
Since it cannot see that this line ends in checkmate, it may believe that the bishop has been lost for a pawn. If the evaluation function had counted the position after 3. Ng5
as high king danger, it would not have pruned the Bf6
line away. As it is, it likely weighed the king danger against the bishop loss and thought it was worse than keeping the bishop. Furthermore, since there are many possible moves instead of Bf6
that keep the bishop, they would likely have pushed the Bf6
line far down in the move-ordering, hence it never got searched deep.