- // Null move search
- 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();
-
- 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;
- }
- }