Rev 96 | Rev 169 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 96 | Rev 154 | ||
|---|---|---|---|
| Line 24... | Line 24... | ||
| 24 | #include "thread.h" | 24 | #include "thread.h" | 
| 25 | 25 | ||
| 26 | namespace { | 26 | namespace { | 
| 27 | 27 | ||
| 28 | enum Stages { | 28 | enum Stages { | 
| 29 | MAIN_SEARCH, GOOD_CAPTURES, KILLERS, | 29 | MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES, | 
| 30 | EVASION, ALL_EVASIONS, | 30 | EVASION, EVASIONS_INIT, ALL_EVASIONS, | 
| 31 | 
 | 31 | PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES, | 
| 32 | 
 | 32 | QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS, | 
| 33 | 
 | 33 | QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2, | 
| 34 | 
 | 34 | QSEARCH_RECAPTURES, QRECAPTURES | 
| 35 | STOP | - | |
| 36 | }; | 35 | }; | 
| 37 | 36 | ||
| 38 |   // Our insertion sort, which is guaranteed to be stable, as it should be | 37 |   // Our insertion sort, which is guaranteed to be stable, as it should be | 
| 39 | void insertion_sort(ExtMove* begin, ExtMove* end) | 38 | void insertion_sort(ExtMove* begin, ExtMove* end) | 
| 40 |   { | 39 |   { | 
| Line 65... | Line 64... | ||
| 65 | /// 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 | 
| 66 | /// 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 | 
| 67 | /// search captures, promotions, and some checks) and how important good move | 66 | /// search captures, promotions, and some checks) and how important good move | 
| 68 | /// ordering is at the current node. | 67 | /// ordering is at the current node. | 
| 69 | 68 | ||
| 70 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, | 69 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Search::Stack* s) | 
| 71 | const CounterMoveStats& cmh, Move cm, Search::Stack* s) | - | |
| 72 | : pos(p | 70 | : pos(p), ss(s), depth(d) { | 
| 73 | 71 | ||
| 74 | assert(d > DEPTH_ZERO); | 72 | assert(d > DEPTH_ZERO); | 
| - | 73 | ||
| - | 74 | Square prevSq = to_sq((ss-1)->currentMove); | |
| - | 75 | countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq]; | |
| 75 | 76 | ||
| 76 | stage = pos.checkers() ? EVASION : MAIN_SEARCH; | 77 | stage = pos.checkers() ? EVASION : MAIN_SEARCH; | 
| 77 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; | 78 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; | 
| 78 | 
 | 79 | stage += (ttMove == MOVE_NONE); | 
| 79 | } | 80 | } | 
| 80 | 81 | ||
| 81 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, | 82 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s) | 
| 82 | const HistoryStats& h, Square s) | - | |
| 83 | : pos(p | 83 | : pos(p) { | 
| 84 | 84 | ||
| 85 | assert(d <= DEPTH_ZERO); | 85 | assert(d <= DEPTH_ZERO); | 
| 86 | 86 | ||
| 87 | if (pos.checkers()) | 87 | if (pos.checkers()) | 
| 88 | stage = EVASION; | 88 | stage = EVASION; | 
| 89 | 89 | ||
| 90 | else if (d > DEPTH_QS_NO_CHECKS) | 90 | else if (d > DEPTH_QS_NO_CHECKS) | 
| 91 | stage = QSEARCH_WITH_CHECKS; | 91 | stage = QSEARCH_WITH_CHECKS; | 
| 92 | 92 | ||
| 93 | else if (d > DEPTH_QS_RECAPTURES) | 93 | else if (d > DEPTH_QS_RECAPTURES) | 
| 94 | stage = | 94 | stage = QSEARCH_NO_CHECKS; | 
| 95 | 95 | ||
| 96 |   else | 96 |   else | 
| 97 |   { | 97 |   { | 
| 98 | stage = | 98 | stage = QSEARCH_RECAPTURES; | 
| 99 | recaptureSquare = s; | 99 | recaptureSquare = s; | 
| 100 | 
 | 100 | return; | 
| 101 |   } | 101 |   } | 
| 102 | 102 | ||
| 103 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; | 103 | ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; | 
| 104 | 
 | 104 | stage += (ttMove == MOVE_NONE); | 
| 105 | } | 105 | } | 
| 106 | 106 | ||
| 107 | MovePicker::MovePicker(const Position& p, Move ttm, | 107 | MovePicker::MovePicker(const Position& p, Move ttm, Value th) | 
| 108 | : pos(p | 108 | : pos(p), threshold(th) { | 
| 109 | 109 | ||
| 110 | assert(!pos.checkers()); | 110 | assert(!pos.checkers()); | 
| 111 | 111 | ||
| 112 | stage = PROBCUT; | 112 | stage = PROBCUT; | 
| 113 | 113 | ||
| 114 |   // In ProbCut we generate captures with SEE higher than the given threshold | 114 |   // In ProbCut we generate captures with SEE higher than the given threshold | 
| 115 |   ttMove =   ttm | 115 |   ttMove =   ttm | 
| 116 | && pos.pseudo_legal(ttm) | 116 | && pos.pseudo_legal(ttm) | 
| 117 | && pos.capture(ttm) | 117 | && pos.capture(ttm) | 
| 118 | && pos. | 118 | && pos.see_ge(ttm, threshold + 1)? ttm : MOVE_NONE; | 
| 119 | 119 | ||
| 120 | 
 | 120 | stage += (ttMove == MOVE_NONE); | 
| 121 | } | 121 | } | 
| 122 | 122 | ||
| 123 | 123 | ||
| 124 | /// score() assigns a numerical value to each move in a move list. The moves with | 124 | /// score() assigns a numerical value to each move in a move list. The moves with | 
| 125 | /// highest values will be picked first. | 125 | /// highest values will be picked first. | 
| Line 137... | Line 137... | ||
| 137 | - Value(200 * relative_rank(pos.side_to_move(), to_sq(m))); | 137 | - Value(200 * relative_rank(pos.side_to_move(), to_sq(m))); | 
| 138 | } | 138 | } | 
| 139 | 139 | ||
| 140 | template<> | 140 | template<> | 
| 141 | void MovePicker::score<QUIETS>() { | 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(); | |
| 142 | 151 | ||
| 143 | for (auto& m : *this) | 152 | for (auto& m : *this) | 
| 144 | m.value = history[pos.moved_piece(m)][to_sq(m)] | 153 | m.value = history[pos.moved_piece(m)][to_sq(m)] | 
| 145 | + (* | 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); | |
| 146 | } | 158 | } | 
| 147 | 159 | ||
| 148 | template<> | 160 | template<> | 
| 149 | void MovePicker::score<EVASIONS>() { | 161 | void MovePicker::score<EVASIONS>() { | 
| 150 |   // Try  | 162 |   // Try captures ordered by MVV/LVA, then non-captures ordered by history value | 
| 151 | 
 | 163 | const HistoryStats& history = pos.this_thread()->history; | 
| 152 | 
 | 164 | const FromToStats& fromTo = pos.this_thread()->fromTo; | 
| 153 | 
 | 165 | Color c = pos.side_to_move(); | 
| 154 | 166 | ||
| 155 | for (auto& m : *this) | 167 | for (auto& m : *this) | 
| 156 | if ((see = pos.see_sign(m)) < VALUE_ZERO) | - | |
| 157 | m.value = see - HistoryStats::Max; // At the bottom | - | |
| 158 | - | ||
| 159 | 
 | 168 | if (pos.capture(m)) | 
| 160 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] | 169 | m.value = PieceValue[MG][pos.piece_on(to_sq(m))] | 
| 161 | - Value(type_of(pos.moved_piece(m))) + HistoryStats::Max; | 170 | - Value(type_of(pos.moved_piece(m))) + HistoryStats::Max; | 
| 162 |       else | 171 |       else | 
| 163 | m.value = history[pos.moved_piece(m)][to_sq(m)]; | 172 | m.value = history[pos.moved_piece(m)][to_sq(m)] + fromTo.get(c, m); | 
| 164 | } | - | |
| 165 | - | ||
| 166 | - | ||
| 167 | /// generate_next_stage() generates, scores, and sorts the next bunch of moves | - | |
| 168 | /// when there are no more moves to try for the current stage. | - | |
| 169 | - | ||
| 170 | void MovePicker::generate_next_stage() { | - | |
| 171 | - | ||
| 172 | assert(stage != STOP); | - | |
| 173 | - | ||
| 174 | cur = moves; | - | |
| 175 | - | ||
| 176 | switch (++stage) { | - | |
| 177 | - | ||
| 178 | case GOOD_CAPTURES: case QCAPTURES_1: case QCAPTURES_2: | - | |
| 179 | case PROBCUT_CAPTURES: case RECAPTURES: | - | |
| 180 | endMoves = generate<CAPTURES>(pos, moves); | - | |
| 181 | score<CAPTURES>(); | - | |
| 182 | break; | - | |
| 183 | - | ||
| 184 | case KILLERS: | - | |
| 185 | killers[0] = ss->killers[0]; | - | |
| 186 | killers[1] = ss->killers[1]; | - | |
| 187 | killers[2] = countermove; | - | |
| 188 | cur = killers; | - | |
| 189 | endMoves = cur + 2 + (countermove != killers[0] && countermove != killers[1]); | - | |
| 190 | break; | - | |
| 191 | - | ||
| 192 | case GOOD_QUIETS: | - | |
| 193 | endQuiets = endMoves = generate<QUIETS>(pos, moves); | - | |
| 194 | score<QUIETS>(); | - | |
| 195 | endMoves = std::partition(cur, endMoves, [](const ExtMove& m) { return m.value > VALUE_ZERO; }); | - | |
| 196 | insertion_sort(cur, endMoves); | - | |
| 197 | break; | - | |
| 198 | - | ||
| 199 | case BAD_QUIETS: | - | |
| 200 | cur = endMoves; | - | |
| 201 | endMoves = endQuiets; | - | |
| 202 | if (depth >= 3 * ONE_PLY) | - | |
| 203 | insertion_sort(cur, endMoves); | - | |
| 204 | break; | - | |
| 205 | - | ||
| 206 | case BAD_CAPTURES: | - | |
| 207 |       // Just pick them in reverse order to get correct ordering | - | |
| 208 | cur = moves + MAX_MOVES - 1; | - | |
| 209 | endMoves = endBadCaptures; | - | |
| 210 | break; | - | |
| 211 | - | ||
| 212 | case ALL_EVASIONS: | - | |
| 213 | endMoves = generate<EVASIONS>(pos, moves); | - | |
| 214 | if (endMoves - moves > 1) | - | |
| 215 | score<EVASIONS>(); | - | |
| 216 | break; | - | |
| 217 | - | ||
| 218 | case CHECKS: | - | |
| 219 | endMoves = generate<QUIET_CHECKS>(pos, moves); | - | |
| 220 | break; | - | |
| 221 | - | ||
| 222 | case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_WITHOUT_CHECKS: | - | |
| 223 | case PROBCUT: case RECAPTURE: case STOP: | - | |
| 224 | stage = STOP; | - | |
| 225 | break; | - | |
| 226 | - | ||
| 227 | default: | - | |
| 228 | assert(false); | - | |
| 229 |   } | - | |
| 230 | } | 173 | } | 
| 231 | 174 | ||
| 232 | 175 | ||
| 233 | /// next_move() is the most important method of the MovePicker class. It returns | 176 | /// next_move() is the most important method of the MovePicker class. It returns | 
| 234 | /// a new pseudo legal move every time it is called, until there are no more moves | 177 | /// a new pseudo legal move every time it is called, until there are no more moves | 
| Line 237... | Line 180... | ||
| 237 | 180 | ||
| 238 | Move MovePicker::next_move() { | 181 | Move MovePicker::next_move() { | 
| 239 | 182 | ||
| 240 |   Move move; | 183 |   Move move; | 
| 241 | 184 | ||
| 242 | 
 | 185 | switch (stage) { | 
| 243 |   { | - | |
| 244 | while (cur == endMoves && stage != STOP) | - | |
| 245 | generate_next_stage(); | - | |
| 246 | 186 | ||
| - | 187 | case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: | |
| - | 188 | case QSEARCH_NO_CHECKS: case PROBCUT: | |
| 247 | 
 | 189 | ++stage; | 
| - | 190 | return ttMove; | |
| 248 | 191 | ||
| - | 192 | case CAPTURES_INIT: | |
| 249 | 
 | 193 | endBadCaptures = cur = moves; | 
| 250 | 
 | 194 | endMoves = generate<CAPTURES>(pos, cur); | 
| 251 | 
 | 195 | score<CAPTURES>(); | 
| 252 | 
 | 196 | ++stage; | 
| 253 | 197 | ||
| 254 | 
 | 198 | case GOOD_CAPTURES: | 
| - | 199 | while (cur < endMoves) | |
| - | 200 |       { | |
| 255 | move = pick_best(cur++, endMoves); | 201 | move = pick_best(cur++, endMoves); | 
| 256 | if (move != ttMove) | 202 | if (move != ttMove) | 
| 257 |           { | 203 |           { | 
| 258 | if (pos. | 204 | if (pos.see_ge(move, VALUE_ZERO)) | 
| 259 | return move; | 205 | return move; | 
| 260 | 206 | ||
| 261 |               // Losing capture, move it to the  | 207 |               // Losing capture, move it to the beginning of the array | 
| 262 | *endBadCaptures | 208 | *endBadCaptures++ = move; | 
| 263 |           } | 209 |           } | 
| 264 | 
 | 210 |       } | 
| 265 | 211 | ||
| 266 | 
 | 212 | ++stage; | 
| 267 | 
 | 213 | move = ss->killers[0]; // First killer move | 
| 268 | 
 | 214 | if ( move != MOVE_NONE | 
| 269 | 
 | 215 | && move != ttMove | 
| 270 | 
 | 216 | && pos.pseudo_legal(move) | 
| 271 | 
 | 217 | && !pos.capture(move)) | 
| 272 | 
 | 218 | return move; | 
| 273 | break; | - | |
| 274 | 219 | ||
| - | 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; }); | |
| 275 | 
 | 248 | insertion_sort(cur, goodQuiet); | 
| - | 249 | } else | |
| - | 250 | insertion_sort(cur, endMoves); | |
| - | 251 | ++stage; | |
| - | 252 | ||
| - | 253 | case QUIET: | |
| - | 254 | while (cur < endMoves) | |
| - | 255 |       { | |
| 276 | move = *cur++; | 256 | move = *cur++; | 
| 277 | if ( move != ttMove | 257 | if ( move != ttMove | 
| 278 | && move != killers[0] | 258 | && move != ss->killers[0] | 
| 279 | && move != killers[1] | 259 | && move != ss->killers[1] | 
| 280 | && move != | 260 | && move != countermove) | 
| 281 | return move; | 261 | return move; | 
| - | 262 |       } | |
| 282 | 
 | 263 | ++stage; | 
| - | 264 | cur = moves; // Point to beginning of bad captures | |
| 283 | 265 | ||
| 284 | 
 | 266 | case BAD_CAPTURES: | 
| - | 267 | if (cur < endBadCaptures) | |
| 285 | return *cur | 268 | return *cur++; | 
| - | 269 | break; | |
| 286 | 270 | ||
| - | 271 | case EVASIONS_INIT: | |
| - | 272 | cur = moves; | |
| 287 | 
 | 273 | endMoves = generate<EVASIONS>(pos, cur); | 
| - | 274 | score<EVASIONS>(); | |
| - | 275 | ++stage; | |
| - | 276 | ||
| - | 277 | case ALL_EVASIONS: | |
| - | 278 | while (cur < endMoves) | |
| - | 279 |       { | |
| 288 | move = pick_best(cur++, endMoves); | 280 | move = pick_best(cur++, endMoves); | 
| 289 | if (move != ttMove) | 281 | if (move != ttMove) | 
| 290 | return move; | 282 | return move; | 
| - | 283 |       } | |
| 291 | 
 | 284 | break; | 
| 292 | 285 | ||
| 293 | 
 | 286 | case PROBCUT_INIT: | 
| 294 | 
 | 287 | cur = moves; | 
| 295 | 
 | 288 | endMoves = generate<CAPTURES>(pos, cur); | 
| 296 | 
 | 289 | score<CAPTURES>(); | 
| 297 | 
 | 290 | ++stage; | 
| 298 | 291 | ||
| 299 | 
 | 292 | case PROBCUT_CAPTURES: | 
| - | 293 | while (cur < endMoves) | |
| - | 294 |       { | |
| 300 | move = pick_best(cur++, endMoves); | 295 | move = pick_best(cur++, endMoves); | 
| 301 | if ( | 296 | if ( move != ttMove | 
| - | 297 | && pos.see_ge(move, threshold + 1)) | |
| 302 | return move; | 298 | return move; | 
| - | 299 |       } | |
| 303 | 
 | 300 | break; | 
| 304 | 301 | ||
| - | 302 | case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: | |
| 305 | 
 | 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 |       { | |
| 306 | move = | 311 | move = pick_best(cur++, endMoves); | 
| 307 | if (move != ttMove) | 312 | if (move != ttMove) | 
| 308 | return move; | 313 | return move; | 
| - | 314 |       } | |
| - | 315 | if (stage == QCAPTURES_2) | |
| 309 | break; | 316 | break; | 
| - | 317 | cur = moves; | |
| - | 318 | endMoves = generate<QUIET_CHECKS>(pos, cur); | |
| - | 319 | ++stage; | |
| 310 | 320 | ||
| 311 | 
 | 321 | case QCHECKS: | 
| - | 322 | while (cur < endMoves) | |
| - | 323 |       { | |
| - | 324 | move = cur++->move; | |
| - | 325 | if (move != ttMove) | |
| 312 | return | 326 | return move; | 
| - | 327 |       } | |
| - | 328 | break; | |
| 313 | 329 | ||
| - | 330 | case QSEARCH_RECAPTURES: | |
| - | 331 | cur = moves; | |
| - | 332 | endMoves = generate<CAPTURES>(pos, cur); | |
| - | 333 | score<CAPTURES>(); | |
| 314 | 
 | 334 | ++stage; | 
| - | 335 | ||
| - | 336 | case QRECAPTURES: | |
| - | 337 | while (cur < endMoves) | |
| - | 338 |       { | |
| - | 339 | move = pick_best(cur++, endMoves); | |
| - | 340 | if (to_sq(move) == recaptureSquare) | |
| 315 | 
 | 341 | return move; | 
| 316 |       } | 342 |       } | 
| - | 343 | break; | |
| - | 344 | ||
| - | 345 | default: | |
| - | 346 | assert(false); | |
| 317 |   } | 347 |   } | 
| - | 348 | ||
| - | 349 | return MOVE_NONE; | |
| 318 | } | 350 | } |