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 | /* last modified 05/08/14 */ |
||
| 4 | /* |
||
| 5 | ******************************************************************************* |
||
| 6 | * * |
||
| 7 | * Search() is the recursive routine used to implement the alpha/beta * |
||
| 8 | * negamax search (similar to minimax but simpler to code.) Search() is * |
||
| 9 | * called whenever there is "depth" remaining so that all moves are subject * |
||
| 10 | * to searching. Search() recursively calls itself so long as there is at * |
||
| 11 | * least one ply of depth left, otherwise it calls Quiesce() instead. * |
||
| 12 | * * |
||
| 13 | ******************************************************************************* |
||
| 14 | */ |
||
| 15 | int Search(TREE * RESTRICT tree, int alpha, int beta, int side, int depth, |
||
| 16 | int ply, int do_null) { |
||
| 17 | ROOT_MOVE temp_rm; |
||
| 18 | uint64_t start_nodes = tree->nodes_searched; |
||
| 19 | int first_tried = 0, moves_searched = 0, repeat = 0; |
||
| 20 | int original_alpha = alpha, value = 0, t_beta = beta; |
||
| 21 | int extend, reduce, max_reduce, i; |
||
| 22 | int pv_node = alpha != beta - 1; |
||
| 23 | |||
| 24 | /* |
||
| 25 | ************************************************************ |
||
| 26 | * * |
||
| 27 | * Step 1. Check to see if we have searched enough nodes * |
||
| 28 | * that it is time to peek at how much time has been used, * |
||
| 29 | * or if is time to check for operator keyboard input. * |
||
| 30 | * This is usually enough nodes to force a time/input * |
||
| 31 | * check about once per second, except when the target * |
||
| 32 | * time per move is very small, in which case we try to * |
||
| 33 | * check the time more frequently. * |
||
| 34 | * * |
||
| 35 | * Note that we check input or time-out in thread 0. This * |
||
| 36 | * makes the code simpler and eliminates some problematic * |
||
| 37 | * race conditions. * |
||
| 38 | * * |
||
| 39 | ************************************************************ |
||
| 40 | */ |
||
| 41 | #if defined(NODES) |
||
| 42 | if (--temp_search_nodes <= 0) { |
||
| 43 | abort_search = 1; |
||
| 44 | return 0; |
||
| 45 | } |
||
| 46 | #endif |
||
| 47 | if (tree->thread_id == 0) { |
||
| 48 | if (--next_time_check <= 0) { |
||
| 49 | next_time_check = nodes_between_time_checks; |
||
| 50 | if (TimeCheck(tree, 1)) { |
||
| 51 | abort_search = 1; |
||
| 52 | return 0; |
||
| 53 | } |
||
| 54 | if (CheckInput()) { |
||
| 55 | Interrupt(ply); |
||
| 56 | if (abort_search) |
||
| 57 | return 0; |
||
| 58 | } |
||
| 59 | } |
||
| 60 | } |
||
| 61 | if (ply >= MAXPLY - 1) |
||
| 62 | return beta; |
||
| 63 | /* |
||
| 64 | ************************************************************ |
||
| 65 | * * |
||
| 66 | * Step 2. Check for draw by repetition, which includes * |
||
| 67 | * 50 move draws also. This is the quickest way to get * |
||
| 68 | * out of further searching, with minimal effort. This * |
||
| 69 | * and the next two steps are skipped for moves at the * |
||
| 70 | * root (ply = 1). * |
||
| 71 | * * |
||
| 72 | ************************************************************ |
||
| 73 | */ |
||
| 74 | if (ply > 1) { |
||
| 75 | if ((repeat = Repeat(tree, ply))) { |
||
| 76 | value = DrawScore(side); |
||
| 77 | if (value < beta) |
||
| 78 | SavePV(tree, ply, 0); |
||
| 79 | #if defined(TRACE) |
||
| 80 | if (ply <= trace_level) |
||
| 81 | printf("draw by repetition detected, ply=%d.\n", ply); |
||
| 82 | #endif |
||
| 83 | return value; |
||
| 84 | } |
||
| 85 | /* |
||
| 86 | ************************************************************ |
||
| 87 | * * |
||
| 88 | * Step 3. Check the transposition/refutation (hash) * |
||
| 89 | * table to see if we have searched this position * |
||
| 90 | * previously and still have the results available. We * |
||
| 91 | * might get a real score, or a bound, or perhaps only a * |
||
| 92 | * good move to try first. The possible results are: * |
||
| 93 | * * |
||
| 94 | * 1. HashProbe() returns "HASH_HIT". This terminates * |
||
| 95 | * the search instantly and we simply return the value * |
||
| 96 | * found in the hash table. This value is simply the * |
||
| 97 | * value we found when we did a real search in this * |
||
| 98 | * position previously, and HashProbe() verifies that the * |
||
| 99 | * value is useful based on draft and current bounds. * |
||
| 100 | * * |
||
| 101 | * 2. HashProbe() returns "AVOID_NULL_MOVE" which means * |
||
| 102 | * the hashed score/bound was no good, but it indicated * |
||
| 103 | * that trying a null-move in this position would be a * |
||
| 104 | * waste of time since it will likely fail low, not high. * |
||
| 105 | * * |
||
| 106 | * 3. HashProbe() returns "HASH_MISS" when forces us to * |
||
| 107 | * do a normal search to resolve this node. * |
||
| 108 | * * |
||
| 109 | ************************************************************ |
||
| 110 | */ |
||
| 111 | switch (HashProbe(tree, ply, depth, side, alpha, beta, &value)) { |
||
| 112 | case HASH_HIT: |
||
| 113 | return value; |
||
| 114 | case AVOID_NULL_MOVE: |
||
| 115 | do_null = 0; |
||
| 116 | case HASH_MISS: |
||
| 117 | break; |
||
| 118 | } |
||
| 119 | /* |
||
| 120 | ************************************************************ |
||
| 121 | * * |
||
| 122 | * Step 4. Now it's time to try a probe into the endgame * |
||
| 123 | * tablebase files. This is done if we notice that there * |
||
| 124 | * are 6 or fewer pieces left on the board. EGTB_use * |
||
| 125 | * tells us how many pieces to probe on. Note that this * |
||
| 126 | * can be zero when trying to swindle the opponent, so * |
||
| 127 | * that no probes are done since we know it is a draw. * |
||
| 128 | * This is another way to get out of the search quickly, * |
||
| 129 | * but not as quickly as the previous steps since this can * |
||
| 130 | * result in an I/O operation. * |
||
| 131 | * * |
||
| 132 | * Note that in "swindle mode" this can be turned off by * |
||
| 133 | * Iterate() setting "EGTB_use = 0" so that we won't probe * |
||
| 134 | * the EGTBs since we are searching only the root moves * |
||
| 135 | * that lead to a draw and we want to play the move that * |
||
| 136 | * makes the draw more difficult to reach by the opponent * |
||
| 137 | * to give him a chance to make a mistake. * |
||
| 138 | * * |
||
| 139 | * Another special case is that we slightly fudge the * |
||
| 140 | * score for draws. In a normal circumstance, draw=0.00 * |
||
| 141 | * since it is "equal". However, here we add 0.01 if * |
||
| 142 | * white has more material, or subtract 0.01 if black has * |
||
| 143 | * more material, since in a drawn KRP vs KR we would * |
||
| 144 | * prefer to have the KRP side since the opponent can make * |
||
| 145 | * a mistake and convert the draw to a loss. * |
||
| 146 | * * |
||
| 147 | ************************************************************ |
||
| 148 | */ |
||
| 149 | #if !defined(NOEGTB) |
||
| 150 | if (depth > 6 && TotalAllPieces <= EGTB_use && |
||
| 151 | Castle(ply, white) + Castle(ply, black) == 0 && |
||
| 152 | (CaptureOrPromote(tree->curmv[ply - 1]) || ply < 3)) { |
||
| 153 | int egtb_value; |
||
| 154 | |||
| 155 | tree->egtb_probes++; |
||
| 156 | if (EGTBProbe(tree, ply, side, &egtb_value)) { |
||
| 157 | tree->egtb_probes_successful++; |
||
| 158 | alpha = egtb_value; |
||
| 159 | if (MateScore(alpha)) |
||
| 160 | alpha += (alpha > 0) ? -ply + 1 : ply; |
||
| 161 | else if (alpha == 0) { |
||
| 162 | alpha = DrawScore(side); |
||
| 163 | if (Material > 0) |
||
| 164 | alpha += (side) ? 1 : -1; |
||
| 165 | else if (Material < 0) |
||
| 166 | alpha -= (side) ? 1 : -1; |
||
| 167 | } |
||
| 168 | if (alpha < beta) |
||
| 169 | SavePV(tree, ply, 2); |
||
| 170 | return alpha; |
||
| 171 | } |
||
| 172 | } |
||
| 173 | #endif |
||
| 174 | /* |
||
| 175 | ************************************************************ |
||
| 176 | * * |
||
| 177 | * Step 5. We now know there is no quick way to get out * |
||
| 178 | * of here, which leaves one more possibility, although it * |
||
| 179 | * does require s search, but to a reduced depth. We * |
||
| 180 | * try a null move to see if we can get a quick cutoff * |
||
| 181 | * with only a little work. This operates as follows. * |
||
| 182 | * Instead of making a legal move, the side on move passes * |
||
| 183 | * and does nothing. The resulting position is searched * |
||
| 184 | * to a shallower depth than normal (usually 3 plies less * |
||
| 185 | * but settable by the user.) This will result in a cutoff * |
||
| 186 | * if our position is very good, but it produces the * |
||
| 187 | * cutoff much quicker since the search is far shallower * |
||
| 188 | * than a normal search that would also be likely to fail * |
||
| 189 | * high. * |
||
| 190 | * * |
||
| 191 | * This is skipped for any of the following reasons: * |
||
| 192 | * * |
||
| 193 | * 1. The side on move is in check. The null move * |
||
| 194 | * results in an illegal position. * |
||
| 195 | * 2. No more than one null move can appear in succession * |
||
| 196 | * as all this does is burn 6 plies of depth. * |
||
| 197 | * 3. The side on move has only pawns left, which makes * |
||
| 198 | * zugzwang positions more likely. * |
||
| 199 | * 4. The transposition table probe found an entry that * |
||
| 200 | * indicates that a null-move search will not fail * |
||
| 201 | * high, so we avoid the wasted effort. * |
||
| 202 | * * |
||
| 203 | ************************************************************ |
||
| 204 | */ |
||
| 205 | tree->inchk[ply + 1] = 0; |
||
| 206 | tree->last[ply] = tree->last[ply - 1]; |
||
| 207 | if (do_null && !pv_node && depth > 1 && !tree->inchk[ply] |
||
| 208 | && TotalPieces(side, occupied)) { |
||
| 209 | uint64_t save_hash_key; |
||
| 210 | |||
| 211 | tree->curmv[ply] = 0; |
||
| 212 | tree->phase[ply] = NULL_MOVE; |
||
| 213 | #if defined(TRACE) |
||
| 214 | if (ply <= trace_level) |
||
| 215 | Trace(tree, ply, depth, side, beta - 1, beta, "Search1", NULL_MOVE); |
||
| 216 | #endif |
||
| 217 | tree->status[ply + 1] = tree->status[ply]; |
||
| 218 | Reversible(ply + 1) = 0; |
||
| 219 | save_hash_key = HashKey; |
||
| 220 | if (EnPassant(ply + 1)) { |
||
| 221 | HashEP(EnPassant(ply + 1)); |
||
| 222 | EnPassant(ply + 1) = 0; |
||
| 223 | } |
||
| 224 | if (depth - null_depth - 1 > 0) |
||
| 225 | value = |
||
| 226 | -Search(tree, -beta, -beta + 1, Flip(side), |
||
| 227 | depth - null_depth - 1, ply + 1, NO_NULL); |
||
| 228 | else |
||
| 229 | value = -Quiesce(tree, -beta, -beta + 1, Flip(side), ply + 1, 1); |
||
| 230 | HashKey = save_hash_key; |
||
| 231 | if (abort_search || tree->stop) |
||
| 232 | return 0; |
||
| 233 | if (value >= beta) { |
||
| 234 | HashStore(tree, ply, depth, side, LOWER, value, tree->hash_move[ply]); |
||
| 235 | return value; |
||
| 236 | } |
||
| 237 | } |
||
| 238 | /* |
||
| 239 | ************************************************************ |
||
| 240 | * * |
||
| 241 | * Step 6. This step is rarely executed. It is used when * |
||
| 242 | * there is no best move from the hash table, and this is * |
||
| 243 | * a PV node, since we need a good move to search first. * |
||
| 244 | * While killers moves are good, they are not quite good * |
||
| 245 | * enough. the simplest solution is to try a shallow * |
||
| 246 | * search (depth-2) to get a move. note that when we call * |
||
| 247 | * Search() with depth-2, it, too, will not have a hash * |
||
| 248 | * move, and will therefore recursively continue this * |
||
| 249 | * process, hence the name "internal iterative deepening." * |
||
| 250 | * * |
||
| 251 | ************************************************************ |
||
| 252 | */ |
||
| 253 | tree->next_status[ply].phase = HASH_MOVE; |
||
| 254 | if (!tree->hash_move[ply] && depth >= 6 && do_null && ply > 1) { |
||
| 255 | if (pv_node) { |
||
| 256 | do { |
||
| 257 | tree->curmv[ply] = 0; |
||
| 258 | if (depth - 2 > 0) |
||
| 259 | value = Search(tree, alpha, beta, side, depth - 2, ply, DO_NULL); |
||
| 260 | else |
||
| 261 | value = Quiesce(tree, alpha, beta, side, ply, 1); |
||
| 262 | if (abort_search || tree->stop) |
||
| 263 | break; |
||
| 264 | if (value > alpha) { |
||
| 265 | if (value < beta) { |
||
| 266 | if ((int) tree->pv[ply - 1].pathl > ply) |
||
| 267 | tree->hash_move[ply] = tree->pv[ply - 1].path[ply]; |
||
| 268 | } else |
||
| 269 | tree->hash_move[ply] = tree->curmv[ply]; |
||
| 270 | tree->last[ply] = tree->last[ply - 1]; |
||
| 271 | tree->next_status[ply].phase = HASH_MOVE; |
||
| 272 | } |
||
| 273 | } while (0); |
||
| 274 | } |
||
| 275 | } |
||
| 276 | } |
||
| 277 | /* |
||
| 278 | ************************************************************ |
||
| 279 | * * |
||
| 280 | * Step 7. Now iterate through the move list and search * |
||
| 281 | * the resulting positions. Note that Search() culls any * |
||
| 282 | * move that is not legal by using Check(). The special * |
||
| 283 | * case is that we must find one legal move to search to * |
||
| 284 | * confirm that it's not a mate or draw. * |
||
| 285 | * * |
||
| 286 | * We have three possible procedures we call here, one is * |
||
| 287 | * specific to ply=1 (NextRootMove()), the second is a * |
||
| 288 | * specific routine to escape check (NextEvasion()) and * |
||
| 289 | * the last is the normal NextMove() procedure that does * |
||
| 290 | * the usual move ordering stuff. * |
||
| 291 | * * |
||
| 292 | * Special case: if we have searched one move at root, * |
||
| 293 | * and the returned score == alpha, we want to get out of * |
||
| 294 | * here and return to Iterate() where the search bounds * |
||
| 295 | * will be adjusted. Otherwise we would search all root * |
||
| 296 | * moves and possibly fail low after expending a sig- * |
||
| 297 | * nificant amount of time. * |
||
| 298 | * * |
||
| 299 | ************************************************************ |
||
| 300 | */ |
||
| 301 | tree->next_status[ply].phase = HASH_MOVE; |
||
| 302 | while (1) { |
||
| 303 | if (ply > 1) |
||
| 304 | tree->phase[ply] = |
||
| 305 | (tree->inchk[ply]) ? NextEvasion(tree, ply, side) : NextMove(tree, |
||
| 306 | ply, side); |
||
| 307 | else if (moves_searched == 1 && alpha == original_alpha) |
||
| 308 | break; |
||
| 309 | else |
||
| 310 | tree->phase[ply] = NextRootMove(tree, tree, side); |
||
| 311 | if (!tree->phase[ply]) |
||
| 312 | break; |
||
| 313 | #if defined(TRACE) |
||
| 314 | if (ply <= trace_level) |
||
| 315 | Trace(tree, ply, depth, side, alpha, beta, "Search2", tree->phase[ply]); |
||
| 316 | #endif |
||
| 317 | MakeMove(tree, ply, tree->curmv[ply], side); |
||
| 318 | tree->nodes_searched++; |
||
| 319 | if (tree->inchk[ply] || !Check(side)) |
||
| 320 | do { |
||
| 321 | if (++moves_searched == 1) |
||
| 322 | first_tried = tree->curmv[ply]; |
||
| 323 | /* |
||
| 324 | ************************************************************ |
||
| 325 | * * |
||
| 326 | * Step 7a. If the move to be made checks the opponent, * |
||
| 327 | * then we need to remember that he's in check and also * |
||
| 328 | * extend the depth by one ply for him to get out. Note * |
||
| 329 | * that if the move gives check, it is not a candidate for * |
||
| 330 | * either depth reduction or forward-pruning. * |
||
| 331 | * * |
||
| 332 | * We do not extend unsafe checking moves (as indicated by * |
||
| 333 | * Swap(), a SEE algorithm, since these are usually a * |
||
| 334 | * waste of time and simply blow up the tree search space. * |
||
| 335 | * * |
||
| 336 | ************************************************************ |
||
| 337 | */ |
||
| 338 | extend = 0; |
||
| 339 | reduce = 0; |
||
| 340 | if (Check(Flip(side))) { |
||
| 341 | tree->inchk[ply + 1] = 1; |
||
| 342 | if (SwapO(tree, tree->curmv[ply], side) <= 0) { |
||
| 343 | extend = check_depth; |
||
| 344 | tree->extensions_done++; |
||
| 345 | } |
||
| 346 | } else |
||
| 347 | tree->inchk[ply + 1] = 0; |
||
| 348 | /* |
||
| 349 | ************************************************************ |
||
| 350 | * * |
||
| 351 | * Step 7b. Now for the forward-pruning stuff. The idea * |
||
| 352 | * here is based on the old FUTILITY idea, where if the * |
||
| 353 | * current material + a fudge factor is lower than alpha, * |
||
| 354 | * then there is little promise in searching this move to * |
||
| 355 | * make up for the material deficit. This is not done if * |
||
| 356 | * we chose to extend this move in the previous step. * |
||
| 357 | * * |
||
| 358 | * This is a useful idea in today's 20+ ply searches, as * |
||
| 359 | * when we near the tips, if we are too far behind in * |
||
| 360 | * material, there is little time left to recover it and * |
||
| 361 | * moves that don't bring us closer to a reasonable * |
||
| 362 | * material balance can safely be skipped. It is much * |
||
| 363 | * more dangerous in shallow searches. * |
||
| 364 | * * |
||
| 365 | * We have an array of pruning margin values that are * |
||
| 366 | * indexed by depth (remaining plies left until we drop * |
||
| 367 | * into the quiescence search) and which increase with * |
||
| 368 | * depth since more depth means a greater chance of * |
||
| 369 | * bringing the score back up to alpha or beyond. If the * |
||
| 370 | * current material + the bonus is less than alpha, we * |
||
| 371 | * simply avoid searching this move at all, and skip to * |
||
| 372 | * the next move without expending any more effort. Note * |
||
| 373 | * that this is classic forward-pruning and can certainly * |
||
| 374 | * introduce errors into the search. However, cluster * |
||
| 375 | * testing has shown that this improves play in real * |
||
| 376 | * games. The current implementation only prunes in the * |
||
| 377 | * last 5 plies before quiescence, although this can be * |
||
| 378 | * tuned with the "eval" command changing the "pruning * |
||
| 379 | * depth" value to something other than 6 (test is for * |
||
| 380 | * depth < pruning depth, current value is 6 which prunes * |
||
| 381 | * in last 5 plies only). Testing shows no benefit in * |
||
| 382 | * larger values than 6, although this might change in * |
||
| 383 | * future versions as other things are modified. * |
||
| 384 | * * |
||
| 385 | * Exception: * |
||
| 386 | * * |
||
| 387 | * We do not prune if we are safely pushing a passed * |
||
| 388 | * pawn to the 6th rank, where it becomes very dangerous * |
||
| 389 | * since it can promote in two more moves. * |
||
| 390 | * * |
||
| 391 | ************************************************************ |
||
| 392 | */ |
||
| 393 | if (tree->phase[ply] == REMAINING_MOVES && !tree->inchk[ply] |
||
| 394 | && !extend && moves_searched > 1) { |
||
| 395 | if (depth < pruning_depth && |
||
| 396 | MaterialSTM(side) + pruning_margin[depth] <= alpha) { |
||
| 397 | if (Piece(tree->curmv[ply]) != pawn || |
||
| 398 | !Passed(To(tree->curmv[ply]), side) |
||
| 399 | || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { |
||
| 400 | tree->moves_fpruned++; |
||
| 401 | continue; |
||
| 402 | } |
||
| 403 | } |
||
| 404 | /* |
||
| 405 | ************************************************************ |
||
| 406 | * * |
||
| 407 | * Step 7c. Now it's time to try to reduce the search * |
||
| 408 | * depth if the move appears to be "poor". To reduce the * |
||
| 409 | * search, the following requirements must be met: * |
||
| 410 | * * |
||
| 411 | * (1) We must be in the REMAINING_MOVES part of the move * |
||
| 412 | * ordering, so that we have nearly given up on * |
||
| 413 | * failing high on any move. * |
||
| 414 | * * |
||
| 415 | * (2) We must not be too close to the horizon (this is * |
||
| 416 | * the LMR_remaining_depth value). * |
||
| 417 | * * |
||
| 418 | * (3) The current move must not be a checking move and * |
||
| 419 | * the side to move can not be in check. * |
||
| 420 | * * |
||
| 421 | ************************************************************ |
||
| 422 | */ |
||
| 423 | if (Piece(tree->curmv[ply]) != pawn || |
||
| 424 | !Passed(To(tree->curmv[ply]), side) |
||
| 425 | || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { |
||
| 426 | reduce = LMR_min_reduction; |
||
| 427 | if (moves_searched > 3) |
||
| 428 | reduce = LMR_max_reduction; |
||
| 429 | max_reduce = Max(depth - 1 - LMR_remaining_depth, 0); |
||
| 430 | if (reduce > max_reduce) |
||
| 431 | reduce = max_reduce; |
||
| 432 | if (reduce) |
||
| 433 | tree->reductions_done++; |
||
| 434 | } |
||
| 435 | } |
||
| 436 | /* |
||
| 437 | ************************************************************ |
||
| 438 | * * |
||
| 439 | * Step 7d. We have determined whether the depth is to * |
||
| 440 | * be changed by an extension or a reduction. If we get * |
||
| 441 | * to this point, then the move is not being pruned. So * |
||
| 442 | * off we go to a recursive search/quiescence call to work * |
||
| 443 | * our way toward a terminal node. * |
||
| 444 | * * |
||
| 445 | * There is one special-case to handle. If the depth was * |
||
| 446 | * reduced, and Search() returns a value >= beta then * |
||
| 447 | * accepting that is risky (we reduced the move as we * |
||
| 448 | * thought it was bad and expected it to fail low) so we * |
||
| 449 | * repeat the search using the original (non-reduced) * |
||
| 450 | * depth to see if the fail-high happens again. * |
||
| 451 | * * |
||
| 452 | ************************************************************ |
||
| 453 | */ |
||
| 454 | if (depth + extend - reduce - 1 > 0) { |
||
| 455 | value = |
||
| 456 | -Search(tree, -t_beta, -alpha, Flip(side), |
||
| 457 | depth + extend - reduce - 1, ply + 1, DO_NULL); |
||
| 458 | if (value > alpha && reduce) |
||
| 459 | value = |
||
| 460 | -Search(tree, -t_beta, -alpha, Flip(side), depth - 1, ply + 1, |
||
| 461 | DO_NULL); |
||
| 462 | } else |
||
| 463 | value = -Quiesce(tree, -t_beta, -alpha, Flip(side), ply + 1, 1); |
||
| 464 | if (abort_search || tree->stop) |
||
| 465 | break; |
||
| 466 | /* |
||
| 467 | ************************************************************ |
||
| 468 | * * |
||
| 469 | * Step 7e. This is the PVS re-search code. If we reach * |
||
| 470 | * this point and value > alpha and value < beta, then * |
||
| 471 | * this can not be a null-window search. We have to re- * |
||
| 472 | * search the position with the original beta value (not * |
||
| 473 | * alpha+1 as is the usual case in PVS) to see if it still * |
||
| 474 | * fails high before we treat this as a real fail-high and * |
||
| 475 | * back up the value to the previous ply. * |
||
| 476 | * * |
||
| 477 | * Special case: ply == 1. * |
||
| 478 | * * |
||
| 479 | * In this case, we need to clean up and then move the * |
||
| 480 | * best move to the top of the root move list, and return * |
||
| 481 | * back to Iterate() to let it produce the usual informa- * |
||
| 482 | * tive output and re-start the search with a new beta * |
||
| 483 | * value. We also reset the failhi_delta back to 16, * |
||
| 484 | * since an earlier fail-high or fail low in this * |
||
| 485 | * iteration could have left it at a large value. * |
||
| 486 | * * |
||
| 487 | * Last step is to build a usable PV in case this move * |
||
| 488 | * fails low on the re-search, because we do want to play * |
||
| 489 | * this move no matter what happens. * |
||
| 490 | * * |
||
| 491 | ************************************************************ |
||
| 492 | */ |
||
| 493 | if (value > alpha && value < beta && moves_searched > 1) { |
||
| 494 | if (ply == 1) { |
||
| 495 | alpha = value; |
||
| 496 | UnmakeMove(tree, ply, tree->curmv[ply], side); |
||
| 497 | root_beta = alpha; |
||
| 498 | failhi_delta = 16; |
||
| 499 | for (i = 0; i < n_root_moves; i++) |
||
| 500 | if (tree->curmv[1] == root_moves[i].move) |
||
| 501 | break; |
||
| 502 | if (i < n_root_moves) { |
||
| 503 | temp_rm = root_moves[i]; |
||
| 504 | for (; i > 0; i--) |
||
| 505 | root_moves[i] = root_moves[i - 1]; |
||
| 506 | root_moves[0] = temp_rm; |
||
| 507 | } |
||
| 508 | root_moves[0].bm_age = 4; |
||
| 509 | tree->pv[1].path[1] = tree->curmv[1]; |
||
| 510 | tree->pv[1].pathl = 2; |
||
| 511 | tree->pv[1].pathh = 0; |
||
| 512 | tree->pv[1].pathd = iteration_depth; |
||
| 513 | tree->pv[0] = tree->pv[1]; |
||
| 514 | return alpha; |
||
| 515 | } |
||
| 516 | if (depth + extend - 1 > 0) |
||
| 517 | value = |
||
| 518 | -Search(tree, -beta, -alpha, Flip(side), depth + extend - 1, |
||
| 519 | ply + 1, DO_NULL); |
||
| 520 | else |
||
| 521 | value = -Quiesce(tree, -beta, -alpha, Flip(side), ply + 1, 1); |
||
| 522 | if (abort_search || tree->stop) |
||
| 523 | break; |
||
| 524 | } |
||
| 525 | /* |
||
| 526 | ************************************************************ |
||
| 527 | * * |
||
| 528 | * Step 7f. We have completed the search/re-search and we * |
||
| 529 | * we have the final score. Now we need to check for a * |
||
| 530 | * fail-high which terminates this search instantly since * |
||
| 531 | * no further searching is required. On a fail high, we * |
||
| 532 | * need to update the killer moves, and hash table before * |
||
| 533 | * we return. * |
||
| 534 | * * |
||
| 535 | * If ply == 1, we call Output() which will dump the new * |
||
| 536 | * PV. But but we need to back up the PV to ply=0 so that * |
||
| 537 | * it will be available to tell main() which move to make. * |
||
| 538 | * * |
||
| 539 | ************************************************************ |
||
| 540 | */ |
||
| 541 | if (value > alpha) { |
||
| 542 | alpha = value; |
||
| 543 | if (ply == 1) { |
||
| 544 | tree->pv[1].pathv = value; |
||
| 545 | Output(tree, beta); |
||
| 546 | tree->pv[0] = tree->pv[1]; |
||
| 547 | } |
||
| 548 | if (value >= beta) { |
||
| 549 | Killer(tree, ply, tree->curmv[ply]); |
||
| 550 | UnmakeMove(tree, ply, tree->curmv[ply], side); |
||
| 551 | HashStore(tree, ply, depth, side, LOWER, value, tree->curmv[ply]); |
||
| 552 | tree->fail_highs++; |
||
| 553 | if (moves_searched == 1) |
||
| 554 | tree->fail_high_first_move++; |
||
| 555 | return value; |
||
| 556 | } |
||
| 557 | } |
||
| 558 | t_beta = alpha + 1; |
||
| 559 | } while (0); |
||
| 560 | UnmakeMove(tree, ply, tree->curmv[ply], side); |
||
| 561 | if (abort_search || tree->stop) |
||
| 562 | return 0; |
||
| 563 | /* |
||
| 564 | ************************************************************ |
||
| 565 | * * |
||
| 566 | * Step 7g. If are doing an SMP search, and we have idle * |
||
| 567 | * processors, now is the time to get them involved. We * |
||
| 568 | * have now satisfied the "young brothers wait" condition * |
||
| 569 | * since we have searched one move. All that is left is * |
||
| 570 | * to check the split constraints to see if we are an * |
||
| 571 | * acceptable split point. * |
||
| 572 | * * |
||
| 573 | * (1) We can't split within N plies of the frontier * |
||
| 574 | * nodes to avoid excessive split overhead. * |
||
| 575 | * * |
||
| 576 | * (2) We can't split until at least M nodes have been * |
||
| 577 | * searched since this thread was last split, to * |
||
| 578 | * avoid splitting too often, mainly in endgames. * |
||
| 579 | * * |
||
| 580 | * (3) We have to have searched one legal move to avoid * |
||
| 581 | * splitting at a node where we have no legal moves * |
||
| 582 | * (the first move tried might have been illegal as * |
||
| 583 | * in when we encounter a stalemate). * |
||
| 584 | * * |
||
| 585 | * (4) If we are at ply=1, we can't split unless the * |
||
| 586 | * smp_split_at_root flag is set to 1, AND the next * |
||
| 587 | * move in the ply=1 move list is not flagged as * |
||
| 588 | * "do not search in parallel" which happens when * |
||
| 589 | * this move was a best move in the last couple of * |
||
| 590 | * searches and we want all processors on it at once * |
||
| 591 | * to get a score back quicker. * |
||
| 592 | * * |
||
| 593 | * (5) if the variable smp_split is > 0, we have idle * |
||
| 594 | * threads that can help, however if smp_split < 0, * |
||
| 595 | * we are already doing a split on another thread * |
||
| 596 | * so there is no point in waiting to try one here. * |
||
| 597 | * * |
||
| 598 | * SearchParallel() primarily contains steps 7 through 7f * |
||
| 599 | * which is the main search loop. We do the final clean- * |
||
| 600 | * up below when either we finish the search normally or * |
||
| 601 | * a parallel search completes and returns to this point. * |
||
| 602 | * * |
||
| 603 | * Special case: we do not split if we are at ply=1 and * |
||
| 604 | * alpha == original_alpha. That means the first move * |
||
| 605 | * failed low, and we are going to exit search and return * |
||
| 606 | * to Iterate() to report this. * |
||
| 607 | * * |
||
| 608 | * One potential problem is that multiple threads can get * |
||
| 609 | * to this point at the same time, and they all stack up * |
||
| 610 | * waiting to grab the lock_smp lock that protects the * |
||
| 611 | * split operation. I now have a new lock, lock_split, * |
||
| 612 | * to try to limit this wasted time. A thread now has to * |
||
| 613 | * acquire that lock, and then it tests the smp_split * |
||
| 614 | * to see if a split STILL needs to be done. If not, we * |
||
| 615 | * release the lock and move on, rather than waiting on * |
||
| 616 | * main lock_smp lock. * |
||
| 617 | * * |
||
| 618 | * If we acquire the lock_split lock AND we notice that * |
||
| 619 | * smp_split is still set to 1, we quickly set smp_split * |
||
| 620 | * to zero (-1) so that other threads will bug out rather * |
||
| 621 | * than trying to split and end up in a queue behind us, * |
||
| 622 | * waiting while we split and they try to split and fail. * |
||
| 623 | * We release lock_split to eliminate the log-jam of * |
||
| 624 | * threads waiting to split and get them back into their * |
||
| 625 | * normal searches, and jump right into Thread(). * |
||
| 626 | * * |
||
| 627 | * The smp_split = -1 has a complex meaning, but simply * |
||
| 628 | * stated it means "split currently in progress". Here, * |
||
| 629 | * that means "do not attempt a split since we are already * |
||
| 630 | * in the middle of one." It also tells individual * |
||
| 631 | * threads to not change smp_split to 1 when they become * |
||
| 632 | * idle, because with a split in progress, it is likely we * |
||
| 633 | * will pick them up automatically. * |
||
| 634 | * * |
||
| 635 | ************************************************************ |
||
| 636 | */ |
||
| 637 | #if (CPUS > 1) |
||
| 638 | if (smp_split > 0 && depth >= smp_min_split_depth && moves_searched && |
||
| 639 | tree->nodes_searched - start_nodes > smp_split_nodes && (ply > 1 || |
||
| 640 | (smp_split_at_root && NextRootMoveParallel() && |
||
| 641 | alpha != original_alpha))) |
||
| 642 | do { |
||
| 643 | Lock(lock_split); |
||
| 644 | if (smp_split <= 0) { |
||
| 645 | Unlock(lock_split); |
||
| 646 | break; |
||
| 647 | } |
||
| 648 | smp_split = -1; |
||
| 649 | Unlock(lock_split); |
||
| 650 | tree->alpha = alpha; |
||
| 651 | tree->beta = beta; |
||
| 652 | tree->value = alpha; |
||
| 653 | tree->side = side; |
||
| 654 | tree->ply = ply; |
||
| 655 | tree->depth = depth; |
||
| 656 | tree->moves_searched = moves_searched; |
||
| 657 | if (Thread(tree)) { |
||
| 658 | if (abort_search || tree->stop) |
||
| 659 | return 0; |
||
| 660 | if (tree->thread_id == 0 && CheckInput()) |
||
| 661 | Interrupt(ply); |
||
| 662 | value = tree->value; |
||
| 663 | if (value > alpha) { |
||
| 664 | if (value >= beta) { |
||
| 665 | HashStore(tree, ply, depth, side, LOWER, value, tree->cutmove); |
||
| 666 | return value; |
||
| 667 | } |
||
| 668 | alpha = value; |
||
| 669 | break; |
||
| 670 | } |
||
| 671 | } |
||
| 672 | } while (0); |
||
| 673 | #endif |
||
| 674 | } |
||
| 675 | /* |
||
| 676 | ************************************************************ |
||
| 677 | * * |
||
| 678 | * Step 8. All moves have been searched. If none were * |
||
| 679 | * legal, return either MATE or DRAW depending on whether * |
||
| 680 | * the side to move is in check or not. * |
||
| 681 | * * |
||
| 682 | ************************************************************ |
||
| 683 | */ |
||
| 684 | if (abort_search || tree->stop) |
||
| 685 | return 0; |
||
| 686 | if (moves_searched == 0) { |
||
| 687 | value = (Check(side)) ? -(MATE - ply) : DrawScore(side); |
||
| 688 | if (value >= alpha && value < beta) { |
||
| 689 | SavePV(tree, ply, 0); |
||
| 690 | #if defined(TRACE) |
||
| 691 | if (ply <= trace_level) |
||
| 692 | printf("Search() no moves! ply=%d\n", ply); |
||
| 693 | #endif |
||
| 694 | } |
||
| 695 | return value; |
||
| 696 | } else { |
||
| 697 | int bestmove, type; |
||
| 698 | bestmove = |
||
| 699 | (alpha == original_alpha) ? first_tried : tree->pv[ply].path[ply]; |
||
| 700 | type = (alpha == original_alpha) ? UPPER : EXACT; |
||
| 701 | if (repeat == 2 && alpha != -(MATE - ply - 1)) { |
||
| 702 | value = DrawScore(side); |
||
| 703 | if (value < beta) |
||
| 704 | SavePV(tree, ply, 0); |
||
| 705 | #if defined(TRACE) |
||
| 706 | if (ply <= trace_level) |
||
| 707 | printf("draw by 50 move rule detected, ply=%d.\n", ply); |
||
| 708 | #endif |
||
| 709 | return value; |
||
| 710 | } else if (alpha != original_alpha) { |
||
| 711 | tree->pv[ply - 1] = tree->pv[ply]; |
||
| 712 | tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1]; |
||
| 713 | Killer(tree, ply, tree->pv[ply].path[ply]); |
||
| 714 | } |
||
| 715 | HashStore(tree, ply, depth, side, type, alpha, bestmove); |
||
| 716 | return alpha; |
||
| 717 | } |
||
| 718 | } |
||
| 719 | |||
| 720 | /* last modified 05/08/14 */ |
||
| 721 | /* |
||
| 722 | ******************************************************************************* |
||
| 723 | * * |
||
| 724 | * SearchParallel() is the recursive routine used to implement alpha/beta * |
||
| 725 | * negamax search using parallel threads. When this code is called, the * |
||
| 726 | * first move has already been searched, so all that is left is to search * |
||
| 727 | * the remainder of the moves and then return. Note that the hash table and * |
||
| 728 | * such can't be modified here since this only represents a part of the * |
||
| 729 | * search at this ply. All of that is deferred until we return and reach * |
||
| 730 | * the original instance of Search() where we have the complete results from * |
||
| 731 | * all the threads that are helping here. * |
||
| 732 | * * |
||
| 733 | ******************************************************************************* |
||
| 734 | */ |
||
| 735 | int SearchParallel(TREE * RESTRICT tree, int alpha, int beta, int value, |
||
| 736 | int side, int depth, int ply) { |
||
| 737 | ROOT_MOVE temp_rm; |
||
| 738 | int extend, reduce, max_reduce, i; |
||
| 739 | |||
| 740 | /* |
||
| 741 | ************************************************************ |
||
| 742 | * * |
||
| 743 | * Step 7. Now we continue to iterate through the move * |
||
| 744 | * list and search the resulting positions. Note that * |
||
| 745 | * SearchParallel() culls any move that is not legal by * |
||
| 746 | * using Check(). The special case mentioned in Search() * |
||
| 747 | * is not an issue here as we don't do a parallel split * |
||
| 748 | * until we have searched one legal move. * |
||
| 749 | * * |
||
| 750 | * We have three possible procedures we call here, one is * |
||
| 751 | * specific to ply=1 (NextRootMove()), the second is a * |
||
| 752 | * specific routine to escape check (NextEvasion()) and * |
||
| 753 | * the last is the normal NextMove() procedure that does * |
||
| 754 | * the usual move ordering stuff. * |
||
| 755 | * * |
||
| 756 | ************************************************************ |
||
| 757 | */ |
||
| 758 | |||
| 759 | while (1) { |
||
| 760 | Lock(tree->parent->lock); |
||
| 761 | if (ply > 1) |
||
| 762 | tree->phase[ply] = |
||
| 763 | (tree->inchk[ply]) ? NextEvasion((TREE *) tree->parent, ply, |
||
| 764 | side) : NextMove((TREE *) |
||
| 765 | tree->parent, ply, side); |
||
| 766 | else |
||
| 767 | tree->phase[ply] = NextRootMove(tree->parent, tree, side); |
||
| 768 | tree->curmv[ply] = tree->parent->curmv[ply]; |
||
| 769 | Unlock(tree->parent->lock); |
||
| 770 | if (!tree->phase[ply]) |
||
| 771 | break; |
||
| 772 | #if defined(TRACE) |
||
| 773 | if (ply <= trace_level) |
||
| 774 | Trace(tree, ply, depth, side, alpha, beta, "SearchParallel", |
||
| 775 | tree->phase[ply]); |
||
| 776 | #endif |
||
| 777 | MakeMove(tree, ply, tree->curmv[ply], side); |
||
| 778 | tree->nodes_searched++; |
||
| 779 | if (tree->inchk[ply] || !Check(side)) |
||
| 780 | do { |
||
| 781 | tree->parent->moves_searched++; |
||
| 782 | /* |
||
| 783 | ************************************************************ |
||
| 784 | * * |
||
| 785 | * Step 7a. If the move to be made checks the opponent, * |
||
| 786 | * then we need to remember that he's in check and also * |
||
| 787 | * extend the depth by one ply for him to get out. Note * |
||
| 788 | * that if the move gives check, it is not a candidate for * |
||
| 789 | * either depth reduction or forward-pruning. * |
||
| 790 | * * |
||
| 791 | * We do not extend unsafe checking moves (as indicated by * |
||
| 792 | * Swap(), a SEE algorithm, since these are usually a * |
||
| 793 | * waste of time and simply blow up the tree search space. * |
||
| 794 | * * |
||
| 795 | ************************************************************ |
||
| 796 | */ |
||
| 797 | extend = 0; |
||
| 798 | reduce = 0; |
||
| 799 | if (Check(Flip(side))) { |
||
| 800 | tree->inchk[ply + 1] = 1; |
||
| 801 | if (SwapO(tree, tree->curmv[ply], side) <= 0) { |
||
| 802 | extend = check_depth; |
||
| 803 | tree->extensions_done++; |
||
| 804 | } |
||
| 805 | } else |
||
| 806 | tree->inchk[ply + 1] = 0; |
||
| 807 | /* |
||
| 808 | ************************************************************ |
||
| 809 | * * |
||
| 810 | * Step 7b. Now for the forward-pruning stuff. The idea * |
||
| 811 | * here is based on the old FUTILITY idea, where if the * |
||
| 812 | * current material + a fudge factor is lower than alpha, * |
||
| 813 | * then there is little promise in searching this move to * |
||
| 814 | * make up for the material deficit. This is not done if * |
||
| 815 | * we chose to extend this move in the previous step. * |
||
| 816 | * * |
||
| 817 | * This is a useful idea in today's 20+ ply searches, as * |
||
| 818 | * when we near the tips, if we are too far behind in * |
||
| 819 | * material, there is little time left to recover it and * |
||
| 820 | * moves that don't bring us closer to a reasonable * |
||
| 821 | * material balance can safely be skipped. It is much * |
||
| 822 | * more dangerous in shallow searches. * |
||
| 823 | * * |
||
| 824 | * We have an array of pruning margin values that are * |
||
| 825 | * indexed by depth (remaining plies left until we drop * |
||
| 826 | * into the quiescence search) and which increase with * |
||
| 827 | * depth since more depth means a greater chance of * |
||
| 828 | * bringing the score back up to alpha or beyond. If the * |
||
| 829 | * current material + the bonus is less than alpha, we * |
||
| 830 | * simply avoid searching this move at all, and skip to * |
||
| 831 | * the next move without expending any more effort. Note * |
||
| 832 | * that this is classic forward-pruning and can certainly * |
||
| 833 | * introduce errors into the search. However, cluster * |
||
| 834 | * testing has shown that this improves play in real * |
||
| 835 | * games. The current implementation only prunes in the * |
||
| 836 | * last 5 plies before quiescence, although this can be * |
||
| 837 | * tuned with the "eval" command changing the "pruning * |
||
| 838 | * depth" value to something other than 6 (test is for * |
||
| 839 | * depth < pruning depth, current value is 6 which prunes * |
||
| 840 | * in last 5 plies only). Testing shows no benefit in * |
||
| 841 | * larger values than 6, although this might change in * |
||
| 842 | * future versions as other things are modified. * |
||
| 843 | * * |
||
| 844 | * Exception: * |
||
| 845 | * * |
||
| 846 | * We do not prune if we are safely pushing a passed * |
||
| 847 | * pawn to the 6th rank, where it becomes very dangerous * |
||
| 848 | * since it can promote in two more moves. * |
||
| 849 | * * |
||
| 850 | ************************************************************ |
||
| 851 | */ |
||
| 852 | if (tree->phase[ply] == REMAINING_MOVES && !tree->inchk[ply] |
||
| 853 | && !extend && tree->parent->moves_searched > 1) { |
||
| 854 | if (depth < pruning_depth && |
||
| 855 | MaterialSTM(side) + pruning_margin[depth] <= alpha) { |
||
| 856 | if (Piece(tree->curmv[ply]) != pawn || |
||
| 857 | !Passed(To(tree->curmv[ply]), side) |
||
| 858 | || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { |
||
| 859 | tree->moves_fpruned++; |
||
| 860 | continue; |
||
| 861 | } |
||
| 862 | } |
||
| 863 | /* |
||
| 864 | ************************************************************ |
||
| 865 | * * |
||
| 866 | * Step 7c. Now it's time to try to reduce the search * |
||
| 867 | * depth if the move appears to be "poor". To reduce the * |
||
| 868 | * search, the following requirements must be met: * |
||
| 869 | * * |
||
| 870 | * (1) We must be in the REMAINING_MOVES part of the move * |
||
| 871 | * ordering, so that we have nearly given up on * |
||
| 872 | * failing high on any move. * |
||
| 873 | * * |
||
| 874 | * (2) We must not be too close to the horizon (this is * |
||
| 875 | * the LMR_remaining_depth value). * |
||
| 876 | * * |
||
| 877 | * (3) The current move must not be a checking move and * |
||
| 878 | * the side to move can not be in check. * |
||
| 879 | * * |
||
| 880 | ************************************************************ |
||
| 881 | */ |
||
| 882 | if (Piece(tree->curmv[ply]) != pawn || |
||
| 883 | !Passed(To(tree->curmv[ply]), side) |
||
| 884 | || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) { |
||
| 885 | reduce = LMR_min_reduction; |
||
| 886 | if (tree->parent->moves_searched > 3) |
||
| 887 | reduce = LMR_max_reduction; |
||
| 888 | max_reduce = Max(depth - 1 - LMR_remaining_depth, 0); |
||
| 889 | if (reduce > max_reduce) |
||
| 890 | reduce = max_reduce; |
||
| 891 | if (reduce) |
||
| 892 | tree->reductions_done++; |
||
| 893 | } |
||
| 894 | } |
||
| 895 | /* |
||
| 896 | ************************************************************ |
||
| 897 | * * |
||
| 898 | * Step 7d. We have determined whether the depth is to * |
||
| 899 | * be changed by an extension or a reduction. If we get * |
||
| 900 | * to this point, then the move is not being pruned. So * |
||
| 901 | * off we go to a recursive search/quiescence call to work * |
||
| 902 | * our way toward a terminal node. * |
||
| 903 | * * |
||
| 904 | * There is one special-cases to handle. If the depth was * |
||
| 905 | * reduced, and Search() returns a value >= beta then * |
||
| 906 | * accepting that is risky (we reduced the move as we * |
||
| 907 | * thought it was bad and expected it to fail low) so we * |
||
| 908 | * repeat the search using the original (non-reduced) * |
||
| 909 | * depth to see if the fail-high happens again. * |
||
| 910 | * * |
||
| 911 | ************************************************************ |
||
| 912 | */ |
||
| 913 | if (depth + extend - reduce - 1 > 0) { |
||
| 914 | value = |
||
| 915 | -Search(tree, -alpha - 1, -alpha, Flip(side), |
||
| 916 | depth + extend - reduce - 1, ply + 1, DO_NULL); |
||
| 917 | if (value > alpha && reduce) |
||
| 918 | value = |
||
| 919 | -Search(tree, -alpha - 1, -alpha, Flip(side), depth - 1, |
||
| 920 | ply + 1, DO_NULL); |
||
| 921 | } else |
||
| 922 | value = -Quiesce(tree, -alpha - 1, -alpha, Flip(side), ply + 1, 1); |
||
| 923 | if (abort_search || tree->stop) |
||
| 924 | break; |
||
| 925 | /* |
||
| 926 | ************************************************************ |
||
| 927 | * * |
||
| 928 | * Step 7e. This is the PVS re-search code. If we reach * |
||
| 929 | * this point and value > alpha and value < beta, then * |
||
| 930 | * this can not be a null-window search. We have to re- * |
||
| 931 | * search the position with the original beta value (not * |
||
| 932 | * alpha+1 as is the usual case in PVS) to see if it still * |
||
| 933 | * fails high before we treat this as a real fail-high and * |
||
| 934 | * back up the value to the previous ply. * |
||
| 935 | * * |
||
| 936 | * Special case: ply == 1. * |
||
| 937 | * * |
||
| 938 | * In this case, we need to clean up and then move the * |
||
| 939 | * best move to the top of the root move list, and then * |
||
| 940 | * return back to the normal Search(), which will then * |
||
| 941 | * return back to Iterate() to let it produce the usual * |
||
| 942 | * informative output and re-start the search with a new * |
||
| 943 | * beta value. We also reset the failhi_delta back to 16, * |
||
| 944 | * since an earlier fail-high or fail low in this * |
||
| 945 | * iteration could have left it at a large value. * |
||
| 946 | * * |
||
| 947 | * Last step is to build a usable PV in case this move * |
||
| 948 | * fails low on the re-search, because we do want to play * |
||
| 949 | * this move no matter what happens. * |
||
| 950 | * * |
||
| 951 | ************************************************************ |
||
| 952 | */ |
||
| 953 | if (value > alpha && value < beta) { |
||
| 954 | if (ply == 1) { |
||
| 955 | int proc; |
||
| 956 | |||
| 957 | alpha = value; |
||
| 958 | parallel_aborts++; |
||
| 959 | UnmakeMove(tree, ply, tree->curmv[ply], side); |
||
| 960 | Lock(lock_smp); |
||
| 961 | Lock(tree->parent->lock); |
||
| 962 | if (!tree->stop) { |
||
| 963 | for (proc = 0; proc < smp_max_threads; proc++) |
||
| 964 | if (tree->parent->siblings[proc] && proc != tree->thread_id) |
||
| 965 | ThreadStop(tree->parent->siblings[proc]); |
||
| 966 | root_beta = alpha; |
||
| 967 | failhi_delta = 16; |
||
| 968 | Lock(lock_root); |
||
| 969 | for (i = 0; i < n_root_moves; i++) |
||
| 970 | if (tree->curmv[1] == root_moves[i].move) |
||
| 971 | break; |
||
| 972 | if (i < n_root_moves) { |
||
| 973 | temp_rm = root_moves[i]; |
||
| 974 | for (; i > 0; i--) |
||
| 975 | root_moves[i] = root_moves[i - 1]; |
||
| 976 | root_moves[0] = temp_rm; |
||
| 977 | } |
||
| 978 | root_moves[0].bm_age = 4; |
||
| 979 | Unlock(lock_root); |
||
| 980 | tree->pv[1].path[1] = tree->curmv[1]; |
||
| 981 | tree->pv[1].pathl = 2; |
||
| 982 | tree->pv[1].pathh = 0; |
||
| 983 | tree->pv[1].pathd = iteration_depth; |
||
| 984 | tree->pv[0] = tree->pv[1]; |
||
| 985 | } |
||
| 986 | Unlock(tree->parent->lock); |
||
| 987 | Unlock(lock_smp); |
||
| 988 | return alpha; |
||
| 989 | } |
||
| 990 | if (depth + extend - 1 > 0) |
||
| 991 | value = |
||
| 992 | -Search(tree, -beta, -alpha, Flip(side), depth + extend - 1, |
||
| 993 | ply + 1, DO_NULL); |
||
| 994 | else |
||
| 995 | value = -Quiesce(tree, -beta, -alpha, Flip(side), ply + 1, 1); |
||
| 996 | if (abort_search || tree->stop) |
||
| 997 | break; |
||
| 998 | } |
||
| 999 | /* |
||
| 1000 | ************************************************************ |
||
| 1001 | * * |
||
| 1002 | * Step 7f. We have completed the search/re-search and we * |
||
| 1003 | * we have the final score. Now we need to check for a * |
||
| 1004 | * fail-high which terminates this search instantly since * |
||
| 1005 | * no further searching is required. On a fail high, we * |
||
| 1006 | * need to update the killer moves, and hash table before * |
||
| 1007 | * we return. * |
||
| 1008 | * * |
||
| 1009 | * Note that we can not produce a new PV here. At best, * |
||
| 1010 | * we can produce a fail-high which will abort other * |
||
| 1011 | * threads at this node (wasting time). * |
||
| 1012 | * * |
||
| 1013 | * Special case: If ply == 1, and we fail high on the * |
||
| 1014 | * null-window search, we simply abort the search and then * |
||
| 1015 | * return to the normal search, which will back us out to * |
||
| 1016 | * Iterate() and inform the user and re-start the search. * |
||
| 1017 | * * |
||
| 1018 | * We then stop all threads (except the current thread * |
||
| 1019 | * that is dealing with the fail high) since we are going * |
||
| 1020 | * to back out quickly and then start a new search from * |
||
| 1021 | * the root position. The split-block sibling ids lets us * |
||
| 1022 | * know which threads should be stopped, and since we are * |
||
| 1023 | * at the root (ply == 1) that essentially means "all * |
||
| 1024 | * threads except for this one." * |
||
| 1025 | * * |
||
| 1026 | ************************************************************ |
||
| 1027 | */ |
||
| 1028 | if (value > alpha) { |
||
| 1029 | alpha = value; |
||
| 1030 | if (value >= beta) { |
||
| 1031 | int proc; |
||
| 1032 | |||
| 1033 | parallel_aborts++; |
||
| 1034 | UnmakeMove(tree, ply, tree->curmv[ply], side); |
||
| 1035 | Lock(lock_smp); |
||
| 1036 | Lock(tree->parent->lock); |
||
| 1037 | if (!tree->stop) |
||
| 1038 | for (proc = 0; proc < smp_max_threads; proc++) |
||
| 1039 | if (tree->parent->siblings[proc] && proc != tree->thread_id) |
||
| 1040 | ThreadStop(tree->parent->siblings[proc]); |
||
| 1041 | Unlock(tree->parent->lock); |
||
| 1042 | Unlock(lock_smp); |
||
| 1043 | return alpha; |
||
| 1044 | } |
||
| 1045 | } |
||
| 1046 | } while (0); |
||
| 1047 | UnmakeMove(tree, ply, tree->curmv[ply], side); |
||
| 1048 | if (abort_search || tree->stop) |
||
| 1049 | break; |
||
| 1050 | } |
||
| 1051 | /* |
||
| 1052 | ************************************************************ |
||
| 1053 | * * |
||
| 1054 | * Step 8. We are doing an SMP search, so there are no * |
||
| 1055 | * "end-of-search" things to do. We have searched all the * |
||
| 1056 | * remaining moves at this ply in parallel, and now return * |
||
| 1057 | * and let the original search that started this sub-tree) * |
||
| 1058 | * clean up, and do the tests for mate/stalemate, update * |
||
| 1059 | * the hash table, etc. * |
||
| 1060 | * * |
||
| 1061 | * As we return, we end back up in Thread() where we * |
||
| 1062 | * started, which then copies the best score/etc back to * |
||
| 1063 | * the parent thread. * |
||
| 1064 | * * |
||
| 1065 | * We do need to flag the root move we tried to search, if * |
||
| 1066 | * we were stopped early due to another root move failing * |
||
| 1067 | * high. Otherwise this move appears to have been * |
||
| 1068 | * searched already and will not be searched again until * |
||
| 1069 | * the next iteration. * |
||
| 1070 | * * |
||
| 1071 | ************************************************************ |
||
| 1072 | */ |
||
| 1073 | if (tree->stop && ply == 1) { |
||
| 1074 | int which; |
||
| 1075 | |||
| 1076 | Lock(lock_root); |
||
| 1077 | for (which = 0; which < n_root_moves; which++) |
||
| 1078 | if (root_moves[which].move == tree->curmv[ply]) { |
||
| 1079 | root_moves[which].status &= 0xf7; |
||
| 1080 | break; |
||
| 1081 | } |
||
| 1082 | Unlock(lock_root); |
||
| 1083 | } |
||
| 1084 | return alpha; |
||
| 1085 | } |