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