Subversion Repositories Games.Chess Giants

Rev

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, GOOD_QUIETS, BAD_QUIETS, BAD_CAPTURES,
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
    QSEARCH_WITH_CHECKS, QCAPTURES_1, CHECKS,
31
    PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES,
32
    QSEARCH_WITHOUT_CHECKS, QCAPTURES_2,
32
    QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS,
33
    PROBCUT, PROBCUT_CAPTURES,
33
    QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2,
34
    RECAPTURE, RECAPTURES,
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, const HistoryStats& h,
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), history(h), counterMoveHistory(&cmh), ss(s), countermove(cm), depth(d) {
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
  endMoves += (ttMove != MOVE_NONE);
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), history(h), counterMoveHistory(nullptr) {
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 = QSEARCH_WITHOUT_CHECKS;
94
      stage = QSEARCH_NO_CHECKS;
95
 
95
 
96
  else
96
  else
97
  {
97
  {
98
      stage = RECAPTURE;
98
      stage = QSEARCH_RECAPTURES;
99
      recaptureSquare = s;
99
      recaptureSquare = s;
100
      ttm = MOVE_NONE;
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
  endMoves += (ttMove != MOVE_NONE);
104
  stage += (ttMove == MOVE_NONE);
105
}
105
}
106
 
106
 
107
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, Value th)
107
MovePicker::MovePicker(const Position& p, Move ttm, Value th)
108
           : pos(p), history(h), counterMoveHistory(nullptr), threshold(th) {
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.see(ttm) > threshold ? ttm : MOVE_NONE;
118
          && pos.see_ge(ttm, threshold + 1)? ttm : MOVE_NONE;
119
 
119
 
120
  endMoves += (ttMove != MOVE_NONE);
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
               + (*counterMoveHistory)[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);
146
}
158
}
147
 
159
 
148
template<>
160
template<>
149
void MovePicker::score<EVASIONS>() {
161
void MovePicker::score<EVASIONS>() {
150
  // Try winning and equal captures ordered by MVV/LVA, then non-captures ordered
162
  // Try captures ordered by MVV/LVA, then non-captures ordered by history value
151
  // by history value, then bad captures and quiet moves with a negative SEE ordered
163
  const HistoryStats& history = pos.this_thread()->history;
152
  // by SEE value.
164
  const FromToStats& fromTo = pos.this_thread()->fromTo;
153
  Value see;
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
      else if (pos.capture(m))
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
  while (true)
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
      switch (stage) {
189
      ++stage;
-
 
190
      return ttMove;
248
 
191
 
-
 
192
  case CAPTURES_INIT:
249
      case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS:
193
      endBadCaptures = cur = moves;
250
      case QSEARCH_WITHOUT_CHECKS: case PROBCUT:
194
      endMoves = generate<CAPTURES>(pos, cur);
251
          ++cur;
195
      score<CAPTURES>();
252
          return ttMove;
196
      ++stage;
253
 
197
 
254
      case GOOD_CAPTURES:
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.see_sign(move) >= VALUE_ZERO)
204
              if (pos.see_ge(move, VALUE_ZERO))
259
                  return move;
205
                  return move;
260
 
206
 
261
              // Losing capture, move it to the tail of the array
207
              // Losing capture, move it to the beginning of the array
262
              *endBadCaptures-- = move;
208
              *endBadCaptures++ = move;
263
          }
209
          }
264
          break;
210
      }
265
 
211
 
266
      case KILLERS:
212
      ++stage;
267
          move = *cur++;
213
      move = ss->killers[0];  // First killer move
268
          if (    move != MOVE_NONE
214
      if (    move != MOVE_NONE
269
              &&  move != ttMove
215
          &&  move != ttMove
270
              &&  pos.pseudo_legal(move)
216
          &&  pos.pseudo_legal(move)
271
              && !pos.capture(move))
217
          && !pos.capture(move))
272
              return move;
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
      case GOOD_QUIETS: case BAD_QUIETS:
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 != killers[2])
260
              && move != countermove)
281
              return move;
261
              return move;
-
 
262
      }
282
          break;
263
      ++stage;
-
 
264
      cur = moves; // Point to beginning of bad captures
283
 
265
 
284
      case BAD_CAPTURES:
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
      case ALL_EVASIONS: case QCAPTURES_1: case QCAPTURES_2:
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
          break;
284
      break;
292
 
285
 
293
      case PROBCUT_CAPTURES:
286
  case PROBCUT_INIT:
294
           move = pick_best(cur++, endMoves);
287
      cur = moves;
295
           if (move != ttMove && pos.see(move) > threshold)
288
      endMoves = generate<CAPTURES>(pos, cur);
296
               return move;
289
      score<CAPTURES>();
297
           break;
290
      ++stage;
298
 
291
 
299
      case RECAPTURES:
292
  case PROBCUT_CAPTURES:
-
 
293
      while (cur < endMoves)
-
 
294
      {
300
          move = pick_best(cur++, endMoves);
295
          move = pick_best(cur++, endMoves);
301
          if (to_sq(move) == recaptureSquare)
296
          if (   move != ttMove
-
 
297
              && pos.see_ge(move, threshold + 1))
302
              return move;
298
              return move;
-
 
299
      }
303
          break;
300
      break;
304
 
301
 
-
 
302
  case QCAPTURES_1_INIT: case QCAPTURES_2_INIT:
305
      case CHECKS:
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 = *cur++;
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
      case STOP:
321
  case QCHECKS:
-
 
322
      while (cur < endMoves)
-
 
323
      {
-
 
324
          move = cur++->move;
-
 
325
          if (move != ttMove)
312
          return MOVE_NONE;
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
      default:
334
      ++stage;
-
 
335
 
-
 
336
  case QRECAPTURES:
-
 
337
      while (cur < endMoves)
-
 
338
      {
-
 
339
          move = pick_best(cur++, endMoves);
-
 
340
          if (to_sq(move) == recaptureSquare)
315
          assert(false);
341
              return move;
316
      }
342
      }
-
 
343
      break;
-
 
344
 
-
 
345
  default:
-
 
346
      assert(false);
317
  }
347
  }
-
 
348
 
-
 
349
  return MOVE_NONE;
318
}
350
}