hgm wrote: ↑Fri Mar 05, 2021 3:04 pm
Not that many positions will be repetitions, so it will definitely not make a significant difference. But doing it in the child definitely would make unneeded moves just to unmake them immediately afterwards, and that must always be slower. There is zero upside.
In Joker I even do the TT probe in the parent; I also don't need anything but the hash key for that, and if I get a TT cut-off, why waste time on make/unmake? This happens much more frequently than repetitions. Downside is that I need to pass the hash move to the child. Futility pruning of course does the stand-pat on behalf of the child (but based on an estimated evaluation, so it cannot do it when it is a close call, and the full evaluation would need the move to be made first).
Seems we're not talking about the same thing.
Previously, I did this:
Code: Select all
for m in move_loop {
// do move loop stuff
let evaluation = if !draw() {
-alpha_beta(d -1, -b, -a)
} else {
DRAW
}
}
So here, evaluation would either become what comes out of the recursive call, or DRAW immediately and then continue on to the next move. Now I do:
Code: Select all
if draw() {
return DRAW;
}
for m in move_loop {
// do move loop things
let evaluation = -alpha_beta(d -1 , -b, -a);
}
In both cases, evaluation will be assigned DRAW. In the first case, through an if-statement, and in the second case, right after it re-enters alpha_beta and returns from there with DRAW. I was testing if the second case would gain anything over the first (as more engines are using the second), but it doesn't seem to.
With regard to hash probe: I do this immediately after the depth <= 0 QSearch check. If there is a TT cutoff by value, alpha-beta returns, and there are no moves generated and the move-loop is not started.