Rev 154 | Details | Compare with Previous | 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" |
||
154 | pmbaty | 4 | #include "tbprobe.h" |
5 | /* last modified 08/03/16 */ |
||
33 | pmbaty | 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 | */ |
||
44 | int Iterate(int wtm, int search_type, int root_list_done) { |
||
45 | TREE *const tree = block[0]; |
||
108 | pmbaty | 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]; |
||
154 | pmbaty | 51 | #if (CPUS > 1) && defined(UNIX) |
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 64 | draw_score[black] = (wtm) ? -abs_draw_score : abs_draw_score; |
65 | draw_score[white] = (wtm) ? abs_draw_score : -abs_draw_score; |
||
33 | pmbaty | 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; |
||
108 | pmbaty | 86 | parallel_splits_wasted = 0; |
33 | pmbaty | 87 | parallel_aborts = 0; |
108 | pmbaty | 88 | parallel_joins = 0; |
154 | pmbaty | 89 | for (i = 0; i < smp_max_threads; i++) { |
108 | pmbaty | 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]; |
||
33 | pmbaty | 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; |
||
108 | pmbaty | 102 | tree->egtb_hits = 0; |
33 | pmbaty | 103 | tree->extensions_done = 0; |
104 | tree->qchecks_done = 0; |
||
105 | tree->moves_fpruned = 0; |
||
108 | pmbaty | 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 | } |
||
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 130 | if (!root_list_done) |
131 | RootMoveList(wtm); |
||
154 | pmbaty | 132 | if (booking || (!Book(tree, wtm) && !RootMoveEGTB(wtm))) |
33 | pmbaty | 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); |
||
108 | pmbaty | 163 | Print(2, " depth time score variation\n"); |
154 | pmbaty | 164 | Print(2, " Mated (no moves)\n"); |
33 | pmbaty | 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); |
||
108 | pmbaty | 182 | iteration = 1; |
33 | pmbaty | 183 | noise_block = 0; |
108 | pmbaty | 184 | force_print = 0; |
33 | pmbaty | 185 | if (last_pv.pathd > 1) { |
108 | pmbaty | 186 | iteration = last_pv.pathd + 1; |
33 | pmbaty | 187 | value = last_root_value; |
188 | tree->pv[0] = last_pv; |
||
108 | pmbaty | 189 | root_moves[0].path = tree->pv[0]; |
33 | pmbaty | 190 | noise_block = 1; |
108 | pmbaty | 191 | force_print = 1; |
33 | pmbaty | 192 | } else |
193 | difficulty = 100; |
||
108 | pmbaty | 194 | Print(2, " depth time score variation (%d)\n", |
195 | iteration); |
||
33 | pmbaty | 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; |
||
108 | pmbaty | 206 | if (iteration > 1) { |
207 | alpha = Max(-MATE, last_value - 16); |
||
208 | beta = Min(MATE, last_value + 16); |
||
33 | pmbaty | 209 | } else { |
108 | pmbaty | 210 | alpha = -MATE; |
211 | beta = MATE; |
||
33 | pmbaty | 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 | * * |
||
108 | pmbaty | 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 | * * |
||
33 | pmbaty | 224 | ************************************************************ |
225 | */ |
||
226 | #if (CPUS > 1) |
||
154 | pmbaty | 227 | if (smp_max_threads > smp_threads + 1) { |
33 | pmbaty | 228 | long proc; |
229 | |||
230 | initialized_threads = 1; |
||
108 | pmbaty | 231 | Print(32, "starting thread"); |
154 | pmbaty | 232 | for (proc = smp_threads + 1; proc < smp_max_threads; proc++) { |
108 | pmbaty | 233 | Print(32, " %d", proc); |
33 | pmbaty | 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 | } |
||
108 | pmbaty | 241 | Print(32, " <done>\n"); |
33 | pmbaty | 242 | } |
243 | WaitForAllThreadsInitialized(); |
||
154 | pmbaty | 244 | ThreadAffinity(0); |
33 | pmbaty | 245 | #endif |
246 | if (search_nodes) |
||
156 | pmbaty | 247 | nodes_between_time_checks = (unsigned int) search_nodes; // Pierre-Marie Baty -- added type cast |
33 | pmbaty | 248 | /* |
249 | ************************************************************ |
||
250 | * * |
||
108 | pmbaty | 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 * |
||
33 | pmbaty | 258 | * the last iteration done could have overwritten the PV * |
259 | * as the last few root moves were searched. * |
||
260 | * * |
||
261 | ************************************************************ |
||
262 | */ |
||
108 | pmbaty | 263 | for (; iteration <= MAXPLY - 5; iteration++) { |
33 | pmbaty | 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])) { |
||
108 | pmbaty | 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", |
||
33 | pmbaty | 269 | From(tree->pv[0].path[i]), To(tree->pv[0].path[i]), |
270 | Piece(tree->pv[0].path[i])); |
||
108 | pmbaty | 271 | Print(2048, "pathlen=%d\n", tree->pv[0].pathl); |
33 | pmbaty | 272 | break; |
273 | } |
||
274 | HashStorePV(tree, twtm, i); |
||
108 | pmbaty | 275 | MakeMove(tree, i, twtm, tree->pv[0].path[i]); |
33 | pmbaty | 276 | twtm = Flip(twtm); |
277 | } |
||
278 | for (i--; i > 0; i--) { |
||
279 | twtm = Flip(twtm); |
||
108 | pmbaty | 280 | UnmakeMove(tree, i, twtm, tree->pv[0].path[i]); |
33 | pmbaty | 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) { |
||
108 | pmbaty | 301 | Print(32, "==================================\n"); |
302 | Print(32, "= search iteration %2d =\n", iteration); |
||
303 | Print(32, "==================================\n"); |
||
33 | pmbaty | 304 | } |
305 | if (tree->nodes_searched) { |
||
108 | pmbaty | 306 | nodes_between_time_checks = |
307 | nodes_per_second / (10 * Max(smp_max_threads, 1)); |
||
33 | pmbaty | 308 | if (!analyze_mode) { |
108 | pmbaty | 309 | if (time_limit < 1000) |
33 | pmbaty | 310 | nodes_between_time_checks /= 10; |
108 | pmbaty | 311 | if (time_limit < 100) |
312 | nodes_between_time_checks /= 10; |
||
33 | pmbaty | 313 | } else |
314 | nodes_between_time_checks = Min(nodes_per_second, 1000000); |
||
315 | } |
||
316 | if (search_nodes) |
||
156 | pmbaty | 317 | nodes_between_time_checks = (unsigned int) (search_nodes - tree->nodes_searched); // Pierre-Marie Baty -- added type cast |
33 | pmbaty | 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; |
||
108 | pmbaty | 335 | for (i = 0; i < n_root_moves; i++) { |
336 | if (i || iteration == 1) |
||
154 | pmbaty | 337 | root_moves[i].path.pathv = -MATE; |
108 | pmbaty | 338 | root_moves[i].status &= 4; |
339 | } |
||
33 | pmbaty | 340 | while (1) { |
341 | if (smp_max_threads > 1) |
||
342 | smp_split = 1; |
||
108 | pmbaty | 343 | rep_index--; |
344 | value = Search(tree, 1, iteration, wtm, alpha, beta, Check(wtm), 0); |
||
345 | rep_index++; |
||
33 | pmbaty | 346 | end_time = ReadClock(); |
347 | if (abort_search) |
||
348 | break; |
||
108 | pmbaty | 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; |
||
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 380 | if (value >= beta) { |
381 | beta = Min(beta + failhi_delta, MATE); |
||
33 | pmbaty | 382 | failhi_delta *= 2; |
383 | if (failhi_delta > 10 * PAWN_VALUE) |
||
384 | failhi_delta = 99999; |
||
108 | pmbaty | 385 | root_moves[current_rm].status &= 7; |
386 | root_moves[current_rm].bm_age = 4; |
||
387 | if ((root_moves[current_rm].status & 2) == 0) |
||
33 | pmbaty | 388 | difficulty = ComputeDifficulty(difficulty, +1); |
108 | pmbaty | 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 | } |
||
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 425 | else if (value <= alpha) { |
426 | alpha = Max(alpha - faillo_delta, -MATE); |
||
33 | pmbaty | 427 | faillo_delta *= 2; |
428 | if (faillo_delta > 10 * PAWN_VALUE) |
||
429 | faillo_delta = 99999; |
||
108 | pmbaty | 430 | root_moves[current_rm].status &= 7; |
431 | if ((root_moves[current_rm].status & 1) == 0) |
||
33 | pmbaty | 432 | difficulty = ComputeDifficulty(Max(100, difficulty), -1); |
108 | pmbaty | 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); |
||
33 | pmbaty | 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 | */ |
||
154 | pmbaty | 449 | if (value > alpha && value < beta) |
450 | last_root_value = value; |
||
33 | pmbaty | 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; |
||
108 | pmbaty | 456 | } else if (solutions[i] == root_moves[current_rm].move) |
33 | pmbaty | 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++) { |
||
108 | pmbaty | 473 | root_moves[i].status &= 3; |
33 | pmbaty | 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 * |
||
108 | pmbaty | 486 | * "do not search in parallel or reduce" flag) to prepare * |
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 493 | if (display_options & 64) { |
494 | Print(64, " rmove score age S ! ?\n"); |
||
33 | pmbaty | 495 | for (i = 0; i < n_root_moves; i++) { |
108 | pmbaty | 496 | Print(64, " %10s ", OutputMove(tree, 1, wtm, root_moves[i].move)); |
154 | pmbaty | 497 | if (root_moves[i].path.pathv > -MATE && |
498 | root_moves[i].path.pathv <= MATE) |
||
108 | pmbaty | 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, |
||
33 | pmbaty | 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) |
||
156 | pmbaty | 519 | nodes_per_second = (unsigned int) // Pierre-Marie Baty -- added type cast |
520 | (tree->nodes_searched * 100 / (uint64_t) (end_time - start_time)); |
||
33 | pmbaty | 521 | else |
522 | nodes_per_second = 1000000; |
||
108 | pmbaty | 523 | tree->pv[0] = root_moves[0].path; |
33 | pmbaty | 524 | if (!abort_search && value != -(MATE - 1)) { |
108 | pmbaty | 525 | if (end_time - start_time >= noise_level) { |
526 | DisplayPV(tree, 5, wtm, end_time - start_time, &tree->pv[0], |
||
527 | force_print); |
||
33 | pmbaty | 528 | noise_block = 0; |
108 | pmbaty | 529 | } else |
530 | noise_block = 1; |
||
33 | pmbaty | 531 | } |
108 | pmbaty | 532 | alpha = Max(-MATE, value - 16); |
533 | beta = Min(MATE, value + 16); |
||
33 | pmbaty | 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; |
||
108 | pmbaty | 552 | if (iteration > 3 && value > 32000 && value >= (MATE - iteration + 3) |
33 | pmbaty | 553 | && value > last_mate_score) |
554 | break; |
||
108 | pmbaty | 555 | if ((iteration >= search_depth) && search_depth) |
33 | pmbaty | 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) |
||
156 | pmbaty | 589 | nodes_per_second = (unsigned int) // Pierre-Marie Baty -- added type cast |
590 | ((uint64_t) tree->nodes_searched * 100 / Max((uint64_t) end_time - |
||
591 | start_time, 1)); |
||
33 | pmbaty | 592 | if (abort_search != 2 && !puzzling) { |
593 | if (noise_block) |
||
108 | pmbaty | 594 | DisplayPV(tree, 5, wtm, end_time - start_time, &tree->pv[0], 1); |
33 | pmbaty | 595 | tree->evaluations = (tree->evaluations) ? tree->evaluations : 1; |
596 | tree->fail_highs++; |
||
597 | tree->fail_high_first_move++; |
||
108 | pmbaty | 598 | idle_time = 0; |
154 | pmbaty | 599 | for (i = 0; i < smp_max_threads; i++) |
108 | pmbaty | 600 | idle_time += thread[i].idle; |
601 | busy_percent = |
||
33 | pmbaty | 602 | 100 - Min(100, |
603 | 100 * idle_time / (smp_max_threads * (end_time - start_time) + |
||
604 | 1)); |
||
605 | Print(8, " time=%s(%d%%)", |
||
108 | pmbaty | 606 | DisplayTimeKibitz(end_time - start_time), busy_percent); |
607 | Print(8, " nodes=%" PRIu64 "(%s)", tree->nodes_searched, |
||
608 | DisplayKMB(tree->nodes_searched, 0)); |
||
33 | pmbaty | 609 | Print(8, " fh1=%d%%", |
610 | tree->fail_high_first_move * 100 / tree->fail_highs); |
||
108 | pmbaty | 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)); |
||
154 | pmbaty | 617 | Print(8, " 50move=%d", |
618 | (ReversibleMove(last_pv.path[1]) ? Reversible(0) + 1 : 0)); |
||
108 | pmbaty | 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)); |
||
156 | pmbaty | 628 | if (npc + (int) strlen(buff) > cpl) { // Pierre-Marie Baty -- added type cast |
108 | pmbaty | 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)); |
||
156 | pmbaty | 644 | if (npc + (int) strlen(buff) > cpl) { // Pierre-Marie Baty -- added type cast |
108 | pmbaty | 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; |
||
154 | pmbaty | 655 | for (i = 0; i < smp_max_threads; i++) { |
108 | pmbaty | 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 | } |
||
33 | pmbaty | 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 { |
||
154 | pmbaty | 678 | last_root_value = tree->pv[0].pathv; |
679 | value = tree->pv[0].pathv; |
||
33 | pmbaty | 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; |
||
108 | pmbaty | 699 | |
700 | Print(64, "terminating SMP processes.\n"); |
||
33 | pmbaty | 701 | for (proc = 1; proc < CPUS; proc++) |
108 | pmbaty | 702 | thread[proc].terminate = 1; |
33 | pmbaty | 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 | } |