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