Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 17 Nov 2019 15:09:04 +0000 (16:09 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 17 Nov 2019 15:09:04 +0000 (16:09 +0100)
bench: 4756806

1  2 
src/evaluate.cpp
src/search.cpp

@@@ -458,14 -377,11 +458,14 @@@ namespace 
    Score Evaluation<T>::king() const {
  
      constexpr Color    Them = (Us == WHITE ? BLACK : WHITE);
 -    constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
 -                                           : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
 +    Rank r = relative_rank(Us, std::min(Rank((pos.max_rank() - 1) / 2 + 1), pos.max_rank()), pos.max_rank());
 +    Bitboard Camp = AllSquares ^ forward_ranks_bb(Us, r);
 +
 +    if (!pos.count<KING>(Us) || !pos.checking_permitted())
 +        return SCORE_ZERO;
  
-     Bitboard weak, b1, b2, safe, unsafeChecks = 0;
+     Bitboard weak, b1, b2, b3, safe, unsafeChecks = 0;
 -    Bitboard rookChecks, queenChecks, bishopChecks, knightChecks;
 +    Bitboard queenChecks, knightChecks, pawnChecks, otherChecks;
      int kingDanger = 0;
      const Square ksq = pos.square<KING>(Us);
  
      b1 = attacks_bb<ROOK  >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
      b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
  
 -    // Enemy rooks checks
 -    rookChecks = b1 & safe & attackedBy[Them][ROOK];
 +    std::function <Bitboard (Color, PieceType)> get_attacks = [this](Color c, PieceType pt) {
 +        return attackedBy[c][pt] | (pos.captures_to_hand() && pos.count_in_hand(c, pt) ? ~pos.pieces() : Bitboard(0));
 +    };
 +    for (PieceType pt : pos.piece_types())
 +    {
 +        switch (pt)
 +        {
 +        case QUEEN:
 +            // Enemy queen safe checks: we count them only if they are from squares from
 +            // which we can't give a rook check, because rook checks are more valuable.
 +            queenChecks = (b1 | b2)
 +                        & get_attacks(Them, QUEEN)
 +                        & safe
 +                        & ~attackedBy[Us][QUEEN]
 +                        & ~(b1 & attackedBy[Them][ROOK]);
 +
 +            if (queenChecks)
 +                kingDanger += QueenSafeCheck;
 +            break;
 +        case ROOK:
 +        case BISHOP:
 +        case KNIGHT:
 +            knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb();
 +            if (knightChecks & safe)
 +                kingDanger +=  pt == ROOK   ? RookSafeCheck
 +                             : pt == BISHOP ? BishopSafeCheck
 +                                            : KnightSafeCheck;
 +            else
 +                unsafeChecks |= knightChecks;
 +            break;
 +        case PAWN:
 +            if (pos.captures_to_hand() && pos.count_in_hand(Them, pt))
 +            {
 +                pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb();
 +                if (pawnChecks & safe)
 +                    kingDanger += OtherSafeCheck;
 +                else
 +                    unsafeChecks |= pawnChecks;
 +            }
 +            break;
 +        case SHOGI_PAWN:
 +        case KING:
 +            break;
 +        default:
 +            otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb();
 +            if (otherChecks & safe)
 +                kingDanger += OtherSafeCheck;
 +            else
 +                unsafeChecks |= otherChecks;
 +        }
 +    }
  
 -    if (rookChecks)
 -        kingDanger += RookSafeCheck;
 -    else
 -        unsafeChecks |= b1 & attackedBy[Them][ROOK];
 -
 -    // Enemy queen safe checks: we count them only if they are from squares from
 -    // which we can't give a rook check, because rook checks are more valuable.
 -    queenChecks =  (b1 | b2)
 -                 & attackedBy[Them][QUEEN]
 -                 & safe
 -                 & ~attackedBy[Us][QUEEN]
 -                 & ~rookChecks;
 -
 -    if (queenChecks)
 -        kingDanger += QueenSafeCheck;
 -
 -    // Enemy bishops checks: we count them only if they are from squares from
 -    // which we can't give a queen check, because queen checks are more valuable.
 -    bishopChecks =  b2
 -                  & attackedBy[Them][BISHOP]
 -                  & safe
 -                  & ~queenChecks;
 -
 -    if (bishopChecks)
 -        kingDanger += BishopSafeCheck;
 -    else
 -        unsafeChecks |= b2 & attackedBy[Them][BISHOP];
 +    if (pos.check_counting())
 +        kingDanger *= 2;
  
 -    // Enemy knights checks
 -    knightChecks = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
 -
 -    if (knightChecks & safe)
 -        kingDanger += KnightSafeCheck;
 -    else
 -        unsafeChecks |= knightChecks;
 +    Square s = file_of(ksq) == FILE_A ? ksq + EAST : file_of(ksq) == pos.max_file() ? ksq + WEST : ksq;
 +    Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(s) | adjacent_files_bb(s);
  
-     // Find the squares that opponent attacks in our king flank, and the squares
-     // which are attacked twice in that flank.
+     // Find the squares that opponent attacks in our king flank, the squares
+     // which they attack twice in that flank, and the squares that we defend.
 -    b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
 +    b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp;
      b2 = b1 & attackedBy2[Them];
 -    b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
++    b3 = attackedBy[Us][ALL_PIECES] & kingFlank & Camp;
  
-     int kingFlankAttacks = popcount(b1) + popcount(b2);
+     int kingFlankAttack = popcount(b1) + popcount(b2);
+     int kingFlankDefense = popcount(b3);
  
      kingDanger +=        kingAttackersCount[Them] * kingAttackersWeight[Them]
 -                 + 185 * popcount(kingRing[Us] & weak)
 +                 +       kingAttackersCountInHand[Them] * kingAttackersWeight[Them]
 +                 +       kingAttackersCount[Them] * kingAttackersWeightInHand[Them]
 +                 + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + pos.check_counting())
                   + 148 * popcount(unsafeChecks)
                   +  98 * popcount(pos.blockers_for_king(Us))
 -                 +  69 * kingAttacksCount[Them]
 +                 +  69 * kingAttacksCount[Them] * (2 + 8 * pos.check_counting() + pos.captures_to_hand()) / 2
-                  +   3 * kingFlankAttacks * kingFlankAttacks / 8
+                  +   4 * (kingFlankAttack - kingFlankDefense)
+                  +   3 * kingFlankAttack * kingFlankAttack / 8
                   +       mg_value(mobility[Them] - mobility[Us])
 -                 - 873 * !pos.count<QUEEN>(Them)
 +                 - 873 * !(pos.major_pieces(Them) || pos.captures_to_hand() || pos.xiangqi_general()) / (1 + pos.check_counting())
                   - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING])
                   -  35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING])
                   -   6 * mg_value(score) / 8
  
      // Transform the kingDanger units into a Score, and subtract it from the evaluation
      if (kingDanger > 100)
 -        score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
 +        score -= make_score(std::min(kingDanger * kingDanger / 4096, 3000), kingDanger / 16);
  
      // Penalty when our king is on a pawnless flank
 -    if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)]))
 +    if (!(pos.pieces(PAWN) & kingFlank))
          score -= PawnlessFlank;
  
-     // King tropism bonus, to anticipate slow motion attacks on our king
-     score -= FlankAttacks * kingFlankAttacks * (1 + 5 * pos.captures_to_hand() + pos.check_counting());
+     // Penalty if king flank is under attack, potentially moving toward the king
 -    score -= FlankAttacks * kingFlankAttack;
++    score -= FlankAttacks * kingFlankAttack * (1 + 5 * pos.captures_to_hand() + pos.check_counting());
 +
 +    if (pos.check_counting())
 +        score += make_score(0, mg_value(score) / 2);
 +
 +    // For drop games, king danger is independent of game phase
 +    if (pos.captures_to_hand())
 +        score = make_score(mg_value(score), mg_value(score)) * 2 / (2 + 3 * !pos.shogi_doubled_pawn());
  
      if (T)
          Trace::add(KING, Us, score);
diff --cc src/search.cpp
@@@ -991,7 -955,45 +991,51 @@@ moves_loop: // When in check, search st
        movedPiece = pos.moved_piece(move);
        givesCheck = pos.gives_check(move);
  
-       // Step 13. Extensions (~70 Elo)
+       // Calculate new depth for this move
+       newDepth = depth - 1;
+       // Step 13. Pruning at shallow depth (~170 Elo)
+       if (  !rootNode
 -          && pos.non_pawn_material(us)
++          && (pos.non_pawn_material(us) || !(pos.pieces(us) ^ pos.pieces(us, PAWN)))
+           && bestValue > VALUE_MATED_IN_MAX_PLY)
+       {
+           // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
 -          moveCountPruning = moveCount >= futility_move_count(improving, depth);
++          moveCountPruning = moveCount >= futility_move_count(improving, depth)
++                            || (pos.must_capture() && (moveCountPruning || (pos.capture(move) && pos.legal(move))));
+           if (   !captureOrPromotion
+               && !givesCheck
 -              && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg))
++              && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us))
++              && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count<ALL_PIECES>(us) == pos.count<PAWN>(us)))
+           {
+               // Reduced depth of the next LMR search
+               int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0);
+               // Countermoves based pruning (~20 Elo)
+               if (   lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1)
 -                  && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold
 -                  && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold)
++                  && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold
++                  && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold)
+                   continue;
+               // Futility pruning: parent node (~2 Elo)
+               if (   lmrDepth < 6
+                   && !inCheck
++                  && !(   pos.extinction_value() == -VALUE_MATE
++                       && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end())
+                   && ss->staticEval + 250 + 211 * lmrDepth <= alpha)
+                   continue;
+               // Prune moves with negative SEE (~10 Elo)
 -              if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth)))
++              if (!pos.must_capture() && !pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth)))
+                   continue;
+           }
 -          else if (!pos.see_ge(move, Value(-199) * depth)) // (~20 Elo)
++          else if (  !(givesCheck && extension)
++                   && !pos.must_capture()
++                   && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * depth)) // (~20 Elo)
+                   continue;
+       }
+       // Step 14. Extensions (~70 Elo)
  
        // Singular extension search (~60 Elo). If all moves but one fail low on a
        // search of (alpha-s, beta-s), and just one fails high on (alpha, beta),
        if (type_of(move) == CASTLING)
            extension = 1;
  
 +      // Losing chess capture extension
 +      else if (    pos.must_capture()
 +               &&  pos.capture(move)
 +               &&  MoveList<CAPTURES>(pos).size() == 1)
 +          extension = 1;
 +
-       // Calculate new depth for this move
-       newDepth = depth - 1 + extension;
-       // Step 14. Pruning at shallow depth (~170 Elo)
-       if (  !rootNode
-           && (pos.non_pawn_material(us) || !(pos.pieces(us) ^ pos.pieces(us, PAWN)))
-           && bestValue > VALUE_MATED_IN_MAX_PLY)
-       {
-           // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
-           moveCountPruning = moveCount >= futility_move_count(improving, depth)
-                             || (pos.must_capture() && (moveCountPruning || (pos.capture(move) && pos.legal(move))));
-           if (   !captureOrPromotion
-               && !givesCheck
-               && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us))
-               && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count<ALL_PIECES>(us) == pos.count<PAWN>(us)))
-           {
-               // Reduced depth of the next LMR search
-               int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0);
-               // Countermoves based pruning (~20 Elo)
-               if (   lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1)
-                   && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold
-                   && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold)
-                   continue;
-               // Futility pruning: parent node (~2 Elo)
-               if (   lmrDepth < 6
-                   && !inCheck
-                   && !(   pos.extinction_value() == -VALUE_MATE
-                        && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end())
-                   && ss->staticEval + 250 + 211 * lmrDepth <= alpha)
-                   continue;
-               // Prune moves with negative SEE (~10 Elo)
-               if (!pos.must_capture() && !pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth)))
-                   continue;
-           }
-           else if (  !(givesCheck && extension)
-                    && !pos.must_capture()
-                    && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * depth)) // (~20 Elo)
-                   continue;
-       }
+       // Add extension to new depth
+       newDepth += extension;
  
        // Speculative prefetch as early as possible
        prefetch(TT.first_entry(pos.key_after(move)));