Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Copyright (c) 2013 Ronald de Man
  3.   This file may be redistributed and/or modified without restrictions.
  4.  
  5.   tbprobe.cpp contains the Stockfish-specific routines of the
  6.   tablebase probing code. It should be relatively easy to adapt
  7.   this code to other chess engines.
  8. */
  9.  
  10. #include "../piece.hpp"
  11. #include "../position.hpp"
  12. #include "../moveGen.hpp"
  13.  
  14. #include <type_traits>
  15.  
  16. #include "rtb-probe.hpp"
  17. #include "rtb-core.hpp"
  18.  
  19. #include "rtb-core-impl.hpp"
  20.  
  21. int Syzygy::TBLargest = 0;
  22.  
  23. // Given a position with 6 or fewer pieces, produce a text string
  24. // of the form KQPvKRP, where "KQP" represents the white pieces if
  25. // mirror == false and the black pieces if mirror == true.
  26. static void prt_str(Position& pos, char *str, bool mirror)
  27. {
  28.     static_assert(Piece::WQUEEN  == Piece::WKING   + 1, "");
  29.     static_assert(Piece::WROOK   == Piece::WQUEEN  + 1, "");
  30.     static_assert(Piece::WBISHOP == Piece::WROOK   + 1, "");
  31.     static_assert(Piece::WKNIGHT == Piece::WBISHOP + 1, "");
  32.     static_assert(Piece::WPAWN   == Piece::WKNIGHT + 1, "");
  33.     static_assert(Piece::BQUEEN  == Piece::BKING   + 1, "");
  34.     static_assert(Piece::BROOK   == Piece::BQUEEN  + 1, "");
  35.     static_assert(Piece::BBISHOP == Piece::BROOK   + 1, "");
  36.     static_assert(Piece::BKNIGHT == Piece::BBISHOP + 1, "");
  37.     static_assert(Piece::BPAWN   == Piece::BKNIGHT + 1, "");
  38.  
  39.     static char pchr[Piece::nPieceTypes+1] = " KQRBNPKQRBNP";
  40.  
  41.     int p1Beg = mirror ? Piece::BKING : Piece::WKING;
  42.     int p1End = mirror ? Piece::BPAWN : Piece::WPAWN;
  43.     int p2Beg = mirror ? Piece::WKING : Piece::BKING;
  44.     int p2End = mirror ? Piece::WPAWN : Piece::BPAWN;
  45.  
  46.     for (int p = p1Beg; p <= p1End; p++) {
  47.         int cnt = BitBoard::bitCount(pos.pieceTypeBB((Piece::Type)p));
  48.         for (int i = 0; i < cnt; i++)
  49.             *str++ = pchr[p];
  50.     }
  51.     *str++ = 'v';
  52.     for (int p = p2Beg; p <= p2End; p++) {
  53.         int cnt = BitBoard::bitCount(pos.pieceTypeBB((Piece::Type)p));
  54.         for (int i = 0; i < cnt; i++)
  55.             *str++ = pchr[p];
  56.     }
  57.     *str++ = 0;
  58. }
  59.  
  60. // Given a position, produce a 64-bit material signature key.
  61. // If the engine supports such a key, it should equal the engine's key.
  62. static uint64_t calc_key(const Position& pos, bool mirror)
  63. {
  64.     uint64_t h = mirror ? MatId::mirror(pos.materialId()) : pos.materialId();
  65.     h *= 0x842c2f50a7ac0ae1ULL;
  66.     h = ((h >> 32) ^ h) * 0xace7b66dbad28265ULL;
  67.     return h;
  68. }
  69.  
  70. // Produce a 64-bit material key corresponding to the material combination
  71. // defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
  72. // pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
  73. // pawns, ..., kings.
  74. static uint64_t calc_key_from_pcs(const int *pcs, bool mirror)
  75. {
  76.     MatId key;
  77.     key.addPieceCnt(Piece::WPAWN,   pcs[1]);
  78.     key.addPieceCnt(Piece::WKNIGHT, pcs[2]);
  79.     key.addPieceCnt(Piece::WBISHOP, pcs[3]);
  80.     key.addPieceCnt(Piece::WROOK,   pcs[4]);
  81.     key.addPieceCnt(Piece::WQUEEN,  pcs[5]);
  82.     key.addPieceCnt(Piece::BPAWN,   pcs[8+1]);
  83.     key.addPieceCnt(Piece::BKNIGHT, pcs[8+2]);
  84.     key.addPieceCnt(Piece::BBISHOP, pcs[8+3]);
  85.     key.addPieceCnt(Piece::BROOK,   pcs[8+4]);
  86.     key.addPieceCnt(Piece::BQUEEN,  pcs[8+5]);
  87.  
  88.     uint64_t h = mirror ? MatId::mirror(key()) : key();
  89.     h *= 0x842c2f50a7ac0ae1ULL;
  90.     h = ((h >> 32) ^ h) * 0xace7b66dbad28265ULL;
  91.     return h;
  92. }
  93.  
  94. static uint64_t get_pieces(const Position& pos, int color, int piece) {
  95.     int p = 7 - piece;
  96.     if (color)
  97.         p += Piece::BKING - Piece::WKING;
  98.     return pos.pieceTypeBB((Piece::Type)p);
  99. }
  100.  
  101. static inline int pop_lsb(uint64_t& bb) {
  102.     return BitBoard::extractSquare(bb);
  103. }
  104.  
  105. // probe_wdl_table and probe_dtz_table require similar adaptations.
  106. static int probe_wdl_table(Position& pos, int *success)
  107. {
  108.     struct TBEntry *ptr;
  109.     struct TBHashEntry *ptr2;
  110.     uint64_t idx;
  111.     uint64_t key;
  112.     int i;
  113.     ubyte res;
  114.     int p[TBPIECES];
  115.  
  116.     // Obtain the position's material signature key.
  117.     key = calc_key(pos, false);
  118.  
  119.     // Test for KvK.
  120.     if (!key) return 0;
  121.  
  122.     ptr2 = WDL_hash[key >> (64 - TBHASHBITS)];
  123.     for (i = 0; i < HSHMAX; i++)
  124.         if (ptr2[i].key == key) break;
  125.     if (i == HSHMAX) {
  126.         *success = 0;
  127.         return 0;
  128.     }
  129.  
  130.     ptr = ptr2[i].ptr;
  131.     ubyte ready = ptr->ready.load(std::memory_order_relaxed);
  132.     std::atomic_thread_fence(std::memory_order_acquire);
  133.     if (!ready) {
  134.         std::lock_guard<std::mutex> L(TB_mutex);
  135.         ready = ptr->ready.load(std::memory_order_relaxed);
  136.         if (!ready) {
  137.             char str[16];
  138.             prt_str(pos, str, ptr->key != key);
  139.             if (!init_table_wdl(ptr, str)) {
  140.                 ptr2[i].key = 0ULL;
  141.                 *success = 0;
  142.                 return 0;
  143.             }
  144.             std::atomic_thread_fence(std::memory_order_release);
  145.             ptr->ready.store(1, std::memory_order_relaxed);
  146.         }
  147.     }
  148.  
  149.     int bside, mirror, cmirror;
  150.     if (!ptr->symmetric) {
  151.         if (key != ptr->key) {
  152.             cmirror = 8;
  153.             mirror = 0x38;
  154.             bside = pos.isWhiteMove();
  155.         } else {
  156.             cmirror = mirror = 0;
  157.             bside = !pos.isWhiteMove();
  158.         }
  159.     } else {
  160.         cmirror = pos.isWhiteMove() ? 0 : 8;
  161.         mirror = pos.isWhiteMove() ? 0 : 0x38;
  162.         bside = 0;
  163.     }
  164.  
  165.     // p[i] is to contain the square 0-63 (A1-H8) for a piece of type
  166.     // pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king.
  167.     // Pieces of the same type are guaranteed to be consecutive.
  168.     if (!ptr->has_pawns) {
  169.         struct TBEntry_piece *entry = (struct TBEntry_piece *)ptr;
  170.         ubyte *pc = entry->pieces[bside];
  171.         for (i = 0; i < entry->num;) {
  172.             uint64_t bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
  173.             do {
  174.                 p[i++] = pop_lsb(bb);
  175.             } while (bb);
  176.         }
  177.         idx = encode_piece(entry, entry->norm[bside], p, entry->factor[bside]);
  178.         res = decompress_pairs(entry->precomp[bside], idx);
  179.     } else {
  180.         struct TBEntry_pawn *entry = (struct TBEntry_pawn *)ptr;
  181.         int k = entry->file[0].pieces[0][0] ^ cmirror;
  182.         uint64_t bb = get_pieces(pos, k >> 3, k & 0x07);
  183.         i = 0;
  184.         do {
  185.             p[i++] = pop_lsb(bb) ^ mirror;
  186.         } while (bb);
  187.         int f = pawn_file(entry, p);
  188.         ubyte *pc = entry->file[f].pieces[bside];
  189.         for (; i < entry->num;) {
  190.             bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
  191.             do {
  192.                 p[i++] = pop_lsb(bb) ^ mirror;
  193.             } while (bb);
  194.         }
  195.         idx = encode_pawn(entry, entry->file[f].norm[bside], p, entry->file[f].factor[bside]);
  196.         res = decompress_pairs(entry->file[f].precomp[bside], idx);
  197.     }
  198.  
  199.     return ((int)res) - 2;
  200. }
  201.  
  202. static int probe_dtz_table(Position& pos, int wdl, int *success)
  203. {
  204.     uint64_t idx;
  205.     int i, res;
  206.     int p[TBPIECES];
  207.  
  208.     // Obtain the position's material signature key.
  209.     uint64_t key = calc_key(pos, false);
  210.  
  211.     DTZTableEntry* dtzTabEnt;
  212.     {
  213.         dtzTabEnt = DTZ_hash[key >> (64 - TBHASHBITS)];
  214.         for (i = 0; i < HSHMAX; i++)
  215.             if (dtzTabEnt[i].key1 == key) break;
  216.         if (i == HSHMAX) {
  217.             uint64_t key2 = calc_key(pos, true);
  218.             dtzTabEnt = DTZ_hash[key2 >> (64 - TBHASHBITS)];
  219.             for (i = 0; i < HSHMAX; i++)
  220.                 if (dtzTabEnt[i].key2 == key) break;
  221.         }
  222.         if (i == HSHMAX) {
  223.             *success = 0;
  224.             return 0;
  225.         }
  226.         dtzTabEnt += i;
  227.     }
  228.  
  229.     TBEntry* ptr = dtzTabEnt->entry.load(std::memory_order_relaxed);
  230.     std::atomic_thread_fence(std::memory_order_acquire);
  231.     if (!ptr) {
  232.         std::lock_guard<std::mutex> L(TB_mutex);
  233.         ptr = dtzTabEnt->entry.load(std::memory_order_relaxed);
  234.         if (!ptr) {
  235.             struct TBHashEntry *ptr2 = WDL_hash[key >> (64 - TBHASHBITS)];
  236.             for (i = 0; i < HSHMAX; i++)
  237.                 if (ptr2[i].key == key) break;
  238.             if (i == HSHMAX) {
  239.                 *success = 0;
  240.                 return 0;
  241.             }
  242.             char str[16];
  243.             bool mirror = (ptr2[i].ptr->key != key);
  244.             prt_str(pos, str, mirror);
  245.             ptr = load_dtz_table(str, calc_key(pos, mirror), calc_key(pos, !mirror));
  246.             std::atomic_thread_fence(std::memory_order_release);
  247.             dtzTabEnt->entry.store(ptr, std::memory_order_relaxed);
  248.         }
  249.     }
  250.  
  251.     if (!ptr) {
  252.         *success = 0;
  253.         return 0;
  254.     }
  255.  
  256.     int bside, mirror, cmirror;
  257.     if (!ptr->symmetric) {
  258.         if (key != ptr->key) {
  259.             cmirror = 8;
  260.             mirror = 0x38;
  261.             bside = pos.isWhiteMove();
  262.         } else {
  263.             cmirror = mirror = 0;
  264.             bside = !pos.isWhiteMove();
  265.         }
  266.     } else {
  267.         cmirror = pos.isWhiteMove() ? 0 : 8;
  268.         mirror = pos.isWhiteMove() ? 0 : 0x38;
  269.         bside = 0;
  270.     }
  271.  
  272.     if (!ptr->has_pawns) {
  273.         struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr;
  274.         if ((entry->flags & 1) != bside && !entry->symmetric) {
  275.             *success = -1;
  276.             return 0;
  277.         }
  278.         ubyte *pc = entry->pieces;
  279.         for (i = 0; i < entry->num;) {
  280.             uint64_t bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
  281.             do {
  282.                 p[i++] = pop_lsb(bb);
  283.             } while (bb);
  284.         }
  285.         idx = encode_piece((struct TBEntry_piece *)entry, entry->norm, p, entry->factor);
  286.         res = decompress_pairs(entry->precomp, idx);
  287.  
  288.         if (entry->flags & 2)
  289.             res = entry->map[entry->map_idx[wdl_to_map[wdl + 2]] + res];
  290.  
  291.         if (!(entry->flags & pa_flags[wdl + 2]) || (wdl & 1))
  292.             res *= 2;
  293.     } else {
  294.         struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr;
  295.         int k = entry->file[0].pieces[0] ^ cmirror;
  296.         uint64_t bb = get_pieces(pos, k >> 3, k & 0x07);
  297.         i = 0;
  298.         do {
  299.             p[i++] = pop_lsb(bb) ^ mirror;
  300.         } while (bb);
  301.         int f = pawn_file((struct TBEntry_pawn *)entry, p);
  302.         if ((entry->flags[f] & 1) != bside) {
  303.             *success = -1;
  304.             return 0;
  305.         }
  306.         ubyte *pc = entry->file[f].pieces;
  307.         for (; i < entry->num;) {
  308.             bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
  309.             do {
  310.                 p[i++] = pop_lsb(bb) ^ mirror;
  311.             } while (bb);
  312.         }
  313.         idx = encode_pawn((struct TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
  314.         res = decompress_pairs(entry->file[f].precomp, idx);
  315.  
  316.         if (entry->flags[f] & 2)
  317.             res = entry->map[entry->map_idx[f][wdl_to_map[wdl + 2]] + res];
  318.  
  319.         if (!(entry->flags[f] & pa_flags[wdl + 2]) || (wdl & 1))
  320.             res *= 2;
  321.     }
  322.  
  323.     return res;
  324. }
  325.  
  326. // Add bishop and rook underpromotion captures to move list.
  327. static void add_underprom_caps(Position& pos, MoveList& moveList)
  328. {
  329.     const int nMoves = moveList.size;
  330.     const bool wtm = pos.isWhiteMove();
  331.     const int queen = wtm ? Piece::WQUEEN : Piece::BQUEEN;
  332.     for (int i = 0; i < nMoves; i++) {
  333.         const Move& m = moveList[i];
  334.         if ((m.promoteTo() == queen) && (pos.getPiece(m.to()) != Piece::EMPTY)) {
  335.             moveList.addMove(m.from(), m.to(), wtm ? Piece::WROOK : Piece::BROOK);
  336.             moveList.addMove(m.from(), m.to(), wtm ? Piece::WBISHOP : Piece::BBISHOP);
  337.         }
  338.     }
  339. }
  340.  
  341. static int probe_ab(Position& pos, int alpha, int beta, int *success)
  342. {
  343.     // Generate (at least) all legal non-ep captures including (under)promotions.
  344.     // It is OK to generate more, as long as they are filtered out below.
  345.     MoveList moveList;
  346.     const bool inCheck = MoveGen::inCheck(pos);
  347.     if (inCheck) {
  348.         MoveGen::checkEvasions(pos, moveList);
  349.     } else {
  350.         MoveGen::pseudoLegalCaptures(pos, moveList);
  351.         // Since bishop and rook promotions are not included, we need to add them.
  352.         add_underprom_caps(pos, moveList);
  353.     }
  354.  
  355.     UndoInfo ui;
  356.     for (int m = 0; m < moveList.size; m++) {
  357.         const Move& capture = moveList[m];
  358.         if ((pos.getPiece(capture.to()) == Piece::EMPTY) ||
  359.             !MoveGen::isLegal(pos, capture, inCheck))
  360.             continue;
  361.         pos.makeMove(capture, ui);
  362.         int v = -probe_ab(pos, -beta, -alpha, success);
  363.         pos.unMakeMove(capture, ui);
  364.         if (*success == 0) return 0;
  365.         if (v > alpha) {
  366.             if (v >= beta) {
  367.                 *success = 2;
  368.                 return v;
  369.             }
  370.             alpha = v;
  371.         }
  372.     }
  373.  
  374.     int v = probe_wdl_table(pos, success);
  375.     if (*success == 0) return 0;
  376.     if (alpha >= v) {
  377.         *success = 1 + (alpha > 0);
  378.         return alpha;
  379.     } else {
  380.         *success = 1;
  381.         return v;
  382.     }
  383. }
  384.  
  385. int Syzygy::probe_wdl(Position& pos, int *success)
  386. {
  387.     *success = 1;
  388.     int v = probe_ab(pos, -2, 2, success);
  389.  
  390.     // If en passant is not possible, we are done.
  391.     if (pos.getEpSquare() == -1)
  392.         return v;
  393.     if (!(*success)) return 0;
  394.  
  395.     // Now handle en passant.
  396.     int v1 = -3;
  397.     // Generate (at least) all legal en passant captures.
  398.     MoveList moveList;
  399.  
  400.     const bool inCheck = MoveGen::inCheck(pos);
  401.     if (inCheck) {
  402.         MoveGen::checkEvasions(pos, moveList);
  403.     } else {
  404.         MoveGen::pseudoLegalMoves(pos, moveList);
  405.     }
  406.  
  407.     const int pawn = pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN;
  408.     UndoInfo ui;
  409.     for (int m = 0; m < moveList.size; m++) {
  410.         const Move& capture = moveList[m];
  411.         if ((capture.to() != pos.getEpSquare()) || (pos.getPiece(capture.from()) != pawn) ||
  412.             !MoveGen::isLegal(pos, capture, inCheck))
  413.             continue;
  414.         pos.makeMove(capture, ui);
  415.         int v0 = -probe_ab(pos, -2, 2, success);
  416.         pos.unMakeMove(capture, ui);
  417.         if (*success == 0) return 0;
  418.         if (v0 > v1) v1 = v0;
  419.     }
  420.     if (v1 > -3) {
  421.         if (v1 >= v) v = v1;
  422.         else if (v == 0) {
  423.             // Check whether there is at least one legal non-ep move.
  424.             for (int m = 0; m < moveList.size; m++) {
  425.                 const Move& capture = moveList[m];
  426.                 if ((capture.to() == pos.getEpSquare()) &&
  427.                     (pos.getPiece(capture.from()) == pawn))
  428.                     continue;
  429.                 if (MoveGen::isLegal(pos, capture, inCheck))
  430.                     return v;
  431.             }
  432.             // If not, then we are forced to play the losing ep capture.
  433.             v = v1;
  434.         }
  435.     }
  436.  
  437.     return v;
  438. }
  439.  
  440. // This routine treats a position with en passant captures as one without.
  441. static int probe_dtz_no_ep(Position& pos, int *success)
  442. {
  443.     const int wdl = probe_ab(pos, -2, 2, success);
  444.     if (*success == 0) return 0;
  445.  
  446.     if (wdl == 0) return 0;
  447.  
  448.     if (*success == 2)
  449.         return wdl == 2 ? 1 : 101;
  450.  
  451.     MoveList moveList;
  452.     const bool inCheck = MoveGen::inCheck(pos);
  453.     const int pawn = pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN;
  454.     UndoInfo ui;
  455.  
  456.     if (wdl > 0) {
  457.         // Generate at least all legal non-capturing pawn moves
  458.         // including non-capturing promotions.
  459.         if (inCheck) {
  460.             MoveGen::checkEvasions(pos, moveList);
  461.         } else {
  462.             MoveGen::pseudoLegalMoves(pos, moveList);
  463.         }
  464.  
  465.         for (int m = 0; m < moveList.size; m++) {
  466.             const Move& move = moveList[m];
  467.             if ((pos.getPiece(move.from()) != pawn) ||
  468.                 (Position::getX(move.from()) != Position::getX(move.to())) ||
  469.                 !MoveGen::isLegal(pos, move, inCheck))
  470.                 continue;
  471.             pos.makeMove(move, ui);
  472.             int v = -probe_ab(pos, -2, -wdl + 1, success);
  473.             pos.unMakeMove(move, ui);
  474.             if (*success == 0) return 0;
  475.             if (v == wdl)
  476.                 return v == 2 ? 1 : 101;
  477.         }
  478.     }
  479.  
  480.     int dtz = 1 + probe_dtz_table(pos, wdl, success);
  481.  
  482.     if (*success >= 0) {
  483.         if (wdl & 1) dtz += 100;
  484.         return wdl >= 0 ? dtz : -dtz;
  485.     }
  486.  
  487.     if (wdl > 0) {
  488.         int best = 0xffff;
  489.         for (int m = 0; m < moveList.size; m++) {
  490.             const Move& move = moveList[m];
  491.             if ((pos.getPiece(move.to()) != Piece::EMPTY) ||
  492.                 (pos.getPiece(move.from()) == pawn) ||
  493.                 !MoveGen::isLegal(pos, move, inCheck))
  494.                 continue;
  495.             pos.makeMove(move, ui);
  496.             int v = -Syzygy::probe_dtz(pos, success);
  497.             pos.unMakeMove(move, ui);
  498.             if (*success == 0) return 0;
  499.             if (v > 0 && v + 1 < best)
  500.                 best = v + 1;
  501.         }
  502.         return best;
  503.     } else {
  504.         int best = -1;
  505.         if (inCheck) {
  506.             MoveGen::checkEvasions(pos, moveList);
  507.         } else {
  508.             MoveGen::pseudoLegalMoves(pos, moveList);
  509.         }
  510.         for (int m = 0; m < moveList.size; m++) {
  511.             const Move& move = moveList[m];
  512.             if (!MoveGen::isLegal(pos, move, inCheck))
  513.                 continue;
  514.             pos.makeMove(move, ui);
  515.             int v;
  516.             if (pos.getHalfMoveClock() == 0) {
  517.                 if (wdl == -2) v = -1;
  518.                 else {
  519.                     v = probe_ab(pos, 1, 2, success);
  520.                     v = (v == 2) ? 0 : -101;
  521.                 }
  522.             } else {
  523.                 v = -Syzygy::probe_dtz(pos, success) - 1;
  524.             }
  525.             pos.unMakeMove(move, ui);
  526.             if (*success == 0) return 0;
  527.             if (v < best)
  528.                 best = v;
  529.         }
  530.         return best;
  531.     }
  532. }
  533.  
  534. static int wdl_to_dtz[] = {
  535.     -1, -101, 0, 101, 1
  536. };
  537.  
  538. int Syzygy::probe_dtz(Position& pos, int *success)
  539. {
  540.     *success = 1;
  541.     int v = probe_dtz_no_ep(pos, success);
  542.  
  543.     if (pos.getEpSquare() == -1)
  544.         return v;
  545.     if (*success == 0) return 0;
  546.  
  547.     // Now handle en passant.
  548.     int v1 = -3;
  549.  
  550.     MoveList moveList;
  551.     const bool inCheck = MoveGen::inCheck(pos);
  552.     const int pawn = pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN;
  553.     UndoInfo ui;
  554.  
  555.     if (!inCheck) {
  556.         MoveGen::pseudoLegalMoves(pos, moveList);
  557.     } else {
  558.         MoveGen::checkEvasions(pos, moveList);
  559.     }
  560.  
  561.     for (int m = 0; m < moveList.size; m++) {
  562.         const Move& capture = moveList[m];
  563.         if ((capture.to() != pos.getEpSquare()) ||
  564.             (pos.getPiece(capture.from()) != pawn) ||
  565.             !MoveGen::isLegal(pos, capture, inCheck))
  566.             continue;
  567.         pos.makeMove(capture, ui);
  568.         int v0 = -probe_ab(pos, -2, 2, success);
  569.         pos.unMakeMove(capture, ui);
  570.         if (*success == 0) return 0;
  571.         if (v0 > v1) v1 = v0;
  572.     }
  573.     if (v1 > -3) {
  574.         v1 = wdl_to_dtz[v1 + 2];
  575.         if (v < -100) {
  576.             if (v1 >= 0)
  577.                 v = v1;
  578.         } else if (v < 0) {
  579.             if (v1 >= 0 || v1 < 100)
  580.                 v = v1;
  581.         } else if (v > 100) {
  582.             if (v1 > 0)
  583.                 v = v1;
  584.         } else if (v > 0) {
  585.             if (v1 == 1)
  586.                 v = v1;
  587.         } else if (v1 >= 0) {
  588.             v = v1;
  589.         } else {
  590.             for (int m = 0; m < moveList.size; m++) {
  591.                 const Move& move = moveList[m];
  592.                 if ((move.to() == pos.getEpSquare()) && (pos.getPiece(move.from()) == pawn))
  593.                     continue;
  594.                 if (MoveGen::isLegal(pos, move, inCheck))
  595.                     return v;
  596.             }
  597.             v = v1;
  598.         }
  599.     }
  600.  
  601.     return v;
  602. }
  603.