Subversion Repositories Games.Chess Giants

Rev

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