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