Subversion Repositories Games.Chess Giants

Rev

Rev 154 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
33 pmbaty 1
#include "chess.h"
2
#include "data.h"
108 pmbaty 3
/* last modified 12/29/15 */
33 pmbaty 4
/*
5
 *******************************************************************************
6
 *                                                                             *
108 pmbaty 7
 *   NextMove() is used to select the next move from the current move list.    *
33 pmbaty 8
 *                                                                             *
108 pmbaty 9
 *   The "excluded move" code below simply collects any moves that were        *
10
 *   searched without being generated (hash move and up to 4 killers).  We     *
11
 *   save them in the NEXT structure and make sure to exclude them when        *
12
 *   searching after a move generation to avoid the duplicated effort.         *
13
 *                                                                             *
33 pmbaty 14
 *******************************************************************************
15
 */
108 pmbaty 16
int NextMove(TREE * RESTRICT tree, int ply, int depth, int side, int in_check) {
17
  unsigned *movep, *bestp;
18
  int hist, bestval, possible;
33 pmbaty 19
 
20
/*
21
 ************************************************************
22
 *                                                          *
108 pmbaty 23
 *  The following "big switch" controls the finate state    *
24
 *  machine that selects moves.  The "phase" value in the   *
25
 *  next_status[ply] structure is always set after a move   *
26
 *  is selected, and it defines the next state of the FSM   *
27
 *  so select the next move in a sequenced order.           *
33 pmbaty 28
 *                                                          *
29
 ************************************************************
30
 */
31
  switch (tree->next_status[ply].phase) {
32
/*
33
 ************************************************************
34
 *                                                          *
35
 *  First, try the transposition table move (which will be  *
36
 *  the principal variation move as we first move down the  *
108 pmbaty 37
 *  tree) or the best move found in this position during a  *
38
 *  prior search.                                           *
33 pmbaty 39
 *                                                          *
40
 ************************************************************
41
 */
108 pmbaty 42
    case HASH:
43
      tree->next_status[ply].order = 0;
44
      tree->next_status[ply].exclude = &tree->next_status[ply].done[0];
45
      tree->next_status[ply].phase = GENERATE_CAPTURES;
33 pmbaty 46
      if (tree->hash_move[ply]) {
47
        tree->curmv[ply] = tree->hash_move[ply];
108 pmbaty 48
        *(tree->next_status[ply].exclude++) = tree->curmv[ply];
49
        if (ValidMove(tree, ply, side, tree->curmv[ply])) {
50
          tree->phase[ply] = HASH;
51
          return ++tree->next_status[ply].order;
52
        }
33 pmbaty 53
#if defined(DEBUG)
54
        else
108 pmbaty 55
          Print(2048, "ERROR:  bad move from hash table, ply=%d\n", ply);
33 pmbaty 56
#endif
57
      }
58
/*
59
 ************************************************************
60
 *                                                          *
61
 *  Generate captures and sort them based on the simple     *
62
 *  MVV/LVA ordering where we try to capture the most       *
63
 *  valuable victim piece possible, using the least         *
64
 *  valuable attacking piece possible.  Later we will test  *
65
 *  to see if the capture appears to lose material and we   *
66
 *  will defer searching it until later.                    *
67
 *                                                          *
108 pmbaty 68
 *  Or, if in check, generate all the legal moves that      *
69
 *  escape check by using GenerateCheckEvasions().  After   *
70
 *  we do this, we sort them using MVV/LVA to move captures *
71
 *  to the front of the list in the correct order.          *
72
 *                                                          *
33 pmbaty 73
 ************************************************************
74
 */
108 pmbaty 75
    case GENERATE_CAPTURES:
76
      tree->next_status[ply].phase = CAPTURES;
77
      if (!in_check)
78
        tree->last[ply] =
79
            GenerateCaptures(tree, ply, side, tree->last[ply - 1]);
80
      else
81
        tree->last[ply] =
82
            GenerateCheckEvasions(tree, ply, side, tree->last[ply - 1]);
33 pmbaty 83
/*
84
 ************************************************************
85
 *                                                          *
108 pmbaty 86
 *  Now make a pass over the moves to assign the sort value *
87
 *  for each.  We simply use MVV/LVA move order here.  A    *
88
 *  simple optimization is to use the pre-computed array    *
89
 *  MVV_LVA[victim][attacker] which returns a simple value  *
90
 *  that indicates MVV/LVA order.                           *
33 pmbaty 91
 *                                                          *
92
 ************************************************************
93
 */
108 pmbaty 94
      tree->next_status[ply].remaining = 0;
95
      for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++)
96
        if (*movep == tree->hash_move[ply]) {
97
          *movep = 0;
98
          tree->next_status[ply].exclude = &tree->next_status[ply].done[0];
99
        } else {
100
          *movep += MVV_LVA[Captured(*movep)][Piece(*movep)];
101
          tree->next_status[ply].remaining++;
33 pmbaty 102
        }
108 pmbaty 103
      NextSort(tree, ply);
33 pmbaty 104
      tree->next_status[ply].last = tree->last[ply - 1];
108 pmbaty 105
      if (in_check)
106
        goto remaining_moves;
33 pmbaty 107
/*
108
 ************************************************************
109
 *                                                          *
110
 *  Try the captures moves, which are in order based on     *
111
 *  MVV/LVA ordering.  If a larger-valued piece captures a  *
108 pmbaty 112
 *  lesser-valued piece, and SEE() says it loses material,  *
33 pmbaty 113
 *  this capture will be deferred until later.              *
114
 *                                                          *
108 pmbaty 115
 *  If we are in check, we jump down to the history moves   *
116
 *  phase (we don't need to generate any more moves as      *
117
 *  GenerateCheckEvasions has already generated all legal   *
118
 *  moves.                                                  *
119
 *                                                          *
33 pmbaty 120
 ************************************************************
121
 */
108 pmbaty 122
    case CAPTURES:
33 pmbaty 123
      while (tree->next_status[ply].remaining) {
108 pmbaty 124
        tree->curmv[ply] = Move(*(tree->next_status[ply].last++));
33 pmbaty 125
        if (!--tree->next_status[ply].remaining)
108 pmbaty 126
          tree->next_status[ply].phase = KILLER1;
127
        if (pcval[Piece(tree->curmv[ply])] <=
128
            pcval[Captured(tree->curmv[ply])]
129
            || SEE(tree, side, tree->curmv[ply]) >= 0) {
130
          *(tree->next_status[ply].last - 1) = 0;
131
          tree->phase[ply] = CAPTURES;
132
          return ++tree->next_status[ply].order;
133
        }
33 pmbaty 134
      }
135
/*
136
 ************************************************************
137
 *                                                          *
138
 *  Now, try the killer moves.  This phase tries the two    *
139
 *  killers for the current ply without generating moves,   *
140
 *  which saves time if a cutoff occurs.  After those two   *
141
 *  killers are searched, we try the killers from two plies *
142
 *  back since they have greater depth and might produce a  *
143
 *  cutoff if the current two do not.                       *
144
 *                                                          *
145
 ************************************************************
146
 */
108 pmbaty 147
    case KILLER1:
148
      possible = tree->killers[ply].move1;
149
      if (!Exclude(tree, ply, possible) &&
150
          ValidMove(tree, ply, side, possible)) {
151
        tree->curmv[ply] = possible;
152
        *(tree->next_status[ply].exclude++) = possible;
153
        tree->next_status[ply].phase = KILLER2;
154
        tree->phase[ply] = KILLER1;
155
        return ++tree->next_status[ply].order;
33 pmbaty 156
      }
108 pmbaty 157
    case KILLER2:
158
      possible = tree->killers[ply].move2;
159
      if (!Exclude(tree, ply, possible) &&
160
          ValidMove(tree, ply, side, possible)) {
161
        tree->curmv[ply] = possible;
162
        *(tree->next_status[ply].exclude++) = possible;
163
        tree->next_status[ply].phase = (ply < 3) ? COUNTER_MOVE1 : KILLER3;
164
        tree->phase[ply] = KILLER2;
165
        return ++tree->next_status[ply].order;
33 pmbaty 166
      }
108 pmbaty 167
    case KILLER3:
168
      possible = tree->killers[ply - 2].move1;
169
      if (!Exclude(tree, ply, possible) &&
170
          ValidMove(tree, ply, side, possible)) {
171
        tree->curmv[ply] = possible;
172
        *(tree->next_status[ply].exclude++) = possible;
173
        tree->next_status[ply].phase = KILLER4;
174
        tree->phase[ply] = KILLER3;
175
        return ++tree->next_status[ply].order;
33 pmbaty 176
      }
108 pmbaty 177
    case KILLER4:
178
      possible = tree->killers[ply - 2].move2;
179
      if (!Exclude(tree, ply, possible) &&
180
          ValidMove(tree, ply, side, possible)) {
181
        tree->curmv[ply] = possible;
182
        *(tree->next_status[ply].exclude++) = possible;
183
        tree->next_status[ply].phase = COUNTER_MOVE1;
184
        tree->phase[ply] = KILLER4;
185
        return ++tree->next_status[ply].order;
33 pmbaty 186
      }
187
/*
188
 ************************************************************
189
 *                                                          *
108 pmbaty 190
 *  Now, before we give up and generate moves, try the      *
191
 *  counter-move which was a move that failed high in the   *
192
 *  past when the move at the previous ply was played.      *
193
 *                                                          *
194
 ************************************************************
195
 */
196
    case COUNTER_MOVE1:
154 pmbaty 197
      possible = tree->counter_move[tree->curmv[ply - 1] & 4095].move1;
108 pmbaty 198
      if (!Exclude(tree, ply, possible) &&
199
          ValidMove(tree, ply, side, possible)) {
200
        tree->curmv[ply] = possible;
201
        *(tree->next_status[ply].exclude++) = possible;
202
        tree->next_status[ply].phase = COUNTER_MOVE2;
203
        tree->phase[ply] = COUNTER_MOVE1;
204
        return ++tree->next_status[ply].order;
205
      }
206
    case COUNTER_MOVE2:
154 pmbaty 207
      possible = tree->counter_move[tree->curmv[ply - 1] & 4095].move2;
108 pmbaty 208
      if (!Exclude(tree, ply, possible) &&
209
          ValidMove(tree, ply, side, possible)) {
210
        tree->curmv[ply] = possible;
211
        *(tree->next_status[ply].exclude++) = possible;
212
        tree->next_status[ply].phase = MOVE_PAIR1;
213
        tree->phase[ply] = COUNTER_MOVE2;
214
        return ++tree->next_status[ply].order;
215
      }
216
/*
217
 ************************************************************
218
 *                                                          *
219
 *  Finally we try paired moves, which are simply moves     *
220
 *  that were good when played after the other move in the  *
221
 *  pair was played two plies back.                         *
222
 *                                                          *
223
 ************************************************************
224
 */
225
    case MOVE_PAIR1:
154 pmbaty 226
      possible = tree->move_pair[tree->curmv[ply - 2] & 4095].move1;
108 pmbaty 227
      if (!Exclude(tree, ply, possible) &&
228
          ValidMove(tree, ply, side, possible)) {
229
        tree->curmv[ply] = possible;
230
        *(tree->next_status[ply].exclude++) = possible;
231
        tree->next_status[ply].phase = MOVE_PAIR2;
232
        tree->phase[ply] = MOVE_PAIR1;
233
        return ++tree->next_status[ply].order;
234
      }
235
    case MOVE_PAIR2:
154 pmbaty 236
      possible = tree->move_pair[tree->curmv[ply - 2] & 4095].move2;
108 pmbaty 237
      if (!Exclude(tree, ply, possible) &&
238
          ValidMove(tree, ply, side, possible)) {
239
        tree->curmv[ply] = possible;
240
        *(tree->next_status[ply].exclude++) = possible;
241
        tree->next_status[ply].phase = GENERATE_QUIET;
242
        tree->phase[ply] = MOVE_PAIR2;
243
        return ++tree->next_status[ply].order;
244
      }
245
/*
246
 ************************************************************
247
 *                                                          *
33 pmbaty 248
 *  Now, generate all non-capturing moves, which get added  *
249
 *  to the move list behind any captures we did not search. *
250
 *                                                          *
251
 ************************************************************
252
 */
108 pmbaty 253
    case GENERATE_QUIET:
254
      if (!in_check)
255
        tree->last[ply] =
256
            GenerateNoncaptures(tree, ply, side, tree->last[ply]);
33 pmbaty 257
      tree->next_status[ply].last = tree->last[ply - 1];
258
/*
259
 ************************************************************
260
 *                                                          *
108 pmbaty 261
 *  Now, try the history moves.  This phase takes the       *
262
 *  complete move list, and passes over them in a classic   *
263
 *  selection-sort, choosing the move with the highest      *
264
 *  history score.  This phase is only done one time, as it *
265
 *  also purges the hash, killer, counter and paired moves  *
266
 *  from the list.                                          *
33 pmbaty 267
 *                                                          *
268
 ************************************************************
269
 */
108 pmbaty 270
      tree->next_status[ply].remaining = 0;
271
      tree->next_status[ply].phase = HISTORY;
272
      bestval = -99999999;
273
      bestp = 0;
274
      for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++)
275
        if (*movep) {
276
          if (Exclude(tree, ply, *movep))
277
            *movep = 0;
278
          else if (depth >= 6) {
279
            tree->next_status[ply].remaining++;
280
            hist = history[HistoryIndex(side, *movep)];
281
            if (hist > bestval) {
282
              bestval = hist;
283
              bestp = movep;
284
            }
285
          }
286
        }
287
      tree->next_status[ply].remaining /= 2;
288
      if (bestp) {
289
        tree->curmv[ply] = Move(*bestp);
290
        *bestp = 0;
291
        tree->phase[ply] = HISTORY;
292
        return ++tree->next_status[ply].order;
293
      }
294
      goto remaining_moves;
295
/*
296
 ************************************************************
297
 *                                                          *
298
 *  Now, continue with the history moves, but since one     *
299
 *  pass has been made over the complete move list, there   *
300
 *  are no hash/killer moves left in the list, so the tests *
301
 *  for these can be avoided.                               *
302
 *                                                          *
303
 ************************************************************
304
 */
305
    case HISTORY:
306
      if (depth >= 6) {
307
        bestval = -99999999;
308
        bestp = 0;
309
        for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++)
310
          if (*movep) {
311
            hist = history[HistoryIndex(side, *movep)];
312
            if (hist > bestval) {
313
              bestval = hist;
314
              bestp = movep;
315
            }
316
          }
317
        if (bestp) {
318
          tree->curmv[ply] = Move(*bestp);
319
          *bestp = 0;
320
          if (--(tree->next_status[ply].remaining) <= 0) {
321
            tree->next_status[ply].phase = REMAINING;
322
            tree->next_status[ply].last = tree->last[ply - 1];
323
          }
324
          tree->phase[ply] = HISTORY;
325
          return ++tree->next_status[ply].order;
326
        }
327
      }
328
/*
329
 ************************************************************
330
 *                                                          *
331
 *  Then we try the rest of the set of moves, and we do not *
332
 *  use Exclude() function to skip any moves we have        *
333
 *  already searched (hash or killers) since the history    *
334
 *  phase above has already done that.                      *
335
 *                                                          *
336
 ************************************************************
337
 */
338
    remaining_moves:
339
      tree->next_status[ply].phase = REMAINING;
340
      tree->next_status[ply].last = tree->last[ply - 1];
341
    case REMAINING:
33 pmbaty 342
      for (; tree->next_status[ply].last < tree->last[ply];
343
          tree->next_status[ply].last++)
344
        if (*tree->next_status[ply].last) {
108 pmbaty 345
          tree->curmv[ply] = Move(*tree->next_status[ply].last++);
346
          tree->phase[ply] = REMAINING;
347
          return ++tree->next_status[ply].order;
33 pmbaty 348
        }
349
      return NONE;
350
    default:
108 pmbaty 351
      Print(4095, "oops!  next_status.phase is bad! [phase=%d]\n",
33 pmbaty 352
          tree->next_status[ply].phase);
353
  }
354
  return NONE;
355
}
356
 
108 pmbaty 357
/* last modified 07/03/14 */
33 pmbaty 358
/*
359
 *******************************************************************************
360
 *                                                                             *
361
 *   NextRootMove() is used to select the next move from the root move list.   *
362
 *                                                                             *
108 pmbaty 363
 *   There is one subtle trick here that must not be broken.  Crafty does LMR  *
364
 *   at the root, and the reduction amount is dependent on the order in which  *
365
 *   a specific move is searched.  With the recent changes dealing with this   *
366
 *   issue in non-root moves, NextRootMove() now simply returns the move's     *
367
 *   order within the move list.  This might be a problem if the last move in  *
368
 *   the list fails high, because it would be reduced on the re-search, which  *
369
 *   is something we definitely don't want.  The solution is found in the code *
370
 *   inside Iterate().  When a move fails high, it is moved to the top of the  *
371
 *   move list so that (a) it is searched first on the re-search (more on this *
372
 *   in a moment) and (b) since its position in the move list is now #1, it    *
373
 *   will get an order value of 1 which is never reduced.  The only warning is *
374
 *   that Iterate() MUST re-sort the ply-1 move list after a fail high, even   *
375
 *   though it seems like a very tiny computational waste.                     *
376
 *                                                                             *
377
 *   The other reason for doing the re-sort has to do with the parallel search *
378
 *   algorithm.  When one thread fails high at the root, it stops the others.  *
379
 *   they have to carefully undo the "this move has been searched" flag since  *
380
 *   these incomplete searches need to be re-done after the fail-high move is  *
381
 *   finished.  But it is possible some of those interrupted moves appear      *
382
 *   before the fail high move in the move list.  Which would lead Crafty to   *
383
 *   fail high, then produce a different best move's PV.  By re-sorting, now   *
384
 *   the fail-high move is always searched first since here we just start at   *
385
 *   the top of the move list and look for the first "not yet searched" move   *
386
 *   to return.  It solves several problems, but if that re-sort is not done,  *
387
 *   things go south quickly.  The voice of experience is all I will say here. *
388
 *                                                                             *
33 pmbaty 389
 *******************************************************************************
390
 */
108 pmbaty 391
int NextRootMove(TREE * RESTRICT tree, TREE * RESTRICT mytree, int side) {
33 pmbaty 392
  uint64_t total_nodes;
108 pmbaty 393
  int which, i, t;
33 pmbaty 394
 
395
/*
396
 ************************************************************
397
 *                                                          *
398
 *  First, we check to see if we only have one legal move.  *
399
 *  If so, and we are not pondering, we stop after a short  *
400
 *  search, saving time, but making sure we have something  *
401
 *  to ponder.                                              *
402
 *                                                          *
403
 ************************************************************
404
 */
405
  if (!annotate_mode && !pondering && !booking && n_root_moves == 1 &&
108 pmbaty 406
      iteration > 10) {
33 pmbaty 407
    abort_search = 1;
408
    return NONE;
409
  }
410
/*
411
 ************************************************************
412
 *                                                          *
413
 *  For the moves at the root of the tree, the list has     *
414
 *  already been generated and sorted.                      *
415
 *                                                          *
416
 *  We simply have to find the first move that has a zero   *
417
 *  "already searched" flag and choose that one.  We do set *
418
 *  the "already searched" flag for this move before we     *
419
 *  return so that it won't be searched again in another    *
420
 *  thread.                                                 *
421
 *                                                          *
422
 ************************************************************
423
 */
108 pmbaty 424
  for (which = 0; which < n_root_moves; which++) {
33 pmbaty 425
    if (!(root_moves[which].status & 8)) {
426
      if (search_move) {
427
        if (root_moves[which].move != search_move) {
428
          root_moves[which].status |= 8;
429
          continue;
430
        }
431
      }
432
      tree->curmv[1] = root_moves[which].move;
433
      root_moves[which].status |= 8;
434
/*
435
 ************************************************************
436
 *                                                          *
437
 *  We have found a move to search.  If appropriate, we     *
438
 *  display this move, along with the time and information  *
439
 *  such as which move this is in the list and how many     *
440
 *  are left to search before this iteration is done, and   *
441
 *  a "status" character that shows the state of the        *
442
 *  current search ("?" means we are pondering, waiting on  *
443
 *  a move to be entered, "*" means we are searching and    *
444
 *  our clock is running).  We also display the NPS for     *
445
 *  the search, simply for information about how fast the   *
446
 *  machine is running.                                     *
447
 *                                                          *
448
 ************************************************************
449
 */
108 pmbaty 450
      if (ReadClock() - start_time > noise_level && display_options & 16) {
451
        sprintf(mytree->remaining_moves_text, "%d/%d", which + 1,
33 pmbaty 452
            n_root_moves);
453
        end_time = ReadClock();
108 pmbaty 454
        Lock(lock_io);
33 pmbaty 455
        if (pondering)
108 pmbaty 456
          printf("         %2i   %s%7s?  ", iteration,
33 pmbaty 457
              Display2Times(end_time - start_time),
458
              mytree->remaining_moves_text);
459
        else
108 pmbaty 460
          printf("         %2i   %s%7s*  ", iteration,
33 pmbaty 461
              Display2Times(end_time - start_time),
462
              mytree->remaining_moves_text);
108 pmbaty 463
        printf("%d. ", move_number);
464
        if (Flip(side))
33 pmbaty 465
          printf("... ");
108 pmbaty 466
        strcpy(mytree->root_move_text, OutputMove(tree, 1, side,
467
                tree->curmv[1]));
33 pmbaty 468
        total_nodes = block[0]->nodes_searched;
154 pmbaty 469
        for (t = 0; t < smp_max_threads; t++)
108 pmbaty 470
          for (i = 0; i < 64; i++)
471
            if (!(thread[t].blocks & SetMask(i)))
472
              total_nodes += block[t * 64 + 1 + i]->nodes_searched;
156 pmbaty 473
        nodes_per_second = (unsigned int) (total_nodes * 100 / Max(end_time - start_time, 1)); // Pierre-Marie Baty -- added type cast
33 pmbaty 474
        i = strlen(mytree->root_move_text);
475
        i = (i < 8) ? i : 8;
108 pmbaty 476
        strncat(mytree->root_move_text, "          ", 8 - i);
33 pmbaty 477
        printf("%s", mytree->root_move_text);
108 pmbaty 478
        printf("(%snps)             \r", DisplayKMB(nodes_per_second, 0));
33 pmbaty 479
        fflush(stdout);
480
        Unlock(lock_io);
481
      }
482
/*
483
 ************************************************************
484
 *                                                          *
485
 *  Bit of a tricky exit.  If the move is not flagged as    *
486
 *  "OK to search in parallel or reduce" then we return     *
108 pmbaty 487
 *  "DO_NOT_REDUCE" which will prevent Search() from        *
488
 *  reducing the move (LMR).  Otherwise we return the more  *
489
 *  common "REMAINING" value which allows LMR to be used on *
33 pmbaty 490
 *  those root moves.                                       *
491
 *                                                          *
492
 ************************************************************
493
 */
108 pmbaty 494
      if (root_moves[which].status & 4)
495
        tree->phase[1] = DO_NOT_REDUCE;
33 pmbaty 496
      else
108 pmbaty 497
        tree->phase[1] = REMAINING;
498
      return which + 1;
33 pmbaty 499
    }
108 pmbaty 500
  }
33 pmbaty 501
  return NONE;
502
}
503
 
108 pmbaty 504
/* last modified 11/13/14 */
33 pmbaty 505
/*
506
 *******************************************************************************
507
 *                                                                             *
508
 *   NextRootMoveParallel() is used to determine if the next root move can be  *
509
 *   searched in parallel.  If it appears to Iterate() that one of the moves   *
510
 *   following the first move might become the best move, the 'no parallel'    *
511
 *   flag is set to speed up finding the new best move.  This flag is set if   *
512
 *   this root move has an "age" value > 0 which indicates this move was the   *
108 pmbaty 513
 *   "best move" within the previous 3 search iterations.  We want to search   *
514
 *   such moves as quickly as possible, prior to starting a parallel search at *
515
 *   the root, in case this move once again becomes the best move and provides *
516
 *   a better alpha bound.                                                     *
33 pmbaty 517
 *                                                                             *
518
 *******************************************************************************
519
 */
520
int NextRootMoveParallel(void) {
521
  int which;
522
 
523
/*
524
 ************************************************************
525
 *                                                          *
526
 *  Here we simply check the root_move status flag that is  *
527
 *  set in Iterate() after each iteration is completed.  A  *
528
 *  value of "1" indicates this move has to be searched by  *
108 pmbaty 529
 *  all processors together, splitting at the root must     *
530
 *  wait until we have searched all moves that have been    *
531
 *  "best" during the previous three plies.                 *
33 pmbaty 532
 *                                                          *
108 pmbaty 533
 *  The root move list has a flag, bit 3, used to indicate  *
534
 *  that this move has been best recently.  If this bit is  *
535
 *  set, we are forced to use all processors to search this *
536
 *  move so that it is completed quickly rather than being  *
537
 *  searched by just one processor, and taking much longer  *
538
 *  to get a score back.  We do this to give the search the *
539
 *  best opportunity to fail high on this move before we    *
540
 *  run out of time.                                        *
541
 *                                                          *
33 pmbaty 542
 ************************************************************
543
 */
544
  for (which = 0; which < n_root_moves; which++)
545
    if (!(root_moves[which].status & 8))
546
      break;
108 pmbaty 547
  if (which < n_root_moves && !(root_moves[which].status & 4))
33 pmbaty 548
    return 1;
549
  return 0;
550
}
551
 
108 pmbaty 552
/* last modified 09/11/15 */
33 pmbaty 553
/*
554
 *******************************************************************************
555
 *                                                                             *
556
 *   Exclude() searches the list of moves searched prior to generating a move  *
557
 *   list to exclude those that were searched via a hash table best move or    *
558
 *   through the killer moves for the current ply and two plies back.          *
559
 *                                                                             *
108 pmbaty 560
 *   The variable next_status[].excluded is the total number of non-generated  *
561
 *   moves we searched.  next_status[].remaining is initially set to excluded, *
562
 *   but each time an excluded move is found, the counter is decremented.      *
563
 *   Once all excluded moves have been found, we avoid running through the     *
564
 *   list of excluded moves on each call and simply return.                    *
33 pmbaty 565
 *                                                                             *
566
 *******************************************************************************
567
 */
568
int Exclude(TREE * RESTRICT tree, int ply, int move) {
108 pmbaty 569
  unsigned *i;
33 pmbaty 570
 
108 pmbaty 571
  if (tree->next_status[ply].exclude > &tree->next_status[ply].done[0])
572
    for (i = &tree->next_status[ply].done[0];
573
        i < tree->next_status[ply].exclude; i++)
574
      if (move == *i)
33 pmbaty 575
        return 1;
576
  return 0;
577
}
108 pmbaty 578
 
579
/* last modified 05/20/15 */
580
/*
581
 *******************************************************************************
582
 *                                                                             *
583
 *   NextSort() is used to sort the move list.  This is a list of 32 bit       *
584
 *   values where the rightmost 21 bits is the compressed move, and the left-  *
585
 *   most 11 bits are the sort key (MVV/LVA values).                           *
586
 *                                                                             *
587
 *******************************************************************************
588
 */
589
void NextSort(TREE * RESTRICT tree, int ply) {
590
  unsigned temp, *movep, *tmovep;
591
 
592
/*
593
 ************************************************************
594
 *                                                          *
595
 *  This is a simple insertion sort algorithm.              *
596
 *                                                          *
597
 ************************************************************
598
 */
599
  if (tree->last[ply] > tree->last[ply - 1] + 1) {
600
    for (movep = tree->last[ply - 1] + 1; movep < tree->last[ply]; movep++) {
601
      temp = *movep;
602
      tmovep = movep - 1;
603
      while (tmovep >= tree->last[ply - 1] && SortV(*tmovep) < SortV(temp)) {
604
        *(tmovep + 1) = *tmovep;
605
        tmovep--;
606
      }
607
      *(tmovep + 1) = temp;
608
    }
609
  }
610
}