Subversion Repositories Games.Chess Giants

Rev

Rev 108 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "chess.h"
  2. #include "data.h"
  3. #include "epdglue.h"
  4. #include "tbprobe.h"
  5. /* last modified 08/03/16 */
  6. /*
  7.  *******************************************************************************
  8.  *                                                                             *
  9.  *   Iterate() is the routine used to drive the iterated search.  It           *
  10.  *   repeatedly calls search, incrementing the search depth after each call,   *
  11.  *   until either time is exhausted or the maximum set search depth is         *
  12.  *   reached.                                                                  *
  13.  *                                                                             *
  14.  *   Crafty has several specialized modes that influence how moves are chosen  *
  15.  *   and when.                                                                 *
  16.  *                                                                             *
  17.  *   (1) "mode tournament" is a special way of handling book moves.  Here we   *
  18.  *   are dealing with pondering.  We play our move, and then we take all of    *
  19.  *   the known book moves for the opponent (moves where we have an instant     *
  20.  *   reply since they are in the book) and eliminate those from the set of     *
  21.  *   root moves to search.  We do a short search to figure out which of those  *
  22.  *   non-book moves is best, and then we ponder that move.  It will look like  *
  23.  *   we are always out of book, but we are not.  We are just looking for one   *
  24.  *   of two cases:  (i) The opponent's book runs out and he doesn't play the   *
  25.  *   expected book line (which is normally a mistake), where this will give us *
  26.  *   a good chance of pondering the move he will actually play (a non-book     *
  27.  *   move) without sitting around and doing nothing until he takes us out of   *
  28.  *   book;  (ii) Our book doesn't have a reasonable choice, so we do a search  *
  29.  *   and ponder a better choice so again we are not wasting time.  The value   *
  30.  *   of "mode" will be set to "tournament" to enable this.                     *
  31.  *                                                                             *
  32.  *   (2) "book random 0" tells the program to enumerate the list of known book *
  33.  *   moves, but rather than playing one randomly, we do a shortened search and *
  34.  *   use the normal move selection approach (which will, unfortunately, accept *
  35.  *   many gambits that a normal book line would bypass as too risky.  But this *
  36.  *   can also find a better book move in many positions, since many book lines *
  37.  *   are not verified with computer searches.                                  *
  38.  *                                                                             *
  39.  *   Those modes are handled within Book() and Ponder() but they all use the   *
  40.  *   same iterated search as is used for normal moves.                         *
  41.  *                                                                             *
  42.  *******************************************************************************
  43.  */
  44. int Iterate(int wtm, int search_type, int root_list_done) {
  45.   TREE *const tree = block[0];
  46.   ROOT_MOVE temp_rm;
  47.   int i, alpha, beta, current_rm = 0, force_print = 0;
  48.   int value = 0, twtm, correct, correct_count, npc, cpl, max;
  49.   unsigned int idle_time;
  50.   char buff[32];
  51. #if (CPUS > 1) && defined(UNIX)
  52.   pthread_t pt;
  53. #endif
  54.  
  55. /*
  56.  ************************************************************
  57.  *                                                          *
  58.  *  Initialize draw score.  This has to be done here since  *
  59.  *  we don't know whether we are searching for black or     *
  60.  *  white until we get to this point.                       *
  61.  *                                                          *
  62.  ************************************************************
  63.  */
  64.   draw_score[black] = (wtm) ? -abs_draw_score : abs_draw_score;
  65.   draw_score[white] = (wtm) ? abs_draw_score : -abs_draw_score;
  66. #if defined(NODES)
  67.   temp_search_nodes = search_nodes;
  68. #endif
  69. /*
  70.  ************************************************************
  71.  *                                                          *
  72.  *  Initialize statistical counters and such.               *
  73.  *                                                          *
  74.  ************************************************************
  75.  */
  76.   abort_search = 0;
  77.   book_move = 0;
  78.   program_start_time = ReadClock();
  79.   start_time = ReadClock();
  80.   root_wtm = wtm;
  81.   kibitz_depth = 0;
  82.   tree->nodes_searched = 0;
  83.   tree->fail_highs = 0;
  84.   tree->fail_high_first_move = 0;
  85.   parallel_splits = 0;
  86.   parallel_splits_wasted = 0;
  87.   parallel_aborts = 0;
  88.   parallel_joins = 0;
  89.   for (i = 0; i < smp_max_threads; i++) {
  90.     thread[i].max_blocks = 0;
  91.     thread[i].tree = 0;
  92.     thread[i].idle = 0;
  93.     thread[i].terminate = 0;
  94.   }
  95.   thread[0].tree = block[0];
  96.   correct_count = 0;
  97.   burp = 15 * 100;
  98.   transposition_age = (transposition_age + 1) & 0x1ff;
  99.   next_time_check = nodes_between_time_checks;
  100.   tree->evaluations = 0;
  101.   tree->egtb_probes = 0;
  102.   tree->egtb_hits = 0;
  103.   tree->extensions_done = 0;
  104.   tree->qchecks_done = 0;
  105.   tree->moves_fpruned = 0;
  106.   tree->moves_mpruned = 0;
  107.   for (i = 0; i < 16; i++) {
  108.     tree->LMR_done[i] = 0;
  109.     tree->null_done[i] = 0;
  110.   }
  111.   root_wtm = wtm;
  112. /*
  113.  ************************************************************
  114.  *                                                          *
  115.  *  We do a quick check to see if this position has a known *
  116.  *  book reply.  If not, we drop into the main iterated     *
  117.  *  search, otherwise we skip to the bottom and return the  *
  118.  *  move that Book() returned.                              *
  119.  *                                                          *
  120.  *  Note the "booking" exception below.  If you use the     *
  121.  *  "book random 0" you instruct Crafty to enumerate the    *
  122.  *  known set of book moves, and then initiate a normal     *
  123.  *  iterated search, but with just those known book moves   *
  124.  *  included in the root move list.  We therefore choose    *
  125.  *  (based on a normal search / evaluation but with a lower *
  126.  *  time limit) from the book moves given.                  *
  127.  *                                                          *
  128.  ************************************************************
  129.  */
  130.   if (!root_list_done)
  131.     RootMoveList(wtm);
  132.   if (booking || (!Book(tree, wtm) && !RootMoveEGTB(wtm)))
  133.     do {
  134.       if (abort_search)
  135.         break;
  136. /*
  137.  ************************************************************
  138.  *                                                          *
  139.  *  The first action for a real search is to generate the   *
  140.  *  root move list if it has not already been done.  For    *
  141.  *  some circumstances, such as a non-random book move      *
  142.  *  search, we are given the root move list, which only     *
  143.  *  contains the known book moves.  Those are all we need   *
  144.  *  to search.  If there are no legal moves, it is either   *
  145.  *  mate or draw depending on whether the side to move is   *
  146.  *  in check or not (mate or stalemate.)                    *
  147.  *                                                          *
  148.  *  Why would there be already be a root move list?  See    *
  149.  *  the two modes described at the top (mode tournament and *
  150.  *  book random 0) which would have already inserted just   *
  151.  *  the moves that should be searched.                      *
  152.  *                                                          *
  153.  ************************************************************
  154.  */
  155.       if (n_root_moves == 0) {
  156.         program_end_time = ReadClock();
  157.         tree->pv[0].pathl = 0;
  158.         tree->pv[0].pathd = 0;
  159.         if (Check(wtm))
  160.           value = -(MATE - 1);
  161.         else
  162.           value = DrawScore(wtm);
  163.         Print(2, "        depth     time       score   variation\n");
  164.         Print(2, "                             Mated   (no moves)\n");
  165.         tree->nodes_searched = 1;
  166.         if (!puzzling)
  167.           last_root_value = value;
  168.         return value;
  169.       }
  170. /*
  171.  ************************************************************
  172.  *                                                          *
  173.  *  Now set the search time and iteratively call Search()   *
  174.  *  to analyze the position deeper and deeper.  Note that   *
  175.  *  Search() is called with an alpha/beta window roughly    *
  176.  *  1/3 of a pawn wide, centered on the score last returned *
  177.  *  by search.                                              *
  178.  *                                                          *
  179.  ************************************************************
  180.  */
  181.       TimeSet(search_type);
  182.       iteration = 1;
  183.       noise_block = 0;
  184.       force_print = 0;
  185.       if (last_pv.pathd > 1) {
  186.         iteration = last_pv.pathd + 1;
  187.         value = last_root_value;
  188.         tree->pv[0] = last_pv;
  189.         root_moves[0].path = tree->pv[0];
  190.         noise_block = 1;
  191.         force_print = 1;
  192.       } else
  193.         difficulty = 100;
  194.       Print(2, "        depth     time       score   variation (%d)\n",
  195.           iteration);
  196.       abort_search = 0;
  197. /*
  198.  ************************************************************
  199.  *                                                          *
  200.  *  Set the initial search bounds based on the last search  *
  201.  *  or default values.                                      *
  202.  *                                                          *
  203.  ************************************************************
  204.  */
  205.       tree->pv[0] = last_pv;
  206.       if (iteration > 1) {
  207.         alpha = Max(-MATE, last_value - 16);
  208.         beta = Min(MATE, last_value + 16);
  209.       } else {
  210.         alpha = -MATE;
  211.         beta = MATE;
  212.       }
  213. /*
  214.  ************************************************************
  215.  *                                                          *
  216.  *  If we are using multiple threads, and they have not     *
  217.  *  been started yet, then start them now as the search is  *
  218.  *  ready to begin.                                         *
  219.  *                                                          *
  220.  *  If we are using CPU affinity, we need to set this up    *
  221.  *  for thread 0 since it could have changed since we       *
  222.  *  initialized everything.                                 *
  223.  *                                                          *
  224.  ************************************************************
  225.  */
  226. #if (CPUS > 1)
  227.       if (smp_max_threads > smp_threads + 1) {
  228.         long proc;
  229.  
  230.         initialized_threads = 1;
  231.         Print(32, "starting thread");
  232.         for (proc = smp_threads + 1; proc < smp_max_threads; proc++) {
  233.           Print(32, " %d", proc);
  234. #  if defined(UNIX)
  235.           pthread_create(&pt, &attributes, ThreadInit, (void *) proc);
  236. #  else
  237.           NumaStartThread(ThreadInit, (void *) proc);
  238. #  endif
  239.           smp_threads++;
  240.         }
  241.         Print(32, " <done>\n");
  242.       }
  243.       WaitForAllThreadsInitialized();
  244.       ThreadAffinity(0);
  245. #endif
  246.       if (search_nodes)
  247.         nodes_between_time_checks = search_nodes;
  248. /*
  249.  ************************************************************
  250.  *                                                          *
  251.  *  Main iterative-deepening loop starts here.  We either   *
  252.  *  start at depth = 1, or if we are pondering and have a   *
  253.  *  PV from the previous search, we use that to set the     *
  254.  *  starting depth.                                         *
  255.  *                                                          *
  256.  *  First install the old PV into the hash table so that    *
  257.  *  these moves will be searched first.  We do this since   *
  258.  *  the last iteration done could have overwritten the PV   *
  259.  *  as the last few root moves were searched.               *
  260.  *                                                          *
  261.  ************************************************************
  262.  */
  263.       for (; iteration <= MAXPLY - 5; iteration++) {
  264.         twtm = wtm;
  265.         for (i = 1; i < (int) tree->pv[0].pathl; i++) {
  266.           if (!VerifyMove(tree, i, twtm, tree->pv[0].path[i])) {
  267.             Print(2048, "ERROR, not installing bogus pv info at ply=%d\n", i);
  268.             Print(2048, "not installing from=%d  to=%d  piece=%d\n",
  269.                 From(tree->pv[0].path[i]), To(tree->pv[0].path[i]),
  270.                 Piece(tree->pv[0].path[i]));
  271.             Print(2048, "pathlen=%d\n", tree->pv[0].pathl);
  272.             break;
  273.           }
  274.           HashStorePV(tree, twtm, i);
  275.           MakeMove(tree, i, twtm, tree->pv[0].path[i]);
  276.           twtm = Flip(twtm);
  277.         }
  278.         for (i--; i > 0; i--) {
  279.           twtm = Flip(twtm);
  280.           UnmakeMove(tree, i, twtm, tree->pv[0].path[i]);
  281.         }
  282. /*
  283.  ************************************************************
  284.  *                                                          *
  285.  *  Now we call Search() and start the next search          *
  286.  *  iteration.  We already have solid alpha/beta bounds set *
  287.  *  up for the aspiration search.  When each iteration      *
  288.  *  completes, these aspiration values are recomputed and   *
  289.  *  used for the next iteration.                            *
  290.  *                                                          *
  291.  *  We need to set "nodes_between_time_checks" to a value   *
  292.  *  that will force us to check the time reasonably often   *
  293.  *  without wasting excessive time doing this check.  As    *
  294.  *  the target time limit gets shorter, we shorten the      *
  295.  *  interval between time checks to avoid burning time off  *
  296.  *  of the clock unnecessarily.                             *
  297.  *                                                          *
  298.  ************************************************************
  299.  */
  300.         if (trace_level) {
  301.           Print(32, "==================================\n");
  302.           Print(32, "=      search iteration %2d       =\n", iteration);
  303.           Print(32, "==================================\n");
  304.         }
  305.         if (tree->nodes_searched) {
  306.           nodes_between_time_checks =
  307.               nodes_per_second / (10 * Max(smp_max_threads, 1));
  308.           if (!analyze_mode) {
  309.             if (time_limit < 1000)
  310.               nodes_between_time_checks /= 10;
  311.             if (time_limit < 100)
  312.               nodes_between_time_checks /= 10;
  313.           } else
  314.             nodes_between_time_checks = Min(nodes_per_second, 1000000);
  315.         }
  316.         if (search_nodes)
  317.           nodes_between_time_checks = search_nodes - tree->nodes_searched;
  318.         nodes_between_time_checks =
  319.             Min(nodes_between_time_checks, MAX_TC_NODES);
  320.         next_time_check = nodes_between_time_checks;
  321. /*
  322.  ************************************************************
  323.  *                                                          *
  324.  *  This loop will execute until we either run out of time  *
  325.  *  or complete this iteration.  Since we can return to     *
  326.  *  Iterate() multiple times during this iteration, due to  *
  327.  *  multiple fail highs (and perhaps even an initial fail   *
  328.  *  low) we stick in this loop until we have completed all  *
  329.  *  root moves or TimeCheck() tells us it is time to stop.  *
  330.  *                                                          *
  331.  ************************************************************
  332.  */
  333.         failhi_delta = 16;
  334.         faillo_delta = 16;
  335.         for (i = 0; i < n_root_moves; i++) {
  336.           if (i || iteration == 1)
  337.             root_moves[i].path.pathv = -MATE;
  338.           root_moves[i].status &= 4;
  339.         }
  340.         while (1) {
  341.           if (smp_max_threads > 1)
  342.             smp_split = 1;
  343.           rep_index--;
  344.           value = Search(tree, 1, iteration, wtm, alpha, beta, Check(wtm), 0);
  345.           rep_index++;
  346.           end_time = ReadClock();
  347.           if (abort_search)
  348.             break;
  349.           for (current_rm = 0; current_rm < n_root_moves; current_rm++)
  350.             if (tree->pv[0].path[1] == root_moves[current_rm].move)
  351.               break;
  352. /*
  353.  ************************************************************
  354.  *                                                          *
  355.  *  Check for the case where we get a score back that is    *
  356.  *  greater than or equal to beta.  This is called a fail   *
  357.  *  high condition and requires a re-search with a better   *
  358.  *  (more optimistic) beta value so that we can discover    *
  359.  *  just how good this move really is.                      *
  360.  *                                                          *
  361.  *  Note that each time we return here, we need to increase *
  362.  *  the upper search bound (beta).  We have a value named   *
  363.  *  failhi_delta that is initially set to 16 on the first   *
  364.  *  fail high of a particular move.  We increase beta by    *
  365.  *  this value each time we fail high.  However, each time  *
  366.  *  we fail high, we also double this value so that we      *
  367.  *  increase beta at an ever-increasing rate.  Small jumps  *
  368.  *  at first let us detect marginal score increases while   *
  369.  *  still allowing cutoffs for branches with excessively    *
  370.  *  high scores.  But each re-search sees the margin double *
  371.  *  which quickly increases the bound as needed.            *
  372.  *                                                          *
  373.  *  We also use ComputeDifficulty() to adjust the level of  *
  374.  *  difficulty for this move since we might be changing our *
  375.  *  mind at the root.  (If we are failing high on the first *
  376.  *  root move we skip this update.)                         *
  377.  *                                                          *
  378.  ************************************************************
  379.  */
  380.           if (value >= beta) {
  381.             beta = Min(beta + failhi_delta, MATE);
  382.             failhi_delta *= 2;
  383.             if (failhi_delta > 10 * PAWN_VALUE)
  384.               failhi_delta = 99999;
  385.             root_moves[current_rm].status &= 7;
  386.             root_moves[current_rm].bm_age = 4;
  387.             if ((root_moves[current_rm].status & 2) == 0)
  388.               difficulty = ComputeDifficulty(difficulty, +1);
  389.             root_moves[current_rm].status |= 2;
  390.             DisplayFail(tree, 1, 5, wtm, end_time - start_time,
  391.                 root_moves[current_rm].move, value, force_print);
  392.             temp_rm = root_moves[current_rm];
  393.             for (i = current_rm; i > 0; i--)
  394.               root_moves[i] = root_moves[i - 1];
  395.             root_moves[0] = temp_rm;
  396.           }
  397. /*
  398.  ************************************************************
  399.  *                                                          *
  400.  *  Check for the case where we get a score back that is    *
  401.  *  less than or equal to alpha.  This is called a fail     *
  402.  *  low condition and requires a re-search with a better    *
  403.  *  more pessimistic)) alpha value so that we can discover  *
  404.  *  just how bad this move really is.                       *
  405.  *                                                          *
  406.  *  Note that each time we return here, we need to decrease *
  407.  *  the lower search bound (alpha).  We have a value named  *
  408.  *  faillo_delta that is initially set to 16 on the first   *
  409.  *  fail low of a particular move.  We decrease alpha by    *
  410.  *  this value each time we fail low.  However, each time   *
  411.  *  we fail low, we also double this value so that we       *
  412.  *  decrease alpha at an ever-increasing rate.  Small jumps *
  413.  *  at first let us detect marginal score decreases while   *
  414.  *  still allowing cutoffs for branches with excessively    *
  415.  *  low scores.  But each re-search sees the margin double  *
  416.  *  which quickly decreases the bound as needed.            *
  417.  *                                                          *
  418.  *  We also use ComputeDifficulty() to adjust the level of  *
  419.  *  difficulty for this move since we are failing low on    *
  420.  *  the first move at the root, and we don't want to stop   *
  421.  *  before we have a chance to find a better one.           *
  422.  *                                                          *
  423.  ************************************************************
  424.  */
  425.           else if (value <= alpha) {
  426.             alpha = Max(alpha - faillo_delta, -MATE);
  427.             faillo_delta *= 2;
  428.             if (faillo_delta > 10 * PAWN_VALUE)
  429.               faillo_delta = 99999;
  430.             root_moves[current_rm].status &= 7;
  431.             if ((root_moves[current_rm].status & 1) == 0)
  432.               difficulty = ComputeDifficulty(Max(100, difficulty), -1);
  433.             root_moves[current_rm].status |= 1;
  434.             DisplayFail(tree, 2, 5, wtm, end_time - start_time,
  435.                 root_moves[current_rm].move, value, force_print);
  436.           } else
  437.             break;
  438.         }
  439. /*
  440.  ************************************************************
  441.  *                                                          *
  442.  *  If we are running a test suite, check to see if we can  *
  443.  *  exit the search.  This happens when N successive        *
  444.  *  iterations produce the correct solution.  N is set by   *
  445.  *  the test command in Option().                           *
  446.  *                                                          *
  447.  ************************************************************
  448.  */
  449.         if (value > alpha && value < beta)
  450.           last_root_value = value;
  451.         correct = solution_type;
  452.         for (i = 0; i < number_of_solutions; i++) {
  453.           if (!solution_type) {
  454.             if (solutions[i] == tree->pv[0].path[1])
  455.               correct = 1;
  456.           } else if (solutions[i] == root_moves[current_rm].move)
  457.             correct = 0;
  458.         }
  459.         if (correct)
  460.           correct_count++;
  461.         else
  462.           correct_count = 0;
  463. /*
  464.  ************************************************************
  465.  *                                                          *
  466.  *  Notice that we don't search moves that were best over   *
  467.  *  the last 3 iterations in parallel, nor do we reduce     *
  468.  *  those since they are potential best moves again.        *
  469.  *                                                          *
  470.  ************************************************************
  471.  */
  472.         for (i = 0; i < n_root_moves; i++) {
  473.           root_moves[i].status &= 3;
  474.           if (root_moves[i].bm_age)
  475.             root_moves[i].bm_age--;
  476.           if (root_moves[i].bm_age)
  477.             root_moves[i].status |= 4;
  478.         }
  479.         difficulty = ComputeDifficulty(difficulty, 0);
  480. /*
  481.  ************************************************************
  482.  *                                                          *
  483.  *  If requested, print the ply=1 move list along with the  *
  484.  *  flags for each move.  Once we print this (if requested) *
  485.  *  we can then clear all of the status flags (except the   *
  486.  *  "do not search in parallel or reduce" flag) to prepare  *
  487.  *  for the start of the next iteration, since that is the  *
  488.  *  only flag that needs to be carried forward to the next  *
  489.  *  iteration.                                              *
  490.  *                                                          *
  491.  ************************************************************
  492.  */
  493.         if (display_options & 64) {
  494.           Print(64, "      rmove   score    age  S ! ?\n");
  495.           for (i = 0; i < n_root_moves; i++) {
  496.             Print(64, " %10s ", OutputMove(tree, 1, wtm, root_moves[i].move));
  497.             if (root_moves[i].path.pathv > -MATE &&
  498.                 root_moves[i].path.pathv <= MATE)
  499.               Print(64, "%s", DisplayEvaluation(root_moves[i].path.pathv,
  500.                       wtm));
  501.             else
  502.               Print(64, "  -----");
  503.             Print(64, "     %d   %d %d %d\n", root_moves[i].bm_age,
  504.                 (root_moves[i].status & 4) != 0,
  505.                 (root_moves[i].status & 2) != 0,
  506.                 (root_moves[i].status & 1) != 0);
  507.           }
  508.         }
  509. /*
  510.  ************************************************************
  511.  *                                                          *
  512.  *  Here we simply display the PV from the current search   *
  513.  *  iteration, and then set the aspiration for the next     *
  514.  *  iteration to the current score +/- 16.                  *
  515.  *                                                          *
  516.  ************************************************************
  517.  */
  518.         if (end_time - start_time > 10)
  519.           nodes_per_second =
  520.               tree->nodes_searched * 100 / (uint64_t) (end_time - start_time);
  521.         else
  522.           nodes_per_second = 1000000;
  523.         tree->pv[0] = root_moves[0].path;
  524.         if (!abort_search && value != -(MATE - 1)) {
  525.           if (end_time - start_time >= noise_level) {
  526.             DisplayPV(tree, 5, wtm, end_time - start_time, &tree->pv[0],
  527.                 force_print);
  528.             noise_block = 0;
  529.           } else
  530.             noise_block = 1;
  531.         }
  532.         alpha = Max(-MATE, value - 16);
  533.         beta = Min(MATE, value + 16);
  534. /*
  535.  ************************************************************
  536.  *                                                          *
  537.  *  There are multiple termination criteria that are used.  *
  538.  *  The first and most obvious is that we have exceeded the *
  539.  *  target time limit.  Others include reaching a user-set  *
  540.  *  maximum search depth, finding a mate and we searched so *
  541.  *  deep there is little chance of another iteration find-  *
  542.  *  ing a shorter mate; the search was aborted due to some  *
  543.  *  sort of user input (usually during pondering);  and     *
  544.  *  finally, when running a test suite, we had the correct  *
  545.  *  best move for N successive iterations and the user      *
  546.  *  asked us to stop after that number.                     *
  547.  *                                                          *
  548.  ************************************************************
  549.  */
  550.         if (TimeCheck(tree, 0))
  551.           break;
  552.         if (iteration > 3 && value > 32000 && value >= (MATE - iteration + 3)
  553.             && value > last_mate_score)
  554.           break;
  555.         if ((iteration >= search_depth) && search_depth)
  556.           break;
  557.         if (abort_search)
  558.           break;
  559.         end_time = ReadClock() - start_time;
  560.         if (correct_count >= early_exit)
  561.           break;
  562.         if (search_nodes && tree->nodes_searched >= search_nodes)
  563.           break;
  564.       }
  565. /*
  566.  ************************************************************
  567.  *                                                          *
  568.  *  Search done, now display statistics, depending on the   *
  569.  *  display options set (see display command in Option().)  *
  570.  *                                                          *
  571.  *  Simple kludge here.  If the last search was quite deep  *
  572.  *  while we were pondering, we start this iteration at the *
  573.  *  last depth - 1.  Sometimes that will result in a search *
  574.  *  that is deep enough that we do not produce/print a PV   *
  575.  *  before time runs out.  On other occasions, noise_level  *
  576.  *  prevents us from printing anything, leaving us with no  *
  577.  *  output during this PV.  We initialize a variable named  *
  578.  *  noise_block to 1.  If, during this iteration, we do     *
  579.  *  manage to print a PV, we set it to zero until the next  *
  580.  *  iteration starts.  Otherwise this will force us to at   *
  581.  *  display the PV from the last iteration (first two moves *
  582.  *  were removed in main(), so they are not present) so we  *
  583.  *  have some sort of output for this iteration.            *
  584.  *                                                          *
  585.  ************************************************************
  586.  */
  587.       end_time = ReadClock();
  588.       if (end_time > 10)
  589.         nodes_per_second =
  590.             (uint64_t) tree->nodes_searched * 100 / Max((uint64_t) end_time -
  591.             start_time, 1);
  592.       if (abort_search != 2 && !puzzling) {
  593.         if (noise_block)
  594.           DisplayPV(tree, 5, wtm, end_time - start_time, &tree->pv[0], 1);
  595.         tree->evaluations = (tree->evaluations) ? tree->evaluations : 1;
  596.         tree->fail_highs++;
  597.         tree->fail_high_first_move++;
  598.         idle_time = 0;
  599.         for (i = 0; i < smp_max_threads; i++)
  600.           idle_time += thread[i].idle;
  601.         busy_percent =
  602.             100 - Min(100,
  603.             100 * idle_time / (smp_max_threads * (end_time - start_time) +
  604.                 1));
  605.         Print(8, "        time=%s(%d%%)",
  606.             DisplayTimeKibitz(end_time - start_time), busy_percent);
  607.         Print(8, "  nodes=%" PRIu64 "(%s)", tree->nodes_searched,
  608.             DisplayKMB(tree->nodes_searched, 0));
  609.         Print(8, "  fh1=%d%%",
  610.             tree->fail_high_first_move * 100 / tree->fail_highs);
  611.         Print(8, "  pred=%d", predicted);
  612.         Print(8, "  nps=%s\n", DisplayKMB(nodes_per_second, 0));
  613.         Print(8, "        chk=%s", DisplayKMB(tree->extensions_done, 0));
  614.         Print(8, "  qchk=%s", DisplayKMB(tree->qchecks_done, 0));
  615.         Print(8, "  fp=%s", DisplayKMB(tree->moves_fpruned, 0));
  616.         Print(8, "  mcp=%s", DisplayKMB(tree->moves_mpruned, 0));
  617.         Print(8, "  50move=%d",
  618.             (ReversibleMove(last_pv.path[1]) ? Reversible(0) + 1 : 0));
  619.         if (tree->egtb_hits)
  620.           Print(8, "  egtb=%s", DisplayKMB(tree->egtb_hits, 0));
  621.         Print(8, "\n");
  622.         Print(8, "        LMReductions:");
  623.         npc = 21;
  624.         cpl = 75;
  625.         for (i = 1; i < 16; i++)
  626.           if (tree->LMR_done[i]) {
  627.             sprintf(buff, "%d/%s", i, DisplayKMB(tree->LMR_done[i], 0));
  628.             if (npc + strlen(buff) > cpl) {
  629.               Print(8, "\n            ");
  630.               npc = 12;
  631.             }
  632.             Print(8, "  %s", buff);
  633.             npc += strlen(buff) + 2;
  634.           }
  635.         if (npc)
  636.           Print(8, "\n");
  637.         npc = 24;
  638.         cpl = 75;
  639.         if (tree->null_done[null_depth])
  640.           Print(8, "        null-move (R):");
  641.         for (i = null_depth; i < 16; i++)
  642.           if (tree->null_done[i]) {
  643.             sprintf(buff, "%d/%s", i, DisplayKMB(tree->null_done[i], 0));
  644.             if (npc + strlen(buff) > cpl) {
  645.               Print(8, "\n            ");
  646.               npc = 12;
  647.             }
  648.             Print(8, "  %s", buff);
  649.             npc += strlen(buff) + 2;
  650.           }
  651.         if (npc)
  652.           Print(8, "\n");
  653.         if (parallel_splits) {
  654.           max = 0;
  655.           for (i = 0; i < smp_max_threads; i++) {
  656.             max = Max(max, PopCnt(thread[i].max_blocks));
  657.             game_max_blocks |= thread[i].max_blocks;
  658.           }
  659.           Print(8, "        splits=%s", DisplayKMB(parallel_splits, 0));
  660.           Print(8, "(%s)", DisplayKMB(parallel_splits_wasted, 0));
  661.           Print(8, "  aborts=%s", DisplayKMB(parallel_aborts, 0));
  662.           Print(8, "  joins=%s", DisplayKMB(parallel_joins, 0));
  663.           Print(8, "  data=%d%%(%d%%)\n", 100 * max / 64,
  664.               100 * PopCnt(game_max_blocks) / 64);
  665.         }
  666.       }
  667.     } while (0);
  668. /*
  669.  ************************************************************
  670.  *                                                          *
  671.  *  If this is a known book position, Book() has already    *
  672.  *  set the PV/best move so we can return without doing the *
  673.  *  iterated search at all.                                 *
  674.  *                                                          *
  675.  ************************************************************
  676.  */
  677.   else {
  678.     last_root_value = tree->pv[0].pathv;
  679.     value = tree->pv[0].pathv;
  680.     book_move = 1;
  681.     if (analyze_mode)
  682.       Kibitz(4, wtm, 0, 0, 0, 0, 0, 0, kibitz_text);
  683.   }
  684. /*
  685.  ************************************************************
  686.  *                                                          *
  687.  *  If "smp_nice" is set, and we are not allowed to ponder  *
  688.  *  while waiting on the opponent to move, then terminate   *
  689.  *  the parallel threads so they won't sit in their normal  *
  690.  *  spin-wait loop while waiting for new work which will    *
  691.  *  "burn" smp_max_threads - 1 cpus, penalizing anything    *
  692.  *  else that might be running (such as another chess       *
  693.  *  engine we might be playing in a ponder=off match.)      *
  694.  *                                                          *
  695.  ************************************************************
  696.  */
  697.   if (smp_nice && ponder == 0 && smp_threads) {
  698.     int proc;
  699.  
  700.     Print(64, "terminating SMP processes.\n");
  701.     for (proc = 1; proc < CPUS; proc++)
  702.       thread[proc].terminate = 1;
  703.     while (smp_threads);
  704.     smp_split = 0;
  705.   }
  706.   program_end_time = ReadClock();
  707.   search_move = 0;
  708.   if (quit)
  709.     CraftyExit(0);
  710.   return last_root_value;
  711. }
  712.