Subversion Repositories Games.Chess Giants

Rev

Rev 108 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "chess.h"
  2. #include "data.h"
  3. #include "epdglue.h"
  4. #if defined(SYZYGY)
  5. #  include "tbprobe.h"
  6. #endif
  7. /* last modified 07/11/16 */
  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];
  20.   ROOT_MOVE rtemp;
  21.   unsigned mvp, *lastm, rmoves[256];
  22.   int value, done;
  23. #if defined(SYZYGY)
  24.   int tb_result, tb_root = -9;
  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.  */
  43. #if defined(SYZYGY)
  44.   EGTB_draw = 0;
  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.     }
  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;
  74.   for (mvp = 0; mvp < n_root_moves; mvp++)
  75.     root_moves[mvp].move = rmoves[mvp];
  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.  */
  90.   abort_search = 0;
  91.   for (mvp = 0; mvp < n_root_moves; mvp++) {
  92.     value = -4000000;
  93. #if defined(TRACE)
  94.     if (trace_level >= 1) {
  95.       tree->curmv[1] = root_moves[mvp].move;
  96.       Trace(tree, 1, 0, wtm, -MATE, MATE, "RootMoves()", serial, HASH,
  97.           mvp + 1);
  98.     }
  99. #endif
  100.     MakeMove(tree, 1, wtm, root_moves[mvp].move);
  101.     tree->nodes_searched++;
  102.     if (!Check(wtm))
  103.       do {
  104.         tree->curmv[1] = root_moves[mvp].move;
  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.           }
  119.         }
  120. #endif
  121.         value = -Quiesce(tree, 2, Flip(wtm), -MATE, MATE, 0);
  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.  */
  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])))
  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.  */
  145.         if (Promote(root_moves[mvp].move) &&
  146.             (Promote(root_moves[mvp].move) != queen))
  147.           value -= 50;
  148.       } while (0);
  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);
  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.  */
  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);
  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--)
  186.     if (root_moves[n_root_moves - 1].path.pathv > -3000000)
  187.       break;
  188.   if (root_moves[0].path.pathv > 1000000)
  189.     root_moves[0].path.pathv -= 2000000;
  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.  */
  198.   if (display_options & 128) {
  199.     Print(128, "%d moves at root\n", n_root_moves);
  200.     Print(128, "     score    move/pv\n");
  201.     for (mvp = 0; mvp < n_root_moves; mvp++)
  202.       Print(128, "%10s    %s\n", DisplayEvaluation(root_moves[mvp].path.pathv,
  203.               wtm), DisplayPath(tree, wtm, &root_moves[mvp].path));
  204.   }
  205. /*
  206.  ************************************************************
  207.  *                                                          *
  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. *
  212.  *                                                          *
  213.  ************************************************************
  214.  */
  215.   for (mvp = 1; mvp < n_root_moves; mvp++)
  216.     root_moves[mvp].path.pathv = -MATE;
  217.   return;
  218. }
  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. }
  387.