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