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  */
Iterate(int wtm,int search_type,int root_list_done)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