Subversion Repositories Games.Chess Giants

Rev

Rev 169 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 169 Rev 185
Line 4... Line 4...
4
  Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
4
  Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
5
  Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
5
  Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
6
 
6
 
7
  Stockfish is free software: you can redistribute it and/or modify
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
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
9
  the Free Software Foundation, either version 3 of the License, or
10
  (at your option) any later version.
10
  (at your option) any later version.
Line 23... Line 23...
23
#include "movepick.h"
23
#include "movepick.h"
24
 
24
 
25
namespace {
25
namespace {
26
 
26
 
27
  enum Stages {
27
  enum Stages {
28
    MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES,
28
    MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE,
29
    EVASION, EVASIONS_INIT, ALL_EVASIONS,
29
    EVASION_TT, EVASION_INIT, EVASION,
30
    PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES,
30
    PROBCUT_TT, PROBCUT_INIT, PROBCUT,
31
    QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS,
31
    QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK
32
    QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2,
-
 
33
    QSEARCH_RECAPTURES, QRECAPTURES
-
 
34
  };
32
  };
-
 
33
 
-
 
34
  // Helper filter used with select()
-
 
35
  const auto Any = [](){ return true; };
35
 
36
 
36
  // partial_insertion_sort() sorts moves in descending order up to and including
37
  // 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
  // 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) {
39
  void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
39
 
40
 
Line 44... Line 45...
44
            *p = *++sortedEnd;
45
            *p = *++sortedEnd;
45
            for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q)
46
            for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q)
46
                *q = *(q - 1);
47
                *q = *(q - 1);
47
            *q = tmp;
48
            *q = tmp;
48
        }
49
        }
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
  }
50
  }
59
 
51
 
60
} // namespace
52
} // namespace
61
 
53
 
62
 
54
 
Line 66... Line 58...
66
/// search captures, promotions, and some checks) and how important good move
58
/// search captures, promotions, and some checks) and how important good move
67
/// ordering is at the current node.
59
/// ordering is at the current node.
68
 
60
 
69
/// MovePicker constructor for the main search
61
/// MovePicker constructor for the main search
70
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
62
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
71
                       const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers_p)
63
                       const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers)
72
           : pos(p), mainHistory(mh), captureHistory(cph), contHistory(ch), countermove(cm),
64
           : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch),
73
             killers{killers_p[0], killers_p[1]}, depth(d){
65
             refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) {
74
 
66
 
75
  assert(d > DEPTH_ZERO);
67
  assert(d > DEPTH_ZERO);
76
 
68
 
77
  stage = pos.checkers() ? EVASION : MAIN_SEARCH;
69
  stage = pos.checkers() ? EVASION_TT : MAIN_TT;
78
  ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
70
  ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
79
  stage += (ttMove == MOVE_NONE);
71
  stage += (ttMove == MOVE_NONE);
80
}
72
}
81
 
73
 
82
/// MovePicker constructor for quiescence search
74
/// MovePicker constructor for quiescence search
83
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,  const CapturePieceToHistory* cph, Square s)
75
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
-
 
76
                       const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs)
84
           : pos(p), mainHistory(mh), captureHistory(cph) {
77
           : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), recaptureSquare(rs), depth(d) {
85
 
78
 
86
  assert(d <= DEPTH_ZERO);
79
  assert(d <= DEPTH_ZERO);
87
 
80
 
88
  if (pos.checkers())
81
  stage = pos.checkers() ? EVASION_TT : QSEARCH_TT;
89
      stage = EVASION;
82
  ttMove =    ttm
90
 
-
 
91
  else if (d > DEPTH_QS_NO_CHECKS)
-
 
92
      stage = QSEARCH_WITH_CHECKS;
-
 
93
 
-
 
94
  else if (d > DEPTH_QS_RECAPTURES)
-
 
95
      stage = QSEARCH_NO_CHECKS;
83
           && pos.pseudo_legal(ttm)
96
 
-
 
97
  else
-
 
98
  {
-
 
99
      stage = QSEARCH_RECAPTURES;
-
 
100
      recaptureSquare = s;
-
 
101
      return;
-
 
102
  }
-
 
103
 
-
 
104
  ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
84
           && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) ? ttm : MOVE_NONE;
105
  stage += (ttMove == MOVE_NONE);
85
  stage += (ttMove == MOVE_NONE);
106
}
86
}
107
 
87
 
108
/// MovePicker constructor for ProbCut: we generate captures with SEE higher
88
/// MovePicker constructor for ProbCut: we generate captures with SEE greater
109
/// than or equal to the given threshold.
89
/// than or equal to the given threshold.
110
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
90
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
111
           : pos(p), captureHistory(cph), threshold(th) {
91
           : pos(p), captureHistory(cph), threshold(th) {
112
 
92
 
113
  assert(!pos.checkers());
93
  assert(!pos.checkers());
114
 
94
 
115
  stage = PROBCUT;
95
  stage = PROBCUT_TT;
116
  ttMove =   ttm
96
  ttMove =   ttm
117
          && pos.pseudo_legal(ttm)
97
          && pos.pseudo_legal(ttm)
118
          && pos.capture(ttm)
98
          && pos.capture(ttm)
119
          && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE;
99
          && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE;
120
 
-
 
121
  stage += (ttMove == MOVE_NONE);
100
  stage += (ttMove == MOVE_NONE);
122
}
101
}
123
 
102
 
124
/// score() assigns a numerical value to each move in a list, used for sorting.
103
/// MovePicker::score() assigns a numerical value to each move in a list, used
125
/// Captures are ordered by Most Valuable Victim (MVV), preferring captures
104
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
126
/// with a good history. Quiets are ordered using the histories.
105
/// captures with a good history. Quiets moves are ordered using the histories.
127
template<GenType Type>
106
template<GenType Type>
128
void MovePicker::score() {
107
void MovePicker::score() {
129
 
108
 
130
  static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
109
  static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
131
 
110
 
132
  for (auto& m : *this)
111
  for (auto& m : *this)
133
      if (Type == CAPTURES)
112
      if (Type == CAPTURES)
134
          m.value =  PieceValue[MG][pos.piece_on(to_sq(m))]
113
          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)))]);
114
                   + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))] / 8;
136
 
115
 
137
      else if (Type == QUIETS)
116
      else if (Type == QUIETS)
138
          m.value =  (*mainHistory)[pos.side_to_move()][from_to(m)]
117
          m.value =  (*mainHistory)[pos.side_to_move()][from_to(m)]
139
                   + (*contHistory[0])[pos.moved_piece(m)][to_sq(m)]
118
                   + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
140
                   + (*contHistory[1])[pos.moved_piece(m)][to_sq(m)]
119
                   + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)]
141
                   + (*contHistory[3])[pos.moved_piece(m)][to_sq(m)];
120
                   + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)];
142
 
121
 
143
      else // Type == EVASIONS
122
      else // Type == EVASIONS
144
      {
123
      {
145
          if (pos.capture(m))
124
          if (pos.capture(m))
146
              m.value =  PieceValue[MG][pos.piece_on(to_sq(m))]
125
              m.value =  PieceValue[MG][pos.piece_on(to_sq(m))]
147
                       - Value(type_of(pos.moved_piece(m)));
126
                       - Value(type_of(pos.moved_piece(m)));
148
          else
127
          else
149
              m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - (1 << 28);
128
              m.value =  (*mainHistory)[pos.side_to_move()][from_to(m)]
-
 
129
                       + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
-
 
130
                       - (1 << 28);
150
      }
131
      }
151
}
132
}
152
 
133
 
153
/// next_move() is the most important method of the MovePicker class. It returns
134
/// MovePicker::select() returns the next move satisfying a predicate function.
154
/// a new pseudo legal move every time it is called, until there are no more moves
135
/// It never returns the TT move.
155
/// left. It picks the move with the biggest value from a list of generated moves
136
template<MovePicker::PickType T, typename Pred>
156
/// taking care not to return the ttMove if it has already been searched.
137
Move MovePicker::select(Pred filter) {
157
 
138
 
-
 
139
  while (cur < endMoves)
-
 
140
  {
-
 
141
      if (T == Best)
158
Move MovePicker::next_move(bool skipQuiets) {
142
          std::swap(*cur, *std::max_element(cur, endMoves));
159
 
143
 
160
  Move move;
144
      move = *cur++;
161
 
145
 
-
 
146
      if (move != ttMove && filter())
-
 
147
          return move;
-
 
148
  }
-
 
149
  return move = MOVE_NONE;
-
 
150
}
-
 
151
 
-
 
152
/// MovePicker::next_move() is the most important method of the MovePicker class. It
-
 
153
/// returns a new pseudo legal move every time it is called until there are no more
-
 
154
/// moves left, picking the move with the highest score from a list of generated moves.
-
 
155
Move MovePicker::next_move(bool skipQuiets) {
-
 
156
 
-
 
157
top:
162
  switch (stage) {
158
  switch (stage) {
163
 
159
 
-
 
160
  case MAIN_TT:
164
  case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS:
161
  case EVASION_TT:
165
  case QSEARCH_NO_CHECKS: case PROBCUT:
162
  case QSEARCH_TT:
-
 
163
  case PROBCUT_TT:
166
      ++stage;
164
      ++stage;
167
      return ttMove;
165
      return ttMove;
168
 
166
 
169
  case CAPTURES_INIT:
167
  case CAPTURE_INIT:
-
 
168
  case PROBCUT_INIT:
-
 
169
  case QCAPTURE_INIT:
170
      endBadCaptures = cur = moves;
170
      cur = endBadCaptures = moves;
171
      endMoves = generate<CAPTURES>(pos, cur);
171
      endMoves = generate<CAPTURES>(pos, cur);
-
 
172
 
172
      score<CAPTURES>();
173
      score<CAPTURES>();
173
      ++stage;
174
      ++stage;
174
      /* fallthrough */
175
      goto top;
175
 
176
 
176
  case GOOD_CAPTURES:
177
  case GOOD_CAPTURE:
177
      while (cur < endMoves)
178
      if (select<Best>([&](){
178
      {
-
 
179
          move = pick_best(cur++, endMoves);
179
                       return pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)) ?
180
          if (move != ttMove)
180
                              // Move losing capture to endBadCaptures to be tried later
181
          {
-
 
182
              if (pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)))
181
                              true : (*endBadCaptures++ = move, false); }))
183
                  return move;
182
          return move;
184
 
183
 
185
              // Losing capture, move it to the beginning of the array
184
      // Prepare the pointers to loop over the refutations array
186
              *endBadCaptures++ = move;
185
      cur = std::begin(refutations);
187
          }
186
      endMoves = std::end(refutations);
-
 
187
 
-
 
188
      // If the countermove is the same as a killer, skip it
-
 
189
      if (   refutations[0].move == refutations[2].move
-
 
190
          || refutations[1].move == refutations[2].move)
188
      }
191
          --endMoves;
189
 
192
 
190
      ++stage;
193
      ++stage;
191
      move = killers[0];  // First killer move
-
 
192
      if (    move != MOVE_NONE
-
 
193
          &&  move != ttMove
-
 
194
          &&  pos.pseudo_legal(move)
-
 
195
          && !pos.capture(move))
-
 
196
          return move;
-
 
197
      /* fallthrough */
194
      /* fallthrough */
198
 
195
 
199
  case KILLERS:
196
  case REFUTATION:
200
      ++stage;
-
 
201
      move = killers[1]; // Second killer move
-
 
202
      if (    move != MOVE_NONE
197
      if (select<Next>([&](){ return    move != MOVE_NONE
203
          &&  move != ttMove
198
                                    && !pos.capture(move)
204
          &&  pos.pseudo_legal(move)
199
                                    &&  pos.pseudo_legal(move); }))
205
          && !pos.capture(move))
-
 
206
          return move;
200
          return move;
207
      /* fallthrough */
-
 
208
 
-
 
209
  case COUNTERMOVE:
-
 
210
      ++stage;
201
      ++stage;
211
      move = countermove;
-
 
212
      if (    move != MOVE_NONE
-
 
213
          &&  move != ttMove
-
 
214
          &&  move != killers[0]
-
 
215
          &&  move != killers[1]
-
 
216
          &&  pos.pseudo_legal(move)
-
 
217
          && !pos.capture(move))
-
 
218
          return move;
-
 
219
      /* fallthrough */
202
      /* fallthrough */
220
 
203
 
221
  case QUIET_INIT:
204
  case QUIET_INIT:
222
      cur = endBadCaptures;
205
      cur = endBadCaptures;
223
      endMoves = generate<QUIETS>(pos, cur);
206
      endMoves = generate<QUIETS>(pos, cur);
-
 
207
 
224
      score<QUIETS>();
208
      score<QUIETS>();
225
      partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY);
209
      partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY);
226
      ++stage;
210
      ++stage;
227
      /* fallthrough */
211
      /* fallthrough */
228
 
212
 
229
  case QUIET:
213
  case QUIET:
230
      while (    cur < endMoves
214
      if (   !skipQuiets
-
 
215
          && select<Next>([&](){return   move != refutations[0]
231
             && (!skipQuiets || cur->value >= VALUE_ZERO))
216
                                      && move != refutations[1]
-
 
217
                                      && move != refutations[2];}))
-
 
218
          return move;
-
 
219
 
-
 
220
      // Prepare the pointers to loop over the bad captures
232
      {
221
      cur = moves;
233
          move = *cur++;
222
      endMoves = endBadCaptures;
234
 
223
 
235
          if (   move != ttMove
-
 
236
              && move != killers[0]
-
 
237
              && move != killers[1]
-
 
238
              && move != countermove)
-
 
239
              return move;
-
 
240
      }
-
 
241
      ++stage;
224
      ++stage;
242
      cur = moves; // Point to beginning of bad captures
-
 
243
      /* fallthrough */
225
      /* fallthrough */
244
 
226
 
245
  case BAD_CAPTURES:
227
  case BAD_CAPTURE:
246
      if (cur < endBadCaptures)
228
      return select<Next>(Any);
247
          return *cur++;
-
 
248
      break;
-
 
249
 
229
 
250
  case EVASIONS_INIT:
230
  case EVASION_INIT:
251
      cur = moves;
231
      cur = moves;
252
      endMoves = generate<EVASIONS>(pos, cur);
232
      endMoves = generate<EVASIONS>(pos, cur);
-
 
233
 
253
      score<EVASIONS>();
234
      score<EVASIONS>();
254
      ++stage;
235
      ++stage;
255
      /* fallthrough */
236
      /* fallthrough */
256
 
237
 
257
  case ALL_EVASIONS:
238
  case EVASION:
258
      while (cur < endMoves)
239
      return select<Best>(Any);
259
      {
-
 
260
          move = pick_best(cur++, endMoves);
-
 
261
          if (move != ttMove)
-
 
262
              return move;
-
 
263
      }
-
 
264
      break;
-
 
265
 
240
 
266
  case PROBCUT_INIT:
241
  case PROBCUT:
267
      cur = moves;
-
 
268
      endMoves = generate<CAPTURES>(pos, cur);
242
      return select<Best>([&](){ return pos.see_ge(move, threshold); });
269
      score<CAPTURES>();
-
 
270
      ++stage;
-
 
271
      /* fallthrough */
-
 
272
 
243
 
273
  case PROBCUT_CAPTURES:
244
  case QCAPTURE:
274
      while (cur < endMoves)
245
      if (select<Best>([&](){ return   depth > DEPTH_QS_RECAPTURES
275
      {
-
 
276
          move = pick_best(cur++, endMoves);
246
                                    || to_sq(move) == recaptureSquare; }))
277
          if (   move != ttMove
247
          return move;
-
 
248
 
278
              && pos.see_ge(move, threshold))
249
      // If we did not find any move and we do not try checks, we have finished
279
              return move;
250
      if (depth != DEPTH_QS_CHECKS)
280
      }
-
 
281
      break;
251
          return MOVE_NONE;
282
 
252
 
283
  case QCAPTURES_1_INIT: case QCAPTURES_2_INIT:
-
 
284
      cur = moves;
-
 
285
      endMoves = generate<CAPTURES>(pos, cur);
-
 
286
      score<CAPTURES>();
-
 
287
      ++stage;
253
      ++stage;
288
      /* fallthrough */
254
      /* fallthrough */
289
 
255
 
290
  case QCAPTURES_1: case QCAPTURES_2:
-
 
291
      while (cur < endMoves)
-
 
292
      {
-
 
293
          move = pick_best(cur++, endMoves);
-
 
294
          if (move != ttMove)
-
 
295
              return move;
-
 
296
      }
-
 
297
      if (stage == QCAPTURES_2)
-
 
298
          break;
256
  case QCHECK_INIT:
299
      cur = moves;
257
      cur = moves;
300
      endMoves = generate<QUIET_CHECKS>(pos, cur);
258
      endMoves = generate<QUIET_CHECKS>(pos, cur);
301
      ++stage;
-
 
302
      /* fallthrough */
-
 
303
 
259
 
304
  case QCHECKS:
-
 
305
      while (cur < endMoves)
-
 
306
      {
-
 
307
          move = cur++->move;
-
 
308
          if (move != ttMove)
-
 
309
              return move;
-
 
310
      }
-
 
311
      break;
-
 
312
 
-
 
313
  case QSEARCH_RECAPTURES:
-
 
314
      cur = moves;
-
 
315
      endMoves = generate<CAPTURES>(pos, cur);
-
 
316
      score<CAPTURES>();
-
 
317
      ++stage;
260
      ++stage;
318
      /* fallthrough */
261
      /* fallthrough */
319
 
262
 
320
  case QRECAPTURES:
263
  case QCHECK:
321
      while (cur < endMoves)
264
      return select<Next>(Any);
322
      {
-
 
323
          move = pick_best(cur++, endMoves);
-
 
324
          if (to_sq(move) == recaptureSquare)
-
 
325
              return move;
-
 
326
      }
-
 
327
      break;
-
 
328
 
-
 
329
  default:
-
 
330
      assert(false);
-
 
331
  }
265
  }
332
 
266
 
-
 
267
  assert(false);
333
  return MOVE_NONE;
268
  return MOVE_NONE; // Silence warning
334
}
269
}