- #include "chess.h" 
- #include "data.h" 
- #if defined(SYZYGY) 
- #  include "tbprobe.h" 
- #endif 
- /* last modified 08/03/16 */ 
- /* 
-  ******************************************************************************* 
-  *                                                                             * 
-  *   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 ply, int depth, int wtm, int alpha, 
-     int beta, int in_check, int do_null) { 
-   int repeat = 0, value = 0, pv_node = alpha != beta - 1, n_depth; 
-   int searched[256]; 
-   
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Timeout.  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 (search_nodes && --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; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Draws.  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 four steps are skipped for moves at the    * 
-  *  root (ply = 1).                                         * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   if (ply > 1) { 
-     if ((repeat = Repeat(tree, ply))) { 
-       if (repeat == 2 || !in_check) { 
-         value = DrawScore(wtm); 
-         if (value < beta) 
-           SavePV(tree, ply, repeat); 
- #if defined(TRACE) 
-         if (ply <= trace_level) 
-           printf("draw by %s detected, ply=%d.\n", 
-               (repeat == 3) ? "50-move" : "repetition", ply); 
- #endif 
-         return value; 
-       } 
-     } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Mate distance pruning.  If we have found a mate, we can * 
-  *  stop if we are too deep to find a shorter mate.  This   * 
-  *  only affects the size of the tree in positions where    * 
-  *  there are forced mates.  It does not change the outcome * 
-  *  of the search at all, just the time it takes.           * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-     alpha = Max(alpha, -MATE + ply - 1); 
-     beta = Min(beta, MATE - ply); 
-     if (alpha >= beta) 
-       return alpha; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Trans/Ref.  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 ProbeTransRef() 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, wtm, alpha, beta, &value)) { 
-       case HASH_HIT: 
-         return value; 
-       case AVOID_NULL_MOVE: 
-         do_null = 0; 
-       case HASH_MISS: 
-         break; 
-     } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  EGTBs.  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 AND the 50 move * 
-  *  counter is zero which enables probing the WDL EGTBs     * 
-  *  correctly.  Probing after a capture won't work as it is * 
-  *  possible that there is a necessary pawn push here and   * 
-  *  there to reset the 50 move counter, otherwise we could  * 
-  *  think we were following a winning path but heading to 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.  The scores are -0.03 for a "blessed   * 
-  *  loss", 0.0 for a pure draw, and +0.03 for a "cursed     * 
-  *  win".  These are then modified by adding 0.01 if the    * 
-  *  side on move is ahead in material, and subtracting 0.01 * 
-  *  if the side on move is behind material.  This creates   * 
-  *  the following inequality:                               * 
-  *                                                          * 
-  *     BL- < BL= < BL+ < D- < D= < D+ < CW- < CW= <CW+      * 
-  *                                                          * 
-  *  Where BL=blessed loss, D = draw, and CW = cursed win,   * 
-  *  and - means behind in material, = means equal material, * 
-  *  and + means ahead in material.                          * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
- #if defined(SYZYGY) 
-     if (depth > EGTB_depth && TotalAllPieces <= EGTB_use && 
-         !Castle(ply, white) && !Castle(ply, black) && Reversible(ply) == 0) { 
-       int tb_result; 
-   
-       tree->egtb_probes++; 
-       tb_result = 
-           tb_probe_wdl(Occupied(white), Occupied(black), 
-           Kings(white) | Kings(black), Queens(white) | Queens(black), 
-           Rooks(white) | Rooks(black), Bishops(white) | Bishops(black), 
-           Knights(white) | Knights(black), Pawns(white) | Pawns(black), 
-           Reversible(ply), 0, EnPassant(ply), wtm, HashKey); 
-       if (tb_result != TB_RESULT_FAILED) { 
-         tree->egtb_hits++; 
-         switch (tb_result) { 
-           case TB_LOSS: 
-             alpha = -TBWIN; 
-             break; 
-           case TB_BLESSED_LOSS: 
-             alpha = -3; 
-             break; 
-           case TB_DRAW: 
-             alpha = 0; 
-             break; 
-           case TB_CURSED_WIN: 
-             alpha = 3; 
-             break; 
-           case TB_WIN: 
-             alpha = TBWIN; 
-             break; 
-         } 
-         if (tb_result != TB_LOSS && tb_result != TB_WIN) { 
-           if (MaterialSTM(wtm) > 0) 
-             alpha += 1; 
-           else if (MaterialSTM(wtm) < 0) 
-             alpha -= 1; 
-         } 
-         if (alpha < beta) 
-           SavePV(tree, ply, 4); 
-         return alpha; 
-       } 
-     } 
- #endif 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Null-move.  We now know there is no quick way to get    * 
-  *  out of here, which leaves one more possibility,         * 
-  *  although it does require a 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 (see       * 
-  *  below).  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.                 * 
-  *                                                          * 
-  *  The reduction amount starts off at null_depth (normally * 
-  *  set to 3 but the user can change this via the crafty    * 
-  *  personality command) but is then increased as follows:  * 
-  *                                                          * 
-  *     R = null_depth + depth / null_divisor                * 
-  *                                                          * 
-  *  null_divisor defaults to 6, but this can also be set    * 
-  *  by the user to try more/less aggressive settings.       * 
-  *                                                          * 
-  *  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 2x 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->last[ply] = tree->last[ply - 1]; 
-     n_depth = (TotalPieces(wtm, occupied) > 9 || n_root_moves > 17 || 
-         depth > 3) ? 1 : 3; 
-     if (do_null && !pv_node && depth > n_depth && !in_check && 
-         TotalPieces(wtm, occupied)) { 
-       uint64_t save_hash_key; 
-       int R = null_depth + depth / null_divisor; 
-   
-       tree->curmv[ply] = 0; 
- #if defined(TRACE) 
-       if (ply <= trace_level) 
-         Trace(tree, ply, depth, wtm, value - 1, value, "SearchNull", serial, 
-             NULL_MOVE, 0); 
- #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; 
-       } 
-       tree->null_done[Min(R, 15)]++; 
-       if (depth - R - 1 > 0) 
-         value = 
-             -Search(tree, ply + 1, depth - R - 1, Flip(wtm), -beta, -beta + 1, 
-             0, NO_NULL); 
-       else 
-         value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -beta + 1, 1); 
-       HashKey = save_hash_key; 
-       if (abort_search || tree->stop) 
-         return 0; 
-       if (value >= beta) { 
-         HashStore(tree, ply, depth, wtm, LOWER, value, tree->hash_move[ply]); 
-         return value; 
-       } 
-     } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  IID.  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; 
-     if (!tree->hash_move[ply] && depth >= 6 && do_null && ply > 1 && pv_node) { 
-       tree->curmv[ply] = 0; 
-       if (depth - 2 > 0) 
-         value = 
-             Search(tree, ply, depth - 2, wtm, alpha, beta, in_check, DO_NULL); 
-       else 
-         value = Quiesce(tree, ply, wtm, alpha, beta, 1); 
-       if (abort_search || tree->stop) 
-         return 0; 
-       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; 
-       } 
-     } 
-   } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Search moves.  Now we call SearchMoveList() to interate * 
-  *  through the move list and search each new position.     * 
-  *  Note that this is done in a separate procedure because  * 
-  *  this is also the code that is used to do the parallel   * 
-  *  search.                                                 * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   searched[0] = 0; 
-   value = 
-       SearchMoveList(tree, ply, depth, wtm, alpha, beta, searched, in_check, 
-       repeat, serial); 
-   return value; 
- } 
-   
- /* last modified 08/03/16 */ 
- /* 
-  ******************************************************************************* 
-  *                                                                             * 
-  *   SearchMoveList() is the recursive routine used to implement the main      * 
-  *   search loop.  This code is responsible for iterating through the move     * 
-  *   list until it encounters a condition that ends the search at this ply.    * 
-  *   At that point it simply returns the current negamax value to the caller   * 
-  *   to handle as necessary.                                                   * 
-  *                                                                             * 
-  *   The "mode" flag indicates which of the following conditions apply here    * 
-  *   which directly controls parts of the search.                              * 
-  *                                                                             * 
-  *      mode = serial   ->  this is a serial search.                           * 
-  *                                                                             * 
-  *      mode = parallel ->  this is a parallel search, which implies that this * 
-  *                          is a partial search which means we do NOT want to  * 
-  *                          do any trans/ref updating and we also need to take * 
-  *                          care about locking things that are being updated   * 
-  *                          by more than one thread in parallel.               * 
-  *                                                                             * 
-  *   When mode = parallel, this code performs the same function as the old     * 
-  *   SearchParallel() code, except that it is the main search loop for the     * 
-  *   program, there is no longer any duplicated code.  This is called by the   * 
-  *   normal Search() function and by ThreadWait() where idle processes wait    * 
-  *   for work and then call this procedure to search a subset of the moves at  * 
-  *   this ply (in parallel with other threads).                                * 
-  *                                                                             * 
-  ******************************************************************************* 
-  */ 
- int SearchMoveList(TREE * RESTRICT tree, int ply, int depth, int wtm, 
-     int alpha, int beta, int searched[], int in_check, int repeat, int mode) { 
-   TREE *current; 
-   int extend, reduce, check, original_alpha = alpha, t_beta; 
-   int i, j, value = 0, pv_node = alpha != beta - 1, search_result, order; 
-   int moves_done = 0, bestmove, type; 
-   
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Basic initialization before we begin the loop through   * 
-  *  the move list.  If this is a parallel search, we have   * 
-  *  already searched one move, so we set t_beta to alpha+1  * 
-  *  to set up for a normal PVS search (for moves 2-n)       * 
-  *  instead of using alpha,beta for the first move as we do * 
-  *  in a normal search.  Also, if this is a serial search,  * 
-  *  we are fixing to search the first move so we set the    * 
-  *  searched move counter to zero, where in a parallel      * 
-  *  search this has already been done and we leave it alone * 
-  *  here.                                                   * 
-  *                                                          * 
-  *  We also set <current> to tree for a serial search, and  * 
-  *  to tree->parent for a parallel search since we need to  * 
-  *  share the move list at split nodes.                     * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   tree->next_status[ply].phase = HASH; 
-   if (mode == parallel) { 
-     current = tree->parent; 
-     t_beta = alpha + 1; 
-   } else { 
-     current = tree; 
-     t_beta = beta; 
-   } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Iterate.  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 call NextMove() which will generate moves in the     * 
-  *  normal way (captures, killers, etc) or it will use the  * 
-  *  GenerateEvasions() generator if we are in check.  For   * 
-  *  the special case of ply=1, we use NextRootMove() since  * 
-  *  the ply=1 move list has been generated and the order is * 
-  *  updated as each search iteration is executed.           * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   while (1) { 
-     if (ply == 1 && moves_done == 1 && alpha == original_alpha && 
-         mode == serial) 
-       break; 
-     if (mode == parallel) 
-       Lock(current->lock); 
-     order = (ply > 1) ? NextMove(current, ply, depth, wtm, in_check) 
-         : NextRootMove(current, tree, wtm); 
-     if (mode == parallel) { 
-       tree->curmv[ply] = current->curmv[ply]; 
-       Unlock(current->lock); 
-     } 
-     if (!order) 
-       break; 
- #if defined(TRACE) 
-     if (ply <= trace_level) 
-       Trace(tree, ply, depth, wtm, alpha, beta, "SearchMoveList", mode, 
-           current->phase[ply], order); 
- #endif 
-     MakeMove(tree, ply, wtm, tree->curmv[ply]); 
-     tree->nodes_searched++; 
-     search_result = ILLEGAL; 
-     if (in_check || !Check(wtm)) 
-       do { 
-         searched[0]++; 
-         moves_done++; 
-         search_result = LEGAL; 
-         searched[searched[0]] = tree->curmv[ply]; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Check.  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.         * 
-  *                                                          * 
-  *  We do not extend unsafe checking moves (as indicated by * 
-  *  the SEE algorithm), since these are usually a waste of  * 
-  *  time and simply blow up the tree search space.          * 
-  *                                                          * 
-  *  Note that extending here disables any potential foward  * 
-  *  pruning or reductions for this move.                    * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         extend = 0; 
-         reduce = 0; 
-         if (Check(Flip(wtm))) { 
-           check = 1; 
-           if (SEEO(tree, wtm, 
-                   tree->curmv[ply]) - pcval[Captured(tree->curmv[ply])] <= 
-               0) { 
-             extend = check_depth; 
-             tree->extensions_done++; 
-           } 
-         } else 
-           check = 0; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Futility.  First attempt at forward pruning based on    * 
-  *  the futility idea.                                      * 
-  *                                                          * 
-  *  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 6 plies before quiescence, although this can be    * 
-  *  tuned with the "eval" command changing the "pruning     * 
-  *  depth" value to something other than 7 (test is for     * 
-  *  depth < pruning depth, current value is 7 which prunes  * 
-  *  in last 6 plies only).  Testing shows no benefit in     * 
-  *  larger values than 7, 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.               * 
-  *                                                          * 
-  *  All pruning and reduction code is skipped if any of the * 
-  *  following are true:                                     * 
-  *                                                          * 
-  *  (1) side on move is in check.                           * 
-  *                                                          * 
-  *  (2) move has not already been flagged for a search      * 
-  *      extension.                                          * 
-  *                                                          * 
-  *  (3) this is not the first move at this ply.             * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-         if (!in_check && (!extend || !pv_node) && order > 1 && 
-             !(PawnPush(wtm, tree->curmv[ply]))) { 
-           if (depth < FP_depth && !check && 
-               MaterialSTM(wtm) + FP_margin[depth] <= alpha && !pv_node) { 
-             tree->moves_fpruned++; 
-             break; 
-           } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  LMP.  Final attempt at forward pruning based on the     * 
-  *  "late move pruning" idea (a take-off on LMR).           * 
-  *                                                          * 
-  *  The basic idea here is that once we have searched a     * 
-  *  significant number of moves at a ply, it becomes less   * 
-  *  and less likely that any of the moves left will produce * 
-  *  a cutoff.  If the move appears to be simple (not a      * 
-  *  check, etc) then we simply skip it, once the move count * 
-  *  has been satisfied.  At present, we only do this in the * 
-  *  last 16 plies although this might be changed in the     * 
-  *  future.  If you look at the LMP array after it has been * 
-  *  initialized, you will notice that it is unlikely that   * 
-  *  LMP can be triggered much beyond depth 8 as you have to * 
-  *  have a BUNCH of moves to search to reach those limits.  * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-           if (order > LMP[depth] && depth < LMP_depth && !pv_node && !check && 
-               alpha > -MATE + 300 && !CaptureOrPromote(tree->curmv[ply])) { 
-             tree->moves_mpruned++; 
-             break; 
-           } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  LMR.  Now it's time to try to reduce the search depth   * 
-  *  if the move appears to be "poor" because it appears     * 
-  *  later in the move list.                                 * 
-  *                                                          * 
-  *  The reduction is variable and is done via a table look- * 
-  *  up that uses a function based on remaining depth (more  * 
-  *  depth remaining, the larger the reduction) and the      * 
-  *  number of moves searched (more moves searched, the      * 
-  *  larger the reduction).  The "shape" of this reduction   * 
-  *  formula is user-settable via the "lmr" command.         * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-           reduce = LMR[Min(depth, 31)][Min(order, 63)]; 
-           if (reduce && (pv_node || extend)) 
-             reduce--; 
-           tree->LMR_done[reduce]++; 
-         } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Now do the PVS search on the current move.              * 
-  *                                                          * 
-  *  Note that we do the usual alpha/beta cutoff tests here  * 
-  *  but we only set an indicator that is used after we have * 
-  *  called Unmake().  This cleaned up the exit from search  * 
-  *  and makes it easier to understand when there is only    * 
-  *  one point where this is done, without needing multiple  * 
-  *  Unmake() calls when there are different exit points.    * 
-  *                                                          * 
-  ************************************************************** 
-  */ 
-         value = 
-             SearchMove(tree, ply, depth, wtm, alpha, t_beta, beta, extend, 
-             reduce, check); 
-         if (value > alpha) { 
-           search_result = IN_WINDOW; 
-           if (value >= beta) 
-             search_result = FAIL_HIGH; 
-           if (mode == parallel && ply == 1) 
-             search_result = FAIL_HIGH; 
-         } 
-       } while (0); 
-     UnmakeMove(tree, ply, wtm, tree->curmv[ply]); 
-     if (abort_search || tree->stop) 
-       break; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Test 1.  When we get here, we have made a move,         * 
-  *  searched it (and re-searched if necessary/appropriate), * 
-  *  and the move has been unmade so that the board is in a  * 
-  *  correct state.                                          * 
-  *                                                          * 
-  *  If search_result = FAIL_HIGH, the search failed high.   * 
-  *  The first thing to handle is the case where we are at   * 
-  *  ply=1, which is a special case.  If we are going to     * 
-  *  fail high here and terminate the search immediately, we * 
-  *  need to build the fail-high PV to back up to Iterate()  * 
-  *  so it will produce the correct output and widen the     * 
-  *  alpha/beta window.                                      * 
-  *                                                          * 
-  *  We then check to see if this is a parallel search.  If  * 
-  *  so then we are done here, but we need to tell all of    * 
-  *  the siblings that are helping at this split point that  * 
-  *  they should immediately stop searching here since we    * 
-  *  don't need their results.                               * 
-  *                                                          * 
-  *  Otherwise we update the killer moves and history        * 
-  *  counters and store the fail-high information in the     * 
-  *  trans/ref table for future use if we happen to reach    * 
-  *  this position again.                                    * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-     if (search_result == FAIL_HIGH) { 
-       if (ply == 1) { 
-         if (!tree->stop) { 
-           tree->pv[1].path[1] = tree->curmv[1]; 
-           tree->pv[1].pathl = 2; 
-           tree->pv[1].pathh = 0; 
-           tree->pv[1].pathd = iteration; 
-           tree->pv[0] = tree->pv[1]; 
-         } 
-       } 
- #if (CPUS > 1) 
-       if (mode == parallel) { 
-         Lock(lock_smp); 
-         Lock(tree->parent->lock); 
-         if (!tree->stop) { 
-           int proc; 
-   
-           parallel_aborts++; 
-           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 beta; 
-       } 
- #endif 
-       tree->fail_highs++; 
-       if (order == 1) 
-         tree->fail_high_first_move++; 
-       HashStore(tree, ply, depth, wtm, LOWER, value, tree->curmv[ply]); 
-       History(tree, ply, depth, wtm, tree->curmv[ply], searched); 
-       return beta; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Test 2.  If search_result = IN_WINDOW, this is a search * 
-  *  that improved alpha without failing high.  We simply    * 
-  *  update alpha and continue searching moves.              * 
-  *                                                          * 
-  *  Special case:  If ply = 1 in a normal search, we have   * 
-  *  a best move and score that just changed.  We need to    * 
-  *  update the root move list by adding the PV and the      * 
-  *  score, and then we look to make sure this new "best     * 
-  *  move" is not actually worse than the best we have found * 
-  *  so far this iteration.  If it is worse, we restore the  * 
-  *  best move and score from the real best move so our      * 
-  *  search window won't be out of whack, which would let    * 
-  *  moves with scores in between this bad move and the best * 
-  *  move fail high, cause re-searches, and waste time.  We  * 
-  *  also need to restore the root move list so that the     * 
-  *  best move (the one we just used to replace the move     * 
-  *  with a worse score) is first so it is searched first on * 
-  *  the next iteration.                                     * 
-  *                                                          * 
-  *  If this is ply = 1, we display the PV to keep the user  * 
-  *  informed.                                               * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-     } else if (search_result == IN_WINDOW) { 
-       alpha = value; 
-       if (ply == 1 && mode == serial) { 
-         int best; 
-   
-        // 
-        // update path/score for this move 
-        // 
-         tree->pv[1].pathv = value; 
-         tree->pv[0] = tree->pv[1]; 
-         for (best = 0; best < n_root_moves; best++) 
-           if (root_moves[best].move == tree->pv[1].path[1]) { 
-             root_moves[best].path = tree->pv[1]; 
-             root_moves[best].path.pathv = alpha; 
-             break; 
-           } 
-        // 
-        // if this move is not #1 in root list, move it there 
-        // 
-         if (best != 0) { 
-           ROOT_MOVE t; 
-           t = root_moves[best]; 
-           for (i = best; i > 0; i--) 
-             root_moves[i] = root_moves[i - 1]; 
-           root_moves[0] = t; 
-         } 
-        // 
-        // if a better score has already been found then move that 
-        // move to the front of the list and update alpha bound. 
-        // 
-         for (i = 0; i < n_root_moves; i++) { 
-           if (value <= root_moves[i].path.pathv) { 
-             ROOT_MOVE t; 
-             value = root_moves[i].path.pathv; 
-             alpha = value; 
-             tree->pv[0] = root_moves[i].path; 
-             tree->pv[1] = tree->pv[0]; 
-             t = root_moves[i]; 
-             for (j = i; j > 0; j--) 
-               root_moves[j] = root_moves[j - 1]; 
-             root_moves[0] = t; 
-           } 
-         } 
-         Output(tree); 
-         failhi_delta = 16; 
-         faillo_delta = 16; 
-       } 
-     } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Test 3.  If search_result = ILLEGAL, this search was    * 
-  *  given an illegal move and no search was done, we skip   * 
-  *  any updating and simply select the next move to search. * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-     else if (search_result == ILLEGAL) 
-       continue; 
-     t_beta = alpha + 1; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  SMP.  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 at least one move.  All that is  * 
-  *  left is to check the split constraints to see if this   * 
-  *  is 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 N 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, which means we want to get * 
-  *        them involved quickly, OR if this node is an      * 
-  *        acceptable "gratuitous-split" point by being far  * 
-  *        enough from the tips of the tree to avoid         * 
-  *        excessive overhead.                               * 
-  *                                                          * 
-  *  We use this code recursively to perform a parallel      * 
-  *  search at this ply.  But when we finish a partial piece * 
-  *  of the search in parallel, we don't need to update any  * 
-  *  search data structures, we will defer that until all of * 
-  *  parallel threads complete and return back into this     * 
-  *  code after the parallel search has been collapsed back  * 
-  *  to one instance of search at this ply.                  * 
-  *                                                          * 
-  *  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.                            * 
-  *                                                          * 
-  *  In Generation II, multiple threads can reach this point * 
-  *  at the same time.  We allow multiple threads to split   * 
-  *  at the same time, but then the idle threads will choose * 
-  *  to join the thread with the most attractive split point * 
-  *  rather than just taking pot-luck.  The only limitation  * 
-  *  on a thread adding a split point here is that if the    * 
-  *  thread already has enough joinable split points that    * 
-  *  have not been joined yet, we do not incur the overhead  * 
-  *  of creating another split point until one of the        * 
-  *  existing split points has been completed or a thread    * 
-  *  joins at at one of those available split points.        * 
-  *                                                          * 
-  *  We do not lock anything here, as the split operation    * 
-  *  only affects thread-local data.  When the split is done * 
-  *  then the ThreadJoin() function will acquire the lock    * 
-  *  needed to avoid race conditions during the join op-     * 
-  *  eration.                                                * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
- #if (CPUS > 1) 
-     if (mode == serial && moves_done && smp_threads && 
-         ThreadSplit(tree, ply, depth, alpha, original_alpha, moves_done)) 
-       do { 
-         tree->alpha = alpha; 
-         tree->beta = beta; 
-         tree->value = alpha; 
-         tree->wtm = wtm; 
-         tree->ply = ply; 
-         tree->depth = depth; 
-         tree->in_check = in_check; 
-         tree->searched = searched; 
-         if (Split(tree)) { 
-           if (abort_search || tree->stop) 
-             return 0; 
-           value = tree->value; 
-           if (value > alpha) { 
-             if (ply == 1) 
-               tree->pv[0] = tree->pv[1]; 
-             if (value >= beta) { 
-               HashStore(tree, ply, depth, wtm, LOWER, value, tree->cutmove); 
-               return value; 
-             } 
-             alpha = value; 
-             break; 
-           } 
-         } 
-       } while (0); 
- #endif 
-   } 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  SMP Cleanup.  If we are doing an SMP search, 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, 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.                                      * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   if (abort_search || tree->stop || mode == parallel) 
-     return alpha; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  Search completed.  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 (moves_done == 0) { 
-     value = (Check(wtm)) ? -(MATE - ply) : DrawScore(wtm); 
-     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 { 
-     bestmove = 
-         (alpha == 
-         original_alpha) ? tree->hash_move[ply] : tree->pv[ply].path[ply]; 
-     type = (alpha == original_alpha) ? UPPER : EXACT; 
-     if (repeat == 2 && alpha != -(MATE - ply - 1)) { 
-       value = DrawScore(wtm); 
-       if (value < beta) 
-         SavePV(tree, ply, 3); 
- #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]; 
-     } 
-     HashStore(tree, ply, depth, wtm, type, alpha, bestmove); 
-     return alpha; 
-   } 
- } 
-   
- /* last modified 08/03/16 */ 
- /* 
-  ******************************************************************************* 
-  *                                                                             * 
-  *   SearchMove() implements the PVS search and returns the value.  We do a    * 
-  *   null-window search with the window (alpha, t_beta) and if that fails high * 
-  *   we repeat the search with the window {alpha, beta} assuming that beta !=  * 
-  *   t_beta.                                                                   * 
-  *                                                                             * 
-  ******************************************************************************* 
-  */ 
- int SearchMove(TREE * RESTRICT tree, int ply, int depth, int wtm, int alpha, 
-     int t_beta, int beta, int extend, int reduce, int check) { 
-   int value; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  PVS search.  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, ply + 1, depth + extend - reduce - 1, Flip(wtm), 
-         -t_beta, -alpha, check, DO_NULL); 
-     if (value > alpha && reduce) { 
-       value = 
-           -Search(tree, ply + 1, depth - 1, Flip(wtm), -t_beta, -alpha, check, 
-           DO_NULL); 
-     } 
-   } else 
-     value = -Quiesce(tree, ply + 1, Flip(wtm), -t_beta, -alpha, 1); 
-   if (abort_search || tree->stop) 
-     return 0; 
- /* 
-  ************************************************************ 
-  *                                                          * 
-  *  PVS re-search.  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     * 
-  *  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.                                                    * 
-  *                                                          * 
-  ************************************************************ 
-  */ 
-   if (value > alpha && value < beta && t_beta < beta) { 
-     if (ply == 1) 
-       return beta; 
-     if (depth + extend - 1 > 0) 
-       value = 
-           -Search(tree, ply + 1, depth + extend - 1, Flip(wtm), -beta, -alpha, 
-           check, DO_NULL); 
-     else 
-       value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -alpha, 1); 
-     if (abort_search || tree->stop) 
-       return 0; 
-   } 
-   return value; 
- } 
-