Rev 96 | Rev 169 | 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 |
||
5 | Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
||
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 | #include "thread.h" |
||
25 | |||
26 | namespace { |
||
27 | |||
28 | enum Stages { |
||
154 | pmbaty | 29 | MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES, |
30 | EVASION, EVASIONS_INIT, ALL_EVASIONS, |
||
31 | PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES, |
||
32 | QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS, |
||
33 | QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2, |
||
34 | QSEARCH_RECAPTURES, QRECAPTURES |
||
96 | pmbaty | 35 | }; |
36 | |||
37 | // Our insertion sort, which is guaranteed to be stable, as it should be |
||
38 | void insertion_sort(ExtMove* begin, ExtMove* end) |
||
39 | { |
||
40 | ExtMove tmp, *p, *q; |
||
41 | |||
42 | for (p = begin + 1; p < end; ++p) |
||
43 | { |
||
44 | tmp = *p; |
||
45 | for (q = p; q != begin && *(q-1) < tmp; --q) |
||
46 | *q = *(q-1); |
||
47 | *q = tmp; |
||
48 | } |
||
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 | } |
||
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 | |||
154 | pmbaty | 69 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Search::Stack* s) |
70 | : pos(p), ss(s), depth(d) { |
||
96 | pmbaty | 71 | |
72 | assert(d > DEPTH_ZERO); |
||
73 | |||
154 | pmbaty | 74 | Square prevSq = to_sq((ss-1)->currentMove); |
75 | countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq]; |
||
76 | |||
96 | pmbaty | 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 | |||
154 | pmbaty | 82 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s) |
83 | : pos(p) { |
||
96 | pmbaty | 84 | |
85 | assert(d <= DEPTH_ZERO); |
||
86 | |||
87 | if (pos.checkers()) |
||
88 | stage = EVASION; |
||
89 | |||
90 | else if (d > DEPTH_QS_NO_CHECKS) |
||
91 | stage = QSEARCH_WITH_CHECKS; |
||
92 | |||
93 | else if (d > DEPTH_QS_RECAPTURES) |
||
154 | pmbaty | 94 | stage = QSEARCH_NO_CHECKS; |
96 | pmbaty | 95 | |
96 | else |
||
97 | { |
||
154 | pmbaty | 98 | stage = QSEARCH_RECAPTURES; |
96 | pmbaty | 99 | recaptureSquare = s; |
154 | pmbaty | 100 | return; |
96 | pmbaty | 101 | } |
102 | |||
103 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; |
||
154 | pmbaty | 104 | stage += (ttMove == MOVE_NONE); |
96 | pmbaty | 105 | } |
106 | |||
154 | pmbaty | 107 | MovePicker::MovePicker(const Position& p, Move ttm, Value th) |
108 | : pos(p), threshold(th) { |
||
96 | pmbaty | 109 | |
110 | assert(!pos.checkers()); |
||
111 | |||
112 | stage = PROBCUT; |
||
113 | |||
114 | // In ProbCut we generate captures with SEE higher than the given threshold |
||
115 | ttMove = ttm |
||
116 | && pos.pseudo_legal(ttm) |
||
117 | && pos.capture(ttm) |
||
154 | pmbaty | 118 | && pos.see_ge(ttm, threshold + 1)? ttm : MOVE_NONE; |
96 | pmbaty | 119 | |
154 | pmbaty | 120 | stage += (ttMove == MOVE_NONE); |
96 | pmbaty | 121 | } |
122 | |||
123 | |||
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 | // Winning and equal captures in the main search are ordered by MVV, preferring |
||
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 | |||
154 | pmbaty | 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 | |||
96 | pmbaty | 152 | for (auto& m : *this) |
154 | pmbaty | 153 | m.value = history[pos.moved_piece(m)][to_sq(m)] |
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); |
||
96 | pmbaty | 158 | } |
159 | |||
160 | template<> |
||
161 | void MovePicker::score<EVASIONS>() { |
||
154 | pmbaty | 162 | // Try captures ordered by MVV/LVA, then non-captures ordered by history value |
163 | const HistoryStats& history = pos.this_thread()->history; |
||
164 | const FromToStats& fromTo = pos.this_thread()->fromTo; |
||
165 | Color c = pos.side_to_move(); |
||
96 | pmbaty | 166 | |
167 | for (auto& m : *this) |
||
154 | pmbaty | 168 | if (pos.capture(m)) |
96 | pmbaty | 169 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] |
170 | - Value(type_of(pos.moved_piece(m))) + HistoryStats::Max; |
||
171 | else |
||
154 | pmbaty | 172 | m.value = history[pos.moved_piece(m)][to_sq(m)] + fromTo.get(c, m); |
96 | pmbaty | 173 | } |
174 | |||
175 | |||
176 | /// 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 |
||
178 | /// 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. |
||
180 | |||
181 | Move MovePicker::next_move() { |
||
182 | |||
183 | Move move; |
||
184 | |||
154 | pmbaty | 185 | switch (stage) { |
96 | pmbaty | 186 | |
154 | pmbaty | 187 | case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: |
188 | case QSEARCH_NO_CHECKS: case PROBCUT: |
||
189 | ++stage; |
||
190 | return ttMove; |
||
96 | pmbaty | 191 | |
154 | pmbaty | 192 | case CAPTURES_INIT: |
193 | endBadCaptures = cur = moves; |
||
194 | endMoves = generate<CAPTURES>(pos, cur); |
||
195 | score<CAPTURES>(); |
||
196 | ++stage; |
||
96 | pmbaty | 197 | |
154 | pmbaty | 198 | case GOOD_CAPTURES: |
199 | while (cur < endMoves) |
||
200 | { |
||
96 | pmbaty | 201 | move = pick_best(cur++, endMoves); |
202 | if (move != ttMove) |
||
203 | { |
||
154 | pmbaty | 204 | if (pos.see_ge(move, VALUE_ZERO)) |
96 | pmbaty | 205 | return move; |
206 | |||
154 | pmbaty | 207 | // Losing capture, move it to the beginning of the array |
208 | *endBadCaptures++ = move; |
||
96 | pmbaty | 209 | } |
154 | pmbaty | 210 | } |
96 | pmbaty | 211 | |
154 | pmbaty | 212 | ++stage; |
213 | move = ss->killers[0]; // First killer move |
||
214 | if ( move != MOVE_NONE |
||
215 | && move != ttMove |
||
216 | && pos.pseudo_legal(move) |
||
217 | && !pos.capture(move)) |
||
218 | return move; |
||
96 | pmbaty | 219 | |
154 | pmbaty | 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; }); |
||
248 | insertion_sort(cur, goodQuiet); |
||
249 | } else |
||
250 | insertion_sort(cur, endMoves); |
||
251 | ++stage; |
||
252 | |||
253 | case QUIET: |
||
254 | while (cur < endMoves) |
||
255 | { |
||
96 | pmbaty | 256 | move = *cur++; |
257 | if ( move != ttMove |
||
154 | pmbaty | 258 | && move != ss->killers[0] |
259 | && move != ss->killers[1] |
||
260 | && move != countermove) |
||
96 | pmbaty | 261 | return move; |
154 | pmbaty | 262 | } |
263 | ++stage; |
||
264 | cur = moves; // Point to beginning of bad captures |
||
96 | pmbaty | 265 | |
154 | pmbaty | 266 | case BAD_CAPTURES: |
267 | if (cur < endBadCaptures) |
||
268 | return *cur++; |
||
269 | break; |
||
96 | pmbaty | 270 | |
154 | pmbaty | 271 | case EVASIONS_INIT: |
272 | cur = moves; |
||
273 | endMoves = generate<EVASIONS>(pos, cur); |
||
274 | score<EVASIONS>(); |
||
275 | ++stage; |
||
276 | |||
277 | case ALL_EVASIONS: |
||
278 | while (cur < endMoves) |
||
279 | { |
||
96 | pmbaty | 280 | move = pick_best(cur++, endMoves); |
281 | if (move != ttMove) |
||
282 | return move; |
||
154 | pmbaty | 283 | } |
284 | break; |
||
96 | pmbaty | 285 | |
154 | pmbaty | 286 | case PROBCUT_INIT: |
287 | cur = moves; |
||
288 | endMoves = generate<CAPTURES>(pos, cur); |
||
289 | score<CAPTURES>(); |
||
290 | ++stage; |
||
96 | pmbaty | 291 | |
154 | pmbaty | 292 | case PROBCUT_CAPTURES: |
293 | while (cur < endMoves) |
||
294 | { |
||
96 | pmbaty | 295 | move = pick_best(cur++, endMoves); |
154 | pmbaty | 296 | if ( move != ttMove |
297 | && pos.see_ge(move, threshold + 1)) |
||
96 | pmbaty | 298 | return move; |
154 | pmbaty | 299 | } |
300 | break; |
||
96 | pmbaty | 301 | |
154 | pmbaty | 302 | case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: |
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 | { |
||
311 | move = pick_best(cur++, endMoves); |
||
96 | pmbaty | 312 | if (move != ttMove) |
313 | return move; |
||
154 | pmbaty | 314 | } |
315 | if (stage == QCAPTURES_2) |
||
96 | pmbaty | 316 | break; |
154 | pmbaty | 317 | cur = moves; |
318 | endMoves = generate<QUIET_CHECKS>(pos, cur); |
||
319 | ++stage; |
||
96 | pmbaty | 320 | |
154 | pmbaty | 321 | case QCHECKS: |
322 | while (cur < endMoves) |
||
323 | { |
||
324 | move = cur++->move; |
||
325 | if (move != ttMove) |
||
326 | return move; |
||
327 | } |
||
328 | break; |
||
96 | pmbaty | 329 | |
154 | pmbaty | 330 | case QSEARCH_RECAPTURES: |
331 | cur = moves; |
||
332 | endMoves = generate<CAPTURES>(pos, cur); |
||
333 | score<CAPTURES>(); |
||
334 | ++stage; |
||
335 | |||
336 | case QRECAPTURES: |
||
337 | while (cur < endMoves) |
||
338 | { |
||
339 | move = pick_best(cur++, endMoves); |
||
340 | if (to_sq(move) == recaptureSquare) |
||
341 | return move; |
||
96 | pmbaty | 342 | } |
154 | pmbaty | 343 | break; |
344 | |||
345 | default: |
||
346 | assert(false); |
||
96 | pmbaty | 347 | } |
154 | pmbaty | 348 | |
349 | return MOVE_NONE; |
||
96 | pmbaty | 350 | } |