- if(!pos.is_check() && allowNullmove && ok_to_do_nullmove(pos)
- && approximateEval >= beta - NullMoveMargin) {
- UndoInfo u;
- Value nullValue;
-
- ss[ply].currentMove = MOVE_NULL;
- pos.do_null_move(u);
- nullValue = -search(pos, ss, -(beta-1), depth-4*OnePly, ply+1, false,
- threadID);
- pos.undo_null_move(u);
-
- if(nullValue >= beta) {
- if(depth >= 6 * OnePly) { // Do zugzwang verification search
- Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID);
- if(v >= beta)
- return beta;
+ if ( allowNullmove
+ && depth > OnePly
+ && !isCheck
+ && !value_is_mate(beta)
+ && ok_to_do_nullmove(pos)
+ && approximateEval >= beta - NullMoveMargin)
+ {
+ ss[ply].currentMove = MOVE_NULL;
+
+ UndoInfo u;
+ pos.do_null_move(u);
+ int R = (depth >= 4 * OnePly ? 4 : 3); // Null move dynamic reduction
+
+ Value nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
+
+ // Check for a null capture artifact, if the value without the null capture
+ // is above beta then mark the node as a suspicious failed low. We will verify
+ // later if we are really under threat.
+ if ( UseNullDrivenIID
+ && nullValue < beta
+ && depth > 6 * OnePly
+ &&!value_is_mate(nullValue)
+ && ttMove == MOVE_NONE
+ && ss[ply + 1].currentMove != MOVE_NONE
+ && pos.move_is_capture(ss[ply + 1].currentMove)
+ && pos.see(ss[ply + 1].currentMove) + nullValue >= beta)
+ nullDrivenIID = true;
+
+ pos.undo_null_move(u);
+
+ if (value_is_mate(nullValue))
+ {
+ /* Do not return unproven mates */
+ }
+ else if (nullValue >= beta)
+ {
+ if (depth < 6 * OnePly)
+ return beta;
+
+ // Do zugzwang verification search
+ Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID);
+ if (v >= beta)
+ return beta;
+ } else {
+ // The null move failed low, which means that we may be faced with
+ // some kind of threat. If the previous move was reduced, check if
+ // the move that refuted the null move was somehow connected to the
+ // move which was reduced. If a connection is found, return a fail
+ // low score (which will cause the reduced move to fail high in the
+ // parent node, which will trigger a re-search with full depth).
+ if (nullValue == value_mated_in(ply + 2))
+ {
+ mateThreat = true;
+ nullDrivenIID = false;
+ }
+ ss[ply].threatMove = ss[ply + 1].currentMove;
+ if ( depth < ThreatDepth
+ && ss[ply - 1].reduction
+ && connected_moves(pos, ss[ply - 1].currentMove, ss[ply].threatMove))
+ return beta - 1;