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