@@ -287,7 +287,7 @@ void aspirationWindow(Thread *thread) {
287287 while (1 ) {
288288
289289 // Perform a search and consider reporting results
290- pv .score = search (thread , & pv , alpha , beta , MAX (1 , depth ));
290+ pv .score = search (thread , & pv , alpha , beta , MAX (1 , depth ), FALSE );
291291 if ( (report && pv .score > alpha && pv .score < beta )
292292 || (report && elapsed_time (thread -> tm ) >= WindowTimerMS ))
293293 uciReport (thread -> threads , & pv , alpha , beta );
@@ -319,7 +319,7 @@ void aspirationWindow(Thread *thread) {
319319 }
320320}
321321
322- int search (Thread * thread , PVariation * pv , int alpha , int beta , int depth ) {
322+ int search (Thread * thread , PVariation * pv , int alpha , int beta , int depth , bool cutnode ) {
323323
324324 Board * const board = & thread -> board ;
325325 NodeState * const ns = & thread -> states [thread -> height ];
@@ -515,7 +515,7 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
515515 R = 4 + depth / 6 + MIN (3 , (eval - beta ) / 200 ) + (ns - 1 )-> tactical ;
516516
517517 apply (thread , board , NULL_MOVE );
518- value = - search (thread , & lpv , - beta , - beta + 1 , depth - R );
518+ value = - search (thread , & lpv , - beta , - beta + 1 , depth - R , ! cutnode );
519519 revert (thread , board , NULL_MOVE );
520520
521521 // Don't return unproven TB-Wins or Mates
@@ -546,7 +546,7 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
546546
547547 // For low depths, or after the above, verify with a reduced search
548548 if (depth < 2 * ProbCutDepth || value >= rBeta )
549- value = - search (thread , & lpv , - rBeta , - rBeta + 1 , depth - 4 );
549+ value = - search (thread , & lpv , - rBeta , - rBeta + 1 , depth - 4 , ! cutnode );
550550
551551 // Revert the board state
552552 revert (thread , board , move );
@@ -561,7 +561,15 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
561561 }
562562 }
563563
564- // Step 11. Initialize the Move Picker and being searching through each
564+ // Step 11. Internal Iterative Reductions. Artifically lower the depth on cutnodes
565+ // that are high enough up in the search tree that we would expect to have found
566+ // a Transposition. This is a modernized approach to Internal Iterative Deepening
567+ if ( cutnode
568+ && depth >= 7
569+ && ttMove == NONE_MOVE )
570+ depth -= 1 ;
571+
572+ // Step 12. Initialize the Move Picker and being searching through each
565573 // move one at a time, until we run out or a move generates a cutoff. We
566574 // reuse an already initialized MovePicker to verify Singular Extension
567575 if (!ns -> excluded ) init_picker (& ns -> mp , thread , ttMove );
@@ -581,47 +589,47 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
581589 hist = !isQuiet ? get_capture_history (thread , move )
582590 : get_quiet_history (thread , move , & cmhist , & fmhist );
583591
584- // Step 12 (~80 elo). Late Move Pruning / Move Count Pruning. If we
592+ // Step 13 (~80 elo). Late Move Pruning / Move Count Pruning. If we
585593 // have seen many moves in this position already, and we don't expect
586594 // anything from this move, we can skip all the remaining quiets
587595 if ( best > - TBWIN_IN_MAX
588596 && depth <= LateMovePruningDepth
589597 && movesSeen >= LateMovePruningCounts [improving ][depth ])
590598 skipQuiets = 1 ;
591599
592- // Step 13 (~175 elo). Quiet Move Pruning. Prune any quiet move that meets one
600+ // Step 14 (~175 elo). Quiet Move Pruning. Prune any quiet move that meets one
593601 // of the criteria below, only after proving a non mated line exists
594602 if (isQuiet && best > - TBWIN_IN_MAX ) {
595603
596604 // Base LMR reduced depth value that we expect to use later
597605 int lmrDepth = MAX (0 , depth - LMRTable [MIN (depth , 63 )][MIN (played , 63 )]);
598606 int fmpMargin = FutilityMarginBase + lmrDepth * FutilityMarginPerDepth ;
599607
600- // Step 13A (~3 elo). Futility Pruning. If our score is far below alpha,
608+ // Step 14A (~3 elo). Futility Pruning. If our score is far below alpha,
601609 // and we don't expect anything from this move, we can skip all other quiets
602610 if ( !inCheck
603611 && eval + fmpMargin <= alpha
604612 && lmrDepth <= FutilityPruningDepth
605613 && hist < FutilityPruningHistoryLimit [improving ])
606614 skipQuiets = 1 ;
607615
608- // Step 13B (~2.5 elo). Futility Pruning. If our score is not only far
616+ // Step 14B (~2.5 elo). Futility Pruning. If our score is not only far
609617 // below alpha but still far below alpha after adding the Futility Margin,
610618 // we can somewhat safely skip all quiet moves after this one
611619 if ( !inCheck
612620 && lmrDepth <= FutilityPruningDepth
613621 && eval + fmpMargin + FutilityMarginNoHistory <= alpha )
614622 skipQuiets = 1 ;
615623
616- // Step 13C (~10 elo). Continuation Pruning. Moves with poor counter
624+ // Step 14C (~10 elo). Continuation Pruning. Moves with poor counter
617625 // or follow-up move history are pruned near the leaf nodes of the search
618626 if ( ns -> mp .stage > STAGE_COUNTER_MOVE
619627 && lmrDepth <= ContinuationPruningDepth [improving ]
620628 && MIN (cmhist , fmhist ) < ContinuationPruningHistoryLimit [improving ])
621629 continue ;
622630 }
623631
624- // Step 14 (~42 elo). Static Exchange Evaluation Pruning. Prune moves which fail
632+ // Step 15 (~42 elo). Static Exchange Evaluation Pruning. Prune moves which fail
625633 // to beat a depth dependent SEE threshold. The use of the Move Picker's stage
626634 // is a speedup, which assumes that good noisy moves have a positive SEE
627635 if ( best > - TBWIN_IN_MAX
@@ -651,15 +659,15 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
651659 && ttDepth >= depth - 3
652660 && (ttBound & BOUND_LOWER );
653661
654- // Step 15 (~60 elo). Extensions. Search an additional ply when the move comes from the
662+ // Step 16 (~60 elo). Extensions. Search an additional ply when the move comes from the
655663 // Transposition Table and appears to beat all other moves by a fair margin. Otherwise,
656664 // extend for any position where our King is checked.
657665
658- extension = singular ? singularity (thread , ttMove , ttValue , depth , PvNode , alpha , beta ) : inCheck ;
666+ extension = singular ? singularity (thread , ttMove , ttValue , depth , PvNode , alpha , beta , cutnode ) : inCheck ;
659667 newDepth = depth + (!RootNode ? extension : 0 );
660668 if (extension > 1 ) ns -> dextensions ++ ;
661669
662- // Step 16 . MultiCut. Sometimes candidate Singular moves are shown to be non-Singular.
670+ // Step 17 . MultiCut. Sometimes candidate Singular moves are shown to be non-Singular.
663671 // If this happens, and the rBeta used is greater than beta, then we have multiple moves
664672 // which appear to beat beta at a reduced depth. singularity() sets the stage to STAGE_DONE
665673
@@ -668,7 +676,7 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
668676
669677 if (depth > 2 && played > 1 ) {
670678
671- // Step 17A (~249 elo). Quiet Late Move Reductions. Reduce the search depth
679+ // Step 18A (~249 elo). Quiet Late Move Reductions. Reduce the search depth
672680 // of Quiet moves after we've explored the main line. If a reduced search
673681 // manages to beat alpha, against our expectations, we perform a research
674682
@@ -690,7 +698,7 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
690698 R -= MAX (-2 , MIN (2 , hist / 5000 ));
691699 }
692700
693- // Step 17B (~3 elo). Noisy Late Move Reductions. The same as Step 17A , but
701+ // Step 18B (~3 elo). Noisy Late Move Reductions. The same as Step 18A , but
694702 // only applied to Tactical moves, based mostly on the Capture History scores
695703
696704 else {
@@ -706,7 +714,7 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
706714 R = MIN (depth - 1 , MAX (R , 1 ));
707715
708716 // Perform reduced depth search on a Null Window
709- value = - search (thread , & lpv , - alpha - 1 , - alpha , newDepth - R );
717+ value = - search (thread , & lpv , - alpha - 1 , - alpha , newDepth - R , true );
710718
711719 // Abandon searching here if we could not beat alpha
712720 doFullSearch = value > alpha && R != 1 ;
@@ -716,11 +724,11 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
716724
717725 // Full depth search on a null window
718726 if (doFullSearch )
719- value = - search (thread , & lpv , - alpha - 1 , - alpha , newDepth - 1 );
727+ value = - search (thread , & lpv , - alpha - 1 , - alpha , newDepth - 1 , ! cutnode );
720728
721729 // Full depth search on a full window for some PvNodes
722730 if (PvNode && (played == 1 || value > alpha ))
723- value = - search (thread , & lpv , - beta , - alpha , newDepth - 1 );
731+ value = - search (thread , & lpv , - beta , - alpha , newDepth - 1 , FALSE );
724732
725733 // Revert the board state
726734 revert (thread , board , move );
@@ -732,7 +740,7 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
732740 if (RootNode && !thread -> index )
733741 thread -> tm -> nodes [move ] += thread -> nodes - starting_nodes ;
734742
735- // Step 18 . Update search stats for the best move and its value. Update
743+ // Step 19 . Update search stats for the best move and its value. Update
736744 // our lower bound (alpha) if exceeded, and also update the PV in that case
737745 if (value > best ) {
738746
@@ -753,7 +761,7 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
753761 }
754762 }
755763
756- // Step 19 (~760 elo). Update History counters on a fail high for a quiet move.
764+ // Step 20 (~760 elo). Update History counters on a fail high for a quiet move.
757765 // We also update Capture History Heuristics, which augment or replace MVV-LVA.
758766
759767 if (best >= beta && !moveIsTactical (board , bestMove ))
@@ -762,17 +770,17 @@ int search(Thread *thread, PVariation *pv, int alpha, int beta, int depth) {
762770 if (best >= beta )
763771 update_capture_histories (thread , bestMove , capturesTried , capturesPlayed , depth );
764772
765- // Step 20 . Stalemate and Checkmate detection. If no moves were found to
773+ // Step 21 . Stalemate and Checkmate detection. If no moves were found to
766774 // be legal then we are either mated or stalemated, For mates, return a
767775 // score based on how far or close the mate is to the root position
768776 if (played == 0 ) return inCheck ? - MATE + thread -> height : 0 ;
769777
770- // Step 21 . When we found a Syzygy entry, don't report a value greater than
778+ // Step 22 . When we found a Syzygy entry, don't report a value greater than
771779 // the known bounds. For example, a non-zeroing move could be played, not be
772780 // held in Syzygy, and then be scored better than the true lost value.
773781 if (PvNode ) best = MAX (syzygyMin , MIN (best , syzygyMax ));
774782
775- // Step 22 . Store results of search into the Transposition Table. We do not overwrite
783+ // Step 23 . Store results of search into the Transposition Table. We do not overwrite
776784 // the Root entry from the first line of play we examined. We also don't store into the
777785 // Transposition Table while attempting to veryify singularities
778786 if (!ns -> excluded && (!RootNode || !thread -> multiPV )) {
@@ -994,7 +1002,7 @@ int staticExchangeEvaluation(Board *board, uint16_t move, int threshold) {
9941002 return board -> turn != colour ;
9951003}
9961004
997- int singularity (Thread * thread , uint16_t ttMove , int ttValue , int depth , int PvNode , int alpha , int beta ) {
1005+ int singularity (Thread * thread , uint16_t ttMove , int ttValue , int depth , int PvNode , int alpha , int beta , bool cutnode ) {
9981006
9991007 Board * const board = & thread -> board ;
10001008 NodeState * const ns = & thread -> states [thread -> height - 1 ];
@@ -1007,7 +1015,7 @@ int singularity(Thread *thread, uint16_t ttMove, int ttValue, int depth, int PvN
10071015
10081016 // Search on a null rBeta window, excluding the tt-move
10091017 ns -> excluded = ttMove ;
1010- value = search (thread , & lpv , rBeta - 1 , rBeta , (depth - 1 ) / 2 );
1018+ value = search (thread , & lpv , rBeta - 1 , rBeta , (depth - 1 ) / 2 , cutnode );
10111019 ns -> excluded = NONE_MOVE ;
10121020
10131021 // We reused the Move Picker, so make sure we cleanup
0 commit comments