if (score - eval_queen >= beta)
return score;
and it should also be "depthLeft == 0". FP prunes futile moves, and you do this either before making them (within the move loop => here you check against alpha) or after making them (here you check against beta since it is now the opponent's viewpoint).
flok wrote:2 questions:
* am I right to return score when pruning? or should it be alpha? it is a fail-soft application
I think there are different opinions about that. I would return the corrected score ("score + eval_queen" resp. "score - eval_queen") since the assumption is that the static eval (which is kind of an estimate) is probably not off by more than your futility margin (eval_queen). But SF 8, for instance, returns "score" at this point.
flok wrote:* the wiki says that you should not do this pruning when either alpha or beta is near the mate score. what is near in this case?
It means, if the score is a mate score and not a score resulting from static eval, for instance:
if (abs(score) >= MATE_SCORE - MAX_PLY)
Furthermore, "eval_queen" is probably too high as a futility margin. The value of two or three pawns might be a slightly better margin for FP at depth 1.
I don't understand when depthLeft == 0 then it is in qsearch when not in check and then you start with a stand pad test with margin == 0 that is eval >= ub
Henk wrote:I don't understand when depthLeft == 0 then it is in qsearch when not in check and then you start with a stand pad test with margin == 0 that is eval >= ub
Yes. But you need to call qsearch() to reach that stand-pat test. So applying futility pruning at the child node and only when depthLeft == 0 does not appear to save more than the recursive call to qsearch(). Many engines apply FP at the parent node so for depthLeft == 1 (same as depthLeft == 0 at the child node) they also save making the move.
In practice we often see the extended form where FP is applied for depthLeft <= N, e.g. N=6 (at child node) in SF8. There your argument is no longer relevant. SF8 even does FP at child node *and* at parent node, and I don't want to try explaining it since I did not check carefully how it works.
Strangely enough all (alpha - score, beta + score, queen versus 2 or 3 pawns) give around -20 elo.
Very strange. I'll look at it again tomorrow.
If you get -20 Elo compared to the code you posted (which prunes strong moves that were made at depthLeft==2, not bad moves made at depthLeft==1 !) then you should check whether you did your changes correctly.
Another explanation might be that the code you posted is simply not futility pruning but a different kind of pruning that works for your engine so that removing it makes your engine weaker. You could check this by adding "correct" futility pruning without removing the code above.
int search(...) {
if (!isCheck && (depthLeft == 1) && (beta-alpha == 1) && alpha > MIN_EVAL_SCORE) {
int score = eval();
if (score + eval_queen <= alpha)
return score;
}
for(Move x : moves) {
etc
}
}
Would you call that "futility pruning", even though it prunes strong moves instead of futile moves (the opponent's previous move raised the static eval far above his beta)?