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