- #include "chess.h" 
- #include "data.h" 
- /* last modified 05/08/14 */ 
- /* 
-  ******************************************************************************* 
-  *                                                                             * 
-  *   Search() is the recursive routine used to implement the alpha/beta        * 
-  *   negamax search (similar to minimax but simpler to code.)  Search() is     * 
-  *   called whenever there is "depth" remaining so that all moves are subject  * 
-  *   to searching.  Search() recursively calls itself so long as there is at   * 
-  *   least one ply of depth left, otherwise it calls Quiesce() instead.        * 
-  *                                                                             * 
-  ******************************************************************************* 
-  */ 
- int Search(TREE * RESTRICT tree, int alpha, int beta, int side, int depth, 
-     int ply, int do_null) { 
-   ROOT_MOVE temp_rm; 
-   uint64_t start_nodes = tree->nodes_searched; 
-   int first_tried = 0, moves_searched = 0, repeat = 0; 
-   int original_alpha = alpha, value = 0, t_beta = beta; 
-   int extend, reduce, max_reduce, i; 
-   int pv_node = alpha != beta - 1; 
-   
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 1.  Check to see if we have searched enough nodes  * 
-  *  that it is time to peek at how much time has been used, * 
-  *  or if is time to check for operator keyboard input.     * 
-  *  This is usually enough nodes to force a time/input      * 
-  *  check about once per second, except when the target     * 
-  *  time per move is very small, in which case we try to    * 
-  *  check the time more frequently.                         * 
-  *                                                          * 
-  *  Note that we check input or time-out in thread 0.  This * 
-  *  makes the code simpler and eliminates some problematic  * 
-  *  race conditions.                                        * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
- #if defined(NODES) 
-   if (--temp_search_nodes <= 0) { 
-     abort_search = 1; 
-     return 0; 
-   } 
- #endif 
-   if (tree->thread_id == 0) { 
-     if (--next_time_check <= 0) { 
-       next_time_check = nodes_between_time_checks; 
-       if (TimeCheck(tree, 1)) { 
-         abort_search = 1; 
-         return 0; 
-       } 
-       if (CheckInput()) { 
-         Interrupt(ply); 
-         if (abort_search) 
-           return 0; 
-       } 
-     } 
-   } 
-   if (ply >= MAXPLY - 1) 
-     return beta; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 2.  Check for draw by repetition, which includes   * 
-  *  50 move draws also.  This is the quickest way to get    * 
-  *  out of further searching, with minimal effort.  This    * 
-  *  and the next two steps are skipped for moves at the     * 
-  *  root (ply = 1).                                         * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   if (ply > 1) { 
-     if ((repeat = Repeat(tree, ply))) { 
-       value = DrawScore(side); 
-       if (value < beta) 
-         SavePV(tree, ply, 0); 
- #if defined(TRACE) 
-       if (ply <= trace_level) 
-         printf("draw by repetition detected, ply=%d.\n",-  ply );
 
- #endif 
-       return value; 
-     } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 3.  Check the transposition/refutation (hash)      * 
-  *  table to see if we have searched this position          * 
-  *  previously and still have the results available.  We    * 
-  *  might get a real score, or a bound, or perhaps only a   * 
-  *  good move to try first.  The possible results are:      * 
-  *                                                          * 
-  *  1. HashProbe() returns "HASH_HIT".  This terminates     * 
-  *  the search instantly and we simply return the value     * 
-  *  found in the hash table.  This value is simply the      * 
-  *  value we found when we did a real search in this        * 
-  *  position previously, and HashProbe() verifies that the  * 
-  *  value is useful based on draft and current bounds.      * 
-  *                                                          * 
-  *  2. HashProbe() returns "AVOID_NULL_MOVE" which means    * 
-  *  the hashed score/bound was no good, but it indicated    * 
-  *  that trying a null-move in this position would be a     * 
-  *  waste of time since it will likely fail low, not high.  * 
-  *                                                          * 
-  *  3. HashProbe() returns "HASH_MISS" when forces us to    * 
-  *  do a normal search to resolve this node.                * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-     switch (HashProbe(tree, ply, depth, side, alpha, beta, &value)) { 
-       case HASH_HIT: 
-         return value; 
-       case AVOID_NULL_MOVE: 
-         do_null = 0; 
-       case HASH_MISS: 
-         break; 
-     } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 4.  Now it's time to try a probe into the endgame  * 
-  *  tablebase files.  This is done if we notice that there  * 
-  *  are 6 or fewer pieces left on the board.  EGTB_use      * 
-  *  tells us how many pieces to probe on.  Note that this   * 
-  *  can be zero when trying to swindle the opponent, so     * 
-  *  that no probes are done since we know it is a draw.     * 
-  *  This is another way to get out of the search quickly,   * 
-  *  but not as quickly as the previous steps since this can * 
-  *  result in an I/O operation.                             * 
-  *                                                          * 
-  *  Note that in "swindle mode" this can be turned off by   * 
-  *  Iterate() setting "EGTB_use = 0" so that we won't probe * 
-  *  the EGTBs since we are searching only the root moves    * 
-  *  that lead to a draw and we want to play the move that   * 
-  *  makes the draw more difficult to reach by the opponent  * 
-  *  to give him a chance to make a mistake.                 * 
-  *                                                          * 
-  *  Another special case is that we slightly fudge the      * 
-  *  score for draws.  In a normal circumstance, draw=0.00   * 
-  *  since it is "equal".  However, here we add 0.01 if      * 
-  *  white has more material, or subtract 0.01 if black has  * 
-  *  more material, since in a drawn KRP vs KR we would      * 
-  *  prefer to have the KRP side since the opponent can make * 
-  *  a mistake and convert the draw to a loss.               * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
- #if !defined(NOEGTB) 
-     if (depth > 6 && TotalAllPieces <= EGTB_use && 
-         Castle(ply, white) + Castle(ply, black) == 0 && 
-         (CaptureOrPromote(tree->curmv[ply - 1]) || ply < 3)) { 
-       int egtb_value; 
-   
-       tree->egtb_probes++; 
-       if (EGTBProbe(tree, ply, side, &egtb_value)) { 
-         tree->egtb_probes_successful++; 
-         alpha = egtb_value; 
-         if (MateScore(alpha)) 
-           alpha += (alpha > 0) ? -ply + 1 : ply; 
-         else if (alpha == 0) { 
-           alpha = DrawScore(side); 
-           if (Material > 0) 
-             alpha += (side) ? 1 : -1; 
-           else if (Material < 0) 
-             alpha -= (side) ? 1 : -1; 
-         } 
-         if (alpha < beta) 
-           SavePV(tree, ply, 2); 
-         return alpha; 
-       } 
-     } 
- #endif 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 5.  We now know there is no quick way to get out   * 
-  *  of here, which leaves one more possibility, although it * 
-  *  does require s search, but to a reduced depth.  We      * 
-  *  try a null move to see if we can get a quick cutoff     * 
-  *  with only a little work.  This operates as follows.     * 
-  *  Instead of making a legal move, the side on move passes * 
-  *  and does nothing.  The resulting position is searched   * 
-  *  to a shallower depth than normal (usually 3 plies less  * 
-  *  but settable by the user.) This will result in a cutoff * 
-  *  if our position is very good, but it produces the       * 
-  *  cutoff much quicker since the search is far shallower   * 
-  *  than a normal search that would also be likely to fail  * 
-  *  high.                                                   * 
-  *                                                          * 
-  *  This is skipped for any of the following reasons:       * 
-  *                                                          * 
-  *  1.  The side on move is in check.  The null move        * 
-  *      results in an illegal position.                     * 
-  *  2.  No more than one null move can appear in succession * 
-  *      as all this does is burn 6 plies of depth.          * 
-  *  3.  The side on move has only pawns left, which makes   * 
-  *      zugzwang positions more likely.                     * 
-  *  4.  The transposition table probe found an entry that   * 
-  *      indicates that a null-move search will not fail     * 
-  *      high, so we avoid the wasted effort.                * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-     tree->inchk[ply + 1] = 0; 
-     tree->last[ply] = tree->last[ply - 1]; 
-     if (do_null && !pv_node && depth > 1 && !tree->inchk[ply] 
-         && TotalPieces(side, occupied)) { 
-       uint64_t save_hash_key; 
-   
-       tree->curmv[ply] = 0; 
-       tree->phase[ply] = NULL_MOVE; 
- #if defined(TRACE) 
-       if (ply <= trace_level) 
-         Trace(tree, ply, depth, side, beta - 1, beta, "Search1", NULL_MOVE); 
- #endif 
-       tree->status[ply + 1] = tree->status[ply]; 
-       Reversible(ply + 1) = 0; 
-       save_hash_key = HashKey; 
-       if (EnPassant(ply + 1)) { 
-         HashEP(EnPassant(ply + 1)); 
-         EnPassant(ply + 1) = 0; 
-       } 
-       if (depth - null_depth - 1 > 0) 
-         value = 
-             -Search(tree, -beta, -beta + 1, Flip(side), 
-             depth - null_depth - 1, ply + 1, NO_NULL); 
-       else 
-         value = -Quiesce(tree, -beta, -beta + 1, Flip(side), ply + 1, 1); 
-       HashKey = save_hash_key; 
-       if (abort_search || tree->stop) 
-         return 0; 
-       if (value >= beta) { 
-         HashStore(tree, ply, depth, side, LOWER, value, tree->hash_move[ply]); 
-         return value; 
-       } 
-     } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 6.  This step is rarely executed.  It is used when * 
-  *  there is no best move from the hash table, and this is  * 
-  *  a PV node, since we need a good move to search first.   * 
-  *  While killers moves are good, they are not quite good   * 
-  *  enough.  the simplest solution is to try a shallow      * 
-  *  search (depth-2) to get a move.  note that when we call * 
-  *  Search() with depth-2, it, too, will not have a hash    * 
-  *  move, and will therefore recursively continue this      * 
-  *  process, hence the name "internal iterative deepening." * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-     tree->next_status[ply].phase = HASH_MOVE; 
-     if (!tree->hash_move[ply] && depth >= 6 && do_null && ply > 1) { 
-       if (pv_node) { 
-         do { 
-           tree->curmv[ply] = 0; 
-           if (depth - 2 > 0) 
-             value = Search(tree, alpha, beta, side, depth - 2, ply, DO_NULL); 
-           else 
-             value = Quiesce(tree, alpha, beta, side, ply, 1); 
-           if (abort_search || tree->stop) 
-             break; 
-           if (value > alpha) { 
-             if (value < beta) { 
-               if ((int) tree->pv[ply - 1].pathl > ply) 
-                 tree->hash_move[ply] = tree->pv[ply - 1].path[ply]; 
-             } else 
-               tree->hash_move[ply] = tree->curmv[ply]; 
-             tree->last[ply] = tree->last[ply - 1]; 
-             tree->next_status[ply].phase = HASH_MOVE; 
-           } 
-         } while (0); 
-       } 
-     } 
-   } 
- /*   
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7.  Now iterate through the move list and search   * 
-  *  the resulting positions.  Note that Search() culls any  * 
-  *  move that is not legal by using Check().  The special   * 
-  *  case is that we must find one legal move to search to   * 
-  *  confirm that it's not a mate or draw.                   * 
-  *                                                          * 
-  *  We have three possible procedures we call here, one is  * 
-  *  specific to ply=1 (NextRootMove()), the second is a     * 
-  *  specific routine to escape check (NextEvasion()) and    * 
-  *  the last is the normal NextMove() procedure that does   * 
-  *  the usual move ordering stuff.                          * 
-  *                                                          * 
-  *  Special case:  if we have searched one move at root,    * 
-  *  and the returned score == alpha, we want to get out of  * 
-  *  here and return to Iterate() where the search bounds    * 
-  *  will be adjusted.  Otherwise we would search all root   * 
-  *  moves and possibly fail low after expending a sig-      * 
-  *  nificant amount of time.                                * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   tree->next_status[ply].phase = HASH_MOVE; 
-   while (1) { 
-     if (ply > 1) 
-       tree->phase[ply] = 
-           (tree->inchk[ply]) ? NextEvasion(tree, ply, side) : NextMove(tree, 
-           ply, side); 
-     else if (moves_searched == 1 && alpha == original_alpha) 
-       break; 
-     else 
-       tree->phase[ply] = NextRootMove(tree, tree, side); 
-     if (!tree->phase[ply]) 
-       break; 
- #if defined(TRACE) 
-     if (ply <= trace_level) 
-       Trace(tree, ply, depth, side, alpha, beta, "Search2", tree->phase[ply]); 
- #endif 
-     MakeMove(tree, ply, tree->curmv[ply], side); 
-     tree->nodes_searched++; 
-     if (tree->inchk[ply] || !Check(side)) 
-       do { 
-         if (++moves_searched == 1) 
-           first_tried = tree->curmv[ply]; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7a.  If the move to be made checks the opponent,   * 
-  *  then we need to remember that he's in check and also    * 
-  *  extend the depth by one ply for him to get out.  Note   * 
-  *  that if the move gives check, it is not a candidate for * 
-  *  either depth reduction or forward-pruning.              * 
-  *                                                          * 
-  *  We do not extend unsafe checking moves (as indicated by * 
-  *  Swap(), a SEE algorithm, since these are usually a      * 
-  *  waste of time and simply blow up the tree search space. * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         extend = 0; 
-         reduce = 0; 
-         if (Check(Flip(side))) { 
-           tree->inchk[ply + 1] = 1; 
-           if (SwapO(tree, tree->curmv[ply], side) <= 0) { 
-             extend = check_depth; 
-             tree->extensions_done++; 
-           } 
-         } else 
-           tree->inchk[ply + 1] = 0; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7b.  Now for the forward-pruning stuff.  The idea  * 
-  *  here is based on the old FUTILITY idea, where if the    * 
-  *  current material + a fudge factor is lower than alpha,  * 
-  *  then there is little promise in searching this move to  * 
-  *  make up for the material deficit.  This is not done if  * 
-  *  we chose to extend this move in the previous step.      * 
-  *                                                          * 
-  *  This is a useful idea in today's 20+ ply searches, as   * 
-  *  when we near the tips, if we are too far behind in      * 
-  *  material, there is little time left to recover it and   * 
-  *  moves that don't bring us closer to a reasonable        * 
-  *  material balance can safely be skipped.  It is much     * 
-  *  more dangerous in shallow searches.                     * 
-  *                                                          * 
-  *  We have an array of pruning margin values that are      * 
-  *  indexed by depth (remaining plies left until we drop    * 
-  *  into the quiescence search) and which increase with     * 
-  *  depth since more depth means a greater chance of        * 
-  *  bringing the score back up to alpha or beyond.  If the  * 
-  *  current material + the bonus is less than alpha, we     * 
-  *  simply avoid searching this move at all, and skip to    * 
-  *  the next move without expending any more effort.  Note  * 
-  *  that this is classic forward-pruning and can certainly  * 
-  *  introduce errors into the search.  However, cluster     * 
-  *  testing has shown that this improves play in real       * 
-  *  games.  The current implementation only prunes in the   * 
-  *  last 5 plies before quiescence, although this can be    * 
-  *  tuned with the "eval" command changing the "pruning     * 
-  *  depth" value to something other than 6 (test is for     * 
-  *  depth < pruning depth, current value is 6 which prunes  * 
-  *  in last 5 plies only).  Testing shows no benefit in     * 
-  *  larger values than 6, although this might change in     * 
-  *  future versions as other things are modified.           * 
-  *                                                          * 
-  *  Exception:                                              * 
-  *                                                          * 
-  *    We do not prune if we are safely pushing a passed     * 
-  *    pawn to the 6th rank, where it becomes very dangerous * 
-  *    since it can promote in two more moves.               * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (tree->phase[ply] == REMAINING_MOVES && !tree->inchk[ply] 
-             && !extend && moves_searched > 1) { 
-           if (depth < pruning_depth && 
-               MaterialSTM(side) + pruning_margin[depth] <= alpha) { 
-             if (Piece(tree->curmv[ply]) != pawn || 
-                 !Passed(To(tree->curmv[ply]), side) 
-                 || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { 
-               tree->moves_fpruned++; 
-               continue; 
-             } 
-           } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7c.  Now it's time to try to reduce the search     * 
-  *  depth if the move appears to be "poor".  To reduce the  * 
-  *  search, the following requirements must be met:         * 
-  *                                                          * 
-  *  (1) We must be in the REMAINING_MOVES part of the move  * 
-  *      ordering, so that we have nearly given up on        * 
-  *      failing high on any move.                           * 
-  *                                                          * 
-  *  (2) We must not be too close to the horizon (this is    * 
-  *      the LMR_remaining_depth value).                     * 
-  *                                                          * 
-  *  (3) The current move must not be a checking move and    * 
-  *      the side to move can not be in check.               * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-           if (Piece(tree->curmv[ply]) != pawn || 
-               !Passed(To(tree->curmv[ply]), side) 
-               || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { 
-             reduce = LMR_min_reduction; 
-             if (moves_searched > 3) 
-               reduce = LMR_max_reduction; 
-             max_reduce = Max(depth - 1 - LMR_remaining_depth, 0); 
-             if (reduce > max_reduce) 
-               reduce = max_reduce; 
-             if (reduce) 
-               tree->reductions_done++; 
-           } 
-         } 
- /*   
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7d.  We have determined whether the depth is to    * 
-  *  be changed by an extension or a reduction.  If we get   * 
-  *  to this point, then the move is not being pruned.  So   * 
-  *  off we go to a recursive search/quiescence call to work * 
-  *  our way toward a terminal node.                         * 
-  *                                                          * 
-  *  There is one special-case to handle.  If the depth was  * 
-  *  reduced, and Search() returns a value >= beta then      * 
-  *  accepting that is risky (we reduced the move as we      * 
-  *  thought it was bad and expected it to fail low) so we   * 
-  *  repeat the search using the original (non-reduced)      * 
-  *  depth to see if the fail-high happens again.            * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (depth + extend - reduce - 1 > 0) { 
-           value = 
-               -Search(tree, -t_beta, -alpha, Flip(side), 
-               depth + extend - reduce - 1, ply + 1, DO_NULL); 
-           if (value > alpha && reduce) 
-             value = 
-                 -Search(tree, -t_beta, -alpha, Flip(side), depth - 1, ply + 1, 
-                 DO_NULL); 
-         } else 
-           value = -Quiesce(tree, -t_beta, -alpha, Flip(side), ply + 1, 1); 
-         if (abort_search || tree->stop) 
-           break; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7e.  This is the PVS re-search code.  If we reach  * 
-  *  this point and value > alpha and value < beta, then     * 
-  *  this can not be a null-window search.  We have to re-   * 
-  *  search the position with the original beta value (not   * 
-  *  alpha+1 as is the usual case in PVS) to see if it still * 
-  *  fails high before we treat this as a real fail-high and * 
-  *  back up the value to the previous ply.                  * 
-  *                                                          * 
-  *  Special case:  ply == 1.                                * 
-  *                                                          * 
-  *  In this case, we need to clean up and then move the     * 
-  *  best move to the top of the root move list, and return  * 
-  *  back to Iterate() to let it produce the usual informa-  * 
-  *  tive output and re-start the search with a new beta     * 
-  *  value.  We also reset the failhi_delta back to 16,      * 
-  *  since an earlier fail-high or fail low in this          * 
-  *  iteration could have left it at a large value.          * 
-  *                                                          * 
-  *  Last step is to build a usable PV in case this move     * 
-  *  fails low on the re-search, because we do want to play  * 
-  *  this move no matter what happens.                       * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (value > alpha && value < beta && moves_searched > 1) { 
-           if (ply == 1) { 
-             alpha = value; 
-             UnmakeMove(tree, ply, tree->curmv[ply], side); 
-             root_beta = alpha; 
-             failhi_delta = 16; 
-             for (i = 0; i < n_root_moves; i++) 
-               if (tree->curmv[1] == root_moves[i].move) 
-                 break; 
-             if (i < n_root_moves) { 
-               temp_rm = root_moves[i]; 
-               for (; i > 0; i--) 
-                 root_moves[i] = root_moves[i - 1]; 
-               root_moves[0] = temp_rm; 
-             } 
-             root_moves[0].bm_age = 4; 
-             tree->pv[1].path[1] = tree->curmv[1]; 
-             tree->pv[1].pathl = 2; 
-             tree->pv[1].pathh = 0; 
-             tree->pv[1].pathd = iteration_depth; 
-             tree->pv[0] = tree->pv[1]; 
-             return alpha; 
-           } 
-           if (depth + extend - 1 > 0) 
-             value = 
-                 -Search(tree, -beta, -alpha, Flip(side), depth + extend - 1, 
-                 ply + 1, DO_NULL); 
-           else 
-             value = -Quiesce(tree, -beta, -alpha, Flip(side), ply + 1, 1); 
-           if (abort_search || tree->stop) 
-             break; 
-         } 
- /*   
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7f.  We have completed the search/re-search and we * 
-  *  we have the final score.  Now we need to check for a    * 
-  *  fail-high which terminates this search instantly since  * 
-  *  no further searching is required.  On a fail high, we   * 
-  *  need to update the killer moves, and hash table before  * 
-  *  we return.                                              * 
-  *                                                          * 
-  *  If ply == 1, we call Output() which will dump the new   * 
-  *  PV.  But but we need to back up the PV to ply=0 so that * 
-  *  it will be available to tell main() which move to make. * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (value > alpha) { 
-           alpha = value; 
-           if (ply == 1) { 
-             tree->pv[1].pathv = value; 
-             Output(tree, beta); 
-             tree->pv[0] = tree->pv[1]; 
-           } 
-           if (value >= beta) { 
-             Killer(tree, ply, tree->curmv[ply]); 
-             UnmakeMove(tree, ply, tree->curmv[ply], side); 
-             HashStore(tree, ply, depth, side, LOWER, value, tree->curmv[ply]); 
-             tree->fail_highs++; 
-             if (moves_searched == 1) 
-               tree->fail_high_first_move++; 
-             return value; 
-           } 
-         } 
-         t_beta = alpha + 1; 
-       } while (0); 
-     UnmakeMove(tree, ply, tree->curmv[ply], side); 
-     if (abort_search || tree->stop) 
-       return 0; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7g.  If are doing an SMP search, and we have idle  * 
-  *  processors, now is the time to get them involved.  We   * 
-  *  have now satisfied the "young brothers wait" condition  * 
-  *  since we have searched one move.  All that is left is   * 
-  *  to check the split constraints to see if we are an      * 
-  *  acceptable split point.                                 * 
-  *                                                          * 
-  *    (1) We can't split within N plies of the frontier     * 
-  *        nodes to avoid excessive split overhead.          * 
-  *                                                          * 
-  *    (2) We can't split until at least M nodes have been   * 
-  *        searched since this thread was last split, to     * 
-  *        avoid splitting too often, mainly in endgames.    * 
-  *                                                          * 
-  *    (3) We have to have searched one legal move to avoid  * 
-  *        splitting at a node where we have no legal moves  * 
-  *        (the first move tried might have been illegal as  * 
-  *        in when we encounter a stalemate).                * 
-  *                                                          * 
-  *    (4) If we are at ply=1, we can't split unless the     * 
-  *        smp_split_at_root flag is set to 1, AND the next  * 
-  *        move in the ply=1 move list is not flagged as     * 
-  *        "do not search in parallel" which happens when    * 
-  *        this move was a best move in the last couple of   * 
-  *        searches and we want all processors on it at once * 
-  *        to get a score back quicker.                      * 
-  *                                                          * 
-  *    (5) if the variable smp_split is > 0, we have idle    * 
-  *        threads that can help, however if smp_split < 0,  * 
-  *        we are already doing a split on another thread    * 
-  *        so there is no point in waiting to try one here.  * 
-  *                                                          * 
-  *  SearchParallel() primarily contains steps 7 through 7f  * 
-  *  which is the main search loop.  We do the final clean-  * 
-  *  up below when either we finish the search normally or   * 
-  *  a parallel search completes and returns to this point.  * 
-  *                                                          * 
-  *  Special case:  we do not split if we are at ply=1 and   * 
-  *  alpha == original_alpha.  That means the first move     * 
-  *  failed low, and we are going to exit search and return  * 
-  *  to Iterate() to report this.                            * 
-  *                                                          * 
-  *  One potential problem is that multiple threads can get  * 
-  *  to this point at the same time, and they all stack up   * 
-  *  waiting to grab the lock_smp lock that protects the     * 
-  *  split operation.  I now have a new lock, lock_split,    * 
-  *  to try to limit this wasted time.  A thread now has to  * 
-  *  acquire that lock, and then it tests the smp_split      * 
-  *  to see if a split STILL needs to be done.  If not, we   * 
-  *  release the lock and move on, rather than waiting on    * 
-  *  main lock_smp lock.                                     * 
-  *                                                          * 
-  *  If we acquire the lock_split lock AND we notice that    * 
-  *  smp_split is still set to 1, we quickly set smp_split   * 
-  *  to zero (-1) so that other threads will bug out rather  * 
-  *  than trying to split and end up in a queue behind us,   * 
-  *  waiting while we split and they try to split and fail.  * 
-  *  We release lock_split to eliminate the log-jam of       * 
-  *  threads waiting to split and get them back into their   * 
-  *  normal searches, and jump right into Thread().          * 
-  *                                                          * 
-  *  The smp_split = -1 has a complex meaning, but simply    * 
-  *  stated it means "split currently in progress".  Here,   * 
-  *  that means "do not attempt a split since we are already * 
-  *  in the middle of one."  It also tells individual        * 
-  *  threads to not change smp_split to 1 when they become   * 
-  *  idle, because with a split in progress, it is likely we * 
-  *  will pick them up automatically.                        * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
- #if (CPUS > 1) 
-     if (smp_split > 0 && depth >= smp_min_split_depth && moves_searched && 
-         tree->nodes_searched - start_nodes > smp_split_nodes && (ply > 1 || 
-             (smp_split_at_root && NextRootMoveParallel() && 
-                 alpha != original_alpha))) 
-       do { 
-         Lock(lock_split); 
-         if (smp_split <= 0) { 
-           Unlock(lock_split); 
-           break; 
-         } 
-         smp_split = -1; 
-         Unlock(lock_split); 
-         tree->alpha = alpha; 
-         tree->beta = beta; 
-         tree->value = alpha; 
-         tree->side = side; 
-         tree->ply = ply; 
-         tree->depth = depth; 
-         tree->moves_searched = moves_searched; 
-         if (Thread(tree)) { 
-           if (abort_search || tree->stop) 
-             return 0; 
-           if (tree->thread_id == 0 && CheckInput()) 
-             Interrupt(ply); 
-           value = tree->value; 
-           if (value > alpha) { 
-             if (value >= beta) { 
-               HashStore(tree, ply, depth, side, LOWER, value, tree->cutmove); 
-               return value; 
-             } 
-             alpha = value; 
-             break; 
-           } 
-         } 
-       } while (0); 
- #endif 
-   } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 8.  All moves have been searched.  If none were    * 
-  *  legal, return either MATE or DRAW depending on whether  * 
-  *  the side to move is in check or not.                    * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   if (abort_search || tree->stop) 
-     return 0; 
-   if (moves_searched == 0) { 
-     value = (Check(side)) ? -(MATE - ply) : DrawScore(side); 
-     if (value >= alpha && value < beta) { 
-       SavePV(tree, ply, 0); 
- #if defined(TRACE) 
-       if (ply <= trace_level) 
-         printf("Search() no moves!  ply=%d\n",-  ply );
 
- #endif 
-     } 
-     return value; 
-   } else { 
-     int bestmove, type; 
-     bestmove = 
-         (alpha == original_alpha) ? first_tried : tree->pv[ply].path[ply]; 
-     type = (alpha == original_alpha) ? UPPER : EXACT; 
-     if (repeat == 2 && alpha != -(MATE - ply - 1)) { 
-       value = DrawScore(side); 
-       if (value < beta) 
-         SavePV(tree, ply, 0); 
- #if defined(TRACE) 
-       if (ply <= trace_level) 
-         printf("draw by 50 move rule detected, ply=%d.\n",-  ply );
 
- #endif 
-       return value; 
-     } else if (alpha != original_alpha) { 
-       tree->pv[ply - 1] = tree->pv[ply]; 
-       tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1]; 
-       Killer(tree, ply, tree->pv[ply].path[ply]); 
-     } 
-     HashStore(tree, ply, depth, side, type, alpha, bestmove); 
-     return alpha; 
-   } 
- } 
-   
- /* last modified 05/08/14 */ 
- /* 
-  ******************************************************************************* 
-  *                                                                             * 
-  *   SearchParallel() is the recursive routine used to implement alpha/beta    * 
-  *   negamax search using parallel threads.  When this code is called, the     * 
-  *   first move has already been searched, so all that is left is to search    * 
-  *   the remainder of the moves and then return.  Note that the hash table and * 
-  *   such can't be modified here since this only represents a part of the      * 
-  *   search at this ply.  All of that is deferred until we return and reach    * 
-  *   the original instance of Search() where we have the complete results from * 
-  *   all the threads that are helping here.                                    * 
-  *                                                                             * 
-  ******************************************************************************* 
-  */ 
- int SearchParallel(TREE * RESTRICT tree, int alpha, int beta, int value, 
-     int side, int depth, int ply) { 
-   ROOT_MOVE temp_rm; 
-   int extend, reduce, max_reduce, i; 
-   
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7.  Now we continue to iterate through the move    * 
-  *  list and search the resulting positions.  Note that     * 
-  *  SearchParallel() culls any move that is not legal by    * 
-  *  using Check().  The special case mentioned in Search()  * 
-  *  is not an issue here as we don't do a parallel split    * 
-  *  until we have searched one legal move.                  * 
-  *                                                          * 
-  *  We have three possible procedures we call here, one is  * 
-  *  specific to ply=1 (NextRootMove()), the second is a     * 
-  *  specific routine to escape check (NextEvasion()) and    * 
-  *  the last is the normal NextMove() procedure that does   * 
-  *  the usual move ordering stuff.                          * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   
-   while (1) { 
-     Lock(tree->parent->lock); 
-     if (ply > 1) 
-       tree->phase[ply] = 
-           (tree->inchk[ply]) ? NextEvasion((TREE *) tree->parent, ply, 
-           side) : NextMove((TREE *) 
-           tree->parent, ply, side); 
-     else 
-       tree->phase[ply] = NextRootMove(tree->parent, tree, side); 
-     tree->curmv[ply] = tree->parent->curmv[ply]; 
-     Unlock(tree->parent->lock); 
-     if (!tree->phase[ply]) 
-       break; 
- #if defined(TRACE) 
-     if (ply <= trace_level) 
-       Trace(tree, ply, depth, side, alpha, beta, "SearchParallel", 
-           tree->phase[ply]); 
- #endif 
-     MakeMove(tree, ply, tree->curmv[ply], side); 
-     tree->nodes_searched++; 
-     if (tree->inchk[ply] || !Check(side)) 
-       do { 
-         tree->parent->moves_searched++; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7a.  If the move to be made checks the opponent,   * 
-  *  then we need to remember that he's in check and also    * 
-  *  extend the depth by one ply for him to get out.  Note   * 
-  *  that if the move gives check, it is not a candidate for * 
-  *  either depth reduction or forward-pruning.              * 
-  *                                                          * 
-  *  We do not extend unsafe checking moves (as indicated by * 
-  *  Swap(), a SEE algorithm, since these are usually a      * 
-  *  waste of time and simply blow up the tree search space. * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         extend = 0; 
-         reduce = 0; 
-         if (Check(Flip(side))) { 
-           tree->inchk[ply + 1] = 1; 
-           if (SwapO(tree, tree->curmv[ply], side) <= 0) { 
-             extend = check_depth; 
-             tree->extensions_done++; 
-           } 
-         } else 
-           tree->inchk[ply + 1] = 0; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7b.  Now for the forward-pruning stuff.  The idea  * 
-  *  here is based on the old FUTILITY idea, where if the    * 
-  *  current material + a fudge factor is lower than alpha,  * 
-  *  then there is little promise in searching this move to  * 
-  *  make up for the material deficit.  This is not done if  * 
-  *  we chose to extend this move in the previous step.      * 
-  *                                                          * 
-  *  This is a useful idea in today's 20+ ply searches, as   * 
-  *  when we near the tips, if we are too far behind in      * 
-  *  material, there is little time left to recover it and   * 
-  *  moves that don't bring us closer to a reasonable        * 
-  *  material balance can safely be skipped.  It is much     * 
-  *  more dangerous in shallow searches.                     * 
-  *                                                          * 
-  *  We have an array of pruning margin values that are      * 
-  *  indexed by depth (remaining plies left until we drop    * 
-  *  into the quiescence search) and which increase with     * 
-  *  depth since more depth means a greater chance of        * 
-  *  bringing the score back up to alpha or beyond.  If the  * 
-  *  current material + the bonus is less than alpha, we     * 
-  *  simply avoid searching this move at all, and skip to    * 
-  *  the next move without expending any more effort.  Note  * 
-  *  that this is classic forward-pruning and can certainly  * 
-  *  introduce errors into the search.  However, cluster     * 
-  *  testing has shown that this improves play in real       * 
-  *  games.  The current implementation only prunes in the   * 
-  *  last 5 plies before quiescence, although this can be    * 
-  *  tuned with the "eval" command changing the "pruning     * 
-  *  depth" value to something other than 6 (test is for     * 
-  *  depth < pruning depth, current value is 6 which prunes  * 
-  *  in last 5 plies only).  Testing shows no benefit in     * 
-  *  larger values than 6, although this might change in     * 
-  *  future versions as other things are modified.           * 
-  *                                                          * 
-  *  Exception:                                              * 
-  *                                                          * 
-  *    We do not prune if we are safely pushing a passed     * 
-  *    pawn to the 6th rank, where it becomes very dangerous * 
-  *    since it can promote in two more moves.               * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (tree->phase[ply] == REMAINING_MOVES && !tree->inchk[ply] 
-             && !extend && tree->parent->moves_searched > 1) { 
-           if (depth < pruning_depth && 
-               MaterialSTM(side) + pruning_margin[depth] <= alpha) { 
-             if (Piece(tree->curmv[ply]) != pawn || 
-                 !Passed(To(tree->curmv[ply]), side) 
-                 || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { 
-               tree->moves_fpruned++; 
-               continue; 
-             } 
-           } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7c.  Now it's time to try to reduce the search     * 
-  *  depth if the move appears to be "poor".  To reduce the  * 
-  *  search, the following requirements must be met:         * 
-  *                                                          * 
-  *  (1) We must be in the REMAINING_MOVES part of the move  * 
-  *      ordering, so that we have nearly given up on        * 
-  *      failing high on any move.                           * 
-  *                                                          * 
-  *  (2) We must not be too close to the horizon (this is    * 
-  *      the LMR_remaining_depth value).                     * 
-  *                                                          * 
-  *  (3) The current move must not be a checking move and    * 
-  *      the side to move can not be in check.               * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-           if (Piece(tree->curmv[ply]) != pawn || 
-               !Passed(To(tree->curmv[ply]), side) 
-               || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { 
-             reduce = LMR_min_reduction; 
-             if (tree->parent->moves_searched > 3) 
-               reduce = LMR_max_reduction; 
-             max_reduce = Max(depth - 1 - LMR_remaining_depth, 0); 
-             if (reduce > max_reduce) 
-               reduce = max_reduce; 
-             if (reduce) 
-               tree->reductions_done++; 
-           } 
-         } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7d.  We have determined whether the depth is to    * 
-  *  be changed by an extension or a reduction.  If we get   * 
-  *  to this point, then the move is not being pruned.  So   * 
-  *  off we go to a recursive search/quiescence call to work * 
-  *  our way toward a terminal node.                         * 
-  *                                                          * 
-  *  There is one special-cases to handle.  If the depth was * 
-  *  reduced, and Search() returns a value >= beta then      * 
-  *  accepting that is risky (we reduced the move as we      * 
-  *  thought it was bad and expected it to fail low) so we   * 
-  *  repeat the search using the original (non-reduced)      * 
-  *  depth to see if the fail-high happens again.            * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (depth + extend - reduce - 1 > 0) { 
-           value = 
-               -Search(tree, -alpha - 1, -alpha, Flip(side), 
-               depth + extend - reduce - 1, ply + 1, DO_NULL); 
-           if (value > alpha && reduce) 
-             value = 
-                 -Search(tree, -alpha - 1, -alpha, Flip(side), depth - 1, 
-                 ply + 1, DO_NULL); 
-         } else 
-           value = -Quiesce(tree, -alpha - 1, -alpha, Flip(side), ply + 1, 1); 
-         if (abort_search || tree->stop) 
-           break; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7e.  This is the PVS re-search code.  If we reach  * 
-  *  this point and value > alpha and value < beta, then     * 
-  *  this can not be a null-window search.  We have to re-   * 
-  *  search the position with the original beta value (not   * 
-  *  alpha+1 as is the usual case in PVS) to see if it still * 
-  *  fails high before we treat this as a real fail-high and * 
-  *  back up the value to the previous ply.                  * 
-  *                                                          * 
-  *  Special case:  ply == 1.                                * 
-  *                                                          * 
-  *  In this case, we need to clean up and then move the     * 
-  *  best move to the top of the root move list, and then    * 
-  *  return back to the normal Search(), which will then     * 
-  *  return back to Iterate() to let it produce the usual    * 
-  *  informative output and re-start the search with a new   * 
-  *  beta value.  We also reset the failhi_delta back to 16, * 
-  *  since an earlier fail-high or fail low in this          * 
-  *  iteration could have left it at a large value.          * 
-  *                                                          * 
-  *  Last step is to build a usable PV in case this move     * 
-  *  fails low on the re-search, because we do want to play  * 
-  *  this move no matter what happens.                       * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (value > alpha && value < beta) { 
-           if (ply == 1) { 
-             int proc; 
-   
-             alpha = value; 
-             parallel_aborts++; 
-             UnmakeMove(tree, ply, tree->curmv[ply], side); 
-             Lock(lock_smp); 
-             Lock(tree->parent->lock); 
-             if (!tree->stop) { 
-               for (proc = 0; proc < smp_max_threads; proc++) 
-                 if (tree->parent->siblings[proc] && proc != tree->thread_id) 
-                   ThreadStop(tree->parent->siblings[proc]); 
-               root_beta = alpha; 
-               failhi_delta = 16; 
-               Lock(lock_root); 
-               for (i = 0; i < n_root_moves; i++) 
-                 if (tree->curmv[1] == root_moves[i].move) 
-                   break; 
-               if (i < n_root_moves) { 
-                 temp_rm = root_moves[i]; 
-                 for (; i > 0; i--) 
-                   root_moves[i] = root_moves[i - 1]; 
-                 root_moves[0] = temp_rm; 
-               } 
-               root_moves[0].bm_age = 4; 
-               Unlock(lock_root); 
-               tree->pv[1].path[1] = tree->curmv[1]; 
-               tree->pv[1].pathl = 2; 
-               tree->pv[1].pathh = 0; 
-               tree->pv[1].pathd = iteration_depth; 
-               tree->pv[0] = tree->pv[1]; 
-             } 
-             Unlock(tree->parent->lock); 
-             Unlock(lock_smp); 
-             return alpha; 
-           } 
-           if (depth + extend - 1 > 0) 
-             value = 
-                 -Search(tree, -beta, -alpha, Flip(side), depth + extend - 1, 
-                 ply + 1, DO_NULL); 
-           else 
-             value = -Quiesce(tree, -beta, -alpha, Flip(side), ply + 1, 1); 
-           if (abort_search || tree->stop) 
-             break; 
-         } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 7f.  We have completed the search/re-search and we * 
-  *  we have the final score.  Now we need to check for a    * 
-  *  fail-high which terminates this search instantly since  * 
-  *  no further searching is required.  On a fail high, we   * 
-  *  need to update the killer moves, and hash table before  * 
-  *  we return.                                              * 
-  *                                                          * 
-  *  Note that we can not produce a new PV here.  At best,   * 
-  *  we can produce a fail-high which will abort other       * 
-  *  threads at this node (wasting time).                    * 
-  *                                                          * 
-  *  Special case:  If ply == 1, and we fail high on the     * 
-  *  null-window search, we simply abort the search and then * 
-  *  return to the normal search, which will back us out to  * 
-  *  Iterate() and inform the user and re-start the search.  * 
-  *                                                          * 
-  *  We then stop all threads (except the current thread     * 
-  *  that is dealing with the fail high) since we are going  * 
-  *  to back out quickly and then start a new search from    * 
-  *  the root position.  The split-block sibling ids lets us * 
-  *  know which threads should be stopped, and since we are  * 
-  *  at the root (ply == 1) that essentially means "all      * 
-  *  threads except for this one."                           * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (value > alpha) { 
-           alpha = value; 
-           if (value >= beta) { 
-             int proc; 
-   
-             parallel_aborts++; 
-             UnmakeMove(tree, ply, tree->curmv[ply], side); 
-             Lock(lock_smp); 
-             Lock(tree->parent->lock); 
-             if (!tree->stop) 
-               for (proc = 0; proc < smp_max_threads; proc++) 
-                 if (tree->parent->siblings[proc] && proc != tree->thread_id) 
-                   ThreadStop(tree->parent->siblings[proc]); 
-             Unlock(tree->parent->lock); 
-             Unlock(lock_smp); 
-             return alpha; 
-           } 
-         } 
-       } while (0); 
-     UnmakeMove(tree, ply, tree->curmv[ply], side); 
-     if (abort_search || tree->stop) 
-       break; 
-   } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Step 8.  We are doing an SMP search, so there are no    * 
-  *  "end-of-search" things to do.  We have searched all the * 
-  *  remaining moves at this ply in parallel, and now return * 
-  *  and let the original search that started this sub-tree) * 
-  *  clean up, and do the tests for mate/stalemate, update   * 
-  *  the hash table, etc.                                    * 
-  *                                                          * 
-  *  As we return, we end back up in Thread() where we       * 
-  *  started, which then copies the best score/etc back to   * 
-  *  the parent thread.                                      * 
-  *                                                          * 
-  *  We do need to flag the root move we tried to search, if * 
-  *  we were stopped early due to another root move failing  * 
-  *  high.  Otherwise this move appears to have been         * 
-  *  searched already and will not be searched again until   * 
-  *  the next iteration.                                     * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   if (tree->stop && ply == 1) { 
-     int which; 
-   
-     Lock(lock_root); 
-     for (which = 0; which < n_root_moves; which++) 
-       if (root_moves[which].move == tree->curmv[ply]) { 
-         root_moves[which].status &= 0xf7; 
-         break; 
-       } 
-     Unlock(lock_root); 
-   } 
-   return alpha; 
- } 
-