Rev 169 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 169 | Rev 185 | ||
|---|---|---|---|
| Line 4... | Line 4... | ||
| 4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
| 5 | Copyright (C) 2015- |
5 | Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
| 6 | 6 | ||
| 7 | Stockfish is free software: you can redistribute it and/or modify |
7 | Stockfish is free software: you can redistribute it and/or modify |
| 8 | it under the terms of the GNU General Public License as published by |
8 | it under the terms of the GNU General Public License as published by |
| 9 | the Free Software Foundation, either version 3 of the License, or |
9 | the Free Software Foundation, either version 3 of the License, or |
| 10 | (at your option) any later version. |
10 | (at your option) any later version. |
| Line 23... | Line 23... | ||
| 23 | #include "movepick.h" |
23 | #include "movepick.h" |
| 24 | 24 | ||
| 25 | namespace { |
25 | namespace { |
| 26 | 26 | ||
| 27 | enum Stages { |
27 | enum Stages { |
| 28 |
|
28 | MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE, |
| 29 |
|
29 | EVASION_TT, EVASION_INIT, EVASION, |
| 30 |
|
30 | PROBCUT_TT, PROBCUT_INIT, PROBCUT, |
| 31 |
|
31 | QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK |
| 32 | QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2, |
- | |
| 33 | QSEARCH_RECAPTURES, QRECAPTURES |
- | |
| 34 | }; |
32 | }; |
| - | 33 | ||
| - | 34 | // Helper filter used with select() |
|
| - | 35 | const auto Any = [](){ return true; }; |
|
| 35 | 36 | ||
| 36 | // partial_insertion_sort() sorts moves in descending order up to and including |
37 | // partial_insertion_sort() sorts moves in descending order up to and including |
| 37 | // a given limit. The order of moves smaller than the limit is left unspecified. |
38 | // a given limit. The order of moves smaller than the limit is left unspecified. |
| 38 | void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) { |
39 | void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) { |
| 39 | 40 | ||
| Line 44... | Line 45... | ||
| 44 | *p = *++sortedEnd; |
45 | *p = *++sortedEnd; |
| 45 | for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q) |
46 | for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q) |
| 46 | *q = *(q - 1); |
47 | *q = *(q - 1); |
| 47 | *q = tmp; |
48 | *q = tmp; |
| 48 | } |
49 | } |
| 49 | } |
- | |
| 50 | - | ||
| 51 | // pick_best() finds the best move in the range (begin, end) and moves it to |
- | |
| 52 | // the front. It's faster than sorting all the moves in advance when there |
- | |
| 53 | // are few moves, e.g., the possible captures. |
- | |
| 54 | Move pick_best(ExtMove* begin, ExtMove* end) { |
- | |
| 55 | - | ||
| 56 | std::swap(*begin, *std::max_element(begin, end)); |
- | |
| 57 | return *begin; |
- | |
| 58 | } |
50 | } |
| 59 | 51 | ||
| 60 | } // namespace |
52 | } // namespace |
| 61 | 53 | ||
| 62 | 54 | ||
| Line 66... | Line 58... | ||
| 66 | /// search captures, promotions, and some checks) and how important good move |
58 | /// search captures, promotions, and some checks) and how important good move |
| 67 | /// ordering is at the current node. |
59 | /// ordering is at the current node. |
| 68 | 60 | ||
| 69 | /// MovePicker constructor for the main search |
61 | /// MovePicker constructor for the main search |
| 70 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, |
62 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, |
| 71 | const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* |
63 | const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers) |
| 72 | : pos(p), mainHistory(mh), captureHistory(cph), |
64 | : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), |
| 73 |
|
65 | refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) { |
| 74 | 66 | ||
| 75 | assert(d > DEPTH_ZERO); |
67 | assert(d > DEPTH_ZERO); |
| 76 | 68 | ||
| 77 | stage = pos.checkers() ? |
69 | stage = pos.checkers() ? EVASION_TT : MAIN_TT; |
| 78 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
70 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
| 79 | stage += (ttMove == MOVE_NONE); |
71 | stage += (ttMove == MOVE_NONE); |
| 80 | } |
72 | } |
| 81 | 73 | ||
| 82 | /// MovePicker constructor for quiescence search |
74 | /// MovePicker constructor for quiescence search |
| 83 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, |
75 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, |
| - | 76 | const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs) |
|
| 84 | : pos(p), mainHistory(mh), captureHistory(cph) { |
77 | : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), recaptureSquare(rs), depth(d) { |
| 85 | 78 | ||
| 86 | assert(d <= DEPTH_ZERO); |
79 | assert(d <= DEPTH_ZERO); |
| 87 | 80 | ||
| 88 |
|
81 | stage = pos.checkers() ? EVASION_TT : QSEARCH_TT; |
| 89 |
|
82 | ttMove = ttm |
| 90 | - | ||
| 91 | else if (d > DEPTH_QS_NO_CHECKS) |
- | |
| 92 | stage = QSEARCH_WITH_CHECKS; |
- | |
| 93 | - | ||
| 94 | else if (d > DEPTH_QS_RECAPTURES) |
- | |
| 95 |
|
83 | && pos.pseudo_legal(ttm) |
| 96 | - | ||
| 97 | else |
- | |
| 98 | { |
- | |
| 99 | stage = QSEARCH_RECAPTURES; |
- | |
| 100 | recaptureSquare = s; |
- | |
| 101 | return; |
- | |
| 102 | } |
- | |
| 103 | - | ||
| 104 |
|
84 | && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) ? ttm : MOVE_NONE; |
| 105 | stage += (ttMove == MOVE_NONE); |
85 | stage += (ttMove == MOVE_NONE); |
| 106 | } |
86 | } |
| 107 | 87 | ||
| 108 | /// MovePicker constructor for ProbCut: we generate captures with SEE |
88 | /// MovePicker constructor for ProbCut: we generate captures with SEE greater |
| 109 | /// than or equal to the given threshold. |
89 | /// than or equal to the given threshold. |
| 110 | MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) |
90 | MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) |
| 111 | : pos(p), captureHistory(cph), threshold(th) { |
91 | : pos(p), captureHistory(cph), threshold(th) { |
| 112 | 92 | ||
| 113 | assert(!pos.checkers()); |
93 | assert(!pos.checkers()); |
| 114 | 94 | ||
| 115 | stage = |
95 | stage = PROBCUT_TT; |
| 116 | ttMove = ttm |
96 | ttMove = ttm |
| 117 | && pos.pseudo_legal(ttm) |
97 | && pos.pseudo_legal(ttm) |
| 118 | && pos.capture(ttm) |
98 | && pos.capture(ttm) |
| 119 | && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE; |
99 | && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE; |
| 120 | - | ||
| 121 | stage += (ttMove == MOVE_NONE); |
100 | stage += (ttMove == MOVE_NONE); |
| 122 | } |
101 | } |
| 123 | 102 | ||
| 124 | /// score() assigns a numerical value to each move in a list, used |
103 | /// MovePicker::score() assigns a numerical value to each move in a list, used |
| 125 | /// Captures are ordered by Most Valuable Victim (MVV), preferring |
104 | /// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring |
| 126 | /// with a good history. Quiets are ordered using the histories. |
105 | /// captures with a good history. Quiets moves are ordered using the histories. |
| 127 | template<GenType Type> |
106 | template<GenType Type> |
| 128 | void MovePicker::score() { |
107 | void MovePicker::score() { |
| 129 | 108 | ||
| 130 | static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); |
109 | static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); |
| 131 | 110 | ||
| 132 | for (auto& m : *this) |
111 | for (auto& m : *this) |
| 133 | if (Type == CAPTURES) |
112 | if (Type == CAPTURES) |
| 134 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
113 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
| 135 | + |
114 | + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))] / 8; |
| 136 | 115 | ||
| 137 | else if (Type == QUIETS) |
116 | else if (Type == QUIETS) |
| 138 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] |
117 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] |
| 139 | + (* |
118 | + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] |
| 140 | + (* |
119 | + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] |
| 141 | + (* |
120 | + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]; |
| 142 | 121 | ||
| 143 | else // Type == EVASIONS |
122 | else // Type == EVASIONS |
| 144 | { |
123 | { |
| 145 | if (pos.capture(m)) |
124 | if (pos.capture(m)) |
| 146 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
125 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
| 147 | - Value(type_of(pos.moved_piece(m))); |
126 | - Value(type_of(pos.moved_piece(m))); |
| 148 | else |
127 | else |
| 149 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] |
128 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] |
| - | 129 | + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] |
|
| - | 130 | - (1 << 28); |
|
| 150 | } |
131 | } |
| 151 | } |
132 | } |
| 152 | 133 | ||
| 153 | /// |
134 | /// MovePicker::select() returns the next move satisfying a predicate function. |
| 154 | /// |
135 | /// It never returns the TT move. |
| 155 |
|
136 | template<MovePicker::PickType T, typename Pred> |
| 156 |
|
137 | Move MovePicker::select(Pred filter) { |
| 157 | 138 | ||
| - | 139 | while (cur < endMoves) |
|
| - | 140 | { |
|
| - | 141 | if (T == Best) |
|
| 158 |
|
142 | std::swap(*cur, *std::max_element(cur, endMoves)); |
| 159 | 143 | ||
| 160 |
|
144 | move = *cur++; |
| 161 | 145 | ||
| - | 146 | if (move != ttMove && filter()) |
|
| - | 147 | return move; |
|
| - | 148 | } |
|
| - | 149 | return move = MOVE_NONE; |
|
| - | 150 | } |
|
| - | 151 | ||
| - | 152 | /// MovePicker::next_move() is the most important method of the MovePicker class. It |
|
| - | 153 | /// returns a new pseudo legal move every time it is called until there are no more |
|
| - | 154 | /// moves left, picking the move with the highest score from a list of generated moves. |
|
| - | 155 | Move MovePicker::next_move(bool skipQuiets) { |
|
| - | 156 | ||
| - | 157 | top: |
|
| 162 | switch (stage) { |
158 | switch (stage) { |
| 163 | 159 | ||
| - | 160 | case MAIN_TT: |
|
| 164 | case |
161 | case EVASION_TT: |
| 165 | case |
162 | case QSEARCH_TT: |
| - | 163 | case PROBCUT_TT: |
|
| 166 | ++stage; |
164 | ++stage; |
| 167 | return ttMove; |
165 | return ttMove; |
| 168 | 166 | ||
| 169 | case |
167 | case CAPTURE_INIT: |
| - | 168 | case PROBCUT_INIT: |
|
| - | 169 | case QCAPTURE_INIT: |
|
| 170 |
|
170 | cur = endBadCaptures = moves; |
| 171 | endMoves = generate<CAPTURES>(pos, cur); |
171 | endMoves = generate<CAPTURES>(pos, cur); |
| - | 172 | ||
| 172 | score<CAPTURES>(); |
173 | score<CAPTURES>(); |
| 173 | ++stage; |
174 | ++stage; |
| 174 |
|
175 | goto top; |
| 175 | 176 | ||
| 176 | case |
177 | case GOOD_CAPTURE: |
| 177 |
|
178 | if (select<Best>([&](){ |
| 178 | { |
- | |
| 179 |
|
179 | return pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)) ? |
| 180 |
|
180 | // Move losing capture to endBadCaptures to be tried later |
| 181 | { |
- | |
| 182 |
|
181 | true : (*endBadCaptures++ = move, false); })) |
| 183 |
|
182 | return move; |
| 184 | 183 | ||
| 185 |
|
184 | // Prepare the pointers to loop over the refutations array |
| 186 |
|
185 | cur = std::begin(refutations); |
| 187 |
|
186 | endMoves = std::end(refutations); |
| - | 187 | ||
| - | 188 | // If the countermove is the same as a killer, skip it |
|
| - | 189 | if ( refutations[0].move == refutations[2].move |
|
| - | 190 | || refutations[1].move == refutations[2].move) |
|
| 188 |
|
191 | --endMoves; |
| 189 | 192 | ||
| 190 | ++stage; |
193 | ++stage; |
| 191 | move = killers[0]; // First killer move |
- | |
| 192 | if ( move != MOVE_NONE |
- | |
| 193 | && move != ttMove |
- | |
| 194 | && pos.pseudo_legal(move) |
- | |
| 195 | && !pos.capture(move)) |
- | |
| 196 | return move; |
- | |
| 197 | /* fallthrough */ |
194 | /* fallthrough */ |
| 198 | 195 | ||
| 199 | case |
196 | case REFUTATION: |
| 200 | ++stage; |
- | |
| 201 | move = killers[1]; // Second killer move |
- | |
| 202 | if ( move != MOVE_NONE |
197 | if (select<Next>([&](){ return move != MOVE_NONE |
| 203 | && |
198 | && !pos.capture(move) |
| 204 | && pos.pseudo_legal(move) |
199 | && pos.pseudo_legal(move); })) |
| 205 | && !pos.capture(move)) |
- | |
| 206 | return move; |
200 | return move; |
| 207 | /* fallthrough */ |
- | |
| 208 | - | ||
| 209 | case COUNTERMOVE: |
- | |
| 210 | ++stage; |
201 | ++stage; |
| 211 | move = countermove; |
- | |
| 212 | if ( move != MOVE_NONE |
- | |
| 213 | && move != ttMove |
- | |
| 214 | && move != killers[0] |
- | |
| 215 | && move != killers[1] |
- | |
| 216 | && pos.pseudo_legal(move) |
- | |
| 217 | && !pos.capture(move)) |
- | |
| 218 | return move; |
- | |
| 219 | /* fallthrough */ |
202 | /* fallthrough */ |
| 220 | 203 | ||
| 221 | case QUIET_INIT: |
204 | case QUIET_INIT: |
| 222 | cur = endBadCaptures; |
205 | cur = endBadCaptures; |
| 223 | endMoves = generate<QUIETS>(pos, cur); |
206 | endMoves = generate<QUIETS>(pos, cur); |
| - | 207 | ||
| 224 | score<QUIETS>(); |
208 | score<QUIETS>(); |
| 225 | partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); |
209 | partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); |
| 226 | ++stage; |
210 | ++stage; |
| 227 | /* fallthrough */ |
211 | /* fallthrough */ |
| 228 | 212 | ||
| 229 | case QUIET: |
213 | case QUIET: |
| 230 |
|
214 | if ( !skipQuiets |
| - | 215 | && select<Next>([&](){return move != refutations[0] |
|
| 231 | && |
216 | && move != refutations[1] |
| - | 217 | && move != refutations[2];})) |
|
| - | 218 | return move; |
|
| - | 219 | ||
| - | 220 | // Prepare the pointers to loop over the bad captures |
|
| 232 |
|
221 | cur = moves; |
| 233 |
|
222 | endMoves = endBadCaptures; |
| 234 | 223 | ||
| 235 | if ( move != ttMove |
- | |
| 236 | && move != killers[0] |
- | |
| 237 | && move != killers[1] |
- | |
| 238 | && move != countermove) |
- | |
| 239 | return move; |
- | |
| 240 | } |
- | |
| 241 | ++stage; |
224 | ++stage; |
| 242 | cur = moves; // Point to beginning of bad captures |
- | |
| 243 | /* fallthrough */ |
225 | /* fallthrough */ |
| 244 | 226 | ||
| 245 | case |
227 | case BAD_CAPTURE: |
| 246 |
|
228 | return select<Next>(Any); |
| 247 | return *cur++; |
- | |
| 248 | break; |
- | |
| 249 | 229 | ||
| 250 | case |
230 | case EVASION_INIT: |
| 251 | cur = moves; |
231 | cur = moves; |
| 252 | endMoves = generate<EVASIONS>(pos, cur); |
232 | endMoves = generate<EVASIONS>(pos, cur); |
| - | 233 | ||
| 253 | score<EVASIONS>(); |
234 | score<EVASIONS>(); |
| 254 | ++stage; |
235 | ++stage; |
| 255 | /* fallthrough */ |
236 | /* fallthrough */ |
| 256 | 237 | ||
| 257 | case |
238 | case EVASION: |
| 258 |
|
239 | return select<Best>(Any); |
| 259 | { |
- | |
| 260 | move = pick_best(cur++, endMoves); |
- | |
| 261 | if (move != ttMove) |
- | |
| 262 | return move; |
- | |
| 263 | } |
- | |
| 264 | break; |
- | |
| 265 | 240 | ||
| 266 | case |
241 | case PROBCUT: |
| 267 | cur = moves; |
- | |
| 268 |
|
242 | return select<Best>([&](){ return pos.see_ge(move, threshold); }); |
| 269 | score<CAPTURES>(); |
- | |
| 270 | ++stage; |
- | |
| 271 | /* fallthrough */ |
- | |
| 272 | 243 | ||
| 273 | case |
244 | case QCAPTURE: |
| 274 |
|
245 | if (select<Best>([&](){ return depth > DEPTH_QS_RECAPTURES |
| 275 | { |
- | |
| 276 |
|
246 | || to_sq(move) == recaptureSquare; })) |
| 277 |
|
247 | return move; |
| - | 248 | ||
| 278 |
|
249 | // If we did not find any move and we do not try checks, we have finished |
| 279 |
|
250 | if (depth != DEPTH_QS_CHECKS) |
| 280 | } |
- | |
| 281 |
|
251 | return MOVE_NONE; |
| 282 | 252 | ||
| 283 | case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: |
- | |
| 284 | cur = moves; |
- | |
| 285 | endMoves = generate<CAPTURES>(pos, cur); |
- | |
| 286 | score<CAPTURES>(); |
- | |
| 287 | ++stage; |
253 | ++stage; |
| 288 | /* fallthrough */ |
254 | /* fallthrough */ |
| 289 | 255 | ||
| 290 | case QCAPTURES_1: case QCAPTURES_2: |
- | |
| 291 | while (cur < endMoves) |
- | |
| 292 | { |
- | |
| 293 | move = pick_best(cur++, endMoves); |
- | |
| 294 | if (move != ttMove) |
- | |
| 295 | return move; |
- | |
| 296 | } |
- | |
| 297 | if (stage == QCAPTURES_2) |
- | |
| 298 |
|
256 | case QCHECK_INIT: |
| 299 | cur = moves; |
257 | cur = moves; |
| 300 | endMoves = generate<QUIET_CHECKS>(pos, cur); |
258 | endMoves = generate<QUIET_CHECKS>(pos, cur); |
| 301 | ++stage; |
- | |
| 302 | /* fallthrough */ |
- | |
| 303 | 259 | ||
| 304 | case QCHECKS: |
- | |
| 305 | while (cur < endMoves) |
- | |
| 306 | { |
- | |
| 307 | move = cur++->move; |
- | |
| 308 | if (move != ttMove) |
- | |
| 309 | return move; |
- | |
| 310 | } |
- | |
| 311 | break; |
- | |
| 312 | - | ||
| 313 | case QSEARCH_RECAPTURES: |
- | |
| 314 | cur = moves; |
- | |
| 315 | endMoves = generate<CAPTURES>(pos, cur); |
- | |
| 316 | score<CAPTURES>(); |
- | |
| 317 | ++stage; |
260 | ++stage; |
| 318 | /* fallthrough */ |
261 | /* fallthrough */ |
| 319 | 262 | ||
| 320 | case |
263 | case QCHECK: |
| 321 |
|
264 | return select<Next>(Any); |
| 322 | { |
- | |
| 323 | move = pick_best(cur++, endMoves); |
- | |
| 324 | if (to_sq(move) == recaptureSquare) |
- | |
| 325 | return move; |
- | |
| 326 | } |
- | |
| 327 | break; |
- | |
| 328 | - | ||
| 329 | default: |
- | |
| 330 | assert(false); |
- | |
| 331 | } |
265 | } |
| 332 | 266 | ||
| - | 267 | assert(false); |
|
| 333 | return MOVE_NONE; |
268 | return MOVE_NONE; // Silence warning |
| 334 | } |
269 | } |