Subversion Repositories Games.Chess Giants

Rev

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

Rev Author Line No. Line
33 pmbaty 1
#include "chess.h"
2
#include "data.h"
3
#include "epdglue.h"
154 pmbaty 4
#if defined(SYZYGY)
5
#  include "tbprobe.h"
6
#endif
7
/* last modified 07/11/16 */
33 pmbaty 8
/*
9
 *******************************************************************************
10
 *                                                                             *
11
 *   RootMoveList() is used to set up the ply one move list.  It is a  more    *
12
 *   accurate ordering of the move list than that done for plies deeper than   *
13
 *   one.  Briefly, Quiesce() is used to obtain the positional score plus the  *
14
 *   expected gain/loss for pieces that can be captured.                       *
15
 *                                                                             *
16
 *******************************************************************************
17
 */
18
void RootMoveList(int wtm) {
19
  TREE *const tree = block[0];
154 pmbaty 20
  ROOT_MOVE rtemp;
156 pmbaty 21
  int mvp; unsigned *lastm, rmoves[256]; // Pierre-Marie Baty -- fixed type
154 pmbaty 22
  int value, done;
23
#if defined(SYZYGY)
24
  int tb_result, tb_root = -9;
33 pmbaty 25
#endif
26
 
27
/*
28
 ************************************************************
29
 *                                                          *
30
 *  If the position at the root is a draw, based on EGTB    *
31
 *  results, we are going to behave differently.  We will   *
32
 *  extract the root moves that are draws, and toss the     *
33
 *  losers out.  Then, we will do a normal search on the    *
34
 *  moves that draw to try and chose the drawing move that  *
35
 *  gives our opponent the best chance to make an error.    *
36
 *  This search will be done sans EGTB probes since we al-  *
37
 *  ready know this is a draw at the root.  We simply find  *
38
 *  the best move (based on search/eval) that preserves the *
39
 *  draw.                                                   *
40
 *                                                          *
41
 ************************************************************
42
 */
154 pmbaty 43
#if defined(SYZYGY)
33 pmbaty 44
  EGTB_draw = 0;
154 pmbaty 45
  if (swindle_mode) {
46
    if (EGTBlimit && TotalAllPieces <= EGTBlimit &&
47
        Castle(1, white) + Castle(1, black) == 0) {
48
      tb_result =
49
          tb_probe_root(Occupied(white), Occupied(black),
50
          Kings(white) | Kings(black), Queens(white) | Queens(black),
51
          Rooks(white) | Rooks(black), Bishops(white) | Bishops(black),
52
          Knights(white) | Knights(black), Pawns(white) | Pawns(black),
53
          Reversible(1), 0, EnPassant(1), wtm, NULL);
54
      if (tb_result != TB_RESULT_FAILED) {
55
        tb_root = TB_GET_WDL(tb_result);
56
        if ((tb_root == TB_DRAW && MaterialSTM(wtm) > 0) ||
57
            (tb_root == TB_CURSED_WIN))
58
          EGTB_draw = 1;
59
      }
60
    }
33 pmbaty 61
  }
62
#endif
63
/*
64
 ************************************************************
65
 *                                                          *
66
 *  First, use GenerateMoves() to generate the set of legal *
67
 *  moves from the root position.                           *
68
 *                                                          *
69
 ************************************************************
70
 */
71
  lastm = GenerateCaptures(tree, 1, wtm, rmoves);
72
  lastm = GenerateNoncaptures(tree, 1, wtm, lastm);
73
  n_root_moves = lastm - rmoves;
154 pmbaty 74
  for (mvp = 0; mvp < n_root_moves; mvp++)
108 pmbaty 75
    root_moves[mvp].move = rmoves[mvp];
33 pmbaty 76
/*
77
 ************************************************************
78
 *                                                          *
79
 *  Now make each move and use Quiesce() to analyze the     *
80
 *  potential captures and return a minimax score.          *
81
 *                                                          *
82
 *  Special case:  if this is an egtb draw at the root,     *
83
 *  then this is where we cull the non-drawing moves by     *
84
 *  doing an EGTB probe for each move.  Any moves that lose *
85
 *  are left with a very bad sorting score to move them to  *
86
 *  the end of the root move list.                          *
87
 *                                                          *
88
 ************************************************************
89
 */
108 pmbaty 90
  abort_search = 0;
154 pmbaty 91
  for (mvp = 0; mvp < n_root_moves; mvp++) {
33 pmbaty 92
    value = -4000000;
93
#if defined(TRACE)
94
    if (trace_level >= 1) {
108 pmbaty 95
      tree->curmv[1] = root_moves[mvp].move;
96
      Trace(tree, 1, 0, wtm, -MATE, MATE, "RootMoves()", serial, HASH,
97
          mvp + 1);
33 pmbaty 98
    }
99
#endif
108 pmbaty 100
    MakeMove(tree, 1, wtm, root_moves[mvp].move);
33 pmbaty 101
    tree->nodes_searched++;
102
    if (!Check(wtm))
103
      do {
108 pmbaty 104
        tree->curmv[1] = root_moves[mvp].move;
154 pmbaty 105
#if defined(SYZYGY)
106
        if (EGTB_draw && TotalAllPieces <= EGTBlimit &&
107
            Castle(2, white) + Castle(2, black) == 0) {
108
          tb_result =
109
              tb_probe_root(Occupied(white), Occupied(black),
110
              Kings(white) | Kings(black), Queens(white) | Queens(black),
111
              Rooks(white) | Rooks(black), Bishops(white) | Bishops(black),
112
              Knights(white) | Knights(black), Pawns(white) | Pawns(black),
113
              Reversible(2), 0, EnPassant(2), Flip(wtm), NULL);
114
          if (tb_result != TB_RESULT_FAILED) {
115
            tb_result = 4 - TB_GET_WDL(tb_result);
116
            if (tb_result < tb_root)
117
              break;
118
          }
33 pmbaty 119
        }
120
#endif
108 pmbaty 121
        value = -Quiesce(tree, 2, Flip(wtm), -MATE, MATE, 0);
33 pmbaty 122
/*
123
 ************************************************************
124
 *                                                          *
125
 *  Add in a bonus if this move is part of the previous     *
126
 *  principal variation.  It was good in the search, we     *
127
 *  should try it first now.                                *
128
 *                                                          *
129
 ************************************************************
130
 */
108 pmbaty 131
        if ((Piece(root_moves[mvp].move) == Piece(last_pv.path[1]))
132
            && (From(root_moves[mvp].move) == From(last_pv.path[1]))
133
            && (To(root_moves[mvp].move) == To(last_pv.path[1]))
134
            && (Captured(root_moves[mvp].move) == Captured(last_pv.path[1]))
135
            && (Promote(root_moves[mvp].move) == Promote(last_pv.path[1])))
33 pmbaty 136
          value += 2000000;
137
/*
138
 ************************************************************
139
 *                                                          *
140
 *  Fudge the score for promotions so that promotion to a   *
141
 *  queen is tried first.                                   *
142
 *                                                          *
143
 ************************************************************
144
 */
108 pmbaty 145
        if (Promote(root_moves[mvp].move) &&
146
            (Promote(root_moves[mvp].move) != queen))
33 pmbaty 147
          value -= 50;
148
      } while (0);
108 pmbaty 149
    root_moves[mvp].path = tree->pv[1];
150
    root_moves[mvp].path.pathv = value;
151
    root_moves[mvp].status = 0;
152
    root_moves[mvp].bm_age = 0;
153
    UnmakeMove(tree, 1, wtm, root_moves[mvp].move);
33 pmbaty 154
  }
155
/*
156
 ************************************************************
157
 *                                                          *
158
 *  Sort the moves into order based on the scores returned  *
159
 *  by Quiesce() which includes evaluation + captures.      *
160
 *                                                          *
161
 ************************************************************
162
 */
154 pmbaty 163
  do {
164
    done = 1;
165
    for (mvp = 0; mvp < n_root_moves - 1; mvp++) {
166
      if (root_moves[mvp].path.pathv < root_moves[mvp + 1].path.pathv) {
167
        rtemp = root_moves[mvp];
168
        root_moves[mvp] = root_moves[mvp + 1];
169
        root_moves[mvp + 1] = rtemp;
170
        done = 0;
171
      }
172
    }
173
  } while (!done);
33 pmbaty 174
/*
175
 ************************************************************
176
 *                                                          *
177
 *  Trim the move list to eliminate those moves that hang   *
178
 *  the king and are illegal.  This also culls any non-     *
179
 *  drawing moves when we are in the swindle-mode situation *
180
 *  and want to do a normal search but only on moves that   *
181
 *  preserve the draw.                                      *
182
 *                                                          *
183
 ************************************************************
184
 */
185
  for (; n_root_moves; n_root_moves--)
108 pmbaty 186
    if (root_moves[n_root_moves - 1].path.pathv > -3000000)
33 pmbaty 187
      break;
108 pmbaty 188
  if (root_moves[0].path.pathv > 1000000)
189
    root_moves[0].path.pathv -= 2000000;
33 pmbaty 190
/*
191
 ************************************************************
192
 *                                                          *
193
 *  Debugging output to dump root move list and the stuff   *
194
 *  used to sort them, for testing and debugging.           *
195
 *                                                          *
196
 ************************************************************
197
 */
108 pmbaty 198
  if (display_options & 128) {
199
    Print(128, "%d moves at root\n", n_root_moves);
200
    Print(128, "     score    move/pv\n");
154 pmbaty 201
    for (mvp = 0; mvp < n_root_moves; mvp++)
108 pmbaty 202
      Print(128, "%10s    %s\n", DisplayEvaluation(root_moves[mvp].path.pathv,
203
              wtm), DisplayPath(tree, wtm, &root_moves[mvp].path));
33 pmbaty 204
  }
205
/*
206
 ************************************************************
207
 *                                                          *
108 pmbaty 208
 *  Finally, before we return the list of moves, we need to *
209
 *  set the values to an impossible negative value so that  *
210
 *  as we sort the root move list after fail highs and lows *
211
 *  the un-searched moves won't pop to the top of the list. *
33 pmbaty 212
 *                                                          *
213
 ************************************************************
214
 */
154 pmbaty 215
  for (mvp = 1; mvp < n_root_moves; mvp++)
216
    root_moves[mvp].path.pathv = -MATE;
33 pmbaty 217
  return;
218
}
154 pmbaty 219
 
220
/* last modified 07/11/16 */
221
/*
222
 *******************************************************************************
223
 *                                                                             *
224
 *   RootMoveEGTB() is used to handle the case where we are using syzygy end-  *
225
 *   game tablebases and the root position is found in them.  We need to use   *
226
 *   the DTZ tables to play the best move we can find since the game outcome   *
227
 *   is known for each possible move at this point.  We return it in a manner  *
228
 *   similar to Book().                                                        *
229
 *                                                                             *
230
 *   Note:  This depends on RootMoveList() being called FIRST since it is the  *
231
 *   responsible party to note that we are drawn at the root according to EGTB *
232
 *   and if appropriate, it will let RootMoveEGTB() know this to activate      *
233
 *   "swindle mode" and play on with a search rather than an instant move.     *
234
 *                                                                             *
235
 *******************************************************************************
236
 */
237
int RootMoveEGTB(int wtm) {
238
#if defined(SYZYGY)
239
  TREE *const tree = block[0];
240
  int tb_result, result;
241
 
242
/*
243
 ************************************************************
244
 *                                                          *
245
 *  first, we need to find the best TB move.  Simply, this  *
246
 *  is the move that gives us the best result, even though  *
247
 *  it might be speculative in the case of choosing a       *
248
 *  "cursed win" which is still technically a draw if the   *
249
 *  opponent makes no errors.                               *
250
 *                                                          *
251
 ************************************************************
252
 */
253
  EGTB_use = EGTBlimit;
254
  if (EGTB_use <= 0)
255
    return 0;
256
  if (EGTB_draw && !puzzling && swindle_mode)
257
    EGTB_use = 0;
258
  if (EGTBlimit && !EGTB_use)
259
    Print(32, "Drawn at root, trying for swindle.\n");
260
  if (EGTB_use && TotalAllPieces <= EGTBlimit && !Castle(0, white) &&
261
      !Castle(0, black)) {
262
    tree->egtb_probes++;
263
    tb_result =
264
        tb_probe_root(Occupied(white), Occupied(black),
265
        Kings(white) | Kings(black), Queens(white) | Queens(black),
266
        Rooks(white) | Rooks(black), Bishops(white) | Bishops(black),
267
        Knights(white) | Knights(black), Pawns(white) | Pawns(black),
268
        Reversible(1), 0, EnPassant(1), wtm, NULL);
269
    if (tb_result != TB_RESULT_FAILED) {
270
      int value, piece, captured;
271
      unsigned cmove, omove;
272
 
273
      if (n_root_moves > 0) {
274
        tree->egtb_hits++;
275
        result = TB_GET_WDL(tb_result);
276
        switch (result) {
277
          case TB_LOSS:
278
            value = -TBWIN;
279
            break;
280
          case TB_WIN:
281
            value = TBWIN;
282
            break;
283
          case TB_BLESSED_LOSS:
284
            value = -3;
285
            break;
286
          case TB_DRAW:
287
            value = 0;
288
            break;
289
          case TB_CURSED_WIN:
290
            value = 3;
291
            break;
292
          default:
293
            value = TB_GET_DTZ(tb_result);;
294
            break;
295
        }
296
        if (result != TB_LOSS && result != TB_WIN) {
297
          if (MaterialSTM(wtm) > 0)
298
            value += 1;
299
          else if (MaterialSTM(wtm) < 0)
300
            value -= 1;
301
        }
302
        piece = abs(PcOnSq(TB_GET_FROM(tb_result)));
303
        captured = abs(PcOnSq(TB_GET_TO(tb_result)));
304
        cmove =
305
            TB_GET_FROM(tb_result) | (TB_GET_TO(tb_result) << 6) | (piece <<
306
            12) | (captured << 15);
307
        if (TB_GET_PROMOTES(tb_result))
308
          cmove |= (6 - TB_GET_PROMOTES(tb_result)) << 18;
309
        end_time = ReadClock();
310
        tree->pv[0].path[1] = cmove;
311
        tree->pv[0].pathl = 2;
312
        tree->pv[0].pathh = 4;
313
        tree->pv[0].pathd = 0;
314
        tree->pv[0].pathv = value;
315
        MakeMove(tree, 1, wtm, cmove);
316
        result = Mated(tree, 2, Flip(wtm));
317
        UnmakeMove(tree, 1, wtm, cmove);
318
        if (result == 1)
319
          tree->pv[0].pathv = MATE - 2;
320
        else if (result == 2)
321
          tree->pv[0].pathv = DrawScore(wtm);
322
/*
323
 ************************************************************
324
 *                                                          *
325
 *  If we are not mated and did not mate on the move, we    *
326
 *  flip the side on move and find the best TB move so that *
327
 *  we can show the expected reply in the PV.               *
328
 *                                                          *
329
 ************************************************************
330
 */
331
        else {
332
          MakeMove(tree, 1, wtm, cmove);
333
          tree->egtb_probes++;
334
          tb_result =
335
              tb_probe_root(Occupied(white), Occupied(black),
336
              Kings(white) | Kings(black), Queens(white) | Queens(black),
337
              Rooks(white) | Rooks(black), Bishops(white) | Bishops(black),
338
              Knights(white) | Knights(black), Pawns(white) | Pawns(black),
339
              Reversible(2), 0, EnPassant(2), Flip(wtm), NULL);
340
          if (tb_result != TB_RESULT_FAILED) {
341
            tree->egtb_hits++;
342
            piece = abs(PcOnSq(TB_GET_FROM(tb_result)));
343
            captured = abs(PcOnSq(TB_GET_TO(tb_result)));
344
            omove =
345
                TB_GET_FROM(tb_result) | (TB_GET_TO(tb_result) << 6) | (piece
346
                << 12) | (captured << 15);
347
            if (TB_GET_PROMOTES(tb_result))
348
              omove |= (6 - TB_GET_PROMOTES(tb_result)) << 18;
349
            end_time = ReadClock();
350
            tree->pv[0].path[2] = omove;
351
            tree->pv[0].pathl = 3;
352
          }
353
          UnmakeMove(tree, 1, wtm, cmove);
354
        }
355
      }
356
/*
357
 ************************************************************
358
 *                                                          *
359
 *  We now know the best move to play, and possibly the     *
360
 *  opponent's best response.  Display this info and then   *
361
 *  we wait for the next move to pop in.                    *
362
 *                                                          *
363
 ************************************************************
364
 */
365
      Print(2, "        depth     time       score   variation\n");
366
      if (n_root_moves == 0) {
367
        program_end_time = ReadClock();
368
        tree->pv[0].pathl = 0;
369
        tree->pv[0].pathd = 0;
370
        if (Check(wtm))
371
          value = -(MATE - 1);
372
        else
373
          value = DrawScore(wtm);
374
        Print(2, "                             Mated   (no moves)\n");
375
        tree->nodes_searched = 1;
376
        if (!puzzling)
377
          last_root_value = value;
378
        return 1;
379
      }
380
      DisplayPV(tree, 5, wtm, end_time - start_time, &tree->pv[0], 1);
381
      return 1;
382
    }
383
  }
384
#endif
385
  return 0;
386
}