Subversion Repositories Games.Chess Giants

Rev

Rev 33 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 33 Rev 108
Line 1... Line 1...
1
#include "chess.h"
1
#include "chess.h"
2
#include "data.h"
2
#include "data.h"
3
/* last modified 05/07/14 */
3
/* last modified 01/10/16 */
4
/*
4
/*
5
 *******************************************************************************
5
 *******************************************************************************
6
 *                                                                             *
6
 *                                                                             *
7
 *   Quiece() is the recursive routine used to implement the quiescence        *
7
 *   Quiece() is the recursive routine used to implement the quiescence        *
8
 *   search part of the alpha/beta negamax search.  It performs the following  *
8
 *   search part of the alpha/beta negamax search.  It performs the following  *
Line 13... Line 13...
13
 *   the current static evaluation, or else it may try captures and/or         *
13
 *   the current static evaluation, or else it may try captures and/or         *
14
 *   checking moves to see if it can improve the stand-pat score by making a   *
14
 *   checking moves to see if it can improve the stand-pat score by making a   *
15
 *   move that leads to some sort of positional or material gain.              *
15
 *   move that leads to some sort of positional or material gain.              *
16
 *                                                                             *
16
 *                                                                             *
17
 *   (2) The first phase is to generate all possible capture moves and then    *
17
 *   (2) The first phase is to generate all possible capture moves and then    *
18
 *   sort them into descending using the value                                 *
18
 *   sort them into descending using the value of the captured piece and the   *
19
 *                                                                             *
-
 
20
 *        val = 128 * captured_piece_value + capturing_piece_value             *
19
 *   complemented value of the capturing piece.  This is the classic MVV/LVA   *
21
 *                                                                             *
-
 
22
 *   This is the classic MVV/LVA ordering approach that removes heavy pieces   *
20
 *   ordering approach that removes heavy pieces first in an attempt to reduce *
23
 *   first in an attempt to reduce the size of the sub-tree these pieces       *
-
 
24
 *   produce.                                                                  *
21
 *   the size of the sub-tree these pieces produce.                            *
25
 *                                                                             *
22
 *                                                                             *
26
 *   (3) When we get ready to actually search each capture, we analyze each    *
23
 *   (3) When we get ready to actually search each capture, we analyze each    *
27
 *   move to see if it appears reasonable.  Small pieces can capture larger    *
24
 *   move to see if it appears reasonable.  Small pieces can capture larger    *
28
 *   ones safely, ditto for equal exchanges.  For the rest, we use Swap() to   *
25
 *   ones safely, ditto for equal exchanges.  For the rest, we use SEE() to    *
29
 *   compute the SEE score.  If this is less than zero, we do not search this  *
26
 *   compute the SEE score.  If this is less than zero, we do not search this  *
30
 *   move at all to avoid wasting time, since a losing capture rarely helps    *
27
 *   move at all to avoid wasting time, since a losing capture rarely helps    *
31
 *   improve the score in the q-search.  The goal here is to find a capture    *
28
 *   improve the score in the q-search.  The goal here is to find a capture    *
32
 *   that improves on the stand-pat score and gets us closer to a position     *
29
 *   that improves on the stand-pat score and gets us closer to a position     *
33
 *   that we would describe as "quiet" or "static".                            *
30
 *   that we would describe as "quiet" or "static".                            *
34
 *                                                                             *
31
 *                                                                             *
35
 *   (4) If the parameter "checks" is non-zero then after searching the        *
32
 *   (4) If the parameter "checks" is non-zero, then after searching the       *
36
 *   captures, we generate checking moves and search those.  This value also   *
33
 *   captures, we generate checking moves and search those.  This value also   *
37
 *   slightly changes the way captures are searched, since those that are also *
34
 *   slightly changes the way captures are searched, since those that are also *
38
 *   checks result in calling QuiesceEvasions() which evades checks to see if  *
35
 *   checks result in calling QuiesceEvasions() which evades checks to see if  *
39
 *   the check is actually a mate.  This means that we have one layer of full- *
36
 *   the check is actually a mate.  This means that we have one layer of full- *
40
 *   width search to escape checks and do not allow a stand-pat which would    *
37
 *   width search to escape checks and do not allow a stand-pat which would    *
41
 *   hide the effect of the check completely.                                  *
38
 *   hide the effect of the check completely.                                  *
42
 *                                                                             *
39
 *                                                                             *
43
 *******************************************************************************
40
 *******************************************************************************
44
 */
41
 */
45
int Quiesce(TREE * RESTRICT tree, int alpha, int beta, int wtm, int ply,
42
int Quiesce(TREE * RESTRICT tree, int ply, int wtm, int alpha, int beta,
46
    int checks) {
43
    int checks) {
-
 
44
  unsigned *next, *movep;
47
  int original_alpha = alpha, value;
45
  int original_alpha = alpha, value;
48
  int *next;
-
 
49
  int *movep, *sortv;
-
 
50
 
46
 
51
/*
47
/*
52
 ************************************************************
48
 ************************************************************
53
 *                                                          *
49
 *                                                          *
54
 *  Initialize.                                             *
50
 *  Initialize.                                             *
Line 56... Line 52...
56
 ************************************************************
52
 ************************************************************
57
 */
53
 */
58
  if (ply >= MAXPLY - 1)
54
  if (ply >= MAXPLY - 1)
59
    return beta;
55
    return beta;
60
#if defined(NODES)
56
#if defined(NODES)
61
  if (--temp_search_nodes <= 0) {
57
  if (search_nodes && --temp_search_nodes <= 0) {
62
    abort_search = 1;
58
    abort_search = 1;
63
    return 0;
59
    return 0;
64
  }
60
  }
65
#endif
61
#endif
66
  if (tree->thread_id == 0)
62
  if (tree->thread_id == 0)
Line 99... Line 95...
99
 *  save the path to this node as it is the PV that leads   *
95
 *  save the path to this node as it is the PV that leads   *
100
 *  to this score.                                          *
96
 *  to this score.                                          *
101
 *                                                          *
97
 *                                                          *
102
 ************************************************************
98
 ************************************************************
103
 */
99
 */
104
  tree->curmv[ply] = 0;
-
 
105
  value = Evaluate(tree, ply, wtm, alpha, beta);
100
  value = Evaluate(tree, ply, wtm, alpha, beta);
106
#if defined(TRACE)
101
#if defined(TRACE)
107
  if (ply <= trace_level)
102
  if (ply <= trace_level)
108
    Trace(tree, ply, value, wtm, alpha, beta, "Quiesce", EVALUATION);
103
    Trace(tree, ply, value, wtm, alpha, beta, "Quiesce", serial, EVALUATION, 0);
109
#endif
104
#endif
110
  if (value > alpha) {
105
  if (value > alpha) {
111
    if (value >= beta)
106
    if (value >= beta)
112
      return value;
107
      return value;
113
    alpha = value;
108
    alpha = value;
114
    tree->pv[ply].pathl = ply;
109
    tree->pv[ply].pathl = ply;
115
    tree->pv[ply].pathh = 0;
110
    tree->pv[ply].pathh = 0;
116
    tree->pv[ply].pathd = iteration_depth;
111
    tree->pv[ply].pathd = iteration;
117
  }
112
  }
118
/*
113
/*
119
 ************************************************************
114
 ************************************************************
120
 *                                                          *
115
 *                                                          *
121
 *  Generate captures and sort them based on simple MVV/LVA *
116
 *  Generate captures and sort them based on simple MVV/LVA *
Line 124... Line 119...
124
 *  possible, to get rid of heavy pieces quickly and reduce *
119
 *  possible, to get rid of heavy pieces quickly and reduce *
125
 *  the overall size of the tree.                           *
120
 *  the overall size of the tree.                           *
126
 *                                                          *
121
 *                                                          *
127
 *  Note that later we use the value of the capturing       *
122
 *  Note that later we use the value of the capturing       *
128
 *  piece, the value of the captured piece, and possibly    *
123
 *  piece, the value of the captured piece, and possibly    *
129
 *  Swap() to exclude captures that appear to lose          *
124
 *  SEE() to exclude captures that appear to lose material, *
130
 *  material, but we delay expending this effort as long as *
125
 *  but we delay expending this effort as long as possible, *
131
 *  possible, since beta cutoffs make it unnecessary to     *
126
 *  since beta cutoffs make it unnecessary to search all of *
132
 *  search all of these moves anyway.                       *
127
 *  these moves anyway.                                     *
133
 *                                                          *
128
 *                                                          *
134
 ************************************************************
129
 ************************************************************
135
 */
130
 */
136
  tree->last[ply] = GenerateCaptures(tree, ply, wtm, tree->last[ply - 1]);
131
  tree->last[ply] = GenerateCaptures(tree, ply, wtm, tree->last[ply - 1]);
137
  sortv = tree->sort_value;
-
 
138
  for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++) {
132
  for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++) {
139
    if (Captured(*movep) == king)
133
    if (Captured(*movep) == king)
140
      return beta;
134
      return beta;
141
    *sortv++ = 128 * pcval[Captured(*movep)] - pcval[Piece(*movep)];
135
    *movep += MVV_LVA[Captured(*movep)][Piece(*movep)];
142
  }
136
  }
143
  if (!checks && tree->last[ply] == tree->last[ply - 1]) {
137
  if (!checks && tree->last[ply] == tree->last[ply - 1]) {
144
    if (alpha != original_alpha) {
138
    if (alpha != original_alpha) {
145
      tree->pv[ply - 1] = tree->pv[ply];
139
      tree->pv[ply - 1] = tree->pv[ply];
146
      tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1];
140
      tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1];
147
    }
141
    }
148
    return value;
142
    return value;
149
  }
143
  }
150
/*
-
 
151
 ************************************************************
-
 
152
 *                                                          *
-
 
153
 *  This is a simple insertion sort algorithm.  It seems be *
-
 
154
 *  be no faster than a normal bubble sort, but using this  *
-
 
155
 *  eliminated a lot of explaining about "why?". :)         *
-
 
156
 *                                                          *
-
 
157
 ************************************************************
-
 
158
 */
-
 
159
  if (tree->last[ply] > tree->last[ply - 1] + 1) {
-
 
160
    int temp1, temp2, *tmovep, *tsortv, *end;
-
 
161
 
-
 
162
    sortv = tree->sort_value + 1;
-
 
163
    end = tree->last[ply];
144
  NextSort(tree, ply);
164
    for (movep = tree->last[ply - 1] + 1; movep < end; movep++, sortv++) {
-
 
165
      temp1 = *movep;
-
 
166
      temp2 = *sortv;
-
 
167
      tmovep = movep - 1;
-
 
168
      tsortv = sortv - 1;
-
 
169
      while (tmovep >= tree->last[ply - 1] && *tsortv < temp2) {
-
 
170
        *(tsortv + 1) = *tsortv;
-
 
171
        *(tmovep + 1) = *tmovep;
-
 
172
        tmovep--;
-
 
173
        tsortv--;
-
 
174
      }
-
 
175
      *(tmovep + 1) = temp1;
-
 
176
      *(tsortv + 1) = temp2;
-
 
177
    }
-
 
178
  }
-
 
179
  tree->next_status[ply].last = tree->last[ply - 1];
-
 
180
/*
145
/*
181
 ************************************************************
146
 ************************************************************
182
 *                                                          *
147
 *                                                          *
183
 *  Iterate through the move list and search the resulting  *
148
 *  Iterate through the move list and search the resulting  *
184
 *  positions.  Now that we are ready to actually search    *
149
 *  positions.  Now that we are ready to actually search    *
185
 *  the set of capturing moves, we try three quick tests to *
150
 *  the set of capturing moves, we try three quick tests to *
186
 *  see if the move should be excluded because it appears   *
151
 *  see if the move should be excluded because it appears   *
187
 *  to lose material.                                       *
152
 *  to lose material.                                       *
188
 *                                                          *
153
 *                                                          *
189
 *  (1) If the capturing piece is not more valuable than    *
154
 *  (1) If the capturing piece is not more valuable than    *
190
 *  the captured piece, then the move can't lose material   *
155
 *  the captured piece, then the move can't lose material   *
191
 *  and should be searched.                                 *
156
 *  and should be searched.                                 *
192
 *                                                          *
157
 *                                                          *
Line 194... Line 159...
194
 *  always search this kind of capture since this can be    *
159
 *  always search this kind of capture since this can be    *
195
 *  the move the allows a passed pawn to promote when the   *
160
 *  the move the allows a passed pawn to promote when the   *
196
 *  opponent has no piece to catch it.                      *
161
 *  opponent has no piece to catch it.                      *
197
 *                                                          *
162
 *                                                          *
198
 *  (3) Otherwise, If the capturing piece is more valuable  *
163
 *  (3) Otherwise, If the capturing piece is more valuable  *
199
 *  than the captured piece, we use Swap() to determine if  *
164
 *  than the captured piece, we use SEE() to determine if   *
200
 *  the capture is losing or not so that we don't search    *
165
 *  the capture is losing or not so that we don't search    *
201
 *  hopeless moves.                                         *
166
 *  hopeless moves.                                         *
202
 *                                                          *
167
 *                                                          *
203
 ************************************************************
168
 ************************************************************
204
 */
169
 */
205
  for (next = tree->last[ply - 1]; next < tree->last[ply]; next++) {
170
  for (next = tree->last[ply - 1]; next < tree->last[ply]; next++) {
206
    tree->curmv[ply] = *next;
171
    tree->curmv[ply] = Move(*next);
207
    if (pcval[Piece(tree->curmv[ply])] > pcval[Captured(tree->curmv[ply])] &&
172
    if (pcval[Piece(tree->curmv[ply])] > pcval[Captured(tree->curmv[ply])] &&
208
        TotalPieces(wtm, occupied)
173
        TotalPieces(Flip(wtm), occupied)
209
        - p_vals[Captured(tree->curmv[ply])] > 0 &&
174
        - p_vals[Captured(tree->curmv[ply])] > 0 &&
210
        Swap(tree, tree->curmv[ply], wtm) < 0)
175
        SEE(tree, wtm, tree->curmv[ply]) < 0)
211
      continue;
176
      continue;
212
#if defined(TRACE)
177
#if defined(TRACE)
213
    if (ply <= trace_level)
178
    if (ply <= trace_level)
214
      Trace(tree, ply, 0, wtm, alpha, beta, "Quiesce", CAPTURE_MOVES);
179
      Trace(tree, ply, 0, wtm, alpha, beta, "Quiesce", serial, CAPTURES,
-
 
180
          next - tree->last[ply - 1] + 1);
215
#endif
181
#endif
216
    MakeMove(tree, ply, tree->curmv[ply], wtm);
182
    MakeMove(tree, ply, wtm, tree->curmv[ply]);
217
    tree->nodes_searched++;
183
    tree->nodes_searched++;
218
    if (!checks)
184
    if (!checks)
219
      value = -Quiesce(tree, -beta, -alpha, Flip(wtm), ply + 1, 0);
185
      value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -alpha, 0);
220
    else if (!Check(wtm)) {
186
    else if (!Check(wtm)) {
221
      if (Check(Flip(wtm))) {
187
      if (Check(Flip(wtm))) {
222
        tree->qchecks_done++;
188
        tree->qchecks_done++;
223
        value = -QuiesceEvasions(tree, -beta, -alpha, Flip(wtm), ply + 1);
189
        value = -QuiesceEvasions(tree, ply + 1, Flip(wtm), -beta, -alpha);
224
      } else
190
      } else
225
        value = -Quiesce(tree, -beta, -alpha, Flip(wtm), ply + 1, 0);
191
        value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -alpha, 0);
226
    }
192
    }
227
    UnmakeMove(tree, ply, tree->curmv[ply], wtm);
193
    UnmakeMove(tree, ply, wtm, tree->curmv[ply]);
228
    if (abort_search || tree->stop)
194
    if (abort_search || tree->stop)
229
      return 0;
195
      return 0;
230
    if (value > alpha) {
196
    if (value > alpha) {
231
      if (value >= beta)
197
      if (value >= beta)
232
        return value;
198
        return value;
Line 239... Line 205...
239
 *  The next block of code is only executed if the checks   *
205
 *  The next block of code is only executed if the checks   *
240
 *  parameter is non-zero, otherwise we skip this and exit  *
206
 *  parameter is non-zero, otherwise we skip this and exit  *
241
 *  with no further searching.                              *
207
 *  with no further searching.                              *
242
 *                                                          *
208
 *                                                          *
243
 *  Generate just the moves (non-captures) that give check  *
209
 *  Generate just the moves (non-captures) that give check  *
244
 *  and search the ones that Swap() says are safe.  Subtle  *
210
 *  and search the ones that SEE() says are safe.  Subtle   *
245
 *  trick:  we discard the captures left over from the      *
211
 *  trick:  we discard the captures left over from the      *
246
 *  above search since we labeled them "losing moves."      *
212
 *  above search since we labeled them "losing moves."      *
247
 *                                                          *
213
 *                                                          *
248
 ************************************************************
214
 ************************************************************
249
 */
215
 */
Line 257... Line 223...
257
 *  GenerateChecks() provides.                              *
223
 *  GenerateChecks() provides.                              *
258
 *                                                          *
224
 *                                                          *
259
 ************************************************************
225
 ************************************************************
260
 */
226
 */
261
    for (next = tree->last[ply - 1]; next < tree->last[ply]; next++) {
227
    for (next = tree->last[ply - 1]; next < tree->last[ply]; next++) {
262
      tree->curmv[ply] = *next;
228
      tree->curmv[ply] = Move(*next);
263
      if (Swap(tree, tree->curmv[ply], wtm) >= 0) {
229
      if (SEE(tree, wtm, tree->curmv[ply]) >= 0) {
264
#if defined(TRACE)
230
#if defined(TRACE)
265
        if (ply <= trace_level)
231
        if (ply <= trace_level)
266
          Trace(tree, ply, 0, wtm, alpha, beta, "Quiesce", REMAINING_MOVES);
232
          Trace(tree, ply, 0, wtm, alpha, beta, "Quiesce+checks", serial,
-
 
233
              REMAINING, next - tree->last[ply - 1] + 1);
267
#endif
234
#endif
268
        MakeMove(tree, ply, tree->curmv[ply], wtm);
235
        MakeMove(tree, ply, wtm, tree->curmv[ply]);
269
        tree->nodes_searched++;
236
        tree->nodes_searched++;
270
        if (!Check(wtm)) {
237
        if (!Check(wtm)) {
271
          tree->qchecks_done++;
238
          tree->qchecks_done++;
272
          value = -QuiesceEvasions(tree, -beta, -alpha, Flip(wtm), ply + 1);
239
          value = -QuiesceEvasions(tree, ply + 1, Flip(wtm), -beta, -alpha);
273
        }
240
        }
274
        UnmakeMove(tree, ply, tree->curmv[ply], wtm);
241
        UnmakeMove(tree, ply, wtm, tree->curmv[ply]);
275
        if (abort_search || tree->stop)
242
        if (abort_search || tree->stop)
276
          return 0;
243
          return 0;
277
        if (value > alpha) {
244
        if (value > alpha) {
278
          if (value >= beta)
245
          if (value >= beta)
279
            return value;
246
            return value;
Line 297... Line 264...
297
    tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1];
264
    tree->pv[ply - 1].path[ply - 1] = tree->curmv[ply - 1];
298
  }
265
  }
299
  return alpha;
266
  return alpha;
300
}
267
}
301
 
268
 
302
/* last modified 05/07/14 */
269
/* last modified 01/10/16 */
303
/*
270
/*
304
 *******************************************************************************
271
 *******************************************************************************
305
 *                                                                             *
272
 *                                                                             *
306
 *   QuiesceEvasions() is the recursive routine used to implement the alpha/   *
273
 *   QuiesceEvasions() is the recursive routine used to implement the alpha/   *
307
 *   beta negamax quiescence search.  The primary function here is to escape a *
274
 *   beta negamax quiescence search.  The primary function here is to escape a *
Line 314... Line 281...
314
 *   in the the order they are generated since we are going to try them all    *
281
 *   in the the order they are generated since we are going to try them all    *
315
 *   unless we get a fail-high.                                                *
282
 *   unless we get a fail-high.                                                *
316
 *                                                                             *
283
 *                                                                             *
317
 *******************************************************************************
284
 *******************************************************************************
318
 */
285
 */
319
int QuiesceEvasions(TREE * RESTRICT tree, int alpha, int beta, int wtm,
286
int QuiesceEvasions(TREE * RESTRICT tree, int ply, int wtm, int alpha,
320
    int ply) {
287
    int beta) {
321
  int original_alpha, value;
288
  int original_alpha, value, moves_searched = 0, order;
322
  int moves_searched = 0;
-
 
323
 
289
 
324
/*
290
/*
325
 ************************************************************
291
 ************************************************************
326
 *                                                          *
292
 *                                                          *
327
 *  Initialize.                                             *
293
 *  Initialize.                                             *
Line 329... Line 295...
329
 ************************************************************
295
 ************************************************************
330
 */
296
 */
331
  if (ply >= MAXPLY - 1)
297
  if (ply >= MAXPLY - 1)
332
    return beta;
298
    return beta;
333
#if defined(NODES)
299
#if defined(NODES)
334
  if (--temp_search_nodes <= 0) {
300
  if (search_nodes && --temp_search_nodes <= 0) {
335
    abort_search = 1;
301
    abort_search = 1;
336
    return 0;
302
    return 0;
337
  }
303
  }
338
  if (tree->thread_id == 0)
304
  if (tree->thread_id == 0)
339
    next_time_check--;
305
    next_time_check--;
Line 369... Line 335...
369
 *  position.                                               *
335
 *  position.                                               *
370
 *                                                          *
336
 *                                                          *
371
 ************************************************************
337
 ************************************************************
372
 */
338
 */
373
  tree->hash_move[ply] = 0;
339
  tree->hash_move[ply] = 0;
374
  tree->next_status[ply].phase = HASH_MOVE;
340
  tree->next_status[ply].phase = HASH;
375
  while ((tree->phase[ply] = NextEvasion(tree, ply, wtm))) {
341
  while ((order = NextMove(tree, ply, 0, wtm, 1))) {
376
#if defined(TRACE)
342
#if defined(TRACE)
377
    if (ply <= trace_level)
343
    if (ply <= trace_level)
378
      Trace(tree, ply, 0, wtm, alpha, beta, "QuiesceEvasions",
344
      Trace(tree, ply, 0, wtm, alpha, beta, "QuiesceEvasions", serial,
379
          tree->phase[ply]);
345
          tree->phase[ply], order);
380
#endif
346
#endif
381
    moves_searched++;
347
    moves_searched++;
382
    MakeMove(tree, ply, tree->curmv[ply], wtm);
348
    MakeMove(tree, ply, wtm, tree->curmv[ply]);
383
    tree->nodes_searched++;
349
    tree->nodes_searched++;
384
    value = -Quiesce(tree, -beta, -alpha, Flip(wtm), ply + 1, 0);
350
    value = -Quiesce(tree, ply + 1, Flip(wtm), -beta, -alpha, 0);
385
    UnmakeMove(tree, ply, tree->curmv[ply], wtm);
351
    UnmakeMove(tree, ply, wtm, tree->curmv[ply]);
386
    if (abort_search || tree->stop)
352
    if (abort_search || tree->stop)
387
      return 0;
353
      return 0;
388
    if (value > alpha) {
354
    if (value > alpha) {
389
      if (value >= beta)
355
      if (value >= beta)
390
        return value;
356
        return value;
Line 392... Line 358...
392
    }
358
    }
393
  }
359
  }
394
/*
360
/*
395
 ************************************************************
361
 ************************************************************
396
 *                                                          *
362
 *                                                          *
397
 *  All moves have been searched.  If none were legal,      *
363
 *  All moves have been searched.  If none were legal, it   *
398
 *  return either MATE or DRAW depending on whether the     *
364
 *  must be a mate since we have to be in check to reach    *
399
 *  side to move is in check or not.                        *
365
 *  QuiesceEvasions().                                      *
400
 *                                                          *
366
 *                                                          *
401
 ************************************************************
367
 ************************************************************
402
 */
368
 */
403
  if (moves_searched == 0) {
369
  if (moves_searched == 0) {
404
    value = (Check(wtm)) ? -(MATE - ply) : DrawScore(wtm);
370
    value = -(MATE - ply);
405
    if (value >= alpha && value < beta) {
371
    if (value >= alpha && value < beta) {
406
      SavePV(tree, ply, 0);
372
      SavePV(tree, ply, 0);
407
#if defined(TRACE)
373
#if defined(TRACE)
408
      if (ply <= trace_level)
374
      if (ply <= trace_level)
409
        printf("Search() no moves!  ply=%d\n", ply);
375
        printf("Search() no moves!  ply=%d\n", ply);