Rev 154 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
96 | pmbaty | 1 | /* |
2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 |
||
3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) |
||
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
||
169 | pmbaty | 5 | Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
96 | pmbaty | 6 | |
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 |
||
9 | the Free Software Foundation, either version 3 of the License, or |
||
10 | (at your option) any later version. |
||
11 | |||
12 | Stockfish is distributed in the hope that it will be useful, |
||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
19 | */ |
||
20 | |||
21 | #include <cassert> |
||
22 | |||
23 | #include "movepick.h" |
||
24 | |||
25 | namespace { |
||
26 | |||
27 | enum Stages { |
||
154 | pmbaty | 28 | MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES, |
29 | EVASION, EVASIONS_INIT, ALL_EVASIONS, |
||
30 | PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES, |
||
31 | QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS, |
||
32 | QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2, |
||
33 | QSEARCH_RECAPTURES, QRECAPTURES |
||
96 | pmbaty | 34 | }; |
35 | |||
169 | pmbaty | 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 partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) { |
||
96 | pmbaty | 39 | |
169 | pmbaty | 40 | for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p) |
41 | if (p->value >= limit) |
||
42 | { |
||
43 | ExtMove tmp = *p, *q; |
||
44 | *p = *++sortedEnd; |
||
45 | for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q) |
||
46 | *q = *(q - 1); |
||
47 | *q = tmp; |
||
48 | } |
||
96 | pmbaty | 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. |
||
169 | pmbaty | 54 | Move pick_best(ExtMove* begin, ExtMove* end) { |
55 | |||
56 | std::swap(*begin, *std::max_element(begin, end)); |
||
57 | return *begin; |
||
96 | pmbaty | 58 | } |
59 | |||
60 | } // namespace |
||
61 | |||
62 | |||
63 | /// Constructors of the MovePicker class. As arguments we pass information |
||
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 |
||
66 | /// search captures, promotions, and some checks) and how important good move |
||
67 | /// ordering is at the current node. |
||
68 | |||
169 | pmbaty | 69 | /// MovePicker constructor for the main search |
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), |
||
73 | killers{killers_p[0], killers_p[1]}, depth(d){ |
||
96 | pmbaty | 74 | |
75 | assert(d > DEPTH_ZERO); |
||
76 | |||
77 | stage = pos.checkers() ? EVASION : MAIN_SEARCH; |
||
78 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
||
154 | pmbaty | 79 | stage += (ttMove == MOVE_NONE); |
96 | pmbaty | 80 | } |
81 | |||
169 | pmbaty | 82 | /// MovePicker constructor for quiescence search |
83 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, Square s) |
||
84 | : pos(p), mainHistory(mh), captureHistory(cph) { |
||
96 | pmbaty | 85 | |
86 | assert(d <= DEPTH_ZERO); |
||
87 | |||
88 | if (pos.checkers()) |
||
89 | stage = EVASION; |
||
90 | |||
91 | else if (d > DEPTH_QS_NO_CHECKS) |
||
92 | stage = QSEARCH_WITH_CHECKS; |
||
93 | |||
94 | else if (d > DEPTH_QS_RECAPTURES) |
||
154 | pmbaty | 95 | stage = QSEARCH_NO_CHECKS; |
96 | pmbaty | 96 | |
97 | else |
||
98 | { |
||
154 | pmbaty | 99 | stage = QSEARCH_RECAPTURES; |
96 | pmbaty | 100 | recaptureSquare = s; |
154 | pmbaty | 101 | return; |
96 | pmbaty | 102 | } |
103 | |||
104 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
||
154 | pmbaty | 105 | stage += (ttMove == MOVE_NONE); |
96 | pmbaty | 106 | } |
107 | |||
169 | pmbaty | 108 | /// MovePicker constructor for ProbCut: we generate captures with SEE higher |
109 | /// than or equal to the given threshold. |
||
110 | MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) |
||
111 | : pos(p), captureHistory(cph), threshold(th) { |
||
96 | pmbaty | 112 | |
113 | assert(!pos.checkers()); |
||
114 | |||
115 | stage = PROBCUT; |
||
116 | ttMove = ttm |
||
117 | && pos.pseudo_legal(ttm) |
||
118 | && pos.capture(ttm) |
||
169 | pmbaty | 119 | && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE; |
96 | pmbaty | 120 | |
154 | pmbaty | 121 | stage += (ttMove == MOVE_NONE); |
96 | pmbaty | 122 | } |
123 | |||
169 | pmbaty | 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() { |
||
96 | pmbaty | 129 | |
169 | pmbaty | 130 | static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); |
96 | pmbaty | 131 | |
132 | for (auto& m : *this) |
||
169 | pmbaty | 133 | if (Type == CAPTURES) |
134 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
||
135 | + Value((*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]); |
||
96 | pmbaty | 136 | |
169 | pmbaty | 137 | else if (Type == QUIETS) |
138 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] |
||
139 | + (*contHistory[0])[pos.moved_piece(m)][to_sq(m)] |
||
140 | + (*contHistory[1])[pos.moved_piece(m)][to_sq(m)] |
||
141 | + (*contHistory[3])[pos.moved_piece(m)][to_sq(m)]; |
||
96 | pmbaty | 142 | |
169 | pmbaty | 143 | else // Type == EVASIONS |
144 | { |
||
145 | if (pos.capture(m)) |
||
146 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
||
147 | - Value(type_of(pos.moved_piece(m))); |
||
148 | else |
||
149 | m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - (1 << 28); |
||
150 | } |
||
96 | pmbaty | 151 | } |
152 | |||
153 | /// next_move() is the most important method of the MovePicker class. It returns |
||
154 | /// a new pseudo legal move every time it is called, until there are no more moves |
||
155 | /// left. It picks the move with the biggest value from a list of generated moves |
||
156 | /// taking care not to return the ttMove if it has already been searched. |
||
157 | |||
169 | pmbaty | 158 | Move MovePicker::next_move(bool skipQuiets) { |
96 | pmbaty | 159 | |
160 | Move move; |
||
161 | |||
154 | pmbaty | 162 | switch (stage) { |
96 | pmbaty | 163 | |
154 | pmbaty | 164 | case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: |
165 | case QSEARCH_NO_CHECKS: case PROBCUT: |
||
166 | ++stage; |
||
167 | return ttMove; |
||
96 | pmbaty | 168 | |
154 | pmbaty | 169 | case CAPTURES_INIT: |
170 | endBadCaptures = cur = moves; |
||
171 | endMoves = generate<CAPTURES>(pos, cur); |
||
172 | score<CAPTURES>(); |
||
173 | ++stage; |
||
169 | pmbaty | 174 | /* fallthrough */ |
96 | pmbaty | 175 | |
154 | pmbaty | 176 | case GOOD_CAPTURES: |
177 | while (cur < endMoves) |
||
178 | { |
||
96 | pmbaty | 179 | move = pick_best(cur++, endMoves); |
180 | if (move != ttMove) |
||
181 | { |
||
169 | pmbaty | 182 | if (pos.see_ge(move, Value(-55 * (cur-1)->value / 1024))) |
96 | pmbaty | 183 | return move; |
184 | |||
154 | pmbaty | 185 | // Losing capture, move it to the beginning of the array |
186 | *endBadCaptures++ = move; |
||
96 | pmbaty | 187 | } |
154 | pmbaty | 188 | } |
96 | pmbaty | 189 | |
154 | pmbaty | 190 | ++stage; |
169 | pmbaty | 191 | move = killers[0]; // First killer move |
154 | pmbaty | 192 | if ( move != MOVE_NONE |
193 | && move != ttMove |
||
194 | && pos.pseudo_legal(move) |
||
195 | && !pos.capture(move)) |
||
196 | return move; |
||
169 | pmbaty | 197 | /* fallthrough */ |
96 | pmbaty | 198 | |
154 | pmbaty | 199 | case KILLERS: |
200 | ++stage; |
||
169 | pmbaty | 201 | move = killers[1]; // Second killer move |
154 | pmbaty | 202 | if ( move != MOVE_NONE |
203 | && move != ttMove |
||
204 | && pos.pseudo_legal(move) |
||
205 | && !pos.capture(move)) |
||
206 | return move; |
||
169 | pmbaty | 207 | /* fallthrough */ |
154 | pmbaty | 208 | |
209 | case COUNTERMOVE: |
||
210 | ++stage; |
||
211 | move = countermove; |
||
212 | if ( move != MOVE_NONE |
||
213 | && move != ttMove |
||
169 | pmbaty | 214 | && move != killers[0] |
215 | && move != killers[1] |
||
154 | pmbaty | 216 | && pos.pseudo_legal(move) |
217 | && !pos.capture(move)) |
||
218 | return move; |
||
169 | pmbaty | 219 | /* fallthrough */ |
154 | pmbaty | 220 | |
221 | case QUIET_INIT: |
||
222 | cur = endBadCaptures; |
||
223 | endMoves = generate<QUIETS>(pos, cur); |
||
224 | score<QUIETS>(); |
||
169 | pmbaty | 225 | partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); |
154 | pmbaty | 226 | ++stage; |
169 | pmbaty | 227 | /* fallthrough */ |
154 | pmbaty | 228 | |
229 | case QUIET: |
||
169 | pmbaty | 230 | while ( cur < endMoves |
231 | && (!skipQuiets || cur->value >= VALUE_ZERO)) |
||
154 | pmbaty | 232 | { |
96 | pmbaty | 233 | move = *cur++; |
169 | pmbaty | 234 | |
96 | pmbaty | 235 | if ( move != ttMove |
169 | pmbaty | 236 | && move != killers[0] |
237 | && move != killers[1] |
||
154 | pmbaty | 238 | && move != countermove) |
96 | pmbaty | 239 | return move; |
154 | pmbaty | 240 | } |
241 | ++stage; |
||
242 | cur = moves; // Point to beginning of bad captures |
||
169 | pmbaty | 243 | /* fallthrough */ |
96 | pmbaty | 244 | |
154 | pmbaty | 245 | case BAD_CAPTURES: |
246 | if (cur < endBadCaptures) |
||
247 | return *cur++; |
||
248 | break; |
||
96 | pmbaty | 249 | |
154 | pmbaty | 250 | case EVASIONS_INIT: |
251 | cur = moves; |
||
252 | endMoves = generate<EVASIONS>(pos, cur); |
||
253 | score<EVASIONS>(); |
||
254 | ++stage; |
||
169 | pmbaty | 255 | /* fallthrough */ |
154 | pmbaty | 256 | |
257 | case ALL_EVASIONS: |
||
258 | while (cur < endMoves) |
||
259 | { |
||
96 | pmbaty | 260 | move = pick_best(cur++, endMoves); |
261 | if (move != ttMove) |
||
262 | return move; |
||
154 | pmbaty | 263 | } |
264 | break; |
||
96 | pmbaty | 265 | |
154 | pmbaty | 266 | case PROBCUT_INIT: |
267 | cur = moves; |
||
268 | endMoves = generate<CAPTURES>(pos, cur); |
||
269 | score<CAPTURES>(); |
||
270 | ++stage; |
||
169 | pmbaty | 271 | /* fallthrough */ |
96 | pmbaty | 272 | |
154 | pmbaty | 273 | case PROBCUT_CAPTURES: |
274 | while (cur < endMoves) |
||
275 | { |
||
96 | pmbaty | 276 | move = pick_best(cur++, endMoves); |
154 | pmbaty | 277 | if ( move != ttMove |
169 | pmbaty | 278 | && pos.see_ge(move, threshold)) |
96 | pmbaty | 279 | return move; |
154 | pmbaty | 280 | } |
281 | break; |
||
96 | pmbaty | 282 | |
154 | pmbaty | 283 | case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: |
284 | cur = moves; |
||
285 | endMoves = generate<CAPTURES>(pos, cur); |
||
286 | score<CAPTURES>(); |
||
287 | ++stage; |
||
169 | pmbaty | 288 | /* fallthrough */ |
154 | pmbaty | 289 | |
290 | case QCAPTURES_1: case QCAPTURES_2: |
||
291 | while (cur < endMoves) |
||
292 | { |
||
293 | move = pick_best(cur++, endMoves); |
||
96 | pmbaty | 294 | if (move != ttMove) |
295 | return move; |
||
154 | pmbaty | 296 | } |
297 | if (stage == QCAPTURES_2) |
||
96 | pmbaty | 298 | break; |
154 | pmbaty | 299 | cur = moves; |
300 | endMoves = generate<QUIET_CHECKS>(pos, cur); |
||
301 | ++stage; |
||
169 | pmbaty | 302 | /* fallthrough */ |
96 | pmbaty | 303 | |
154 | pmbaty | 304 | case QCHECKS: |
305 | while (cur < endMoves) |
||
306 | { |
||
307 | move = cur++->move; |
||
308 | if (move != ttMove) |
||
309 | return move; |
||
310 | } |
||
311 | break; |
||
96 | pmbaty | 312 | |
154 | pmbaty | 313 | case QSEARCH_RECAPTURES: |
314 | cur = moves; |
||
315 | endMoves = generate<CAPTURES>(pos, cur); |
||
316 | score<CAPTURES>(); |
||
317 | ++stage; |
||
169 | pmbaty | 318 | /* fallthrough */ |
154 | pmbaty | 319 | |
320 | case QRECAPTURES: |
||
321 | while (cur < endMoves) |
||
322 | { |
||
323 | move = pick_best(cur++, endMoves); |
||
324 | if (to_sq(move) == recaptureSquare) |
||
325 | return move; |
||
96 | pmbaty | 326 | } |
154 | pmbaty | 327 | break; |
328 | |||
329 | default: |
||
330 | assert(false); |
||
96 | pmbaty | 331 | } |
154 | pmbaty | 332 | |
333 | return MOVE_NONE; |
||
96 | pmbaty | 334 | } |