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