Rev 96 | Rev 169 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 96 | Rev 154 | ||
---|---|---|---|
Line 24... | Line 24... | ||
24 | #include "thread.h" |
24 | #include "thread.h" |
25 | 25 | ||
26 | namespace { |
26 | namespace { |
27 | 27 | ||
28 | enum Stages { |
28 | enum Stages { |
29 | MAIN_SEARCH, GOOD_CAPTURES, KILLERS, |
29 | MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES, |
30 | EVASION, ALL_EVASIONS, |
30 | EVASION, EVASIONS_INIT, ALL_EVASIONS, |
31 |
|
31 | PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES, |
32 |
|
32 | QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS, |
33 |
|
33 | QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2, |
34 |
|
34 | QSEARCH_RECAPTURES, QRECAPTURES |
35 | STOP |
- | |
36 | }; |
35 | }; |
37 | 36 | ||
38 | // Our insertion sort, which is guaranteed to be stable, as it should be |
37 | // Our insertion sort, which is guaranteed to be stable, as it should be |
39 | void insertion_sort(ExtMove* begin, ExtMove* end) |
38 | void insertion_sort(ExtMove* begin, ExtMove* end) |
40 | { |
39 | { |
Line 65... | Line 64... | ||
65 | /// to help it to return the (presumably) good moves first, to decide which |
64 | /// to help it to return the (presumably) good moves first, to decide which |
66 | /// moves to return (in the quiescence search, for instance, we only want to |
65 | /// moves to return (in the quiescence search, for instance, we only want to |
67 | /// search captures, promotions, and some checks) and how important good move |
66 | /// search captures, promotions, and some checks) and how important good move |
68 | /// ordering is at the current node. |
67 | /// ordering is at the current node. |
69 | 68 | ||
70 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, |
69 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Search::Stack* s) |
71 | const CounterMoveStats& cmh, Move cm, Search::Stack* s) |
- | |
72 | : pos(p |
70 | : pos(p), ss(s), depth(d) { |
73 | 71 | ||
74 | assert(d > DEPTH_ZERO); |
72 | assert(d > DEPTH_ZERO); |
- | 73 | ||
- | 74 | Square prevSq = to_sq((ss-1)->currentMove); |
|
- | 75 | countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq]; |
|
75 | 76 | ||
76 | stage = pos.checkers() ? EVASION : MAIN_SEARCH; |
77 | stage = pos.checkers() ? EVASION : MAIN_SEARCH; |
77 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
78 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
78 |
|
79 | stage += (ttMove == MOVE_NONE); |
79 | } |
80 | } |
80 | 81 | ||
81 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, |
82 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s) |
82 | const HistoryStats& h, Square s) |
- | |
83 | : pos(p |
83 | : pos(p) { |
84 | 84 | ||
85 | assert(d <= DEPTH_ZERO); |
85 | assert(d <= DEPTH_ZERO); |
86 | 86 | ||
87 | if (pos.checkers()) |
87 | if (pos.checkers()) |
88 | stage = EVASION; |
88 | stage = EVASION; |
89 | 89 | ||
90 | else if (d > DEPTH_QS_NO_CHECKS) |
90 | else if (d > DEPTH_QS_NO_CHECKS) |
91 | stage = QSEARCH_WITH_CHECKS; |
91 | stage = QSEARCH_WITH_CHECKS; |
92 | 92 | ||
93 | else if (d > DEPTH_QS_RECAPTURES) |
93 | else if (d > DEPTH_QS_RECAPTURES) |
94 | stage = |
94 | stage = QSEARCH_NO_CHECKS; |
95 | 95 | ||
96 | else |
96 | else |
97 | { |
97 | { |
98 | stage = |
98 | stage = QSEARCH_RECAPTURES; |
99 | recaptureSquare = s; |
99 | recaptureSquare = s; |
100 |
|
100 | return; |
101 | } |
101 | } |
102 | 102 | ||
103 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
103 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
104 |
|
104 | stage += (ttMove == MOVE_NONE); |
105 | } |
105 | } |
106 | 106 | ||
107 | MovePicker::MovePicker(const Position& p, Move ttm, |
107 | MovePicker::MovePicker(const Position& p, Move ttm, Value th) |
108 | : pos(p |
108 | : pos(p), threshold(th) { |
109 | 109 | ||
110 | assert(!pos.checkers()); |
110 | assert(!pos.checkers()); |
111 | 111 | ||
112 | stage = PROBCUT; |
112 | stage = PROBCUT; |
113 | 113 | ||
114 | // In ProbCut we generate captures with SEE higher than the given threshold |
114 | // In ProbCut we generate captures with SEE higher than the given threshold |
115 | ttMove = ttm |
115 | ttMove = ttm |
116 | && pos.pseudo_legal(ttm) |
116 | && pos.pseudo_legal(ttm) |
117 | && pos.capture(ttm) |
117 | && pos.capture(ttm) |
118 | && pos. |
118 | && pos.see_ge(ttm, threshold + 1)? ttm : MOVE_NONE; |
119 | 119 | ||
120 |
|
120 | stage += (ttMove == MOVE_NONE); |
121 | } |
121 | } |
122 | 122 | ||
123 | 123 | ||
124 | /// score() assigns a numerical value to each move in a move list. The moves with |
124 | /// score() assigns a numerical value to each move in a move list. The moves with |
125 | /// highest values will be picked first. |
125 | /// highest values will be picked first. |
Line 137... | Line 137... | ||
137 | - Value(200 * relative_rank(pos.side_to_move(), to_sq(m))); |
137 | - Value(200 * relative_rank(pos.side_to_move(), to_sq(m))); |
138 | } |
138 | } |
139 | 139 | ||
140 | template<> |
140 | template<> |
141 | void MovePicker::score<QUIETS>() { |
141 | void MovePicker::score<QUIETS>() { |
- | 142 | ||
- | 143 | const HistoryStats& history = pos.this_thread()->history; |
|
- | 144 | const FromToStats& fromTo = pos.this_thread()->fromTo; |
|
- | 145 | ||
- | 146 | const CounterMoveStats* cm = (ss-1)->counterMoves; |
|
- | 147 | const CounterMoveStats* fm = (ss-2)->counterMoves; |
|
- | 148 | const CounterMoveStats* f2 = (ss-4)->counterMoves; |
|
- | 149 | ||
- | 150 | Color c = pos.side_to_move(); |
|
142 | 151 | ||
143 | for (auto& m : *this) |
152 | for (auto& m : *this) |
144 | m.value = history[pos.moved_piece(m)][to_sq(m)] |
153 | m.value = history[pos.moved_piece(m)][to_sq(m)] |
145 | + (* |
154 | + (cm ? (*cm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO) |
- | 155 | + (fm ? (*fm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO) |
|
- | 156 | + (f2 ? (*f2)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO) |
|
- | 157 | + fromTo.get(c, m); |
|
146 | } |
158 | } |
147 | 159 | ||
148 | template<> |
160 | template<> |
149 | void MovePicker::score<EVASIONS>() { |
161 | void MovePicker::score<EVASIONS>() { |
150 | // Try |
162 | // Try captures ordered by MVV/LVA, then non-captures ordered by history value |
151 |
|
163 | const HistoryStats& history = pos.this_thread()->history; |
152 |
|
164 | const FromToStats& fromTo = pos.this_thread()->fromTo; |
153 |
|
165 | Color c = pos.side_to_move(); |
154 | 166 | ||
155 | for (auto& m : *this) |
167 | for (auto& m : *this) |
156 | if ((see = pos.see_sign(m)) < VALUE_ZERO) |
- | |
157 | m.value = see - HistoryStats::Max; // At the bottom |
- | |
158 | - | ||
159 |
|
168 | if (pos.capture(m)) |
160 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
169 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
161 | - Value(type_of(pos.moved_piece(m))) + HistoryStats::Max; |
170 | - Value(type_of(pos.moved_piece(m))) + HistoryStats::Max; |
162 | else |
171 | else |
163 | m.value = history[pos.moved_piece(m)][to_sq(m)]; |
172 | m.value = history[pos.moved_piece(m)][to_sq(m)] + fromTo.get(c, m); |
164 | } |
- | |
165 | - | ||
166 | - | ||
167 | /// generate_next_stage() generates, scores, and sorts the next bunch of moves |
- | |
168 | /// when there are no more moves to try for the current stage. |
- | |
169 | - | ||
170 | void MovePicker::generate_next_stage() { |
- | |
171 | - | ||
172 | assert(stage != STOP); |
- | |
173 | - | ||
174 | cur = moves; |
- | |
175 | - | ||
176 | switch (++stage) { |
- | |
177 | - | ||
178 | case GOOD_CAPTURES: case QCAPTURES_1: case QCAPTURES_2: |
- | |
179 | case PROBCUT_CAPTURES: case RECAPTURES: |
- | |
180 | endMoves = generate<CAPTURES>(pos, moves); |
- | |
181 | score<CAPTURES>(); |
- | |
182 | break; |
- | |
183 | - | ||
184 | case KILLERS: |
- | |
185 | killers[0] = ss->killers[0]; |
- | |
186 | killers[1] = ss->killers[1]; |
- | |
187 | killers[2] = countermove; |
- | |
188 | cur = killers; |
- | |
189 | endMoves = cur + 2 + (countermove != killers[0] && countermove != killers[1]); |
- | |
190 | break; |
- | |
191 | - | ||
192 | case GOOD_QUIETS: |
- | |
193 | endQuiets = endMoves = generate<QUIETS>(pos, moves); |
- | |
194 | score<QUIETS>(); |
- | |
195 | endMoves = std::partition(cur, endMoves, [](const ExtMove& m) { return m.value > VALUE_ZERO; }); |
- | |
196 | insertion_sort(cur, endMoves); |
- | |
197 | break; |
- | |
198 | - | ||
199 | case BAD_QUIETS: |
- | |
200 | cur = endMoves; |
- | |
201 | endMoves = endQuiets; |
- | |
202 | if (depth >= 3 * ONE_PLY) |
- | |
203 | insertion_sort(cur, endMoves); |
- | |
204 | break; |
- | |
205 | - | ||
206 | case BAD_CAPTURES: |
- | |
207 | // Just pick them in reverse order to get correct ordering |
- | |
208 | cur = moves + MAX_MOVES - 1; |
- | |
209 | endMoves = endBadCaptures; |
- | |
210 | break; |
- | |
211 | - | ||
212 | case ALL_EVASIONS: |
- | |
213 | endMoves = generate<EVASIONS>(pos, moves); |
- | |
214 | if (endMoves - moves > 1) |
- | |
215 | score<EVASIONS>(); |
- | |
216 | break; |
- | |
217 | - | ||
218 | case CHECKS: |
- | |
219 | endMoves = generate<QUIET_CHECKS>(pos, moves); |
- | |
220 | break; |
- | |
221 | - | ||
222 | case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_WITHOUT_CHECKS: |
- | |
223 | case PROBCUT: case RECAPTURE: case STOP: |
- | |
224 | stage = STOP; |
- | |
225 | break; |
- | |
226 | - | ||
227 | default: |
- | |
228 | assert(false); |
- | |
229 | } |
- | |
230 | } |
173 | } |
231 | 174 | ||
232 | 175 | ||
233 | /// next_move() is the most important method of the MovePicker class. It returns |
176 | /// next_move() is the most important method of the MovePicker class. It returns |
234 | /// a new pseudo legal move every time it is called, until there are no more moves |
177 | /// a new pseudo legal move every time it is called, until there are no more moves |
Line 237... | Line 180... | ||
237 | 180 | ||
238 | Move MovePicker::next_move() { |
181 | Move MovePicker::next_move() { |
239 | 182 | ||
240 | Move move; |
183 | Move move; |
241 | 184 | ||
242 |
|
185 | switch (stage) { |
243 | { |
- | |
244 | while (cur == endMoves && stage != STOP) |
- | |
245 | generate_next_stage(); |
- | |
246 | 186 | ||
- | 187 | case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: |
|
- | 188 | case QSEARCH_NO_CHECKS: case PROBCUT: |
|
247 |
|
189 | ++stage; |
- | 190 | return ttMove; |
|
248 | 191 | ||
- | 192 | case CAPTURES_INIT: |
|
249 |
|
193 | endBadCaptures = cur = moves; |
250 |
|
194 | endMoves = generate<CAPTURES>(pos, cur); |
251 |
|
195 | score<CAPTURES>(); |
252 |
|
196 | ++stage; |
253 | 197 | ||
254 |
|
198 | case GOOD_CAPTURES: |
- | 199 | while (cur < endMoves) |
|
- | 200 | { |
|
255 | move = pick_best(cur++, endMoves); |
201 | move = pick_best(cur++, endMoves); |
256 | if (move != ttMove) |
202 | if (move != ttMove) |
257 | { |
203 | { |
258 | if (pos. |
204 | if (pos.see_ge(move, VALUE_ZERO)) |
259 | return move; |
205 | return move; |
260 | 206 | ||
261 | // Losing capture, move it to the |
207 | // Losing capture, move it to the beginning of the array |
262 | *endBadCaptures |
208 | *endBadCaptures++ = move; |
263 | } |
209 | } |
264 |
|
210 | } |
265 | 211 | ||
266 |
|
212 | ++stage; |
267 |
|
213 | move = ss->killers[0]; // First killer move |
268 |
|
214 | if ( move != MOVE_NONE |
269 |
|
215 | && move != ttMove |
270 |
|
216 | && pos.pseudo_legal(move) |
271 |
|
217 | && !pos.capture(move)) |
272 |
|
218 | return move; |
273 | break; |
- | |
274 | 219 | ||
- | 220 | case KILLERS: |
|
- | 221 | ++stage; |
|
- | 222 | move = ss->killers[1]; // Second killer move |
|
- | 223 | if ( move != MOVE_NONE |
|
- | 224 | && move != ttMove |
|
- | 225 | && pos.pseudo_legal(move) |
|
- | 226 | && !pos.capture(move)) |
|
- | 227 | return move; |
|
- | 228 | ||
- | 229 | case COUNTERMOVE: |
|
- | 230 | ++stage; |
|
- | 231 | move = countermove; |
|
- | 232 | if ( move != MOVE_NONE |
|
- | 233 | && move != ttMove |
|
- | 234 | && move != ss->killers[0] |
|
- | 235 | && move != ss->killers[1] |
|
- | 236 | && pos.pseudo_legal(move) |
|
- | 237 | && !pos.capture(move)) |
|
- | 238 | return move; |
|
- | 239 | ||
- | 240 | case QUIET_INIT: |
|
- | 241 | cur = endBadCaptures; |
|
- | 242 | endMoves = generate<QUIETS>(pos, cur); |
|
- | 243 | score<QUIETS>(); |
|
- | 244 | if (depth < 3 * ONE_PLY) |
|
- | 245 | { |
|
- | 246 | ExtMove* goodQuiet = std::partition(cur, endMoves, [](const ExtMove& m) |
|
- | 247 | { return m.value > VALUE_ZERO; }); |
|
275 |
|
248 | insertion_sort(cur, goodQuiet); |
- | 249 | } else |
|
- | 250 | insertion_sort(cur, endMoves); |
|
- | 251 | ++stage; |
|
- | 252 | ||
- | 253 | case QUIET: |
|
- | 254 | while (cur < endMoves) |
|
- | 255 | { |
|
276 | move = *cur++; |
256 | move = *cur++; |
277 | if ( move != ttMove |
257 | if ( move != ttMove |
278 | && move != killers[0] |
258 | && move != ss->killers[0] |
279 | && move != killers[1] |
259 | && move != ss->killers[1] |
280 | && move != |
260 | && move != countermove) |
281 | return move; |
261 | return move; |
- | 262 | } |
|
282 |
|
263 | ++stage; |
- | 264 | cur = moves; // Point to beginning of bad captures |
|
283 | 265 | ||
284 |
|
266 | case BAD_CAPTURES: |
- | 267 | if (cur < endBadCaptures) |
|
285 | return *cur |
268 | return *cur++; |
- | 269 | break; |
|
286 | 270 | ||
- | 271 | case EVASIONS_INIT: |
|
- | 272 | cur = moves; |
|
287 |
|
273 | endMoves = generate<EVASIONS>(pos, cur); |
- | 274 | score<EVASIONS>(); |
|
- | 275 | ++stage; |
|
- | 276 | ||
- | 277 | case ALL_EVASIONS: |
|
- | 278 | while (cur < endMoves) |
|
- | 279 | { |
|
288 | move = pick_best(cur++, endMoves); |
280 | move = pick_best(cur++, endMoves); |
289 | if (move != ttMove) |
281 | if (move != ttMove) |
290 | return move; |
282 | return move; |
- | 283 | } |
|
291 |
|
284 | break; |
292 | 285 | ||
293 |
|
286 | case PROBCUT_INIT: |
294 |
|
287 | cur = moves; |
295 |
|
288 | endMoves = generate<CAPTURES>(pos, cur); |
296 |
|
289 | score<CAPTURES>(); |
297 |
|
290 | ++stage; |
298 | 291 | ||
299 |
|
292 | case PROBCUT_CAPTURES: |
- | 293 | while (cur < endMoves) |
|
- | 294 | { |
|
300 | move = pick_best(cur++, endMoves); |
295 | move = pick_best(cur++, endMoves); |
301 | if ( |
296 | if ( move != ttMove |
- | 297 | && pos.see_ge(move, threshold + 1)) |
|
302 | return move; |
298 | return move; |
- | 299 | } |
|
303 |
|
300 | break; |
304 | 301 | ||
- | 302 | case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: |
|
305 |
|
303 | cur = moves; |
- | 304 | endMoves = generate<CAPTURES>(pos, cur); |
|
- | 305 | score<CAPTURES>(); |
|
- | 306 | ++stage; |
|
- | 307 | ||
- | 308 | case QCAPTURES_1: case QCAPTURES_2: |
|
- | 309 | while (cur < endMoves) |
|
- | 310 | { |
|
306 | move = |
311 | move = pick_best(cur++, endMoves); |
307 | if (move != ttMove) |
312 | if (move != ttMove) |
308 | return move; |
313 | return move; |
- | 314 | } |
|
- | 315 | if (stage == QCAPTURES_2) |
|
309 | break; |
316 | break; |
- | 317 | cur = moves; |
|
- | 318 | endMoves = generate<QUIET_CHECKS>(pos, cur); |
|
- | 319 | ++stage; |
|
310 | 320 | ||
311 |
|
321 | case QCHECKS: |
- | 322 | while (cur < endMoves) |
|
- | 323 | { |
|
- | 324 | move = cur++->move; |
|
- | 325 | if (move != ttMove) |
|
312 | return |
326 | return move; |
- | 327 | } |
|
- | 328 | break; |
|
313 | 329 | ||
- | 330 | case QSEARCH_RECAPTURES: |
|
- | 331 | cur = moves; |
|
- | 332 | endMoves = generate<CAPTURES>(pos, cur); |
|
- | 333 | score<CAPTURES>(); |
|
314 |
|
334 | ++stage; |
- | 335 | ||
- | 336 | case QRECAPTURES: |
|
- | 337 | while (cur < endMoves) |
|
- | 338 | { |
|
- | 339 | move = pick_best(cur++, endMoves); |
|
- | 340 | if (to_sq(move) == recaptureSquare) |
|
315 |
|
341 | return move; |
316 | } |
342 | } |
- | 343 | break; |
|
- | 344 | ||
- | 345 | default: |
|
- | 346 | assert(false); |
|
317 | } |
347 | } |
- | 348 | ||
- | 349 | return MOVE_NONE; |
|
318 | } |
350 | } |