Rev 154 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 154 | Rev 169 | ||
|---|---|---|---|
| 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-2018 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 19... | Line 19... | ||
| 19 | */ |
19 | */ |
| 20 | 20 | ||
| 21 | #include <cassert> |
21 | #include <cassert> |
| 22 | 22 | ||
| 23 | #include "movepick.h" |
23 | #include "movepick.h" |
| 24 | #include "thread.h" |
- | |
| 25 | 24 | ||
| 26 | namespace { |
25 | namespace { |
| 27 | 26 | ||
| 28 | enum Stages { |
27 | enum Stages { |
| 29 | MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES, |
28 | MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES, |
| Line 32... | Line 31... | ||
| 32 | QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS, |
31 | QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS, |
| 33 | QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2, |
32 | QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2, |
| 34 | QSEARCH_RECAPTURES, QRECAPTURES |
33 | QSEARCH_RECAPTURES, QRECAPTURES |
| 35 | }; |
34 | }; |
| 36 | 35 | ||
| 37 | // |
36 | // 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 | void |
38 | void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) { |
| 39 | { |
- | |
| 40 | ExtMove tmp, *p, *q; |
- | |
| 41 | 39 | ||
| 42 | for (p = begin + 1; p < end; ++p) |
40 | for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p) |
| - | 41 | if (p->value >= limit) |
|
| 43 | { |
42 | { |
| 44 | tmp = * |
43 | ExtMove tmp = *p, *q; |
| - | 44 | *p = *++sortedEnd; |
|
| 45 | for (q = |
45 | for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q) |
| 46 | *q = *(q-1); |
46 | *q = *(q - 1); |
| 47 | *q = tmp; |
47 | *q = tmp; |
| 48 | } |
48 | } |
| 49 | } |
49 | } |
| 50 | 50 | ||
| 51 | // pick_best() finds the best move in the range (begin, end) and moves it to |
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 |
52 | // the front. It's faster than sorting all the moves in advance when there |
| 53 | // are few moves, e.g., the possible captures. |
53 | // are few moves, e.g., the possible captures. |
| 54 | Move pick_best(ExtMove* begin, ExtMove* end) |
54 | Move pick_best(ExtMove* begin, ExtMove* end) { |
| 55 | { |
55 | |
| 56 |
|
56 | std::swap(*begin, *std::max_element(begin, end)); |
| 57 |
|
57 | return *begin; |
| 58 | } |
58 | } |
| 59 | 59 | ||
| 60 | } // namespace |
60 | } // namespace |
| 61 | 61 | ||
| 62 | 62 | ||
| Line 64... | Line 64... | ||
| 64 | /// 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 |
| 65 | /// 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 |
| 66 | /// search captures, promotions, and some checks) and how important good move |
66 | /// search captures, promotions, and some checks) and how important good move |
| 67 | /// ordering is at the current node. |
67 | /// ordering is at the current node. |
| 68 | 68 | ||
| - | 69 | /// MovePicker constructor for the main search |
|
| 69 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, |
70 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, |
| - | 71 | const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers_p) |
|
| - | 72 | : pos(p), mainHistory(mh), captureHistory(cph), contHistory(ch), countermove(cm), |
|
| 70 |
|
73 | killers{killers_p[0], killers_p[1]}, depth(d){ |
| 71 | 74 | ||
| 72 | assert(d > DEPTH_ZERO); |
75 | assert(d > DEPTH_ZERO); |
| 73 | - | ||
| 74 | Square prevSq = to_sq((ss-1)->currentMove); |
- | |
| 75 | countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq]; |
- | |
| 76 | 76 | ||
| 77 | stage = pos.checkers() ? EVASION : MAIN_SEARCH; |
77 | stage = pos.checkers() ? EVASION : MAIN_SEARCH; |
| 78 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
78 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
| 79 | stage += (ttMove == MOVE_NONE); |
79 | stage += (ttMove == MOVE_NONE); |
| 80 | } |
80 | } |
| 81 | 81 | ||
| - | 82 | /// MovePicker constructor for quiescence search |
|
| 82 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s) |
83 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, Square s) |
| 83 | : pos(p) { |
84 | : pos(p), mainHistory(mh), captureHistory(cph) { |
| 84 | 85 | ||
| 85 | assert(d <= DEPTH_ZERO); |
86 | assert(d <= DEPTH_ZERO); |
| 86 | 87 | ||
| 87 | if (pos.checkers()) |
88 | if (pos.checkers()) |
| 88 | stage = EVASION; |
89 | stage = EVASION; |
| Line 102... | Line 103... | ||
| 102 | 103 | ||
| 103 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
104 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
| 104 | stage += (ttMove == MOVE_NONE); |
105 | stage += (ttMove == MOVE_NONE); |
| 105 | } |
106 | } |
| 106 | 107 | ||
| - | 108 | /// MovePicker constructor for ProbCut: we generate captures with SEE higher |
|
| - | 109 | /// than or equal to the given threshold. |
|
| 107 | MovePicker::MovePicker(const Position& p, Move ttm, Value |
110 | MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) |
| 108 | : pos(p), threshold(th) { |
111 | : pos(p), captureHistory(cph), threshold(th) { |
| 109 | 112 | ||
| 110 | assert(!pos.checkers()); |
113 | assert(!pos.checkers()); |
| 111 | 114 | ||
| 112 | stage = PROBCUT; |
115 | stage = PROBCUT; |
| 113 | - | ||
| 114 | // In ProbCut we generate captures with SEE higher than the given threshold |
- | |
| 115 | ttMove = ttm |
116 | ttMove = ttm |
| 116 | && pos.pseudo_legal(ttm) |
117 | && pos.pseudo_legal(ttm) |
| 117 | && pos.capture(ttm) |
118 | && pos.capture(ttm) |
| 118 | && pos.see_ge(ttm, threshold |
119 | && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE; |
| 119 | 120 | ||
| 120 | stage += (ttMove == MOVE_NONE); |
121 | stage += (ttMove == MOVE_NONE); |
| 121 | } |
122 | } |
| 122 | 123 | ||
| - | 124 | /// score() assigns a numerical value to each move in a list, used for sorting. |
|
| - | 125 | /// Captures are ordered by Most Valuable Victim (MVV), preferring captures |
|
| - | 126 | /// with a good history. Quiets are ordered using the histories. |
|
| - | 127 | template<GenType Type> |
|
| - | 128 | void MovePicker::score() { |
|
| 123 | 129 | ||
| 124 | /// score() assigns a numerical value to each move in a move list. The moves with |
- | |
| 125 | /// highest values will be picked first. |
- | |
| 126 | template<> |
- | |
| 127 | void MovePicker::score<CAPTURES>() { |
- | |
| 128 |
|
130 | static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); |
| 129 | // captures near our home rank. Surprisingly, this appears to perform slightly |
- | |
| 130 | // better than SEE-based move ordering: exchanging big pieces before capturing |
- | |
| 131 | // a hanging piece probably helps to reduce the subtree size. |
- | |
| 132 | // In the main search we want to push captures with negative SEE values to the |
- | |
| 133 | // badCaptures[] array, but instead of doing it now we delay until the move |
- | |
| 134 | // has been picked up, saving some SEE calls in case we get a cutoff. |
- | |
| 135 | for (auto& m : *this) |
- | |
| 136 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
- | |
| 137 | - Value(200 * relative_rank(pos.side_to_move(), to_sq(m))); |
- | |
| 138 | } |
- | |
| 139 | - | ||
| 140 | template<> |
- | |
| 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(); |
- | |
| 151 | 131 | ||
| 152 | for (auto& m : *this) |
132 | for (auto& m : *this) |
| 153 |
|
133 | if (Type == CAPTURES) |
| 154 |
|
134 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
| 155 | + (fm ? (*fm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO) |
- | |
| 156 | + ( |
135 | + Value((*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]); |
| 157 | + fromTo.get(c, m); |
- | |
| 158 | } |
- | |
| 159 | 136 | ||
| 160 | template<> |
- | |
| 161 |
|
137 | else if (Type == QUIETS) |
| 162 |
|
138 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] |
| 163 |
|
139 | + (*contHistory[0])[pos.moved_piece(m)][to_sq(m)] |
| 164 |
|
140 | + (*contHistory[1])[pos.moved_piece(m)][to_sq(m)] |
| 165 |
|
141 | + (*contHistory[3])[pos.moved_piece(m)][to_sq(m)]; |
| 166 | 142 | ||
| 167 |
|
143 | else // Type == EVASIONS |
| - | 144 | { |
|
| 168 | if (pos.capture(m)) |
145 | if (pos.capture(m)) |
| 169 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
146 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
| 170 | - Value(type_of(pos.moved_piece(m))) |
147 | - Value(type_of(pos.moved_piece(m))); |
| 171 | else |
148 | else |
| 172 | m.value = |
149 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - (1 << 28); |
| - | 150 | } |
|
| 173 | } |
151 | } |
| 174 | - | ||
| 175 | 152 | ||
| 176 | /// next_move() is the most important method of the MovePicker class. It returns |
153 | /// next_move() is the most important method of the MovePicker class. It returns |
| 177 | /// a new pseudo legal move every time it is called, until there are no more moves |
154 | /// a new pseudo legal move every time it is called, until there are no more moves |
| 178 | /// left. It picks the move with the biggest value from a list of generated moves |
155 | /// left. It picks the move with the biggest value from a list of generated moves |
| 179 | /// taking care not to return the ttMove if it has already been searched. |
156 | /// taking care not to return the ttMove if it has already been searched. |
| 180 | 157 | ||
| 181 | Move MovePicker::next_move() { |
158 | Move MovePicker::next_move(bool skipQuiets) { |
| 182 | 159 | ||
| 183 | Move move; |
160 | Move move; |
| 184 | 161 | ||
| 185 | switch (stage) { |
162 | switch (stage) { |
| 186 | 163 | ||
| Line 192... | Line 169... | ||
| 192 | case CAPTURES_INIT: |
169 | case CAPTURES_INIT: |
| 193 | endBadCaptures = cur = moves; |
170 | endBadCaptures = cur = moves; |
| 194 | endMoves = generate<CAPTURES>(pos, cur); |
171 | endMoves = generate<CAPTURES>(pos, cur); |
| 195 | score<CAPTURES>(); |
172 | score<CAPTURES>(); |
| 196 | ++stage; |
173 | ++stage; |
| - | 174 | /* fallthrough */ |
|
| 197 | 175 | ||
| 198 | case GOOD_CAPTURES: |
176 | case GOOD_CAPTURES: |
| 199 | while (cur < endMoves) |
177 | while (cur < endMoves) |
| 200 | { |
178 | { |
| 201 | move = pick_best(cur++, endMoves); |
179 | move = pick_best(cur++, endMoves); |
| 202 | if (move != ttMove) |
180 | if (move != ttMove) |
| 203 | { |
181 | { |
| 204 | if (pos.see_ge(move, |
182 | if (pos.see_ge(move, Value(-55 * (cur-1)->value / 1024))) |
| 205 | return move; |
183 | return move; |
| 206 | 184 | ||
| 207 | // Losing capture, move it to the beginning of the array |
185 | // Losing capture, move it to the beginning of the array |
| 208 | *endBadCaptures++ = move; |
186 | *endBadCaptures++ = move; |
| 209 | } |
187 | } |
| 210 | } |
188 | } |
| 211 | 189 | ||
| 212 | ++stage; |
190 | ++stage; |
| 213 | move = |
191 | move = killers[0]; // First killer move |
| 214 | if ( move != MOVE_NONE |
192 | if ( move != MOVE_NONE |
| 215 | && move != ttMove |
193 | && move != ttMove |
| 216 | && pos.pseudo_legal(move) |
194 | && pos.pseudo_legal(move) |
| 217 | && !pos.capture(move)) |
195 | && !pos.capture(move)) |
| 218 | return move; |
196 | return move; |
| - | 197 | /* fallthrough */ |
|
| 219 | 198 | ||
| 220 | case KILLERS: |
199 | case KILLERS: |
| 221 | ++stage; |
200 | ++stage; |
| 222 | move = |
201 | move = killers[1]; // Second killer move |
| 223 | if ( move != MOVE_NONE |
202 | if ( move != MOVE_NONE |
| 224 | && move != ttMove |
203 | && move != ttMove |
| 225 | && pos.pseudo_legal(move) |
204 | && pos.pseudo_legal(move) |
| 226 | && !pos.capture(move)) |
205 | && !pos.capture(move)) |
| 227 | return move; |
206 | return move; |
| - | 207 | /* fallthrough */ |
|
| 228 | 208 | ||
| 229 | case COUNTERMOVE: |
209 | case COUNTERMOVE: |
| 230 | ++stage; |
210 | ++stage; |
| 231 | move = countermove; |
211 | move = countermove; |
| 232 | if ( move != MOVE_NONE |
212 | if ( move != MOVE_NONE |
| 233 | && move != ttMove |
213 | && move != ttMove |
| 234 | && move != |
214 | && move != killers[0] |
| 235 | && move != |
215 | && move != killers[1] |
| 236 | && pos.pseudo_legal(move) |
216 | && pos.pseudo_legal(move) |
| 237 | && !pos.capture(move)) |
217 | && !pos.capture(move)) |
| 238 | return move; |
218 | return move; |
| - | 219 | /* fallthrough */ |
|
| 239 | 220 | ||
| 240 | case QUIET_INIT: |
221 | case QUIET_INIT: |
| 241 | cur = endBadCaptures; |
222 | cur = endBadCaptures; |
| 242 | endMoves = generate<QUIETS>(pos, cur); |
223 | endMoves = generate<QUIETS>(pos, cur); |
| 243 | score<QUIETS>(); |
224 | 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; }); |
- | |
| 248 | insertion_sort(cur, goodQuiet); |
- | |
| 249 | } else |
- | |
| 250 |
|
225 | partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); |
| 251 | ++stage; |
226 | ++stage; |
| - | 227 | /* fallthrough */ |
|
| 252 | 228 | ||
| 253 | case QUIET: |
229 | case QUIET: |
| 254 | while (cur < endMoves |
230 | while ( cur < endMoves |
| - | 231 | && (!skipQuiets || cur->value >= VALUE_ZERO)) |
|
| 255 | { |
232 | { |
| 256 | move = *cur++; |
233 | move = *cur++; |
| - | 234 | ||
| 257 | if ( move != ttMove |
235 | if ( move != ttMove |
| 258 | && move != |
236 | && move != killers[0] |
| 259 | && move != |
237 | && move != killers[1] |
| 260 | && move != countermove) |
238 | && move != countermove) |
| 261 | return move; |
239 | return move; |
| 262 | } |
240 | } |
| 263 | ++stage; |
241 | ++stage; |
| 264 | cur = moves; // Point to beginning of bad captures |
242 | cur = moves; // Point to beginning of bad captures |
| - | 243 | /* fallthrough */ |
|
| 265 | 244 | ||
| 266 | case BAD_CAPTURES: |
245 | case BAD_CAPTURES: |
| 267 | if (cur < endBadCaptures) |
246 | if (cur < endBadCaptures) |
| 268 | return *cur++; |
247 | return *cur++; |
| 269 | break; |
248 | break; |
| Line 271... | Line 250... | ||
| 271 | case EVASIONS_INIT: |
250 | case EVASIONS_INIT: |
| 272 | cur = moves; |
251 | cur = moves; |
| 273 | endMoves = generate<EVASIONS>(pos, cur); |
252 | endMoves = generate<EVASIONS>(pos, cur); |
| 274 | score<EVASIONS>(); |
253 | score<EVASIONS>(); |
| 275 | ++stage; |
254 | ++stage; |
| - | 255 | /* fallthrough */ |
|
| 276 | 256 | ||
| 277 | case ALL_EVASIONS: |
257 | case ALL_EVASIONS: |
| 278 | while (cur < endMoves) |
258 | while (cur < endMoves) |
| 279 | { |
259 | { |
| 280 | move = pick_best(cur++, endMoves); |
260 | move = pick_best(cur++, endMoves); |
| Line 286... | Line 266... | ||
| 286 | case PROBCUT_INIT: |
266 | case PROBCUT_INIT: |
| 287 | cur = moves; |
267 | cur = moves; |
| 288 | endMoves = generate<CAPTURES>(pos, cur); |
268 | endMoves = generate<CAPTURES>(pos, cur); |
| 289 | score<CAPTURES>(); |
269 | score<CAPTURES>(); |
| 290 | ++stage; |
270 | ++stage; |
| - | 271 | /* fallthrough */ |
|
| 291 | 272 | ||
| 292 | case PROBCUT_CAPTURES: |
273 | case PROBCUT_CAPTURES: |
| 293 | while (cur < endMoves) |
274 | while (cur < endMoves) |
| 294 | { |
275 | { |
| 295 | move = pick_best(cur++, endMoves); |
276 | move = pick_best(cur++, endMoves); |
| 296 | if ( move != ttMove |
277 | if ( move != ttMove |
| 297 | && pos.see_ge(move, threshold |
278 | && pos.see_ge(move, threshold)) |
| 298 | return move; |
279 | return move; |
| 299 | } |
280 | } |
| 300 | break; |
281 | break; |
| 301 | 282 | ||
| 302 | case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: |
283 | case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: |
| 303 | cur = moves; |
284 | cur = moves; |
| 304 | endMoves = generate<CAPTURES>(pos, cur); |
285 | endMoves = generate<CAPTURES>(pos, cur); |
| 305 | score<CAPTURES>(); |
286 | score<CAPTURES>(); |
| 306 | ++stage; |
287 | ++stage; |
| - | 288 | /* fallthrough */ |
|
| 307 | 289 | ||
| 308 | case QCAPTURES_1: case QCAPTURES_2: |
290 | case QCAPTURES_1: case QCAPTURES_2: |
| 309 | while (cur < endMoves) |
291 | while (cur < endMoves) |
| 310 | { |
292 | { |
| 311 | move = pick_best(cur++, endMoves); |
293 | move = pick_best(cur++, endMoves); |
| Line 315... | Line 297... | ||
| 315 | if (stage == QCAPTURES_2) |
297 | if (stage == QCAPTURES_2) |
| 316 | break; |
298 | break; |
| 317 | cur = moves; |
299 | cur = moves; |
| 318 | endMoves = generate<QUIET_CHECKS>(pos, cur); |
300 | endMoves = generate<QUIET_CHECKS>(pos, cur); |
| 319 | ++stage; |
301 | ++stage; |
| - | 302 | /* fallthrough */ |
|
| 320 | 303 | ||
| 321 | case QCHECKS: |
304 | case QCHECKS: |
| 322 | while (cur < endMoves) |
305 | while (cur < endMoves) |
| 323 | { |
306 | { |
| 324 | move = cur++->move; |
307 | move = cur++->move; |
| Line 330... | Line 313... | ||
| 330 | case QSEARCH_RECAPTURES: |
313 | case QSEARCH_RECAPTURES: |
| 331 | cur = moves; |
314 | cur = moves; |
| 332 | endMoves = generate<CAPTURES>(pos, cur); |
315 | endMoves = generate<CAPTURES>(pos, cur); |
| 333 | score<CAPTURES>(); |
316 | score<CAPTURES>(); |
| 334 | ++stage; |
317 | ++stage; |
| - | 318 | /* fallthrough */ |
|
| 335 | 319 | ||
| 336 | case QRECAPTURES: |
320 | case QRECAPTURES: |
| 337 | while (cur < endMoves) |
321 | while (cur < endMoves) |
| 338 | { |
322 | { |
| 339 | move = pick_best(cur++, endMoves); |
323 | move = pick_best(cur++, endMoves); |