Subversion Repositories Games.Chess Giants

Rev

Rev 108 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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