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