Subversion Repositories Games.Chess Giants

Rev

Rev 108 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
33 pmbaty 1
#include "chess.h"
2
#include "data.h"
3
/* last modified 05/08/14 */
4
/*
5
 *******************************************************************************
6
 *                                                                             *
7
 *   Search() is the recursive routine used to implement the alpha/beta        *
8
 *   negamax search (similar to minimax but simpler to code.)  Search() is     *
9
 *   called whenever there is "depth" remaining so that all moves are subject  *
10
 *   to searching.  Search() recursively calls itself so long as there is at   *
11
 *   least one ply of depth left, otherwise it calls Quiesce() instead.        *
12
 *                                                                             *
13
 *******************************************************************************
14
 */
15
int Search(TREE * RESTRICT tree, int alpha, int beta, int side, int depth,
16
    int ply, int do_null) {
17
  ROOT_MOVE temp_rm;
18
  uint64_t start_nodes = tree->nodes_searched;
19
  int first_tried = 0, moves_searched = 0, repeat = 0;
20
  int original_alpha = alpha, value = 0, t_beta = beta;
21
  int extend, reduce, max_reduce, i;
22
  int pv_node = alpha != beta - 1;
23
 
24
/*
25
 ************************************************************
26
 *                                                          *
27
 *  Step 1.  Check to see if we have searched enough nodes  *
28
 *  that it is time to peek at how much time has been used, *
29
 *  or if is time to check for operator keyboard input.     *
30
 *  This is usually enough nodes to force a time/input      *
31
 *  check about once per second, except when the target     *
32
 *  time per move is very small, in which case we try to    *
33
 *  check the time more frequently.                         *
34
 *                                                          *
35
 *  Note that we check input or time-out in thread 0.  This *
36
 *  makes the code simpler and eliminates some problematic  *
37
 *  race conditions.                                        *
38
 *                                                          *
39
 ************************************************************
40
 */
41
#if defined(NODES)
42
  if (--temp_search_nodes <= 0) {
43
    abort_search = 1;
44
    return 0;
45
  }
46
#endif
47
  if (tree->thread_id == 0) {
48
    if (--next_time_check <= 0) {
49
      next_time_check = nodes_between_time_checks;
50
      if (TimeCheck(tree, 1)) {
51
        abort_search = 1;
52
        return 0;
53
      }
54
      if (CheckInput()) {
55
        Interrupt(ply);
56
        if (abort_search)
57
          return 0;
58
      }
59
    }
60
  }
61
  if (ply >= MAXPLY - 1)
62
    return beta;
63
/*
64
 ************************************************************
65
 *                                                          *
66
 *  Step 2.  Check for draw by repetition, which includes   *
67
 *  50 move draws also.  This is the quickest way to get    *
68
 *  out of further searching, with minimal effort.  This    *
69
 *  and the next two steps are skipped for moves at the     *
70
 *  root (ply = 1).                                         *
71
 *                                                          *
72
 ************************************************************
73
 */
74
  if (ply > 1) {
75
    if ((repeat = Repeat(tree, ply))) {
76
      value = DrawScore(side);
77
      if (value < beta)
78
        SavePV(tree, ply, 0);
79
#if defined(TRACE)
80
      if (ply <= trace_level)
81
        printf("draw by repetition detected, ply=%d.\n", ply);
82
#endif
83
      return value;
84
    }
85
/*
86
 ************************************************************
87
 *                                                          *
88
 *  Step 3.  Check the transposition/refutation (hash)      *
89
 *  table to see if we have searched this position          *
90
 *  previously and still have the results available.  We    *
91
 *  might get a real score, or a bound, or perhaps only a   *
92
 *  good move to try first.  The possible results are:      *
93
 *                                                          *
94
 *  1. HashProbe() returns "HASH_HIT".  This terminates     *
95
 *  the search instantly and we simply return the value     *
96
 *  found in the hash table.  This value is simply the      *
97
 *  value we found when we did a real search in this        *
98
 *  position previously, and HashProbe() verifies that the  *
99
 *  value is useful based on draft and current bounds.      *
100
 *                                                          *
101
 *  2. HashProbe() returns "AVOID_NULL_MOVE" which means    *
102
 *  the hashed score/bound was no good, but it indicated    *
103
 *  that trying a null-move in this position would be a     *
104
 *  waste of time since it will likely fail low, not high.  *
105
 *                                                          *
106
 *  3. HashProbe() returns "HASH_MISS" when forces us to    *
107
 *  do a normal search to resolve this node.                *
108
 *                                                          *
109
 ************************************************************
110
 */
111
    switch (HashProbe(tree, ply, depth, side, alpha, beta, &value)) {
112
      case HASH_HIT:
113
        return value;
114
      case AVOID_NULL_MOVE:
115
        do_null = 0;
116
      case HASH_MISS:
117
        break;
118
    }
119
/*
120
 ************************************************************
121
 *                                                          *
122
 *  Step 4.  Now it's time to try a probe into the endgame  *
123
 *  tablebase files.  This is done if we notice that there  *
124
 *  are 6 or fewer pieces left on the board.  EGTB_use      *
125
 *  tells us how many pieces to probe on.  Note that this   *
126
 *  can be zero when trying to swindle the opponent, so     *
127
 *  that no probes are done since we know it is a draw.     *
128
 *  This is another way to get out of the search quickly,   *
129
 *  but not as quickly as the previous steps since this can *
130
 *  result in an I/O operation.                             *
131
 *                                                          *
132
 *  Note that in "swindle mode" this can be turned off by   *
133
 *  Iterate() setting "EGTB_use = 0" so that we won't probe *
134
 *  the EGTBs since we are searching only the root moves    *
135
 *  that lead to a draw and we want to play the move that   *
136
 *  makes the draw more difficult to reach by the opponent  *
137
 *  to give him a chance to make a mistake.                 *
138
 *                                                          *
139
 *  Another special case is that we slightly fudge the      *
140
 *  score for draws.  In a normal circumstance, draw=0.00   *
141
 *  since it is "equal".  However, here we add 0.01 if      *
142
 *  white has more material, or subtract 0.01 if black has  *
143
 *  more material, since in a drawn KRP vs KR we would      *
144
 *  prefer to have the KRP side since the opponent can make *
145
 *  a mistake and convert the draw to a loss.               *
146
 *                                                          *
147
 ************************************************************
148
 */
149
#if !defined(NOEGTB)
150
    if (depth > 6 && TotalAllPieces <= EGTB_use &&
151
        Castle(ply, white) + Castle(ply, black) == 0 &&
152
        (CaptureOrPromote(tree->curmv[ply - 1]) || ply < 3)) {
153
      int egtb_value;
154
 
155
      tree->egtb_probes++;
156
      if (EGTBProbe(tree, ply, side, &egtb_value)) {
157
        tree->egtb_probes_successful++;
158
        alpha = egtb_value;
159
        if (MateScore(alpha))
160
          alpha += (alpha > 0) ? -ply + 1 : ply;
161
        else if (alpha == 0) {
162
          alpha = DrawScore(side);
163
          if (Material > 0)
164
            alpha += (side) ? 1 : -1;
165
          else if (Material < 0)
166
            alpha -= (side) ? 1 : -1;
167
        }
168
        if (alpha < beta)
169
          SavePV(tree, ply, 2);
170
        return alpha;
171
      }
172
    }
173
#endif
174
/*
175
 ************************************************************
176
 *                                                          *
177
 *  Step 5.  We now know there is no quick way to get out   *
178
 *  of here, which leaves one more possibility, although it *
179
 *  does require s search, but to a reduced depth.  We      *
180
 *  try a null move to see if we can get a quick cutoff     *
181
 *  with only a little work.  This operates as follows.     *
182
 *  Instead of making a legal move, the side on move passes *
183
 *  and does nothing.  The resulting position is searched   *
184
 *  to a shallower depth than normal (usually 3 plies less  *
185
 *  but settable by the user.) This will result in a cutoff *
186
 *  if our position is very good, but it produces the       *
187
 *  cutoff much quicker since the search is far shallower   *
188
 *  than a normal search that would also be likely to fail  *
189
 *  high.                                                   *
190
 *                                                          *
191
 *  This is skipped for any of the following reasons:       *
192
 *                                                          *
193
 *  1.  The side on move is in check.  The null move        *
194
 *      results in an illegal position.                     *
195
 *  2.  No more than one null move can appear in succession *
196
 *      as all this does is burn 6 plies of depth.          *
197
 *  3.  The side on move has only pawns left, which makes   *
198
 *      zugzwang positions more likely.                     *
199
 *  4.  The transposition table probe found an entry that   *
200
 *      indicates that a null-move search will not fail     *
201
 *      high, so we avoid the wasted effort.                *
202
 *                                                          *
203
 ************************************************************
204
 */
205
    tree->inchk[ply + 1] = 0;
206
    tree->last[ply] = tree->last[ply - 1];
207
    if (do_null && !pv_node && depth > 1 && !tree->inchk[ply]
208
        && TotalPieces(side, occupied)) {
209
      uint64_t save_hash_key;
210
 
211
      tree->curmv[ply] = 0;
212
      tree->phase[ply] = NULL_MOVE;
213
#if defined(TRACE)
214
      if (ply <= trace_level)
215
        Trace(tree, ply, depth, side, beta - 1, beta, "Search1", NULL_MOVE);
216
#endif
217
      tree->status[ply + 1] = tree->status[ply];
218
      Reversible(ply + 1) = 0;
219
      save_hash_key = HashKey;
220
      if (EnPassant(ply + 1)) {
221
        HashEP(EnPassant(ply + 1));
222
        EnPassant(ply + 1) = 0;
223
      }
224
      if (depth - null_depth - 1 > 0)
225
        value =
226
            -Search(tree, -beta, -beta + 1, Flip(side),
227
            depth - null_depth - 1, ply + 1, NO_NULL);
228
      else
229
        value = -Quiesce(tree, -beta, -beta + 1, Flip(side), ply + 1, 1);
230
      HashKey = save_hash_key;
231
      if (abort_search || tree->stop)
232
        return 0;
233
      if (value >= beta) {
234
        HashStore(tree, ply, depth, side, LOWER, value, tree->hash_move[ply]);
235
        return value;
236
      }
237
    }
238
/*
239
 ************************************************************
240
 *                                                          *
241
 *  Step 6.  This step is rarely executed.  It is used when *
242
 *  there is no best move from the hash table, and this is  *
243
 *  a PV node, since we need a good move to search first.   *
244
 *  While killers moves are good, they are not quite good   *
245
 *  enough.  the simplest solution is to try a shallow      *
246
 *  search (depth-2) to get a move.  note that when we call *
247
 *  Search() with depth-2, it, too, will not have a hash    *
248
 *  move, and will therefore recursively continue this      *
249
 *  process, hence the name "internal iterative deepening." *
250
 *                                                          *
251
 ************************************************************
252
 */
253
    tree->next_status[ply].phase = HASH_MOVE;
254
    if (!tree->hash_move[ply] && depth >= 6 && do_null && ply > 1) {
255
      if (pv_node) {
256
        do {
257
          tree->curmv[ply] = 0;
258
          if (depth - 2 > 0)
259
            value = Search(tree, alpha, beta, side, depth - 2, ply, DO_NULL);
260
          else
261
            value = Quiesce(tree, alpha, beta, side, ply, 1);
262
          if (abort_search || tree->stop)
263
            break;
264
          if (value > alpha) {
265
            if (value < beta) {
266
              if ((int) tree->pv[ply - 1].pathl > ply)
267
                tree->hash_move[ply] = tree->pv[ply - 1].path[ply];
268
            } else
269
              tree->hash_move[ply] = tree->curmv[ply];
270
            tree->last[ply] = tree->last[ply - 1];
271
            tree->next_status[ply].phase = HASH_MOVE;
272
          }
273
        } while (0);
274
      }
275
    }
276
  }
277
/*  
278
 ************************************************************
279
 *                                                          *
280
 *  Step 7.  Now iterate through the move list and search   *
281
 *  the resulting positions.  Note that Search() culls any  *
282
 *  move that is not legal by using Check().  The special   *
283
 *  case is that we must find one legal move to search to   *
284
 *  confirm that it's not a mate or draw.                   *
285
 *                                                          *
286
 *  We have three possible procedures we call here, one is  *
287
 *  specific to ply=1 (NextRootMove()), the second is a     *
288
 *  specific routine to escape check (NextEvasion()) and    *
289
 *  the last is the normal NextMove() procedure that does   *
290
 *  the usual move ordering stuff.                          *
291
 *                                                          *
292
 *  Special case:  if we have searched one move at root,    *
293
 *  and the returned score == alpha, we want to get out of  *
294
 *  here and return to Iterate() where the search bounds    *
295
 *  will be adjusted.  Otherwise we would search all root   *
296
 *  moves and possibly fail low after expending a sig-      *
297
 *  nificant amount of time.                                *
298
 *                                                          *
299
 ************************************************************
300
 */
301
  tree->next_status[ply].phase = HASH_MOVE;
302
  while (1) {
303
    if (ply > 1)
304
      tree->phase[ply] =
305
          (tree->inchk[ply]) ? NextEvasion(tree, ply, side) : NextMove(tree,
306
          ply, side);
307
    else if (moves_searched == 1 && alpha == original_alpha)
308
      break;
309
    else
310
      tree->phase[ply] = NextRootMove(tree, tree, side);
311
    if (!tree->phase[ply])
312
      break;
313
#if defined(TRACE)
314
    if (ply <= trace_level)
315
      Trace(tree, ply, depth, side, alpha, beta, "Search2", tree->phase[ply]);
316
#endif
317
    MakeMove(tree, ply, tree->curmv[ply], side);
318
    tree->nodes_searched++;
319
    if (tree->inchk[ply] || !Check(side))
320
      do {
321
        if (++moves_searched == 1)
322
          first_tried = tree->curmv[ply];
323
/*
324
 ************************************************************
325
 *                                                          *
326
 *  Step 7a.  If the move to be made checks the opponent,   *
327
 *  then we need to remember that he's in check and also    *
328
 *  extend the depth by one ply for him to get out.  Note   *
329
 *  that if the move gives check, it is not a candidate for *
330
 *  either depth reduction or forward-pruning.              *
331
 *                                                          *
332
 *  We do not extend unsafe checking moves (as indicated by *
333
 *  Swap(), a SEE algorithm, since these are usually a      *
334
 *  waste of time and simply blow up the tree search space. *
335
 *                                                          *
336
 ************************************************************
337
 */
338
        extend = 0;
339
        reduce = 0;
340
        if (Check(Flip(side))) {
341
          tree->inchk[ply + 1] = 1;
342
          if (SwapO(tree, tree->curmv[ply], side) <= 0) {
343
            extend = check_depth;
344
            tree->extensions_done++;
345
          }
346
        } else
347
          tree->inchk[ply + 1] = 0;
348
/*
349
 ************************************************************
350
 *                                                          *
351
 *  Step 7b.  Now for the forward-pruning stuff.  The idea  *
352
 *  here is based on the old FUTILITY idea, where if the    *
353
 *  current material + a fudge factor is lower than alpha,  *
354
 *  then there is little promise in searching this move to  *
355
 *  make up for the material deficit.  This is not done if  *
356
 *  we chose to extend this move in the previous step.      *
357
 *                                                          *
358
 *  This is a useful idea in today's 20+ ply searches, as   *
359
 *  when we near the tips, if we are too far behind in      *
360
 *  material, there is little time left to recover it and   *
361
 *  moves that don't bring us closer to a reasonable        *
362
 *  material balance can safely be skipped.  It is much     *
363
 *  more dangerous in shallow searches.                     *
364
 *                                                          *
365
 *  We have an array of pruning margin values that are      *
366
 *  indexed by depth (remaining plies left until we drop    *
367
 *  into the quiescence search) and which increase with     *
368
 *  depth since more depth means a greater chance of        *
369
 *  bringing the score back up to alpha or beyond.  If the  *
370
 *  current material + the bonus is less than alpha, we     *
371
 *  simply avoid searching this move at all, and skip to    *
372
 *  the next move without expending any more effort.  Note  *
373
 *  that this is classic forward-pruning and can certainly  *
374
 *  introduce errors into the search.  However, cluster     *
375
 *  testing has shown that this improves play in real       *
376
 *  games.  The current implementation only prunes in the   *
377
 *  last 5 plies before quiescence, although this can be    *
378
 *  tuned with the "eval" command changing the "pruning     *
379
 *  depth" value to something other than 6 (test is for     *
380
 *  depth < pruning depth, current value is 6 which prunes  *
381
 *  in last 5 plies only).  Testing shows no benefit in     *
382
 *  larger values than 6, although this might change in     *
383
 *  future versions as other things are modified.           *
384
 *                                                          *
385
 *  Exception:                                              *
386
 *                                                          *
387
 *    We do not prune if we are safely pushing a passed     *
388
 *    pawn to the 6th rank, where it becomes very dangerous *
389
 *    since it can promote in two more moves.               *
390
 *                                                          *
391
 ************************************************************
392
 */
393
        if (tree->phase[ply] == REMAINING_MOVES && !tree->inchk[ply]
394
            && !extend && moves_searched > 1) {
395
          if (depth < pruning_depth &&
396
              MaterialSTM(side) + pruning_margin[depth] <= alpha) {
397
            if (Piece(tree->curmv[ply]) != pawn ||
398
                !Passed(To(tree->curmv[ply]), side)
399
                || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) {
400
              tree->moves_fpruned++;
401
              continue;
402
            }
403
          }
404
/*
405
 ************************************************************
406
 *                                                          *
407
 *  Step 7c.  Now it's time to try to reduce the search     *
408
 *  depth if the move appears to be "poor".  To reduce the  *
409
 *  search, the following requirements must be met:         *
410
 *                                                          *
411
 *  (1) We must be in the REMAINING_MOVES part of the move  *
412
 *      ordering, so that we have nearly given up on        *
413
 *      failing high on any move.                           *
414
 *                                                          *
415
 *  (2) We must not be too close to the horizon (this is    *
416
 *      the LMR_remaining_depth value).                     *
417
 *                                                          *
418
 *  (3) The current move must not be a checking move and    *
419
 *      the side to move can not be in check.               *
420
 *                                                          *
421
 ************************************************************
422
 */
423
          if (Piece(tree->curmv[ply]) != pawn ||
424
              !Passed(To(tree->curmv[ply]), side)
425
              || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) {
426
            reduce = LMR_min_reduction;
427
            if (moves_searched > 3)
428
              reduce = LMR_max_reduction;
429
            max_reduce = Max(depth - 1 - LMR_remaining_depth, 0);
430
            if (reduce > max_reduce)
431
              reduce = max_reduce;
432
            if (reduce)
433
              tree->reductions_done++;
434
          }
435
        }
436
/*  
437
 ************************************************************
438
 *                                                          *
439
 *  Step 7d.  We have determined whether the depth is to    *
440
 *  be changed by an extension or a reduction.  If we get   *
441
 *  to this point, then the move is not being pruned.  So   *
442
 *  off we go to a recursive search/quiescence call to work *
443
 *  our way toward a terminal node.                         *
444
 *                                                          *
445
 *  There is one special-case to handle.  If the depth was  *
446
 *  reduced, and Search() returns a value >= beta then      *
447
 *  accepting that is risky (we reduced the move as we      *
448
 *  thought it was bad and expected it to fail low) so we   *
449
 *  repeat the search using the original (non-reduced)      *
450
 *  depth to see if the fail-high happens again.            *
451
 *                                                          *
452
 ************************************************************
453
 */
454
        if (depth + extend - reduce - 1 > 0) {
455
          value =
456
              -Search(tree, -t_beta, -alpha, Flip(side),
457
              depth + extend - reduce - 1, ply + 1, DO_NULL);
458
          if (value > alpha && reduce)
459
            value =
460
                -Search(tree, -t_beta, -alpha, Flip(side), depth - 1, ply + 1,
461
                DO_NULL);
462
        } else
463
          value = -Quiesce(tree, -t_beta, -alpha, Flip(side), ply + 1, 1);
464
        if (abort_search || tree->stop)
465
          break;
466
/*
467
 ************************************************************
468
 *                                                          *
469
 *  Step 7e.  This is the PVS re-search code.  If we reach  *
470
 *  this point and value > alpha and value < beta, then     *
471
 *  this can not be a null-window search.  We have to re-   *
472
 *  search the position with the original beta value (not   *
473
 *  alpha+1 as is the usual case in PVS) to see if it still *
474
 *  fails high before we treat this as a real fail-high and *
475
 *  back up the value to the previous ply.                  *
476
 *                                                          *
477
 *  Special case:  ply == 1.                                *
478
 *                                                          *
479
 *  In this case, we need to clean up and then move the     *
480
 *  best move to the top of the root move list, and return  *
481
 *  back to Iterate() to let it produce the usual informa-  *
482
 *  tive output and re-start the search with a new beta     *
483
 *  value.  We also reset the failhi_delta back to 16,      *
484
 *  since an earlier fail-high or fail low in this          *
485
 *  iteration could have left it at a large value.          *
486
 *                                                          *
487
 *  Last step is to build a usable PV in case this move     *
488
 *  fails low on the re-search, because we do want to play  *
489
 *  this move no matter what happens.                       *
490
 *                                                          *
491
 ************************************************************
492
 */
493
        if (value > alpha && value < beta && moves_searched > 1) {
494
          if (ply == 1) {
495
            alpha = value;
496
            UnmakeMove(tree, ply, tree->curmv[ply], side);
497
            root_beta = alpha;
498
            failhi_delta = 16;
499
            for (i = 0; i < n_root_moves; i++)
500
              if (tree->curmv[1] == root_moves[i].move)
501
                break;
502
            if (i < n_root_moves) {
503
              temp_rm = root_moves[i];
504
              for (; i > 0; i--)
505
                root_moves[i] = root_moves[i - 1];
506
              root_moves[0] = temp_rm;
507
            }
508
            root_moves[0].bm_age = 4;
509
            tree->pv[1].path[1] = tree->curmv[1];
510
            tree->pv[1].pathl = 2;
511
            tree->pv[1].pathh = 0;
512
            tree->pv[1].pathd = iteration_depth;
513
            tree->pv[0] = tree->pv[1];
514
            return alpha;
515
          }
516
          if (depth + extend - 1 > 0)
517
            value =
518
                -Search(tree, -beta, -alpha, Flip(side), depth + extend - 1,
519
                ply + 1, DO_NULL);
520
          else
521
            value = -Quiesce(tree, -beta, -alpha, Flip(side), ply + 1, 1);
522
          if (abort_search || tree->stop)
523
            break;
524
        }
525
/*  
526
 ************************************************************
527
 *                                                          *
528
 *  Step 7f.  We have completed the search/re-search and we *
529
 *  we have the final score.  Now we need to check for a    *
530
 *  fail-high which terminates this search instantly since  *
531
 *  no further searching is required.  On a fail high, we   *
532
 *  need to update the killer moves, and hash table before  *
533
 *  we return.                                              *
534
 *                                                          *
535
 *  If ply == 1, we call Output() which will dump the new   *
536
 *  PV.  But but we need to back up the PV to ply=0 so that *
537
 *  it will be available to tell main() which move to make. *
538
 *                                                          *
539
 ************************************************************
540
 */
541
        if (value > alpha) {
542
          alpha = value;
543
          if (ply == 1) {
544
            tree->pv[1].pathv = value;
545
            Output(tree, beta);
546
            tree->pv[0] = tree->pv[1];
547
          }
548
          if (value >= beta) {
549
            Killer(tree, ply, tree->curmv[ply]);
550
            UnmakeMove(tree, ply, tree->curmv[ply], side);
551
            HashStore(tree, ply, depth, side, LOWER, value, tree->curmv[ply]);
552
            tree->fail_highs++;
553
            if (moves_searched == 1)
554
              tree->fail_high_first_move++;
555
            return value;
556
          }
557
        }
558
        t_beta = alpha + 1;
559
      } while (0);
560
    UnmakeMove(tree, ply, tree->curmv[ply], side);
561
    if (abort_search || tree->stop)
562
      return 0;
563
/*
564
 ************************************************************
565
 *                                                          *
566
 *  Step 7g.  If are doing an SMP search, and we have idle  *
567
 *  processors, now is the time to get them involved.  We   *
568
 *  have now satisfied the "young brothers wait" condition  *
569
 *  since we have searched one move.  All that is left is   *
570
 *  to check the split constraints to see if we are an      *
571
 *  acceptable split point.                                 *
572
 *                                                          *
573
 *    (1) We can't split within N plies of the frontier     *
574
 *        nodes to avoid excessive split overhead.          *
575
 *                                                          *
576
 *    (2) We can't split until at least M nodes have been   *
577
 *        searched since this thread was last split, to     *
578
 *        avoid splitting too often, mainly in endgames.    *
579
 *                                                          *
580
 *    (3) We have to have searched one legal move to avoid  *
581
 *        splitting at a node where we have no legal moves  *
582
 *        (the first move tried might have been illegal as  *
583
 *        in when we encounter a stalemate).                *
584
 *                                                          *
585
 *    (4) If we are at ply=1, we can't split unless the     *
586
 *        smp_split_at_root flag is set to 1, AND the next  *
587
 *        move in the ply=1 move list is not flagged as     *
588
 *        "do not search in parallel" which happens when    *
589
 *        this move was a best move in the last couple of   *
590
 *        searches and we want all processors on it at once *
591
 *        to get a score back quicker.                      *
592
 *                                                          *
593
 *    (5) if the variable smp_split is > 0, we have idle    *
594
 *        threads that can help, however if smp_split < 0,  *
595
 *        we are already doing a split on another thread    *
596
 *        so there is no point in waiting to try one here.  *
597
 *                                                          *
598
 *  SearchParallel() primarily contains steps 7 through 7f  *
599
 *  which is the main search loop.  We do the final clean-  *
600
 *  up below when either we finish the search normally or   *
601
 *  a parallel search completes and returns to this point.  *
602
 *                                                          *
603
 *  Special case:  we do not split if we are at ply=1 and   *
604
 *  alpha == original_alpha.  That means the first move     *
605
 *  failed low, and we are going to exit search and return  *
606
 *  to Iterate() to report this.                            *
607
 *                                                          *
608
 *  One potential problem is that multiple threads can get  *
609
 *  to this point at the same time, and they all stack up   *
610
 *  waiting to grab the lock_smp lock that protects the     *
611
 *  split operation.  I now have a new lock, lock_split,    *
612
 *  to try to limit this wasted time.  A thread now has to  *
613
 *  acquire that lock, and then it tests the smp_split      *
614
 *  to see if a split STILL needs to be done.  If not, we   *
615
 *  release the lock and move on, rather than waiting on    *
616
 *  main lock_smp lock.                                     *
617
 *                                                          *
618
 *  If we acquire the lock_split lock AND we notice that    *
619
 *  smp_split is still set to 1, we quickly set smp_split   *
620
 *  to zero (-1) so that other threads will bug out rather  *
621
 *  than trying to split and end up in a queue behind us,   *
622
 *  waiting while we split and they try to split and fail.  *
623
 *  We release lock_split to eliminate the log-jam of       *
624
 *  threads waiting to split and get them back into their   *
625
 *  normal searches, and jump right into Thread().          *
626
 *                                                          *
627
 *  The smp_split = -1 has a complex meaning, but simply    *
628
 *  stated it means "split currently in progress".  Here,   *
629
 *  that means "do not attempt a split since we are already *
630
 *  in the middle of one."  It also tells individual        *
631
 *  threads to not change smp_split to 1 when they become   *
632
 *  idle, because with a split in progress, it is likely we *
633
 *  will pick them up automatically.                        *
634
 *                                                          *
635
 ************************************************************
636
 */
637
#if (CPUS > 1)
638
    if (smp_split > 0 && depth >= smp_min_split_depth && moves_searched &&
639
        tree->nodes_searched - start_nodes > smp_split_nodes && (ply > 1 ||
640
            (smp_split_at_root && NextRootMoveParallel() &&
641
                alpha != original_alpha)))
642
      do {
643
        Lock(lock_split);
644
        if (smp_split <= 0) {
645
          Unlock(lock_split);
646
          break;
647
        }
648
        smp_split = -1;
649
        Unlock(lock_split);
650
        tree->alpha = alpha;
651
        tree->beta = beta;
652
        tree->value = alpha;
653
        tree->side = side;
654
        tree->ply = ply;
655
        tree->depth = depth;
656
        tree->moves_searched = moves_searched;
657
        if (Thread(tree)) {
658
          if (abort_search || tree->stop)
659
            return 0;
660
          if (tree->thread_id == 0 && CheckInput())
661
            Interrupt(ply);
662
          value = tree->value;
663
          if (value > alpha) {
664
            if (value >= beta) {
665
              HashStore(tree, ply, depth, side, LOWER, value, tree->cutmove);
666
              return value;
667
            }
668
            alpha = value;
669
            break;
670
          }
671
        }
672
      } while (0);
673
#endif
674
  }
675
/*
676
 ************************************************************
677
 *                                                          *
678
 *  Step 8.  All moves have been searched.  If none were    *
679
 *  legal, return either MATE or DRAW depending on whether  *
680
 *  the side to move is in check or not.                    *
681
 *                                                          *
682
 ************************************************************
683
 */
684
  if (abort_search || tree->stop)
685
    return 0;
686
  if (moves_searched == 0) {
687
    value = (Check(side)) ? -(MATE - ply) : DrawScore(side);
688
    if (value >= alpha && value < beta) {
689
      SavePV(tree, ply, 0);
690
#if defined(TRACE)
691
      if (ply <= trace_level)
692
        printf("Search() no moves!  ply=%d\n", ply);
693
#endif
694
    }
695
    return value;
696
  } else {
697
    int bestmove, type;
698
    bestmove =
699
        (alpha == original_alpha) ? first_tried : tree->pv[ply].path[ply];
700
    type = (alpha == original_alpha) ? UPPER : EXACT;
701
    if (repeat == 2 && alpha != -(MATE - ply - 1)) {
702
      value = DrawScore(side);
703
      if (value < beta)
704
        SavePV(tree, ply, 0);
705
#if defined(TRACE)
706
      if (ply <= trace_level)
707
        printf("draw by 50 move rule detected, ply=%d.\n", ply);
708
#endif
709
      return value;
710
    } else if (alpha != original_alpha) {
711
      tree->pv[ply - 1] = tree->pv[ply];
712
      tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1];
713
      Killer(tree, ply, tree->pv[ply].path[ply]);
714
    }
715
    HashStore(tree, ply, depth, side, type, alpha, bestmove);
716
    return alpha;
717
  }
718
}
719
 
720
/* last modified 05/08/14 */
721
/*
722
 *******************************************************************************
723
 *                                                                             *
724
 *   SearchParallel() is the recursive routine used to implement alpha/beta    *
725
 *   negamax search using parallel threads.  When this code is called, the     *
726
 *   first move has already been searched, so all that is left is to search    *
727
 *   the remainder of the moves and then return.  Note that the hash table and *
728
 *   such can't be modified here since this only represents a part of the      *
729
 *   search at this ply.  All of that is deferred until we return and reach    *
730
 *   the original instance of Search() where we have the complete results from *
731
 *   all the threads that are helping here.                                    *
732
 *                                                                             *
733
 *******************************************************************************
734
 */
735
int SearchParallel(TREE * RESTRICT tree, int alpha, int beta, int value,
736
    int side, int depth, int ply) {
737
  ROOT_MOVE temp_rm;
738
  int extend, reduce, max_reduce, i;
739
 
740
/*
741
 ************************************************************
742
 *                                                          *
743
 *  Step 7.  Now we continue to iterate through the move    *
744
 *  list and search the resulting positions.  Note that     *
745
 *  SearchParallel() culls any move that is not legal by    *
746
 *  using Check().  The special case mentioned in Search()  *
747
 *  is not an issue here as we don't do a parallel split    *
748
 *  until we have searched one legal move.                  *
749
 *                                                          *
750
 *  We have three possible procedures we call here, one is  *
751
 *  specific to ply=1 (NextRootMove()), the second is a     *
752
 *  specific routine to escape check (NextEvasion()) and    *
753
 *  the last is the normal NextMove() procedure that does   *
754
 *  the usual move ordering stuff.                          *
755
 *                                                          *
756
 ************************************************************
757
 */
758
 
759
  while (1) {
760
    Lock(tree->parent->lock);
761
    if (ply > 1)
762
      tree->phase[ply] =
763
          (tree->inchk[ply]) ? NextEvasion((TREE *) tree->parent, ply,
764
          side) : NextMove((TREE *)
765
          tree->parent, ply, side);
766
    else
767
      tree->phase[ply] = NextRootMove(tree->parent, tree, side);
768
    tree->curmv[ply] = tree->parent->curmv[ply];
769
    Unlock(tree->parent->lock);
770
    if (!tree->phase[ply])
771
      break;
772
#if defined(TRACE)
773
    if (ply <= trace_level)
774
      Trace(tree, ply, depth, side, alpha, beta, "SearchParallel",
775
          tree->phase[ply]);
776
#endif
777
    MakeMove(tree, ply, tree->curmv[ply], side);
778
    tree->nodes_searched++;
779
    if (tree->inchk[ply] || !Check(side))
780
      do {
781
        tree->parent->moves_searched++;
782
/*
783
 ************************************************************
784
 *                                                          *
785
 *  Step 7a.  If the move to be made checks the opponent,   *
786
 *  then we need to remember that he's in check and also    *
787
 *  extend the depth by one ply for him to get out.  Note   *
788
 *  that if the move gives check, it is not a candidate for *
789
 *  either depth reduction or forward-pruning.              *
790
 *                                                          *
791
 *  We do not extend unsafe checking moves (as indicated by *
792
 *  Swap(), a SEE algorithm, since these are usually a      *
793
 *  waste of time and simply blow up the tree search space. *
794
 *                                                          *
795
 ************************************************************
796
 */
797
        extend = 0;
798
        reduce = 0;
799
        if (Check(Flip(side))) {
800
          tree->inchk[ply + 1] = 1;
801
          if (SwapO(tree, tree->curmv[ply], side) <= 0) {
802
            extend = check_depth;
803
            tree->extensions_done++;
804
          }
805
        } else
806
          tree->inchk[ply + 1] = 0;
807
/*
808
 ************************************************************
809
 *                                                          *
810
 *  Step 7b.  Now for the forward-pruning stuff.  The idea  *
811
 *  here is based on the old FUTILITY idea, where if the    *
812
 *  current material + a fudge factor is lower than alpha,  *
813
 *  then there is little promise in searching this move to  *
814
 *  make up for the material deficit.  This is not done if  *
815
 *  we chose to extend this move in the previous step.      *
816
 *                                                          *
817
 *  This is a useful idea in today's 20+ ply searches, as   *
818
 *  when we near the tips, if we are too far behind in      *
819
 *  material, there is little time left to recover it and   *
820
 *  moves that don't bring us closer to a reasonable        *
821
 *  material balance can safely be skipped.  It is much     *
822
 *  more dangerous in shallow searches.                     *
823
 *                                                          *
824
 *  We have an array of pruning margin values that are      *
825
 *  indexed by depth (remaining plies left until we drop    *
826
 *  into the quiescence search) and which increase with     *
827
 *  depth since more depth means a greater chance of        *
828
 *  bringing the score back up to alpha or beyond.  If the  *
829
 *  current material + the bonus is less than alpha, we     *
830
 *  simply avoid searching this move at all, and skip to    *
831
 *  the next move without expending any more effort.  Note  *
832
 *  that this is classic forward-pruning and can certainly  *
833
 *  introduce errors into the search.  However, cluster     *
834
 *  testing has shown that this improves play in real       *
835
 *  games.  The current implementation only prunes in the   *
836
 *  last 5 plies before quiescence, although this can be    *
837
 *  tuned with the "eval" command changing the "pruning     *
838
 *  depth" value to something other than 6 (test is for     *
839
 *  depth < pruning depth, current value is 6 which prunes  *
840
 *  in last 5 plies only).  Testing shows no benefit in     *
841
 *  larger values than 6, although this might change in     *
842
 *  future versions as other things are modified.           *
843
 *                                                          *
844
 *  Exception:                                              *
845
 *                                                          *
846
 *    We do not prune if we are safely pushing a passed     *
847
 *    pawn to the 6th rank, where it becomes very dangerous *
848
 *    since it can promote in two more moves.               *
849
 *                                                          *
850
 ************************************************************
851
 */
852
        if (tree->phase[ply] == REMAINING_MOVES && !tree->inchk[ply]
853
            && !extend && tree->parent->moves_searched > 1) {
854
          if (depth < pruning_depth &&
855
              MaterialSTM(side) + pruning_margin[depth] <= alpha) {
856
            if (Piece(tree->curmv[ply]) != pawn ||
857
                !Passed(To(tree->curmv[ply]), side)
858
                || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) {
859
              tree->moves_fpruned++;
860
              continue;
861
            }
862
          }
863
/*
864
 ************************************************************
865
 *                                                          *
866
 *  Step 7c.  Now it's time to try to reduce the search     *
867
 *  depth if the move appears to be "poor".  To reduce the  *
868
 *  search, the following requirements must be met:         *
869
 *                                                          *
870
 *  (1) We must be in the REMAINING_MOVES part of the move  *
871
 *      ordering, so that we have nearly given up on        *
872
 *      failing high on any move.                           *
873
 *                                                          *
874
 *  (2) We must not be too close to the horizon (this is    *
875
 *      the LMR_remaining_depth value).                     *
876
 *                                                          *
877
 *  (3) The current move must not be a checking move and    *
878
 *      the side to move can not be in check.               *
879
 *                                                          *
880
 ************************************************************
881
 */
882
          if (Piece(tree->curmv[ply]) != pawn ||
883
              !Passed(To(tree->curmv[ply]), side)
884
              || rankflip[side][Rank(To(tree->curmv[ply]))] < RANK6) {
885
            reduce = LMR_min_reduction;
886
            if (tree->parent->moves_searched > 3)
887
              reduce = LMR_max_reduction;
888
            max_reduce = Max(depth - 1 - LMR_remaining_depth, 0);
889
            if (reduce > max_reduce)
890
              reduce = max_reduce;
891
            if (reduce)
892
              tree->reductions_done++;
893
          }
894
        }
895
/*
896
 ************************************************************
897
 *                                                          *
898
 *  Step 7d.  We have determined whether the depth is to    *
899
 *  be changed by an extension or a reduction.  If we get   *
900
 *  to this point, then the move is not being pruned.  So   *
901
 *  off we go to a recursive search/quiescence call to work *
902
 *  our way toward a terminal node.                         *
903
 *                                                          *
904
 *  There is one special-cases to handle.  If the depth was *
905
 *  reduced, and Search() returns a value >= beta then      *
906
 *  accepting that is risky (we reduced the move as we      *
907
 *  thought it was bad and expected it to fail low) so we   *
908
 *  repeat the search using the original (non-reduced)      *
909
 *  depth to see if the fail-high happens again.            *
910
 *                                                          *
911
 ************************************************************
912
 */
913
        if (depth + extend - reduce - 1 > 0) {
914
          value =
915
              -Search(tree, -alpha - 1, -alpha, Flip(side),
916
              depth + extend - reduce - 1, ply + 1, DO_NULL);
917
          if (value > alpha && reduce)
918
            value =
919
                -Search(tree, -alpha - 1, -alpha, Flip(side), depth - 1,
920
                ply + 1, DO_NULL);
921
        } else
922
          value = -Quiesce(tree, -alpha - 1, -alpha, Flip(side), ply + 1, 1);
923
        if (abort_search || tree->stop)
924
          break;
925
/*
926
 ************************************************************
927
 *                                                          *
928
 *  Step 7e.  This is the PVS re-search code.  If we reach  *
929
 *  this point and value > alpha and value < beta, then     *
930
 *  this can not be a null-window search.  We have to re-   *
931
 *  search the position with the original beta value (not   *
932
 *  alpha+1 as is the usual case in PVS) to see if it still *
933
 *  fails high before we treat this as a real fail-high and *
934
 *  back up the value to the previous ply.                  *
935
 *                                                          *
936
 *  Special case:  ply == 1.                                *
937
 *                                                          *
938
 *  In this case, we need to clean up and then move the     *
939
 *  best move to the top of the root move list, and then    *
940
 *  return back to the normal Search(), which will then     *
941
 *  return back to Iterate() to let it produce the usual    *
942
 *  informative output and re-start the search with a new   *
943
 *  beta value.  We also reset the failhi_delta back to 16, *
944
 *  since an earlier fail-high or fail low in this          *
945
 *  iteration could have left it at a large value.          *
946
 *                                                          *
947
 *  Last step is to build a usable PV in case this move     *
948
 *  fails low on the re-search, because we do want to play  *
949
 *  this move no matter what happens.                       *
950
 *                                                          *
951
 ************************************************************
952
 */
953
        if (value > alpha && value < beta) {
954
          if (ply == 1) {
955
            int proc;
956
 
957
            alpha = value;
958
            parallel_aborts++;
959
            UnmakeMove(tree, ply, tree->curmv[ply], side);
960
            Lock(lock_smp);
961
            Lock(tree->parent->lock);
962
            if (!tree->stop) {
963
              for (proc = 0; proc < smp_max_threads; proc++)
964
                if (tree->parent->siblings[proc] && proc != tree->thread_id)
965
                  ThreadStop(tree->parent->siblings[proc]);
966
              root_beta = alpha;
967
              failhi_delta = 16;
968
              Lock(lock_root);
969
              for (i = 0; i < n_root_moves; i++)
970
                if (tree->curmv[1] == root_moves[i].move)
971
                  break;
972
              if (i < n_root_moves) {
973
                temp_rm = root_moves[i];
974
                for (; i > 0; i--)
975
                  root_moves[i] = root_moves[i - 1];
976
                root_moves[0] = temp_rm;
977
              }
978
              root_moves[0].bm_age = 4;
979
              Unlock(lock_root);
980
              tree->pv[1].path[1] = tree->curmv[1];
981
              tree->pv[1].pathl = 2;
982
              tree->pv[1].pathh = 0;
983
              tree->pv[1].pathd = iteration_depth;
984
              tree->pv[0] = tree->pv[1];
985
            }
986
            Unlock(tree->parent->lock);
987
            Unlock(lock_smp);
988
            return alpha;
989
          }
990
          if (depth + extend - 1 > 0)
991
            value =
992
                -Search(tree, -beta, -alpha, Flip(side), depth + extend - 1,
993
                ply + 1, DO_NULL);
994
          else
995
            value = -Quiesce(tree, -beta, -alpha, Flip(side), ply + 1, 1);
996
          if (abort_search || tree->stop)
997
            break;
998
        }
999
/*
1000
 ************************************************************
1001
 *                                                          *
1002
 *  Step 7f.  We have completed the search/re-search and we *
1003
 *  we have the final score.  Now we need to check for a    *
1004
 *  fail-high which terminates this search instantly since  *
1005
 *  no further searching is required.  On a fail high, we   *
1006
 *  need to update the killer moves, and hash table before  *
1007
 *  we return.                                              *
1008
 *                                                          *
1009
 *  Note that we can not produce a new PV here.  At best,   *
1010
 *  we can produce a fail-high which will abort other       *
1011
 *  threads at this node (wasting time).                    *
1012
 *                                                          *
1013
 *  Special case:  If ply == 1, and we fail high on the     *
1014
 *  null-window search, we simply abort the search and then *
1015
 *  return to the normal search, which will back us out to  *
1016
 *  Iterate() and inform the user and re-start the search.  *
1017
 *                                                          *
1018
 *  We then stop all threads (except the current thread     *
1019
 *  that is dealing with the fail high) since we are going  *
1020
 *  to back out quickly and then start a new search from    *
1021
 *  the root position.  The split-block sibling ids lets us *
1022
 *  know which threads should be stopped, and since we are  *
1023
 *  at the root (ply == 1) that essentially means "all      *
1024
 *  threads except for this one."                           *
1025
 *                                                          *
1026
 ************************************************************
1027
 */
1028
        if (value > alpha) {
1029
          alpha = value;
1030
          if (value >= beta) {
1031
            int proc;
1032
 
1033
            parallel_aborts++;
1034
            UnmakeMove(tree, ply, tree->curmv[ply], side);
1035
            Lock(lock_smp);
1036
            Lock(tree->parent->lock);
1037
            if (!tree->stop)
1038
              for (proc = 0; proc < smp_max_threads; proc++)
1039
                if (tree->parent->siblings[proc] && proc != tree->thread_id)
1040
                  ThreadStop(tree->parent->siblings[proc]);
1041
            Unlock(tree->parent->lock);
1042
            Unlock(lock_smp);
1043
            return alpha;
1044
          }
1045
        }
1046
      } while (0);
1047
    UnmakeMove(tree, ply, tree->curmv[ply], side);
1048
    if (abort_search || tree->stop)
1049
      break;
1050
  }
1051
/*
1052
 ************************************************************
1053
 *                                                          *
1054
 *  Step 8.  We are doing an SMP search, so there are no    *
1055
 *  "end-of-search" things to do.  We have searched all the *
1056
 *  remaining moves at this ply in parallel, and now return *
1057
 *  and let the original search that started this sub-tree) *
1058
 *  clean up, and do the tests for mate/stalemate, update   *
1059
 *  the hash table, etc.                                    *
1060
 *                                                          *
1061
 *  As we return, we end back up in Thread() where we       *
1062
 *  started, which then copies the best score/etc back to   *
1063
 *  the parent thread.                                      *
1064
 *                                                          *
1065
 *  We do need to flag the root move we tried to search, if *
1066
 *  we were stopped early due to another root move failing  *
1067
 *  high.  Otherwise this move appears to have been         *
1068
 *  searched already and will not be searched again until   *
1069
 *  the next iteration.                                     *
1070
 *                                                          *
1071
 ************************************************************
1072
 */
1073
  if (tree->stop && ply == 1) {
1074
    int which;
1075
 
1076
    Lock(lock_root);
1077
    for (which = 0; which < n_root_moves; which++)
1078
      if (root_moves[which].move == tree->curmv[ply]) {
1079
        root_moves[which].status &= 0xf7;
1080
        break;
1081
      }
1082
    Unlock(lock_root);
1083
  }
1084
  return alpha;
1085
}