Subversion Repositories Games.Chess Giants

Rev

Rev 33 | Go to most recent revision | 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 01/10/16 */
33 pmbaty 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
 */
108 pmbaty 15
int Search(TREE * RESTRICT tree, int ply, int depth, int wtm, int alpha,
16
    int beta, int in_check, int do_null) {
17
  int repeat = 0, value = 0, pv_node = alpha != beta - 1, n_depth;
18
  int searched[256];
33 pmbaty 19
 
20
/*
21
 ************************************************************
22
 *                                                          *
108 pmbaty 23
 *  Timeout.  Check to see if we have searched enough nodes *
33 pmbaty 24
 *  that it is time to peek at how much time has been used, *
25
 *  or if is time to check for operator keyboard input.     *
26
 *  This is usually enough nodes to force a time/input      *
27
 *  check about once per second, except when the target     *
28
 *  time per move is very small, in which case we try to    *
29
 *  check the time more frequently.                         *
30
 *                                                          *
31
 *  Note that we check input or time-out in thread 0.  This *
32
 *  makes the code simpler and eliminates some problematic  *
33
 *  race conditions.                                        *
34
 *                                                          *
35
 ************************************************************
36
 */
37
#if defined(NODES)
108 pmbaty 38
  if (search_nodes && --temp_search_nodes <= 0) {
33 pmbaty 39
    abort_search = 1;
40
    return 0;
41
  }
42
#endif
43
  if (tree->thread_id == 0) {
44
    if (--next_time_check <= 0) {
45
      next_time_check = nodes_between_time_checks;
46
      if (TimeCheck(tree, 1)) {
47
        abort_search = 1;
48
        return 0;
49
      }
50
      if (CheckInput()) {
51
        Interrupt(ply);
52
        if (abort_search)
53
          return 0;
54
      }
55
    }
56
  }
57
  if (ply >= MAXPLY - 1)
58
    return beta;
59
/*
60
 ************************************************************
61
 *                                                          *
108 pmbaty 62
 *  Draws.  Check for draw by repetition, which includes    *
33 pmbaty 63
 *  50 move draws also.  This is the quickest way to get    *
64
 *  out of further searching, with minimal effort.  This    *
108 pmbaty 65
 *  and the next four steps are skipped for moves at the    *
33 pmbaty 66
 *  root (ply = 1).                                         *
67
 *                                                          *
68
 ************************************************************
69
 */
70
  if (ply > 1) {
71
    if ((repeat = Repeat(tree, ply))) {
108 pmbaty 72
      if (repeat == 1 || !in_check) {
73
        value = DrawScore(wtm);
74
        if (value < beta)
75
          SavePV(tree, ply, 3);
33 pmbaty 76
#if defined(TRACE)
108 pmbaty 77
        if (ply <= trace_level)
78
          printf("draw by repetition detected, ply=%d.\n", ply);
33 pmbaty 79
#endif
108 pmbaty 80
        return value;
81
      }
33 pmbaty 82
    }
83
/*
84
 ************************************************************
85
 *                                                          *
108 pmbaty 86
 *  Mate distance pruning.  If we have found a mate, we can *
87
 *  stop if we are too deep to find a shorter mate.  This   *
88
 *  only affects the size of the tree in positions where    *
89
 *  there are forced mates.  It does not change the outcome *
90
 *  of the search at all, just the time it takes.           *
91
 *                                                          *
92
 ************************************************************
93
 */
94
    alpha = Max(alpha, -MATE + ply - 1);
95
    beta = Min(beta, MATE - ply);
96
    if (alpha >= beta)
97
      return alpha;
98
/*
99
 ************************************************************
100
 *                                                          *
101
 *  Trans/Ref.  Check the transposition/refutation (hash)   *
33 pmbaty 102
 *  table to see if we have searched this position          *
103
 *  previously and still have the results available.  We    *
104
 *  might get a real score, or a bound, or perhaps only a   *
105
 *  good move to try first.  The possible results are:      *
106
 *                                                          *
108 pmbaty 107
 *  1. HashProbe() returns "HASH_HIT".  This terminates the *
108
 *  search instantly and we simply return the value found   *
109
 *  in the hash table.  This value is simply the value we   *
110
 *  found when we did a real search in this position        *
111
 *  previously, and ProbeTransRef() verifies that the value *
112
 *  is useful based on draft and current bounds.            *
33 pmbaty 113
 *                                                          *
114
 *  2. HashProbe() returns "AVOID_NULL_MOVE" which means    *
115
 *  the hashed score/bound was no good, but it indicated    *
116
 *  that trying a null-move in this position would be a     *
117
 *  waste of time since it will likely fail low, not high.  *
118
 *                                                          *
108 pmbaty 119
 *  3. HashProbe() returns "HASH_MISS" when forces us to do *
120
 *  a normal search to resolve this node.                   *
33 pmbaty 121
 *                                                          *
122
 ************************************************************
123
 */
108 pmbaty 124
    switch (HashProbe(tree, ply, depth, wtm, alpha, beta, &value)) {
33 pmbaty 125
      case HASH_HIT:
126
        return value;
127
      case AVOID_NULL_MOVE:
128
        do_null = 0;
129
      case HASH_MISS:
130
        break;
131
    }
132
/*
133
 ************************************************************
134
 *                                                          *
108 pmbaty 135
 *  EGTBs.  Now it's time to try a probe into the endgame   *
33 pmbaty 136
 *  tablebase files.  This is done if we notice that there  *
108 pmbaty 137
 *  are 6 or fewer pieces left on the board AND the move at *
138
 *  the previous ply was a capture.  If it was not, then we *
139
 *  would have already probed the EGTBs so if it was a miss *
140
 *  when we probed then, it will also miss here.  EGTB_use  *
33 pmbaty 141
 *  tells us how many pieces to probe on.  Note that this   *
142
 *  can be zero when trying to swindle the opponent, so     *
143
 *  that no probes are done since we know it is a draw.     *
144
 *  This is another way to get out of the search quickly,   *
145
 *  but not as quickly as the previous steps since this can *
146
 *  result in an I/O operation.                             *
147
 *                                                          *
148
 *  Note that in "swindle mode" this can be turned off by   *
149
 *  Iterate() setting "EGTB_use = 0" so that we won't probe *
150
 *  the EGTBs since we are searching only the root moves    *
151
 *  that lead to a draw and we want to play the move that   *
152
 *  makes the draw more difficult to reach by the opponent  *
153
 *  to give him a chance to make a mistake.                 *
154
 *                                                          *
155
 *  Another special case is that we slightly fudge the      *
156
 *  score for draws.  In a normal circumstance, draw=0.00   *
157
 *  since it is "equal".  However, here we add 0.01 if      *
158
 *  white has more material, or subtract 0.01 if black has  *
159
 *  more material, since in a drawn KRP vs KR we would      *
160
 *  prefer to have the KRP side since the opponent can make *
161
 *  a mistake and convert the draw to a loss.               *
162
 *                                                          *
163
 ************************************************************
164
 */
165
#if !defined(NOEGTB)
108 pmbaty 166
    if (depth > EGTB_depth && TotalAllPieces <= EGTB_use &&
167
        !Castle(ply, white) && !Castle(ply, black) &&
168
        (Captured(tree->curmv[ply - 1]) || ply < 3)) {
33 pmbaty 169
      int egtb_value;
170
 
171
      tree->egtb_probes++;
108 pmbaty 172
      if (EGTBProbe(tree, ply, wtm, &egtb_value)) {
173
        tree->egtb_hits++;
33 pmbaty 174
        alpha = egtb_value;
175
        if (MateScore(alpha))
176
          alpha += (alpha > 0) ? -ply + 1 : ply;
177
        else if (alpha == 0) {
108 pmbaty 178
          alpha = DrawScore(wtm);
179
          if (MaterialSTM(wtm) > 0)
180
            alpha += 1;
181
          else if (MaterialSTM(wtm) < 0)
182
            alpha -= 1;
33 pmbaty 183
        }
184
        if (alpha < beta)
185
          SavePV(tree, ply, 2);
186
        return alpha;
187
      }
188
    }
189
#endif
190
/*
191
 ************************************************************
192
 *                                                          *
108 pmbaty 193
 *  Null-move.  We now know there is no quick way to get    *
194
 *  out of here, which leaves one more possibility,         *
195
 *  although it does require a search, but to a reduced     *
196
 *  depth.  We try a null move to see if we can get a quick *
197
 *  cutoff with only a little work.  This operates as       *
198
 *  follows.  Instead of making a legal move, the side on   *
199
 *  move passes and does nothing.  The resulting position   *
200
 *  is searched to a shallower depth than normal (see       *
201
 *  below).  This will result in a cutoff if our position   *
202
 *  is very good, but it produces the cutoff much quicker   *
203
 *  since the search is far shallower than a normal search  *
204
 *  that would also be likely to fail high.                 *
33 pmbaty 205
 *                                                          *
108 pmbaty 206
 *  The reduction amount starts off at null_depth (normally *
207
 *  set to 3 but the user can change this via the crafty    *
208
 *  personality command) but is then increased as follows:  *
209
 *                                                          *
210
 *     R = null_depth + depth / null_divisor                *
211
 *                                                          *
212
 *  null_divisor defaults to 6, but this can also be set    *
213
 *  by the user to try more/less aggressive settings.       *
214
 *                                                          *
33 pmbaty 215
 *  This is skipped for any of the following reasons:       *
216
 *                                                          *
108 pmbaty 217
 *  1. The side on move is in check.  The null move         *
218
 *     results in an illegal position.                      *
219
 *  2. No more than one null move can appear in succession  *
220
 *     as all this does is burn 2x plies of depth.          *
221
 *  3. The side on move has only pawns left, which makes    *
222
 *     zugzwang positions more likely.                      *
223
 *  4. The transposition table probe found an entry that    *
224
 *     indicates that a null-move search will not fail      *
225
 *     high, so we avoid the wasted effort.                 *
33 pmbaty 226
 *                                                          *
227
 ************************************************************
228
 */
108 pmbaty 229
 
33 pmbaty 230
    tree->last[ply] = tree->last[ply - 1];
108 pmbaty 231
    n_depth = (TotalPieces(wtm, occupied) > 9 || n_root_moves > 17 ||
232
            depth > 3) ? 1 : 3;
233
    if (do_null && !pv_node && depth > n_depth && !in_check &&
234
        TotalPieces(wtm, occupied)) {
33 pmbaty 235
      uint64_t save_hash_key;
108 pmbaty 236
      int R = null_depth + depth / null_divisor;
33 pmbaty 237
 
238
      tree->curmv[ply] = 0;
239
#if defined(TRACE)
240
      if (ply <= trace_level)
108 pmbaty 241
        Trace(tree, ply, depth, wtm, value - 1, value, "SearchNull", serial,
242
            NULL_MOVE, 0);
33 pmbaty 243
#endif
244
      tree->status[ply + 1] = tree->status[ply];
245
      Reversible(ply + 1) = 0;
246
      save_hash_key = HashKey;
247
      if (EnPassant(ply + 1)) {
248
        HashEP(EnPassant(ply + 1));
249
        EnPassant(ply + 1) = 0;
250
      }
108 pmbaty 251
      tree->null_done[Min(R, 15)]++;
252
      if (depth - R - 1 > 0)
33 pmbaty 253
        value =
108 pmbaty 254
            -Search(tree, ply + 1, depth - R - 1, Flip(wtm), -beta, -beta + 1,
255
            0, NO_NULL);
33 pmbaty 256
      else
108 pmbaty 257
        value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -beta + 1, 1);
33 pmbaty 258
      HashKey = save_hash_key;
259
      if (abort_search || tree->stop)
260
        return 0;
261
      if (value >= beta) {
108 pmbaty 262
        HashStore(tree, ply, depth, wtm, LOWER, value, tree->hash_move[ply]);
33 pmbaty 263
        return value;
264
      }
265
    }
266
/*
267
 ************************************************************
268
 *                                                          *
108 pmbaty 269
 *  IID.  This step is rarely executed.  It is used when    *
33 pmbaty 270
 *  there is no best move from the hash table, and this is  *
271
 *  a PV node, since we need a good move to search first.   *
272
 *  While killers moves are good, they are not quite good   *
273
 *  enough.  the simplest solution is to try a shallow      *
274
 *  search (depth-2) to get a move.  note that when we call *
275
 *  Search() with depth-2, it, too, will not have a hash    *
276
 *  move, and will therefore recursively continue this      *
277
 *  process, hence the name "internal iterative deepening." *
278
 *                                                          *
279
 ************************************************************
280
 */
108 pmbaty 281
    tree->next_status[ply].phase = HASH;
282
    if (!tree->hash_move[ply] && depth >= 6 && do_null && ply > 1 && pv_node) {
283
      tree->curmv[ply] = 0;
284
      if (depth - 2 > 0)
285
        value =
286
            Search(tree, ply, depth - 2, wtm, alpha, beta, in_check, DO_NULL);
287
      else
288
        value = Quiesce(tree, ply, wtm, alpha, beta, 1);
289
      if (abort_search || tree->stop)
290
        return 0;
291
      if (value > alpha) {
292
        if (value < beta) {
293
          if ((int) tree->pv[ply - 1].pathl > ply)
294
            tree->hash_move[ply] = tree->pv[ply - 1].path[ply];
295
        } else
296
          tree->hash_move[ply] = tree->curmv[ply];
297
        tree->last[ply] = tree->last[ply - 1];
298
        tree->next_status[ply].phase = HASH;
33 pmbaty 299
      }
300
    }
301
  }
108 pmbaty 302
/*
33 pmbaty 303
 ************************************************************
304
 *                                                          *
108 pmbaty 305
 *  Search moves.  Now we call SearchMoveList() to interate *
306
 *  through the move list and search each new position.     *
307
 *  Note that this is done in a separate procedure because  *
308
 *  this is also the code that is used to do the parallel   *
309
 *  search.                                                 *
310
 *                                                          *
311
 ************************************************************
312
 */
313
  searched[0] = 0;
314
  value =
315
      SearchMoveList(tree, ply, depth, wtm, alpha, beta, searched, in_check,
316
      repeat, serial);
317
  return value;
318
}
319
 
320
/* last modified 09/28/15 */
321
/*
322
 *******************************************************************************
323
 *                                                                             *
324
 *   SearchMoveList() is the recursive routine used to implement the main      *
325
 *   search loop.  This code is responsible for iterating through the move     *
326
 *   list until it encounters a condition that ends the search at this ply.    *
327
 *   At that point it simply returns the current negamax value to the caller   *
328
 *   to handle as necessary.                                                   *
329
 *                                                                             *
330
 *   The "mode" flag indicates which of the following conditions apply here    *
331
 *   which directly controls parts of the search.                              *
332
 *                                                                             *
333
 *      mode = serial   ->  this is a serial search.                           *
334
 *                                                                             *
335
 *      mode = parallel ->  this is a parallel search, which implies that this *
336
 *                          is a partial search which means we do NOT want to  *
337
 *                          do any trans/ref updating and we also need to take *
338
 *                          care about locking things that are being updated   *
339
 *                          by more than one thread in parallel.               *
340
 *                                                                             *
341
 *   When mode = parallel, this code performs the same function as the old     *
342
 *   SearchParallel() code, except that it is the main search loop for the     *
343
 *   program, there is no longer any duplicated code.  This is called by the   *
344
 *   normal Search() function and by ThreadWait() where idle processes wait    *
345
 *   for work and then call this procedure to search a subset of the moves at  *
346
 *   this ply (in parallel with other threads).                                *
347
 *                                                                             *
348
 *******************************************************************************
349
 */
350
int SearchMoveList(TREE * RESTRICT tree, int ply, int depth, int wtm,
351
    int alpha, int beta, int searched[], int in_check, int repeat, int mode) {
352
  TREE *current;
353
  int extend, reduce, check, original_alpha = alpha, t_beta;
354
  int i, value = 0, pv_node = alpha != beta - 1, status, order;
355
  int moves_done = 0, phase, bestmove, type;
356
 
357
/*
358
 ************************************************************
359
 *                                                          *
360
 *  Basic initialization before we begin the loop through   *
361
 *  the move list.  If this is a parallel search, we have   *
362
 *  already searched one move, so we set t_beta to alpha+1  *
363
 *  to set up for a normal PVS search (for moves 2-n)       *
364
 *  instead of using alpha,beta for the first move as we do *
365
 *  in a normal search.  Also, if this is a serial search,  *
366
 *  we are fixing to search the first move so we set the    *
367
 *  searched move counter to zero, where in a parallel      *
368
 *  search this has already been done and we leave it alone *
369
 *  here.                                                   *
370
 *                                                          *
371
 *  We also set <current> to tree for a serial search, and  *
372
 *  to tree->parent for a parallel search since we need to  *
373
 *  share the move list at split nodes.                     *
374
 *                                                          *
375
 ************************************************************
376
 */
377
  tree->next_status[ply].phase = HASH;
378
  if (mode == parallel) {
379
    current = tree->parent;
380
    t_beta = alpha + 1;
381
  } else {
382
    current = tree;
383
    t_beta = beta;
384
  }
385
/*
386
 ************************************************************
387
 *                                                          *
388
 *  Iterate.  Now iterate through the move list and search  *
33 pmbaty 389
 *  the resulting positions.  Note that Search() culls any  *
390
 *  move that is not legal by using Check().  The special   *
391
 *  case is that we must find one legal move to search to   *
392
 *  confirm that it's not a mate or draw.                   *
393
 *                                                          *
108 pmbaty 394
 *  We call NextMove() which will generate moves in the     *
395
 *  normal way (captures, killers, etc) or it will use the  *
396
 *  GenerateEvasions() generator if we are in check.  For   *
397
 *  the special case of ply=1, we use NextRootMove() since  *
398
 *  the ply=1 move list has been generated and the order is *
399
 *  updated as each search iteration is executed.           *
33 pmbaty 400
 *                                                          *
401
 ************************************************************
402
 */
403
  while (1) {
108 pmbaty 404
    if (ply == 1 && moves_done == 1 && alpha == original_alpha &&
405
        mode == serial)
33 pmbaty 406
      break;
108 pmbaty 407
    if (mode == parallel)
408
      Lock(current->lock);
409
    order = (ply > 1) ? NextMove(current, ply, depth, wtm, in_check) :
410
      NextRootMove(current, tree, wtm);
411
    phase = current->phase[ply];
412
    if (mode == parallel) {
413
      tree->curmv[ply] = tree->parent->curmv[ply];
414
      Unlock(current->lock);
415
    }
416
    if (!order)
33 pmbaty 417
      break;
418
#if defined(TRACE)
419
    if (ply <= trace_level)
108 pmbaty 420
      Trace(tree, ply, depth, wtm, alpha, beta, "SearchMoveList", mode, phase,
421
          order);
33 pmbaty 422
#endif
108 pmbaty 423
    MakeMove(tree, ply, wtm, tree->curmv[ply]);
33 pmbaty 424
    tree->nodes_searched++;
108 pmbaty 425
    status = ILLEGAL;
426
    if (in_check || !Check(wtm))
33 pmbaty 427
      do {
108 pmbaty 428
        searched[0]++;
429
        moves_done++;
430
        status = LEGAL;
431
        searched[searched[0]] = tree->curmv[ply];
33 pmbaty 432
/*
433
 ************************************************************
434
 *                                                          *
108 pmbaty 435
 *  Check.  If the move to be made checks the opponent,     *
33 pmbaty 436
 *  then we need to remember that he's in check and also    *
108 pmbaty 437
 *  extend the depth by one ply for him to get out.         *
33 pmbaty 438
 *                                                          *
439
 *  We do not extend unsafe checking moves (as indicated by *
108 pmbaty 440
 *  the SEE algorithm), since these are usually a waste of  *
441
 *  time and simply blow up the tree search space.          *
33 pmbaty 442
 *                                                          *
108 pmbaty 443
 *  Note that extending here disables any potential foward  *
444
 *  pruning or reductions for this move.                    *
445
 *                                                          *
33 pmbaty 446
 ************************************************************
447
 */
448
        extend = 0;
449
        reduce = 0;
108 pmbaty 450
        if (Check(Flip(wtm))) {
451
          check = 1;
452
          if (SEEO(tree, wtm,
453
                  tree->curmv[ply]) - pcval[Captured(tree->curmv[ply])] <=
454
              0) {
33 pmbaty 455
            extend = check_depth;
456
            tree->extensions_done++;
457
          }
458
        } else
108 pmbaty 459
          check = 0;
33 pmbaty 460
/*
461
 ************************************************************
462
 *                                                          *
108 pmbaty 463
 *  Futility.  First attempt at forward pruning based on    *
464
 *  the futility idea.                                      *
33 pmbaty 465
 *                                                          *
466
 *  We have an array of pruning margin values that are      *
467
 *  indexed by depth (remaining plies left until we drop    *
468
 *  into the quiescence search) and which increase with     *
469
 *  depth since more depth means a greater chance of        *
470
 *  bringing the score back up to alpha or beyond.  If the  *
471
 *  current material + the bonus is less than alpha, we     *
472
 *  simply avoid searching this move at all, and skip to    *
473
 *  the next move without expending any more effort.  Note  *
474
 *  that this is classic forward-pruning and can certainly  *
475
 *  introduce errors into the search.  However, cluster     *
476
 *  testing has shown that this improves play in real       *
477
 *  games.  The current implementation only prunes in the   *
108 pmbaty 478
 *  last 6 plies before quiescence, although this can be    *
33 pmbaty 479
 *  tuned with the "eval" command changing the "pruning     *
108 pmbaty 480
 *  depth" value to something other than 7 (test is for     *
481
 *  depth < pruning depth, current value is 7 which prunes  *
482
 *  in last 6 plies only).  Testing shows no benefit in     *
483
 *  larger values than 7, although this might change in     *
33 pmbaty 484
 *  future versions as other things are modified.           *
485
 *                                                          *
486
 *  Exception:                                              *
487
 *                                                          *
488
 *    We do not prune if we are safely pushing a passed     *
489
 *    pawn to the 6th rank, where it becomes very dangerous *
490
 *    since it can promote in two more moves.               *
491
 *                                                          *
108 pmbaty 492
 *  All pruning and reduction code is skipped if any of the *
493
 *  following are true:                                     *
494
 *                                                          *
495
 *  (1) side on move is in check.                           *
496
 *                                                          *
497
 *  (2) move has not already been flagged for a search      *
498
 *      extension.                                          *
499
 *                                                          *
500
 *  (3) this is not the first move at this ply.             *
501
 *                                                          *
502
 *  (4) we are in the REMAINING phase, which means that a   *
503
 *      cutoff is not very likely.                          *
504
 *                                                          *
33 pmbaty 505
 ************************************************************
506
 */
108 pmbaty 507
        if (!in_check && !extend && order > 1 && phase >= HISTORY &&
508
            !(PawnPush(wtm, tree->curmv[ply]))) {
509
          if (!pv_node && depth < pruning_depth &&
510
              MaterialSTM(wtm) + pruning_margin[depth] <= alpha) {
511
            tree->moves_fpruned++;
512
            break;
33 pmbaty 513
          }
514
/*
515
 ************************************************************
516
 *                                                          *
108 pmbaty 517
 *  LMP.  Final attempt at forward pruning based on the     *
518
 *  "late move pruning" idea (a take-off on LMR).           *
33 pmbaty 519
 *                                                          *
108 pmbaty 520
 *  The basic idea here is that once we have searched a     *
521
 *  significant number of moves at a ply, it becomes less   *
522
 *  and less likely that any of the moves left will produce *
523
 *  a cutoff.  If the move appears to be simple (not a      *
524
 *  check, etc) then we simply skip it, once the move count *
525
 *  has been satisfied.  At present, we only do this in the *
526
 *  last two plies although this might be changed in the    *
527
 *  future.                                                 *
33 pmbaty 528
 *                                                          *
108 pmbaty 529
 ************************************************************
530
 */
531
          if (!pv_node && alpha > -MATE + 300 && depth < movecnt_depth &&
532
              !CaptureOrPromote(tree->curmv[ply]) &&
533
              order > movecnt_pruning[depth]) {
534
            tree->moves_mpruned++;
535
            break;
536
          }
537
/*
538
 ************************************************************
33 pmbaty 539
 *                                                          *
108 pmbaty 540
 *  LMR.  Now it's time to try to reduce the search depth   *
541
 *  if the move appears to be "poor" because it appears     *
542
 *  later in the move list.                                 *
33 pmbaty 543
 *                                                          *
108 pmbaty 544
 *  The reduction is variable and is done via a table look- *
545
 *  up that uses a function based on remaining depth (more  *
546
 *  depth remaining, the larger the reduction) and the      *
547
 *  number of moves searched (more moves searched, the      *
548
 *  larger the reduction).  The "shape" of this reduction   *
549
 *  formula is user-settable via the "lmr" command.         *
550
 *                                                          *
33 pmbaty 551
 ************************************************************
552
 */
108 pmbaty 553
          reduce = LMR[Min(depth, 31)][Min(order, 63)];
554
          tree->LMR_done[reduce]++;
33 pmbaty 555
        }
108 pmbaty 556
/*
33 pmbaty 557
 ************************************************************
558
 *                                                          *
108 pmbaty 559
 *  Now do the PVS search on the current move.              *
33 pmbaty 560
 *                                                          *
108 pmbaty 561
 *  Note that we do the usual alpha/beta cutoff tests here  *
562
 *  but we only set an indicator that is used after we have *
563
 *  called Unmake().  This cleaned up the exit from search  *
564
 *  and makes it easier to understand when there is only    *
565
 *  one point where this is done, without needing multiple  *
566
 *  Unmake() calls when there are different exit points.    *
33 pmbaty 567
 *                                                          *
568
 ************************************************************
569
 */
108 pmbaty 570
        value =
571
            SearchMove(tree, ply, depth, wtm, alpha, t_beta, beta, extend,
572
            reduce, check);
573
        if (value > alpha) {
574
          status = IN_WINDOW;
575
          if (value >= beta)
576
            status = FAIL_HIGH;
577
          if (mode == parallel && ply == 1)
578
            status = FAIL_HIGH;
579
        }
580
      } while (0);
581
    UnmakeMove(tree, ply, wtm, tree->curmv[ply]);
582
    if (abort_search || tree->stop)
583
      break;
33 pmbaty 584
/*
585
 ************************************************************
586
 *                                                          *
108 pmbaty 587
 *  Test 1.  When we get here, we have made a move,         *
588
 *  searched it (and re-searched if necessary/appropriate), *
589
 *  and the move has been unmade so that the board is in a  *
590
 *  correct state.                                          *
33 pmbaty 591
 *                                                          *
108 pmbaty 592
 *  If status = FAIL_HIGH, the search failed high.  The     *
593
 *  first thing to handle is the case where we are at       *
594
 *  ply=1, which is a special case.  If we are going to     *
595
 *  fail high here and terminate the search immediately, we *
596
 *  need to build the fail-high PV to back up to Iterate()  *
597
 *  so it will produce the correct output and widen the     *
598
 *  alpha/beta window.                                      *
33 pmbaty 599
 *                                                          *
108 pmbaty 600
 *  We then check to see if this is a parallel search.  If  *
601
 *  so then we are done here, but we need to tell all of    *
602
 *  the siblings that are helping at this split point that  *
603
 *  they should immediately stop searching here since we    *
604
 *  don't need their results.                               *
33 pmbaty 605
 *                                                          *
108 pmbaty 606
 *  Otherwise we update the killer moves and history        *
607
 *  counters and store the fail-high information in the     *
608
 *  trans/ref table for future use if we happen to reach    *
609
 *  this position again.                                    *
33 pmbaty 610
 *                                                          *
611
 ************************************************************
612
 */
108 pmbaty 613
    if (status == FAIL_HIGH) {
614
      if (ply == 1) {
615
        if (!tree->stop) {
616
          tree->pv[1].path[1] = tree->curmv[1];
617
          tree->pv[1].pathl = 2;
618
          tree->pv[1].pathh = 0;
619
          tree->pv[1].pathd = iteration;
620
          tree->pv[0] = tree->pv[1];
33 pmbaty 621
        }
108 pmbaty 622
      }
623
#if (CPUS > 1)
624
      if (mode == parallel) {
625
        Lock(lock_smp);
626
        Lock(tree->parent->lock);
627
        if (!tree->stop) {
628
          int proc;
629
 
630
          parallel_aborts++;
631
          for (proc = 0; proc < (int) smp_max_threads; proc++) // Pierre-Marie Baty -- added type cast
632
            if (tree->parent->siblings[proc] && proc != tree->thread_id)
633
              ThreadStop(tree->parent->siblings[proc]);
634
        }
635
        Unlock(tree->parent->lock);
636
        Unlock(lock_smp);
637
        return value;
638
      }
639
#endif
640
      tree->fail_highs++;
641
      if (order == 1)
642
        tree->fail_high_first_move++;
643
      HashStore(tree, ply, depth, wtm, LOWER, value, tree->curmv[ply]);
644
      History(tree, ply, depth, wtm, tree->curmv[ply], searched);
645
      return beta;
646
/*
33 pmbaty 647
 ************************************************************
648
 *                                                          *
108 pmbaty 649
 *  Test 2.  If status = IN_WINDOW, this is a search that   *
650
 *  improved alpha without failing high.  We simply update  *
651
 *  alpha and continue searching moves.                     *
33 pmbaty 652
 *                                                          *
108 pmbaty 653
 *  Special case:  If ply = 1 in a normal search, we have   *
654
 *  a best move and score that just changed.  We need to    *
655
 *  update the root move list by adding the PV and the      *
656
 *  score, and then we look to make sure this new "best     *
657
 *  move" is not actually worse than the best we have found *
658
 *  so far this iteration.  If it is worse, we restore the  *
659
 *  best move and score from the real best move so our      *
660
 *  search window won't be out of whack, which would let    *
661
 *  moves with scores in between this bad move and the best *
662
 *  move fail high, cause re-searches, and waste time.      *
33 pmbaty 663
 *                                                          *
108 pmbaty 664
 *  If this is ply = 1, we display the PV to keep the user  *
665
 *  informed.                                               *
666
 *                                                          *
33 pmbaty 667
 ************************************************************
668
 */
108 pmbaty 669
    } else if (status == IN_WINDOW) {
670
      alpha = value;
671
      if (ply == 1 && mode == serial) {
672
        tree->pv[1].pathv = value;
673
        tree->pv[0] = tree->pv[1];
674
        for (i = 0; i < n_root_moves; i++)
675
          if (root_moves[i].move == tree->pv[1].path[1]) {
676
            root_moves[i].path = tree->pv[1];
677
            root_moves[i].path.pathv = alpha;
33 pmbaty 678
          }
108 pmbaty 679
        for (i = 0; i < n_root_moves; i++)
680
          if (value < root_moves[i].path.pathv) {
681
            value = root_moves[i].path.pathv;
682
            alpha = value;
683
            tree->pv[0] = root_moves[i].path;
684
            tree->pv[1] = tree->pv[0];
33 pmbaty 685
          }
108 pmbaty 686
        Output(tree);
687
        failhi_delta = 16;
688
        faillo_delta = 16;
689
      }
690
    }
33 pmbaty 691
/*
692
 ************************************************************
693
 *                                                          *
108 pmbaty 694
 *  Test 3.  If status = ILLEGAL, this search was given an  *
695
 *  illegal move and no search was done, we skip any        *
696
 *  updating and simply select the next move to search.     *
697
 *                                                          *
698
 ************************************************************
699
 */
700
    else if (status == ILLEGAL)
701
      continue;
702
    t_beta = alpha + 1;
703
/*
704
 ************************************************************
705
 *                                                          *
706
 *  SMP.  If are doing an SMP search, and we have idle      *
33 pmbaty 707
 *  processors, now is the time to get them involved.  We   *
708
 *  have now satisfied the "young brothers wait" condition  *
108 pmbaty 709
 *  since we have searched at least one move.  All that is  *
710
 *  left is to check the split constraints to see if this   *
711
 *  is an acceptable split point.                           *
33 pmbaty 712
 *                                                          *
713
 *    (1) We can't split within N plies of the frontier     *
714
 *        nodes to avoid excessive split overhead.          *
715
 *                                                          *
108 pmbaty 716
 *    (2) We can't split until at least N nodes have been   *
33 pmbaty 717
 *        searched since this thread was last split, to     *
718
 *        avoid splitting too often, mainly in endgames.    *
719
 *                                                          *
720
 *    (3) We have to have searched one legal move to avoid  *
721
 *        splitting at a node where we have no legal moves  *
722
 *        (the first move tried might have been illegal as  *
723
 *        in when we encounter a stalemate).                *
724
 *                                                          *
725
 *    (4) If we are at ply=1, we can't split unless the     *
726
 *        smp_split_at_root flag is set to 1, AND the next  *
727
 *        move in the ply=1 move list is not flagged as     *
728
 *        "do not search in parallel" which happens when    *
729
 *        this move was a best move in the last couple of   *
730
 *        searches and we want all processors on it at once *
731
 *        to get a score back quicker.                      *
732
 *                                                          *
108 pmbaty 733
 *    (5) if the variable smp_split is != 0, we have idle   *
734
 *        threads that can help, which means we want to get *
735
 *        them involved quickly, OR if this node is an      *
736
 *        acceptable "gratuitous-split" point by being far  *
737
 *        enough from the tips of the tree to avoid         *
738
 *        excessive overhead.                               *
33 pmbaty 739
 *                                                          *
108 pmbaty 740
 *  We use this code recursively to perform a parallel      *
741
 *  search at this ply.  But when we finish a partial piece *
742
 *  of the search in parallel, we don't need to update any  *
743
 *  search data structures, we will defer that until all of *
744
 *  parallel threads complete and return back into this     *
745
 *  code after the parallel search has been collapsed back  *
746
 *  to one instance of search at this ply.                  *
33 pmbaty 747
 *                                                          *
748
 *  Special case:  we do not split if we are at ply=1 and   *
749
 *  alpha == original_alpha.  That means the first move     *
750
 *  failed low, and we are going to exit search and return  *
751
 *  to Iterate() to report this.                            *
752
 *                                                          *
108 pmbaty 753
 *  In Generation II, multiple threads can reach this point *
754
 *  at the same time.  We allow multiple threads to split   *
755
 *  at the same time, but then the idle threads will choose *
756
 *  to join the thread with the most attractive split point *
757
 *  rather than just taking pot-luck.  The only limitation  *
758
 *  on a thread adding a split point here is that if the    *
759
 *  thread already has enough joinable split points have    *
760
 *  not been joined yet, we do not incur the overhead of    *
761
 *  creating another split point until the existing split   *
762
 *  point is completed or a thread joins at at that point.  *
33 pmbaty 763
 *                                                          *
108 pmbaty 764
 *  We do not lock anything here, as the split operation    *
765
 *  only affects thread-local data.  When the split is done *
766
 *  then the ThreadJoin() function will acquire the lock    *
767
 *  needed to avoid race conditions during the join op-     *
768
 *  eration.                                                *
33 pmbaty 769
 *                                                          *
770
 ************************************************************
771
 */
772
#if (CPUS > 1)
108 pmbaty 773
    if (mode == serial && moves_done && smp_threads &&
774
        ThreadSplit(tree, ply, depth, alpha, original_alpha, moves_done))
33 pmbaty 775
      do {
776
        tree->alpha = alpha;
777
        tree->beta = beta;
778
        tree->value = alpha;
108 pmbaty 779
        tree->wtm = wtm;
33 pmbaty 780
        tree->ply = ply;
781
        tree->depth = depth;
108 pmbaty 782
        tree->in_check = in_check;
783
        tree->searched = searched;
784
        if (Split(tree)) {
33 pmbaty 785
          if (abort_search || tree->stop)
786
            return 0;
787
          value = tree->value;
788
          if (value > alpha) {
108 pmbaty 789
            if (ply == 1)
790
              tree->pv[0] = tree->pv[1];
33 pmbaty 791
            if (value >= beta) {
108 pmbaty 792
              HashStore(tree, ply, depth, wtm, LOWER, value, tree->cutmove);
33 pmbaty 793
              return value;
794
            }
795
            alpha = value;
796
            break;
797
          }
798
        }
799
      } while (0);
800
#endif
801
  }
802
/*
803
 ************************************************************
804
 *                                                          *
108 pmbaty 805
 *  SMP Cleanup.  If we are doing an SMP search, there are  *
806
 *  no "end-of-search" things to do.  We have searched all  *
807
 *  the remaining moves at this ply in parallel, and now    *
808
 *  return and let the original search that started this    *
809
 *  sub-tree clean up, do the tests for mate/stalemate,     *
810
 *  update the hash table, etc.                             *
33 pmbaty 811
 *                                                          *
108 pmbaty 812
 *  As we return, we end back up in Thread() where we       *
813
 *  started, which then copies the best score/etc back to   *
814
 *  the parent thread.                                      *
815
 *                                                          *
33 pmbaty 816
 ************************************************************
817
 */
108 pmbaty 818
  if (abort_search || tree->stop || mode == parallel)
819
    return alpha;
820
/*
821
 ************************************************************
822
 *                                                          *
823
 *  Search completed.  All moves have been searched.  If    *
824
 *  none were legal, return either MATE or DRAW depending   *
825
 *  on whether the side to move is in check or not.         *
826
 *                                                          *
827
 ************************************************************
828
 */
829
  if (moves_done == 0) {
830
    value = (Check(wtm)) ? -(MATE - ply) : DrawScore(wtm);
33 pmbaty 831
    if (value >= alpha && value < beta) {
832
      SavePV(tree, ply, 0);
833
#if defined(TRACE)
834
      if (ply <= trace_level)
835
        printf("Search() no moves!  ply=%d\n", ply);
836
#endif
837
    }
838
    return value;
839
  } else {
840
    bestmove =
108 pmbaty 841
        (alpha ==
842
        original_alpha) ? tree->hash_move[ply] : tree->pv[ply].path[ply];
33 pmbaty 843
    type = (alpha == original_alpha) ? UPPER : EXACT;
844
    if (repeat == 2 && alpha != -(MATE - ply - 1)) {
108 pmbaty 845
      value = DrawScore(wtm);
33 pmbaty 846
      if (value < beta)
108 pmbaty 847
        SavePV(tree, ply, 4);
33 pmbaty 848
#if defined(TRACE)
849
      if (ply <= trace_level)
850
        printf("draw by 50 move rule detected, ply=%d.\n", ply);
851
#endif
852
      return value;
853
    } else if (alpha != original_alpha) {
854
      tree->pv[ply - 1] = tree->pv[ply];
855
      tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1];
856
    }
108 pmbaty 857
    HashStore(tree, ply, depth, wtm, type, alpha, bestmove);
33 pmbaty 858
    return alpha;
859
  }
860
}
861
 
108 pmbaty 862
/* last modified 07/01/15 */
33 pmbaty 863
/*
864
 *******************************************************************************
865
 *                                                                             *
108 pmbaty 866
 *   SearchMove() implements the PVS search and returns the value.  We do a    *
867
 *   null-window search with the window (alpha, t_beta) and if that fails high *
868
 *   we repeat the search with the window {alpha, beta} assuming that beta !=  *
869
 *   t_beta.                                                                   *
33 pmbaty 870
 *                                                                             *
871
 *******************************************************************************
872
 */
108 pmbaty 873
int SearchMove(TREE * RESTRICT tree, int ply, int depth, int wtm, int alpha,
874
    int t_beta, int beta, int extend, int reduce, int check) {
875
  int value;
33 pmbaty 876
/*
877
 ************************************************************
878
 *                                                          *
108 pmbaty 879
 *  PVS search.  We have determined whether the depth is to *
33 pmbaty 880
 *  be changed by an extension or a reduction.  If we get   *
881
 *  to this point, then the move is not being pruned.  So   *
882
 *  off we go to a recursive search/quiescence call to work *
883
 *  our way toward a terminal node.                         *
884
 *                                                          *
108 pmbaty 885
 *  There is one special-case to handle.  If the depth was  *
33 pmbaty 886
 *  reduced, and Search() returns a value >= beta then      *
887
 *  accepting that is risky (we reduced the move as we      *
888
 *  thought it was bad and expected it to fail low) so we   *
889
 *  repeat the search using the original (non-reduced)      *
890
 *  depth to see if the fail-high happens again.            *
891
 *                                                          *
892
 ************************************************************
893
 */
108 pmbaty 894
  if (depth + extend - reduce - 1 > 0) {
895
    value =
896
        -Search(tree, ply + 1, depth + extend - reduce - 1, Flip(wtm),
897
        -t_beta, -alpha, check, DO_NULL);
898
    if (value > alpha && reduce) {
899
      value =
900
          -Search(tree, ply + 1, depth - 1, Flip(wtm), -t_beta, -alpha, check,
901
          DO_NULL);
902
    }
903
  } else
904
    value = -Quiesce(tree, ply + 1, Flip(wtm), -t_beta, -alpha, 1);
905
  if (abort_search || tree->stop)
906
    return 0;
33 pmbaty 907
/*
908
 ************************************************************
909
 *                                                          *
108 pmbaty 910
 *  PVS re-search.  This is the PVS re-search code.  If we  *
911
 *  reach this point and value > alpha and value < beta,    *
912
 *  then this can not be a null-window search.  We have to  *
913
 *  re-search the position with the original beta value     *
914
 *  to see if it still fails high before we treat this as a *
915
 *  real fail-high and back up the value to the previous    *
916
 *  ply.                                                    *
33 pmbaty 917
 *                                                          *
918
 ************************************************************
919
 */
108 pmbaty 920
  if (value > alpha && value < beta && t_beta < beta) {
921
    if (ply == 1)
922
      return beta;
923
    if (depth + extend - 1 > 0)
924
      value =
925
          -Search(tree, ply + 1, depth + extend - 1, Flip(wtm), -beta, -alpha,
926
          check, DO_NULL);
927
    else
928
      value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -alpha, 1);
33 pmbaty 929
    if (abort_search || tree->stop)
108 pmbaty 930
      return 0;
33 pmbaty 931
  }
108 pmbaty 932
  return value;
33 pmbaty 933
}