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 | } |