Rev 33 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 33 | Rev 108 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | #include "chess.h" |
1 | #include "chess.h" |
2 | #include "data.h" |
2 | #include "data.h" |
3 | /* last modified |
3 | /* last modified 01/10/16 */ |
4 | /* |
4 | /* |
5 | ******************************************************************************* |
5 | ******************************************************************************* |
6 | * * |
6 | * * |
7 | * Search() is the recursive routine used to implement the alpha/beta * |
7 | * Search() is the recursive routine used to implement the alpha/beta * |
8 | * negamax search (similar to minimax but simpler to code.) Search() is * |
8 | * negamax search (similar to minimax but simpler to code.) Search() is * |
Line 10... | Line 10... | ||
10 | * to searching. Search() recursively calls itself so long as there is at * |
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. * |
11 | * least one ply of depth left, otherwise it calls Quiesce() instead. * |
12 | * * |
12 | * * |
13 | ******************************************************************************* |
13 | ******************************************************************************* |
14 | */ |
14 | */ |
15 | int Search(TREE * RESTRICT tree, int |
15 | int Search(TREE * RESTRICT tree, int ply, int depth, int wtm, int alpha, |
16 | int |
16 | int beta, int in_check, 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 |
17 | int repeat = 0, value = 0, pv_node = alpha != beta - 1, n_depth; |
21 | int extend, reduce, max_reduce, i; |
- | |
22 | int |
18 | int searched[256]; |
23 | 19 | ||
24 | /* |
20 | /* |
25 | ************************************************************ |
21 | ************************************************************ |
26 | * * |
22 | * * |
27 | * |
23 | * Timeout. Check to see if we have searched enough nodes * |
28 | * that it is time to peek at how much time has been used, * |
24 | * that it is time to peek at how much time has been used, * |
29 | * or if is time to check for operator keyboard input. * |
25 | * or if is time to check for operator keyboard input. * |
30 | * This is usually enough nodes to force a time/input * |
26 | * This is usually enough nodes to force a time/input * |
31 | * check about once per second, except when the target * |
27 | * check about once per second, except when the target * |
32 | * time per move is very small, in which case we try to * |
28 | * time per move is very small, in which case we try to * |
Line 37... | Line 33... | ||
37 | * race conditions. * |
33 | * race conditions. * |
38 | * * |
34 | * * |
39 | ************************************************************ |
35 | ************************************************************ |
40 | */ |
36 | */ |
41 | #if defined(NODES) |
37 | #if defined(NODES) |
42 | if (--temp_search_nodes <= 0) { |
38 | if (search_nodes && --temp_search_nodes <= 0) { |
43 | abort_search = 1; |
39 | abort_search = 1; |
44 | return 0; |
40 | return 0; |
45 | } |
41 | } |
46 | #endif |
42 | #endif |
47 | if (tree->thread_id == 0) { |
43 | if (tree->thread_id == 0) { |
Line 61... | Line 57... | ||
61 | if (ply >= MAXPLY - 1) |
57 | if (ply >= MAXPLY - 1) |
62 | return beta; |
58 | return beta; |
63 | /* |
59 | /* |
64 | ************************************************************ |
60 | ************************************************************ |
65 | * * |
61 | * * |
66 | * |
62 | * Draws. Check for draw by repetition, which includes * |
67 | * 50 move draws also. This is the quickest way to get * |
63 | * 50 move draws also. This is the quickest way to get * |
68 | * out of further searching, with minimal effort. This * |
64 | * out of further searching, with minimal effort. This * |
69 | * and the next |
65 | * and the next four steps are skipped for moves at the * |
70 | * root (ply = 1). * |
66 | * root (ply = 1). * |
71 | * * |
67 | * * |
72 | ************************************************************ |
68 | ************************************************************ |
73 | */ |
69 | */ |
74 | if (ply > 1) { |
70 | if (ply > 1) { |
75 | if ((repeat = Repeat(tree, ply))) { |
71 | if ((repeat = Repeat(tree, ply))) { |
- | 72 | if (repeat == 1 || !in_check) { |
|
76 | value = DrawScore( |
73 | value = DrawScore(wtm); |
77 | if (value < beta) |
74 | if (value < beta) |
78 | SavePV(tree, ply, |
75 | SavePV(tree, ply, 3); |
79 | #if defined(TRACE) |
76 | #if defined(TRACE) |
80 | if (ply <= trace_level) |
77 | if (ply <= trace_level) |
81 | printf("draw by repetition detected, ply=%d.\n", ply); |
78 | printf("draw by repetition detected, ply=%d.\n", ply); |
82 | #endif |
79 | #endif |
83 | return value; |
80 | return value; |
- | 81 | } |
|
84 | } |
82 | } |
85 | /* |
83 | /* |
86 | ************************************************************ |
84 | ************************************************************ |
87 | * * |
85 | * * |
- | 86 | * Mate distance pruning. If we have found a mate, we can * |
|
- | 87 | * stop if we are too deep to find a shorter mate. This * |
|
- | 88 | * only affects the size of the tree in positions where * |
|
- | 89 | * there are forced mates. It does not change the outcome * |
|
- | 90 | * of the search at all, just the time it takes. * |
|
- | 91 | * * |
|
- | 92 | ************************************************************ |
|
- | 93 | */ |
|
- | 94 | alpha = Max(alpha, -MATE + ply - 1); |
|
- | 95 | beta = Min(beta, MATE - ply); |
|
- | 96 | if (alpha >= beta) |
|
- | 97 | return alpha; |
|
- | 98 | /* |
|
- | 99 | ************************************************************ |
|
- | 100 | * * |
|
88 | * |
101 | * Trans/Ref. Check the transposition/refutation (hash) * |
89 | * table to see if we have searched this position * |
102 | * table to see if we have searched this position * |
90 | * previously and still have the results available. We * |
103 | * previously and still have the results available. We * |
91 | * might get a real score, or a bound, or perhaps only a * |
104 | * might get a real score, or a bound, or perhaps only a * |
92 | * good move to try first. The possible results are: * |
105 | * good move to try first. The possible results are: * |
93 | * * |
106 | * * |
94 | * 1. HashProbe() returns "HASH_HIT". This terminates |
107 | * 1. HashProbe() returns "HASH_HIT". This terminates the * |
95 | * |
108 | * search instantly and we simply return the value found * |
96 | * |
109 | * in the hash table. This value is simply the value we * |
97 | * |
110 | * found when we did a real search in this position * |
98 | * |
111 | * previously, and ProbeTransRef() verifies that the value * |
99 | * |
112 | * is useful based on draft and current bounds. * |
100 | * * |
113 | * * |
101 | * 2. HashProbe() returns "AVOID_NULL_MOVE" which means * |
114 | * 2. HashProbe() returns "AVOID_NULL_MOVE" which means * |
102 | * the hashed score/bound was no good, but it indicated * |
115 | * the hashed score/bound was no good, but it indicated * |
103 | * that trying a null-move in this position would be a * |
116 | * that trying a null-move in this position would be a * |
104 | * waste of time since it will likely fail low, not high. * |
117 | * waste of time since it will likely fail low, not high. * |
105 | * * |
118 | * * |
106 | * 3. HashProbe() returns "HASH_MISS" when forces us to |
119 | * 3. HashProbe() returns "HASH_MISS" when forces us to do * |
107 | * |
120 | * a normal search to resolve this node. * |
108 | * * |
121 | * * |
109 | ************************************************************ |
122 | ************************************************************ |
110 | */ |
123 | */ |
111 | switch (HashProbe(tree, ply, depth, |
124 | switch (HashProbe(tree, ply, depth, wtm, alpha, beta, &value)) { |
112 | case HASH_HIT: |
125 | case HASH_HIT: |
113 | return value; |
126 | return value; |
114 | case AVOID_NULL_MOVE: |
127 | case AVOID_NULL_MOVE: |
115 | do_null = 0; |
128 | do_null = 0; |
116 | case HASH_MISS: |
129 | case HASH_MISS: |
117 | break; |
130 | break; |
118 | } |
131 | } |
119 | /* |
132 | /* |
120 | ************************************************************ |
133 | ************************************************************ |
121 | * * |
134 | * * |
122 | * |
135 | * EGTBs. Now it's time to try a probe into the endgame * |
123 | * tablebase files. This is done if we notice that there * |
136 | * tablebase files. This is done if we notice that there * |
124 | * are 6 or fewer pieces left on the board |
137 | * are 6 or fewer pieces left on the board AND the move at * |
- | 138 | * the previous ply was a capture. If it was not, then we * |
|
- | 139 | * would have already probed the EGTBs so if it was a miss * |
|
- | 140 | * when we probed then, it will also miss here. EGTB_use * |
|
125 | * tells us how many pieces to probe on. Note that this * |
141 | * tells us how many pieces to probe on. Note that this * |
126 | * can be zero when trying to swindle the opponent, so * |
142 | * can be zero when trying to swindle the opponent, so * |
127 | * that no probes are done since we know it is a draw. * |
143 | * that no probes are done since we know it is a draw. * |
128 | * This is another way to get out of the search quickly, * |
144 | * This is another way to get out of the search quickly, * |
129 | * but not as quickly as the previous steps since this can * |
145 | * but not as quickly as the previous steps since this can * |
Line 145... | Line 161... | ||
145 | * a mistake and convert the draw to a loss. * |
161 | * a mistake and convert the draw to a loss. * |
146 | * * |
162 | * * |
147 | ************************************************************ |
163 | ************************************************************ |
148 | */ |
164 | */ |
149 | #if !defined(NOEGTB) |
165 | #if !defined(NOEGTB) |
150 | if (depth > |
166 | if (depth > EGTB_depth && TotalAllPieces <= EGTB_use && |
151 | Castle(ply, white) |
167 | !Castle(ply, white) && !Castle(ply, black) && |
152 | ( |
168 | (Captured(tree->curmv[ply - 1]) || ply < 3)) { |
153 | int egtb_value; |
169 | int egtb_value; |
154 | 170 | ||
155 | tree->egtb_probes++; |
171 | tree->egtb_probes++; |
156 | if (EGTBProbe(tree, ply, |
172 | if (EGTBProbe(tree, ply, wtm, &egtb_value)) { |
157 | tree-> |
173 | tree->egtb_hits++; |
158 | alpha = egtb_value; |
174 | alpha = egtb_value; |
159 | if (MateScore(alpha)) |
175 | if (MateScore(alpha)) |
160 | alpha += (alpha > 0) ? -ply + 1 : ply; |
176 | alpha += (alpha > 0) ? -ply + 1 : ply; |
161 | else if (alpha == 0) { |
177 | else if (alpha == 0) { |
162 | alpha = DrawScore( |
178 | alpha = DrawScore(wtm); |
163 | if ( |
179 | if (MaterialSTM(wtm) > 0) |
164 | alpha += |
180 | alpha += 1; |
165 | else if ( |
181 | else if (MaterialSTM(wtm) < 0) |
166 | alpha -= |
182 | alpha -= 1; |
167 | } |
183 | } |
168 | if (alpha < beta) |
184 | if (alpha < beta) |
169 | SavePV(tree, ply, 2); |
185 | SavePV(tree, ply, 2); |
170 | return alpha; |
186 | return alpha; |
171 | } |
187 | } |
172 | } |
188 | } |
173 | #endif |
189 | #endif |
174 | /* |
190 | /* |
175 | ************************************************************ |
191 | ************************************************************ |
176 | * * |
192 | * * |
177 | * |
193 | * Null-move. We now know there is no quick way to get * |
178 | * of here, which leaves one more possibility, |
194 | * out of here, which leaves one more possibility, * |
179 | * |
195 | * although it does require a search, but to a reduced * |
180 | * |
196 | * depth. We try a null move to see if we can get a quick * |
181 | * with only a little work. This operates as |
197 | * cutoff with only a little work. This operates as * |
182 | * Instead of making a legal move, the side on |
198 | * follows. Instead of making a legal move, the side on * |
183 | * and does nothing. The resulting position |
199 | * move passes and does nothing. The resulting position * |
184 | * to a shallower depth than normal ( |
200 | * is searched to a shallower depth than normal (see * |
185 | * |
201 | * below). This will result in a cutoff if our position * |
186 | * |
202 | * is very good, but it produces the cutoff much quicker * |
187 | * |
203 | * since the search is far shallower than a normal search * |
188 | * |
204 | * that would also be likely to fail high. * |
- | 205 | * * |
|
- | 206 | * The reduction amount starts off at null_depth (normally * |
|
- | 207 | * set to 3 but the user can change this via the crafty * |
|
- | 208 | * personality command) but is then increased as follows: * |
|
- | 209 | * * |
|
- | 210 | * R = null_depth + depth / null_divisor * |
|
189 | * |
211 | * * |
- | 212 | * null_divisor defaults to 6, but this can also be set * |
|
- | 213 | * by the user to try more/less aggressive settings. * |
|
190 | * * |
214 | * * |
191 | * This is skipped for any of the following reasons: * |
215 | * This is skipped for any of the following reasons: * |
192 | * * |
216 | * * |
193 | * 1. |
217 | * 1. The side on move is in check. The null move * |
194 | * |
218 | * results in an illegal position. * |
195 | * 2. |
219 | * 2. No more than one null move can appear in succession * |
196 | * |
220 | * as all this does is burn 2x plies of depth. * |
197 | * 3. |
221 | * 3. The side on move has only pawns left, which makes * |
198 | * |
222 | * zugzwang positions more likely. * |
199 | * 4. |
223 | * 4. The transposition table probe found an entry that * |
200 | * |
224 | * indicates that a null-move search will not fail * |
201 | * |
225 | * high, so we avoid the wasted effort. * |
202 | * * |
226 | * * |
203 | ************************************************************ |
227 | ************************************************************ |
204 | */ |
228 | */ |
205 | tree->inchk[ply + 1] = 0; |
- | |
- | 229 | ||
206 | tree->last[ply] = tree->last[ply - 1]; |
230 | tree->last[ply] = tree->last[ply - 1]; |
- | 231 | n_depth = (TotalPieces(wtm, occupied) > 9 || n_root_moves > 17 || |
|
- | 232 | depth > 3) ? 1 : 3; |
|
207 | if (do_null && !pv_node && depth > |
233 | if (do_null && !pv_node && depth > n_depth && !in_check && |
208 |
|
234 | TotalPieces(wtm, occupied)) { |
209 | uint64_t save_hash_key; |
235 | uint64_t save_hash_key; |
- | 236 | int R = null_depth + depth / null_divisor; |
|
210 | 237 | ||
211 | tree->curmv[ply] = 0; |
238 | tree->curmv[ply] = 0; |
212 | tree->phase[ply] = NULL_MOVE; |
- | |
213 | #if defined(TRACE) |
239 | #if defined(TRACE) |
214 | if (ply <= trace_level) |
240 | if (ply <= trace_level) |
215 | Trace(tree, ply, depth, |
241 | Trace(tree, ply, depth, wtm, value - 1, value, "SearchNull", serial, |
- | 242 | NULL_MOVE, 0); |
|
216 | #endif |
243 | #endif |
217 | tree->status[ply + 1] = tree->status[ply]; |
244 | tree->status[ply + 1] = tree->status[ply]; |
218 | Reversible(ply + 1) = 0; |
245 | Reversible(ply + 1) = 0; |
219 | save_hash_key = HashKey; |
246 | save_hash_key = HashKey; |
220 | if (EnPassant(ply + 1)) { |
247 | if (EnPassant(ply + 1)) { |
221 | HashEP(EnPassant(ply + 1)); |
248 | HashEP(EnPassant(ply + 1)); |
222 | EnPassant(ply + 1) = 0; |
249 | EnPassant(ply + 1) = 0; |
223 | } |
250 | } |
- | 251 | tree->null_done[Min(R, 15)]++; |
|
224 | if (depth - |
252 | if (depth - R - 1 > 0) |
225 | value = |
253 | value = |
226 | -Search(tree, |
254 | -Search(tree, ply + 1, depth - R - 1, Flip(wtm), -beta, -beta + 1, |
227 |
|
255 | 0, NO_NULL); |
228 | else |
256 | else |
229 | value = -Quiesce(tree, |
257 | value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -beta + 1, 1); |
230 | HashKey = save_hash_key; |
258 | HashKey = save_hash_key; |
231 | if (abort_search || tree->stop) |
259 | if (abort_search || tree->stop) |
232 | return 0; |
260 | return 0; |
233 | if (value >= beta) { |
261 | if (value >= beta) { |
234 | HashStore(tree, ply, depth, |
262 | HashStore(tree, ply, depth, wtm, LOWER, value, tree->hash_move[ply]); |
235 | return value; |
263 | return value; |
236 | } |
264 | } |
237 | } |
265 | } |
238 | /* |
266 | /* |
239 | ************************************************************ |
267 | ************************************************************ |
240 | * * |
268 | * * |
241 | * |
269 | * IID. This step is rarely executed. It is used when * |
242 | * there is no best move from the hash table, and this is * |
270 | * 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. * |
271 | * a PV node, since we need a good move to search first. * |
244 | * While killers moves are good, they are not quite good * |
272 | * While killers moves are good, they are not quite good * |
245 | * enough. the simplest solution is to try a shallow * |
273 | * enough. the simplest solution is to try a shallow * |
246 | * search (depth-2) to get a move. note that when we call * |
274 | * search (depth-2) to get a move. note that when we call * |
Line 248... | Line 276... | ||
248 | * move, and will therefore recursively continue this * |
276 | * move, and will therefore recursively continue this * |
249 | * process, hence the name "internal iterative deepening." * |
277 | * process, hence the name "internal iterative deepening." * |
250 | * * |
278 | * * |
251 | ************************************************************ |
279 | ************************************************************ |
252 | */ |
280 | */ |
253 | tree->next_status[ply].phase = |
281 | tree->next_status[ply].phase = HASH; |
254 | if (!tree->hash_move[ply] && depth >= 6 && do_null && ply > 1) { |
282 | if (!tree->hash_move[ply] && depth >= 6 && do_null && ply > 1 && pv_node) { |
255 | if (pv_node) { |
- | |
256 | do { |
- | |
257 |
|
283 | tree->curmv[ply] = 0; |
258 |
|
284 | if (depth - 2 > 0) |
- | 285 | value = |
|
259 |
|
286 | Search(tree, ply, depth - 2, wtm, alpha, beta, in_check, DO_NULL); |
260 |
|
287 | else |
261 |
|
288 | value = Quiesce(tree, ply, wtm, alpha, beta, 1); |
262 |
|
289 | if (abort_search || tree->stop) |
263 |
|
290 | return 0; |
264 |
|
291 | if (value > alpha) { |
265 |
|
292 | if (value < beta) { |
266 |
|
293 | if ((int) tree->pv[ply - 1].pathl > ply) |
267 |
|
294 | tree->hash_move[ply] = tree->pv[ply - 1].path[ply]; |
268 |
|
295 | } else |
269 |
|
296 | tree->hash_move[ply] = tree->curmv[ply]; |
270 |
|
297 | tree->last[ply] = tree->last[ply - 1]; |
271 |
|
298 | tree->next_status[ply].phase = HASH; |
272 | } |
- | |
273 | } while (0); |
- | |
274 | } |
299 | } |
275 | } |
300 | } |
276 | } |
301 | } |
277 | /* |
302 | /* |
278 | ************************************************************ |
303 | ************************************************************ |
279 | * * |
304 | * * |
- | 305 | * Search moves. Now we call SearchMoveList() to interate * |
|
- | 306 | * through the move list and search each new position. * |
|
- | 307 | * Note that this is done in a separate procedure because * |
|
- | 308 | * this is also the code that is used to do the parallel * |
|
- | 309 | * search. * |
|
- | 310 | * * |
|
- | 311 | ************************************************************ |
|
- | 312 | */ |
|
- | 313 | searched[0] = 0; |
|
- | 314 | value = |
|
- | 315 | SearchMoveList(tree, ply, depth, wtm, alpha, beta, searched, in_check, |
|
- | 316 | repeat, serial); |
|
- | 317 | return value; |
|
- | 318 | } |
|
- | 319 | ||
- | 320 | /* last modified 09/28/15 */ |
|
- | 321 | /* |
|
- | 322 | ******************************************************************************* |
|
- | 323 | * * |
|
- | 324 | * SearchMoveList() is the recursive routine used to implement the main * |
|
- | 325 | * search loop. This code is responsible for iterating through the move * |
|
- | 326 | * list until it encounters a condition that ends the search at this ply. * |
|
- | 327 | * At that point it simply returns the current negamax value to the caller * |
|
- | 328 | * to handle as necessary. * |
|
- | 329 | * * |
|
- | 330 | * The "mode" flag indicates which of the following conditions apply here * |
|
- | 331 | * which directly controls parts of the search. * |
|
- | 332 | * * |
|
- | 333 | * mode = serial -> this is a serial search. * |
|
- | 334 | * * |
|
- | 335 | * mode = parallel -> this is a parallel search, which implies that this * |
|
- | 336 | * is a partial search which means we do NOT want to * |
|
- | 337 | * do any trans/ref updating and we also need to take * |
|
- | 338 | * care about locking things that are being updated * |
|
- | 339 | * by more than one thread in parallel. * |
|
- | 340 | * * |
|
- | 341 | * When mode = parallel, this code performs the same function as the old * |
|
- | 342 | * SearchParallel() code, except that it is the main search loop for the * |
|
- | 343 | * program, there is no longer any duplicated code. This is called by the * |
|
- | 344 | * normal Search() function and by ThreadWait() where idle processes wait * |
|
- | 345 | * for work and then call this procedure to search a subset of the moves at * |
|
- | 346 | * this ply (in parallel with other threads). * |
|
- | 347 | * * |
|
- | 348 | ******************************************************************************* |
|
- | 349 | */ |
|
- | 350 | int SearchMoveList(TREE * RESTRICT tree, int ply, int depth, int wtm, |
|
- | 351 | int alpha, int beta, int searched[], int in_check, int repeat, int mode) { |
|
- | 352 | TREE *current; |
|
- | 353 | int extend, reduce, check, original_alpha = alpha, t_beta; |
|
- | 354 | int i, value = 0, pv_node = alpha != beta - 1, status, order; |
|
- | 355 | int moves_done = 0, phase, bestmove, type; |
|
- | 356 | ||
- | 357 | /* |
|
- | 358 | ************************************************************ |
|
- | 359 | * * |
|
- | 360 | * Basic initialization before we begin the loop through * |
|
- | 361 | * the move list. If this is a parallel search, we have * |
|
- | 362 | * already searched one move, so we set t_beta to alpha+1 * |
|
- | 363 | * to set up for a normal PVS search (for moves 2-n) * |
|
- | 364 | * instead of using alpha,beta for the first move as we do * |
|
- | 365 | * in a normal search. Also, if this is a serial search, * |
|
- | 366 | * we are fixing to search the first move so we set the * |
|
- | 367 | * searched move counter to zero, where in a parallel * |
|
- | 368 | * search this has already been done and we leave it alone * |
|
- | 369 | * here. * |
|
- | 370 | * * |
|
- | 371 | * We also set <current> to tree for a serial search, and * |
|
- | 372 | * to tree->parent for a parallel search since we need to * |
|
- | 373 | * share the move list at split nodes. * |
|
- | 374 | * * |
|
- | 375 | ************************************************************ |
|
- | 376 | */ |
|
- | 377 | tree->next_status[ply].phase = HASH; |
|
- | 378 | if (mode == parallel) { |
|
- | 379 | current = tree->parent; |
|
- | 380 | t_beta = alpha + 1; |
|
- | 381 | } else { |
|
- | 382 | current = tree; |
|
- | 383 | t_beta = beta; |
|
- | 384 | } |
|
- | 385 | /* |
|
- | 386 | ************************************************************ |
|
- | 387 | * * |
|
280 | * |
388 | * Iterate. Now iterate through the move list and search * |
281 | * the resulting positions. Note that Search() culls any * |
389 | * the resulting positions. Note that Search() culls any * |
282 | * move that is not legal by using Check(). The special * |
390 | * move that is not legal by using Check(). The special * |
283 | * case is that we must find one legal move to search to * |
391 | * case is that we must find one legal move to search to * |
284 | * confirm that it's not a mate or draw. * |
392 | * confirm that it's not a mate or draw. * |
285 | * * |
393 | * * |
286 | * We |
394 | * We call NextMove() which will generate moves in the * |
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 | * |
395 | * normal way (captures, killers, etc) or it will use the * |
291 | * |
396 | * GenerateEvasions() generator if we are in check. For * |
292 | * |
397 | * the special case of ply=1, we use NextRootMove() since * |
293 | * and the returned score == alpha, we want to get out of * |
- | |
294 | * |
398 | * the ply=1 move list has been generated and the order is * |
295 | * will be adjusted. Otherwise we would search all root * |
- | |
296 | * moves and possibly fail low after expending a sig- * |
- | |
297 | * |
399 | * updated as each search iteration is executed. * |
298 | * * |
400 | * * |
299 | ************************************************************ |
401 | ************************************************************ |
300 | */ |
402 | */ |
301 | tree->next_status[ply].phase = HASH_MOVE; |
- | |
302 | while (1) { |
403 | while (1) { |
303 | if (ply > 1) |
- | |
304 | tree->phase[ply] = |
- | |
305 |
|
404 | if (ply == 1 && moves_done == 1 && alpha == original_alpha && |
306 |
|
405 | mode == serial) |
307 | else if (moves_searched == 1 && alpha == original_alpha) |
- | |
308 | break; |
406 | break; |
309 | |
407 | if (mode == parallel) |
- | 408 | Lock(current->lock); |
|
- | 409 | order = (ply > 1) ? NextMove(current, ply, depth, wtm, in_check) : |
|
310 |
|
410 | NextRootMove(current, tree, wtm); |
311 |
|
411 | phase = current->phase[ply]; |
- | 412 | if (mode == parallel) { |
|
- | 413 | tree->curmv[ply] = tree->parent->curmv[ply]; |
|
- | 414 | Unlock(current->lock); |
|
- | 415 | } |
|
- | 416 | if (!order) |
|
312 | break; |
417 | break; |
313 | #if defined(TRACE) |
418 | #if defined(TRACE) |
314 | if (ply <= trace_level) |
419 | if (ply <= trace_level) |
315 | Trace(tree, ply, depth, |
420 | Trace(tree, ply, depth, wtm, alpha, beta, "SearchMoveList", mode, phase, |
- | 421 | order); |
|
316 | #endif |
422 | #endif |
317 | MakeMove(tree, ply, tree->curmv[ply] |
423 | MakeMove(tree, ply, wtm, tree->curmv[ply]); |
318 | tree->nodes_searched++; |
424 | tree->nodes_searched++; |
- | 425 | status = ILLEGAL; |
|
319 | if ( |
426 | if (in_check || !Check(wtm)) |
320 | do { |
427 | do { |
321 |
|
428 | searched[0]++; |
- | 429 | moves_done++; |
|
- | 430 | status = LEGAL; |
|
322 |
|
431 | searched[searched[0]] = tree->curmv[ply]; |
323 | /* |
432 | /* |
324 | ************************************************************ |
433 | ************************************************************ |
325 | * * |
434 | * * |
326 | * |
435 | * Check. If the move to be made checks the opponent, * |
327 | * then we need to remember that he's in check and also * |
436 | * then we need to remember that he's in check and also * |
328 | * extend the depth by one ply for him to get out. |
437 | * extend the depth by one ply for him to get out. * |
329 | * that if the move gives check, it is not a candidate for * |
- | |
330 | * either depth reduction or forward-pruning. * |
- | |
331 | * * |
438 | * * |
332 | * We do not extend unsafe checking moves (as indicated by * |
439 | * We do not extend unsafe checking moves (as indicated by * |
333 | * |
440 | * the SEE algorithm), since these are usually a waste of * |
334 | * |
441 | * time and simply blow up the tree search space. * |
- | 442 | * * |
|
- | 443 | * Note that extending here disables any potential foward * |
|
- | 444 | * pruning or reductions for this move. * |
|
335 | * * |
445 | * * |
336 | ************************************************************ |
446 | ************************************************************ |
337 | */ |
447 | */ |
338 | extend = 0; |
448 | extend = 0; |
339 | reduce = 0; |
449 | reduce = 0; |
340 | if (Check(Flip( |
450 | if (Check(Flip(wtm))) { |
341 |
|
451 | check = 1; |
342 | if ( |
452 | if (SEEO(tree, wtm, |
- | 453 | tree->curmv[ply]) - pcval[Captured(tree->curmv[ply])] <= |
|
- | 454 | 0) { |
|
343 | extend = check_depth; |
455 | extend = check_depth; |
344 | tree->extensions_done++; |
456 | tree->extensions_done++; |
345 | } |
457 | } |
346 | } else |
458 | } else |
347 |
|
459 | check = 0; |
348 | /* |
460 | /* |
349 | ************************************************************ |
461 | ************************************************************ |
350 | * * |
462 | * * |
351 | * |
463 | * Futility. First attempt at forward pruning based on * |
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 | * |
464 | * the futility idea. * |
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 | * * |
465 | * * |
365 | * We have an array of pruning margin values that are * |
466 | * We have an array of pruning margin values that are * |
366 | * indexed by depth (remaining plies left until we drop * |
467 | * indexed by depth (remaining plies left until we drop * |
367 | * into the quiescence search) and which increase with * |
468 | * into the quiescence search) and which increase with * |
368 | * depth since more depth means a greater chance of * |
469 | * depth since more depth means a greater chance of * |
Line 372... | Line 473... | ||
372 | * the next move without expending any more effort. Note * |
473 | * the next move without expending any more effort. Note * |
373 | * that this is classic forward-pruning and can certainly * |
474 | * that this is classic forward-pruning and can certainly * |
374 | * introduce errors into the search. However, cluster * |
475 | * introduce errors into the search. However, cluster * |
375 | * testing has shown that this improves play in real * |
476 | * testing has shown that this improves play in real * |
376 | * games. The current implementation only prunes in the * |
477 | * games. The current implementation only prunes in the * |
377 | * last |
478 | * last 6 plies before quiescence, although this can be * |
378 | * tuned with the "eval" command changing the "pruning * |
479 | * tuned with the "eval" command changing the "pruning * |
379 | * depth" value to something other than |
480 | * depth" value to something other than 7 (test is for * |
380 | * depth < pruning depth, current value is |
481 | * depth < pruning depth, current value is 7 which prunes * |
381 | * in last |
482 | * in last 6 plies only). Testing shows no benefit in * |
382 | * larger values than |
483 | * larger values than 7, although this might change in * |
383 | * future versions as other things are modified. * |
484 | * future versions as other things are modified. * |
384 | * * |
485 | * * |
385 | * Exception: * |
486 | * Exception: * |
386 | * * |
487 | * * |
387 | * We do not prune if we are safely pushing a passed * |
488 | * We do not prune if we are safely pushing a passed * |
388 | * pawn to the 6th rank, where it becomes very dangerous * |
489 | * pawn to the 6th rank, where it becomes very dangerous * |
389 | * since it can promote in two more moves. * |
490 | * since it can promote in two more moves. * |
- | 491 | * * |
|
- | 492 | * All pruning and reduction code is skipped if any of the * |
|
- | 493 | * following are true: * |
|
- | 494 | * * |
|
- | 495 | * (1) side on move is in check. * |
|
- | 496 | * * |
|
- | 497 | * (2) move has not already been flagged for a search * |
|
- | 498 | * extension. * |
|
- | 499 | * * |
|
- | 500 | * (3) this is not the first move at this ply. * |
|
- | 501 | * * |
|
- | 502 | * (4) we are in the REMAINING phase, which means that a * |
|
- | 503 | * cutoff is not very likely. * |
|
390 | * * |
504 | * * |
391 | ************************************************************ |
505 | ************************************************************ |
392 | */ |
506 | */ |
393 | if ( |
507 | if (!in_check && !extend && order > 1 && phase >= HISTORY && |
394 |
|
508 | !(PawnPush(wtm, tree->curmv[ply]))) { |
395 | if (depth < pruning_depth && |
509 | if (!pv_node && depth < pruning_depth && |
396 | MaterialSTM( |
510 | MaterialSTM(wtm) + 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 |
|
511 | tree->moves_fpruned++; |
401 | continue; |
- | |
402 |
|
512 | break; |
403 | } |
513 | } |
404 | /* |
514 | /* |
405 | ************************************************************ |
515 | ************************************************************ |
406 | * * |
516 | * * |
407 | * Step 7c. Now it's time to try to reduce the search * |
- | |
408 | * |
517 | * LMP. Final attempt at forward pruning based on the * |
409 | * |
518 | * "late move pruning" idea (a take-off on LMR). * |
410 | * * |
519 | * * |
411 | * |
520 | * The basic idea here is that once we have searched a * |
- | 521 | * significant number of moves at a ply, it becomes less * |
|
- | 522 | * and less likely that any of the moves left will produce * |
|
412 | * |
523 | * a cutoff. If the move appears to be simple (not a * |
- | 524 | * check, etc) then we simply skip it, once the move count * |
|
- | 525 | * has been satisfied. At present, we only do this in the * |
|
- | 526 | * last two plies although this might be changed in the * |
|
413 | * |
527 | * future. * |
414 | * * |
528 | * * |
- | 529 | ************************************************************ |
|
- | 530 | */ |
|
- | 531 | if (!pv_node && alpha > -MATE + 300 && depth < movecnt_depth && |
|
- | 532 | !CaptureOrPromote(tree->curmv[ply]) && |
|
- | 533 | order > movecnt_pruning[depth]) { |
|
- | 534 | tree->moves_mpruned++; |
|
- | 535 | break; |
|
- | 536 | } |
|
- | 537 | /* |
|
- | 538 | ************************************************************ |
|
415 | * |
539 | * * |
- | 540 | * LMR. Now it's time to try to reduce the search depth * |
|
- | 541 | * if the move appears to be "poor" because it appears * |
|
416 | * |
542 | * later in the move list. * |
417 | * * |
543 | * * |
- | 544 | * The reduction is variable and is done via a table look- * |
|
418 | * |
545 | * up that uses a function based on remaining depth (more * |
419 | * |
546 | * depth remaining, the larger the reduction) and the * |
- | 547 | * number of moves searched (more moves searched, the * |
|
- | 548 | * larger the reduction). The "shape" of this reduction * |
|
- | 549 | * formula is user-settable via the "lmr" command. * |
|
420 | * * |
550 | * * |
421 | ************************************************************ |
551 | ************************************************************ |
422 | */ |
552 | */ |
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 |
|
553 | reduce = LMR[Min(depth, 31)][Min(order, 63)]; |
430 | if (reduce > max_reduce) |
- | |
431 | reduce = max_reduce; |
- | |
432 | if (reduce) |
- | |
433 |
|
554 | tree->LMR_done[reduce]++; |
434 | } |
- | |
435 | } |
555 | } |
436 | /* |
556 | /* |
437 | ************************************************************ |
557 | ************************************************************ |
438 | * * |
558 | * * |
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 | * |
559 | * Now do the PVS search on the current move. * |
444 | * * |
560 | * * |
445 | * |
561 | * Note that we do the usual alpha/beta cutoff tests here * |
446 | * |
562 | * but we only set an indicator that is used after we have * |
447 | * |
563 | * called Unmake(). This cleaned up the exit from search * |
448 | * |
564 | * and makes it easier to understand when there is only * |
449 | * |
565 | * one point where this is done, without needing multiple * |
450 | * |
566 | * Unmake() calls when there are different exit points. * |
451 | * * |
567 | * * |
452 | ************************************************************ |
568 | ************************************************************ |
453 | */ |
569 | */ |
454 | if (depth + extend - reduce - 1 > 0) { |
- | |
455 |
|
570 | value = |
456 |
|
571 | SearchMove(tree, ply, depth, wtm, alpha, t_beta, beta, extend, |
457 |
|
572 | reduce, check); |
458 |
|
573 | if (value > alpha) { |
- | 574 | status = IN_WINDOW; |
|
459 |
|
575 | if (value >= beta) |
- | 576 | status = FAIL_HIGH; |
|
460 |
|
577 | if (mode == parallel && ply == 1) |
461 |
|
578 | status = FAIL_HIGH; |
462 | } |
579 | } |
- | 580 | } while (0); |
|
463 |
|
581 | UnmakeMove(tree, ply, wtm, tree->curmv[ply]); |
464 |
|
582 | if (abort_search || tree->stop) |
465 |
|
583 | break; |
466 | /* |
584 | /* |
467 | ************************************************************ |
585 | ************************************************************ |
468 | * * |
586 | * * |
469 | * Step 7e. This is the PVS re-search code. If we reach * |
- | |
470 | * |
587 | * Test 1. When we get here, we have made a move, * |
471 | * this can not be a null-window search. We have to re- * |
- | |
472 | * |
588 | * searched it (and re-searched if necessary/appropriate), * |
473 | * |
589 | * and the move has been unmade so that the board is in a * |
474 | * fails high before we treat this as a real fail-high and * |
- | |
475 | * |
590 | * correct state. * |
476 | * * |
591 | * * |
- | 592 | * If status = FAIL_HIGH, the search failed high. The * |
|
- | 593 | * first thing to handle is the case where we are at * |
|
- | 594 | * ply=1, which is a special case. If we are going to * |
|
- | 595 | * fail high here and terminate the search immediately, we * |
|
- | 596 | * need to build the fail-high PV to back up to Iterate() * |
|
- | 597 | * so it will produce the correct output and widen the * |
|
477 | * |
598 | * alpha/beta window. * |
478 | * * |
599 | * * |
479 | * |
600 | * We then check to see if this is a parallel search. If * |
480 | * |
601 | * so then we are done here, but we need to tell all of * |
481 | * |
602 | * the siblings that are helping at this split point that * |
482 | * |
603 | * they should immediately stop searching here since we * |
483 | * value. We also reset the failhi_delta back to 16, * |
- | |
484 | * |
604 | * don't need their results. * |
485 | * iteration could have left it at a large value. * |
- | |
486 | * * |
605 | * * |
- | 606 | * Otherwise we update the killer moves and history * |
|
487 | * |
607 | * counters and store the fail-high information in the * |
488 | * |
608 | * trans/ref table for future use if we happen to reach * |
489 | * this |
609 | * this position again. * |
490 | * * |
610 | * * |
491 | ************************************************************ |
611 | ************************************************************ |
492 | */ |
612 | */ |
493 |
|
613 | if (status == FAIL_HIGH) { |
494 |
|
614 | 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 |
|
615 | if (!tree->stop) { |
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 |
|
616 | tree->pv[1].path[1] = tree->curmv[1]; |
510 |
|
617 | tree->pv[1].pathl = 2; |
511 |
|
618 | tree->pv[1].pathh = 0; |
512 |
|
619 | tree->pv[1].pathd = iteration; |
513 |
|
620 | 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 | } |
621 | } |
- | 622 | } |
|
- | 623 | #if (CPUS > 1) |
|
- | 624 | if (mode == parallel) { |
|
- | 625 | Lock(lock_smp); |
|
- | 626 | Lock(tree->parent->lock); |
|
- | 627 | if (!tree->stop) { |
|
- | 628 | int proc; |
|
- | 629 | ||
- | 630 | parallel_aborts++; |
|
- | 631 | for (proc = 0; proc < (int) smp_max_threads; proc++) // Pierre-Marie Baty -- added type cast |
|
- | 632 | if (tree->parent->siblings[proc] && proc != tree->thread_id) |
|
- | 633 | ThreadStop(tree->parent->siblings[proc]); |
|
- | 634 | } |
|
- | 635 | Unlock(tree->parent->lock); |
|
- | 636 | Unlock(lock_smp); |
|
- | 637 | return value; |
|
- | 638 | } |
|
- | 639 | #endif |
|
- | 640 | tree->fail_highs++; |
|
- | 641 | if (order == 1) |
|
- | 642 | tree->fail_high_first_move++; |
|
- | 643 | HashStore(tree, ply, depth, wtm, LOWER, value, tree->curmv[ply]); |
|
- | 644 | History(tree, ply, depth, wtm, tree->curmv[ply], searched); |
|
- | 645 | return beta; |
|
525 | /* |
646 | /* |
526 | ************************************************************ |
647 | ************************************************************ |
527 | * * |
648 | * * |
528 | * |
649 | * Test 2. If status = IN_WINDOW, this is a search that * |
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 | * |
650 | * improved alpha without failing high. We simply update * |
533 | * |
651 | * alpha and continue searching moves. * |
534 | * * |
652 | * * |
- | 653 | * Special case: If ply = 1 in a normal search, we have * |
|
- | 654 | * a best move and score that just changed. We need to * |
|
535 | * |
655 | * update the root move list by adding the PV and the * |
536 | * |
656 | * score, and then we look to make sure this new "best * |
- | 657 | * move" is not actually worse than the best we have found * |
|
- | 658 | * so far this iteration. If it is worse, we restore the * |
|
- | 659 | * best move and score from the real best move so our * |
|
537 | * |
660 | * search window won't be out of whack, which would let * |
- | 661 | * moves with scores in between this bad move and the best * |
|
- | 662 | * move fail high, cause re-searches, and waste time. * |
|
- | 663 | * * |
|
- | 664 | * If this is ply = 1, we display the PV to keep the user * |
|
- | 665 | * informed. * |
|
538 | * * |
666 | * * |
539 | ************************************************************ |
667 | ************************************************************ |
540 | */ |
668 | */ |
541 |
|
669 | } else if (status == IN_WINDOW) { |
542 |
|
670 | alpha = value; |
543 |
|
671 | if (ply == 1 && mode == serial) { |
544 |
|
672 | tree->pv[1].pathv = value; |
545 |
|
673 | tree->pv[0] = tree->pv[1]; |
- | 674 | for (i = 0; i < n_root_moves; i++) |
|
- | 675 | if (root_moves[i].move == tree->pv[1].path[1]) { |
|
546 |
|
676 | root_moves[i].path = tree->pv[1]; |
- | 677 | root_moves[i].path.pathv = alpha; |
|
547 | } |
678 | } |
548 |
|
679 | for (i = 0; i < n_root_moves; i++) |
549 |
|
680 | if (value < root_moves[i].path.pathv) { |
550 |
|
681 | value = root_moves[i].path.pathv; |
551 | HashStore(tree, ply, depth, side, LOWER, value, tree->curmv[ply]); |
- | |
552 |
|
682 | alpha = value; |
553 | if (moves_searched == 1) |
- | |
554 |
|
683 | tree->pv[0] = root_moves[i].path; |
555 |
|
684 | tree->pv[1] = tree->pv[0]; |
556 | } |
685 | } |
557 | |
686 | Output(tree); |
558 |
|
687 | failhi_delta = 16; |
559 |
|
688 | faillo_delta = 16; |
- | 689 | } |
|
- | 690 | } |
|
- | 691 | /* |
|
- | 692 | ************************************************************ |
|
- | 693 | * * |
|
- | 694 | * Test 3. If status = ILLEGAL, this search was given an * |
|
560 |
|
695 | * illegal move and no search was done, we skip any * |
- | 696 | * updating and simply select the next move to search. * |
|
- | 697 | * * |
|
- | 698 | ************************************************************ |
|
- | 699 | */ |
|
561 | if ( |
700 | else if (status == ILLEGAL) |
562 |
|
701 | continue; |
- | 702 | t_beta = alpha + 1; |
|
563 | /* |
703 | /* |
564 | ************************************************************ |
704 | ************************************************************ |
565 | * * |
705 | * * |
566 | * |
706 | * SMP. If are doing an SMP search, and we have idle * |
567 | * processors, now is the time to get them involved. We * |
707 | * processors, now is the time to get them involved. We * |
568 | * have now satisfied the "young brothers wait" condition * |
708 | * have now satisfied the "young brothers wait" condition * |
569 | * since we have searched |
709 | * since we have searched at least one move. All that is * |
570 | * |
710 | * left is to check the split constraints to see if this * |
571 | * |
711 | * is an acceptable split point. * |
572 | * * |
712 | * * |
573 | * (1) We can't split within N plies of the frontier * |
713 | * (1) We can't split within N plies of the frontier * |
574 | * nodes to avoid excessive split overhead. * |
714 | * nodes to avoid excessive split overhead. * |
575 | * * |
715 | * * |
576 | * (2) We can't split until at least |
716 | * (2) We can't split until at least N nodes have been * |
577 | * searched since this thread was last split, to * |
717 | * searched since this thread was last split, to * |
578 | * avoid splitting too often, mainly in endgames. * |
718 | * avoid splitting too often, mainly in endgames. * |
579 | * * |
719 | * * |
580 | * (3) We have to have searched one legal move to avoid * |
720 | * (3) We have to have searched one legal move to avoid * |
581 | * splitting at a node where we have no legal moves * |
721 | * splitting at a node where we have no legal moves * |
Line 588... | Line 728... | ||
588 | * "do not search in parallel" which happens when * |
728 | * "do not search in parallel" which happens when * |
589 | * this move was a best move in the last couple of * |
729 | * this move was a best move in the last couple of * |
590 | * searches and we want all processors on it at once * |
730 | * searches and we want all processors on it at once * |
591 | * to get a score back quicker. * |
731 | * to get a score back quicker. * |
592 | * * |
732 | * * |
593 | * (5) if the variable smp_split is |
733 | * (5) if the variable smp_split is != 0, we have idle * |
594 | * threads that can help, |
734 | * threads that can help, which means we want to get * |
595 | * |
735 | * them involved quickly, OR if this node is an * |
- | 736 | * acceptable "gratuitous-split" point by being far * |
|
596 | * |
737 | * enough from the tips of the tree to avoid * |
- | 738 | * excessive overhead. * |
|
597 | * * |
739 | * * |
- | 740 | * We use this code recursively to perform a parallel * |
|
598 | * |
741 | * search at this ply. But when we finish a partial piece * |
599 | * |
742 | * of the search in parallel, we don't need to update any * |
600 | * |
743 | * search data structures, we will defer that until all of * |
601 | * |
744 | * parallel threads complete and return back into this * |
- | 745 | * code after the parallel search has been collapsed back * |
|
- | 746 | * to one instance of search at this ply. * |
|
602 | * * |
747 | * * |
603 | * Special case: we do not split if we are at ply=1 and * |
748 | * Special case: we do not split if we are at ply=1 and * |
604 | * alpha == original_alpha. That means the first move * |
749 | * alpha == original_alpha. That means the first move * |
605 | * failed low, and we are going to exit search and return * |
750 | * failed low, and we are going to exit search and return * |
606 | * to Iterate() to report this. * |
751 | * to Iterate() to report this. * |
607 | * * |
752 | * * |
- | 753 | * In Generation II, multiple threads can reach this point * |
|
608 | * |
754 | * at the same time. We allow multiple threads to split * |
609 | * |
755 | * at the same time, but then the idle threads will choose * |
610 | * |
756 | * to join the thread with the most attractive split point * |
611 | * |
757 | * rather than just taking pot-luck. The only limitation * |
612 | * |
758 | * on a thread adding a split point here is that if the * |
613 | * |
759 | * thread already has enough joinable split points have * |
614 | * |
760 | * not been joined yet, we do not incur the overhead of * |
615 | * |
761 | * creating another split point until the existing split * |
616 | * |
762 | * point is completed or a thread joins at at that point. * |
617 | * * |
763 | * * |
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 | * |
764 | * We do not lock anything here, as the split operation * |
621 | * than trying to split and end up in a queue behind us, * |
- | |
622 | * |
765 | * only affects thread-local data. When the split is done * |
623 | * We release lock_split to eliminate the log-jam of * |
- | |
624 | * |
766 | * then the ThreadJoin() function will acquire the lock * |
625 | * |
767 | * needed to avoid race conditions during the join op- * |
626 | * |
768 | * eration. * |
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 | * * |
769 | * * |
635 | ************************************************************ |
770 | ************************************************************ |
636 | */ |
771 | */ |
637 | #if (CPUS > 1) |
772 | #if (CPUS > 1) |
638 | if ( |
773 | if (mode == serial && moves_done && smp_threads && |
639 | tree->nodes_searched - start_nodes > smp_split_nodes && (ply > 1 || |
- | |
640 | (smp_split_at_root && NextRootMoveParallel() && |
- | |
641 |
|
774 | ThreadSplit(tree, ply, depth, alpha, original_alpha, moves_done)) |
642 | do { |
775 | 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; |
776 | tree->alpha = alpha; |
651 | tree->beta = beta; |
777 | tree->beta = beta; |
652 | tree->value = alpha; |
778 | tree->value = alpha; |
653 | tree-> |
779 | tree->wtm = wtm; |
654 | tree->ply = ply; |
780 | tree->ply = ply; |
655 | tree->depth = depth; |
781 | tree->depth = depth; |
- | 782 | tree->in_check = in_check; |
|
656 | tree-> |
783 | tree->searched = searched; |
657 | if ( |
784 | if (Split(tree)) { |
658 | if (abort_search || tree->stop) |
785 | if (abort_search || tree->stop) |
659 | return 0; |
786 | return 0; |
660 | if (tree->thread_id == 0 && CheckInput()) |
- | |
661 | Interrupt(ply); |
- | |
662 | value = tree->value; |
787 | value = tree->value; |
663 | if (value > alpha) { |
788 | if (value > alpha) { |
- | 789 | if (ply == 1) |
|
- | 790 | tree->pv[0] = tree->pv[1]; |
|
664 | if (value >= beta) { |
791 | if (value >= beta) { |
665 | HashStore(tree, ply, depth, |
792 | HashStore(tree, ply, depth, wtm, LOWER, value, tree->cutmove); |
666 | return value; |
793 | return value; |
667 | } |
794 | } |
668 | alpha = value; |
795 | alpha = value; |
669 | break; |
796 | break; |
670 | } |
797 | } |
Line 673... | Line 800... | ||
673 | #endif |
800 | #endif |
674 | } |
801 | } |
675 | /* |
802 | /* |
676 | ************************************************************ |
803 | ************************************************************ |
677 | * * |
804 | * * |
- | 805 | * SMP Cleanup. If we are doing an SMP search, there are * |
|
- | 806 | * no "end-of-search" things to do. We have searched all * |
|
- | 807 | * the remaining moves at this ply in parallel, and now * |
|
678 | * |
808 | * return and let the original search that started this * |
- | 809 | * sub-tree clean up, do the tests for mate/stalemate, * |
|
- | 810 | * update the hash table, etc. * |
|
- | 811 | * * |
|
679 | * |
812 | * As we return, we end back up in Thread() where we * |
- | 813 | * started, which then copies the best score/etc back to * |
|
680 | * the |
814 | * the parent thread. * |
681 | * * |
815 | * * |
682 | ************************************************************ |
816 | ************************************************************ |
683 | */ |
817 | */ |
684 | if (abort_search || tree->stop) |
818 | if (abort_search || tree->stop || mode == parallel) |
685 | return |
819 | return alpha; |
- | 820 | /* |
|
- | 821 | ************************************************************ |
|
- | 822 | * * |
|
- | 823 | * Search completed. All moves have been searched. If * |
|
- | 824 | * none were legal, return either MATE or DRAW depending * |
|
- | 825 | * on whether the side to move is in check or not. * |
|
- | 826 | * * |
|
- | 827 | ************************************************************ |
|
- | 828 | */ |
|
686 | if ( |
829 | if (moves_done == 0) { |
687 | value = (Check( |
830 | value = (Check(wtm)) ? -(MATE - ply) : DrawScore(wtm); |
688 | if (value >= alpha && value < beta) { |
831 | if (value >= alpha && value < beta) { |
689 | SavePV(tree, ply, 0); |
832 | SavePV(tree, ply, 0); |
690 | #if defined(TRACE) |
833 | #if defined(TRACE) |
691 | if (ply <= trace_level) |
834 | if (ply <= trace_level) |
692 | printf("Search() no moves! ply=%d\n", ply); |
835 | printf("Search() no moves! ply=%d\n", ply); |
693 | #endif |
836 | #endif |
694 | } |
837 | } |
695 | return value; |
838 | return value; |
696 | } else { |
839 | } else { |
697 | int bestmove, type; |
- | |
698 | bestmove = |
840 | bestmove = |
- | 841 | (alpha == |
|
699 |
|
842 | original_alpha) ? tree->hash_move[ply] : tree->pv[ply].path[ply]; |
700 | type = (alpha == original_alpha) ? UPPER : EXACT; |
843 | type = (alpha == original_alpha) ? UPPER : EXACT; |
701 | if (repeat == 2 && alpha != -(MATE - ply - 1)) { |
844 | if (repeat == 2 && alpha != -(MATE - ply - 1)) { |
702 | value = DrawScore( |
845 | value = DrawScore(wtm); |
703 | if (value < beta) |
846 | if (value < beta) |
704 | SavePV(tree, ply, |
847 | SavePV(tree, ply, 4); |
705 | #if defined(TRACE) |
848 | #if defined(TRACE) |
706 | if (ply <= trace_level) |
849 | if (ply <= trace_level) |
707 | printf("draw by 50 move rule detected, ply=%d.\n", ply); |
850 | printf("draw by 50 move rule detected, ply=%d.\n", ply); |
708 | #endif |
851 | #endif |
709 | return value; |
852 | return value; |
710 | } else if (alpha != original_alpha) { |
853 | } else if (alpha != original_alpha) { |
711 | tree->pv[ply - 1] = tree->pv[ply]; |
854 | tree->pv[ply - 1] = tree->pv[ply]; |
712 | tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1]; |
855 | tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1]; |
713 | Killer(tree, ply, tree->pv[ply].path[ply]); |
- | |
714 | } |
856 | } |
715 | HashStore(tree, ply, depth, |
857 | HashStore(tree, ply, depth, wtm, type, alpha, bestmove); |
716 | return alpha; |
858 | return alpha; |
717 | } |
859 | } |
718 | } |
860 | } |
719 | 861 | ||
720 | /* last modified |
862 | /* last modified 07/01/15 */ |
721 | /* |
863 | /* |
722 | ******************************************************************************* |
864 | ******************************************************************************* |
723 | * * |
865 | * * |
724 | * SearchParallel() is the recursive routine used to implement alpha/beta * |
- | |
725 | * negamax search using parallel threads. When this code is called, the * |
- | |
726 | * |
866 | * SearchMove() implements the PVS search and returns the value. We do a * |
727 | * the remainder of the moves and then return. Note that the hash table and * |
- | |
728 | * |
867 | * null-window search with the window (alpha, t_beta) and if that fails high * |
729 | * |
868 | * we repeat the search with the window {alpha, beta} assuming that beta != * |
730 | * the original instance of Search() where we have the complete results from * |
- | |
731 | * |
869 | * t_beta. * |
732 | * * |
870 | * * |
733 | ******************************************************************************* |
871 | ******************************************************************************* |
734 | */ |
872 | */ |
735 | int |
873 | int SearchMove(TREE * RESTRICT tree, int ply, int depth, int wtm, int alpha, |
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 |
|
874 | int t_beta, int beta, int extend, int reduce, int check) { |
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 |
|
875 | int value; |
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 | /* |
876 | /* |
896 | ************************************************************ |
877 | ************************************************************ |
897 | * * |
878 | * * |
898 | * |
879 | * PVS search. We have determined whether the depth is to * |
899 | * be changed by an extension or a reduction. If we get * |
880 | * be changed by an extension or a reduction. If we get * |
900 | * to this point, then the move is not being pruned. So * |
881 | * to this point, then the move is not being pruned. So * |
901 | * off we go to a recursive search/quiescence call to work * |
882 | * off we go to a recursive search/quiescence call to work * |
902 | * our way toward a terminal node. * |
883 | * our way toward a terminal node. * |
903 | * * |
884 | * * |
904 | * There is one special- |
885 | * There is one special-case to handle. If the depth was * |
905 | * reduced, and Search() returns a value >= beta then * |
886 | * reduced, and Search() returns a value >= beta then * |
906 | * accepting that is risky (we reduced the move as we * |
887 | * accepting that is risky (we reduced the move as we * |
907 | * thought it was bad and expected it to fail low) so we * |
888 | * thought it was bad and expected it to fail low) so we * |
908 | * repeat the search using the original (non-reduced) * |
889 | * repeat the search using the original (non-reduced) * |
909 | * depth to see if the fail-high happens again. * |
890 | * depth to see if the fail-high happens again. * |
910 | * * |
891 | * * |
911 | ************************************************************ |
892 | ************************************************************ |
912 | */ |
893 | */ |
913 |
|
894 | if (depth + extend - reduce - 1 > 0) { |
914 |
|
895 | value = |
915 |
|
896 | -Search(tree, ply + 1, depth + extend - reduce - 1, Flip(wtm), |
916 |
|
897 | -t_beta, -alpha, check, DO_NULL); |
917 |
|
898 | if (value > alpha && reduce) { |
918 |
|
899 | value = |
919 |
|
900 | -Search(tree, ply + 1, depth - 1, Flip(wtm), -t_beta, -alpha, check, |
920 |
|
901 | DO_NULL); |
- | 902 | } |
|
921 |
|
903 | } else |
922 |
|
904 | value = -Quiesce(tree, ply + 1, Flip(wtm), -t_beta, -alpha, 1); |
923 |
|
905 | if (abort_search || tree->stop) |
924 |
|
906 | return 0; |
925 | /* |
907 | /* |
926 | ************************************************************ |
908 | ************************************************************ |
927 | * * |
909 | * * |
928 | * |
910 | * PVS re-search. This is the PVS re-search code. If we * |
929 | * this point and value > alpha and value < beta, |
911 | * reach this point and value > alpha and value < beta, * |
930 | * this can not be a null-window search. We have to |
912 | * then this can not be a null-window search. We have to * |
931 | * search the position with the original beta value |
913 | * re-search the position with the original beta value * |
932 | * alpha+1 as is the usual case in PVS) to see if it still * |
- | |
933 | * fails high before we treat this as a |
914 | * to see if it still fails high before we treat this as a * |
934 | * |
915 | * real fail-high and back up the value to the previous * |
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 | * |
916 | * ply. * |
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 | * * |
917 | * * |
951 | ************************************************************ |
918 | ************************************************************ |
952 | */ |
919 | */ |
953 |
|
920 | if (value > alpha && value < beta && t_beta < beta) { |
954 |
|
921 | 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 |
|
922 | return beta; |
989 | } |
- | |
990 |
|
923 | if (depth + extend - 1 > 0) |
991 |
|
924 | value = |
992 |
|
925 | -Search(tree, ply + 1, depth + extend - 1, Flip(wtm), -beta, -alpha, |
993 |
|
926 | check, DO_NULL); |
994 |
|
927 | else |
995 |
|
928 | value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -alpha, 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) |
929 | 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 |
|
930 | return 0; |
1081 | } |
- | |
1082 | Unlock(lock_root); |
- | |
1083 | } |
931 | } |
1084 | return |
932 | return value; |
1085 | } |
933 | } |