Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 9 Aug 2020 10:35:44 +0000 (12:35 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 9 Aug 2020 10:35:44 +0000 (12:35 +0200)
bench: 4542650

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

@@@ -489,77 -396,44 +489,78 @@@ namespace 
      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];
 -    if (rookChecks)
 -        kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 3/2
 -                                                : 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 += more_than_one(queenChecks) ? QueenSafeCheck * 3/2
 -                                                 : 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 += more_than_one(bishopChecks) ? BishopSafeCheck * 3/2
 -                                                  : BishopSafeCheck;
 -    else
 -        unsafeChecks |= b2 & attackedBy[Them][BISHOP];
 +    std::function <Bitboard (Color, PieceType)> get_attacks = [this](Color c, PieceType pt) {
 +        return attackedBy[c][pt] | (pos.piece_drops() && pos.count_in_hand(c, pt) ? pos.drop_region(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)
 +                        & pos.board_bb()
 +                        & safe
 +                        & ~attackedBy[Us][QUEEN]
 +                        & ~(b1 & attackedBy[Them][ROOK]);
 +
 +            if (queenChecks)
-                 kingDanger += QueenSafeCheck;
++                kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 3/2
++                                                         : 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
++                kingDanger += (pt == ROOK   ? RookSafeCheck
 +                             : pt == BISHOP ? BishopSafeCheck
-                                             : KnightSafeCheck;
++                                            : KnightSafeCheck) * (more_than_one(knightChecks & safe) ? 3 : 2) / 2;
 +            else
 +                unsafeChecks |= knightChecks;
 +            break;
 +        case PAWN:
 +            if (pos.piece_drops() && 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;
++                kingDanger += OtherSafeCheck * (more_than_one(otherChecks & safe) ? 3 : 2) / 2;
 +            else
 +                unsafeChecks |= otherChecks;
 +        }
 +    }
  
 -    // Enemy knights checks
 -    knightChecks = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
 -    if (knightChecks & safe)
 -        kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 3/2
 -                                                         : KnightSafeCheck;
 -    else
 -        unsafeChecks |= knightChecks;
 +    // Virtual piece drops
 +    if (pos.two_boards() && pos.piece_drops())
 +    {
 +        for (PieceType pt : pos.piece_types())
 +            if (!pos.count_in_hand(Them, pt) && (attacks_bb(Us, pt, ksq, pos.pieces()) & safe & pos.drop_region(Them, pt) & ~pos.pieces()))
 +            {
 +                kingDanger += OtherSafeCheck * 500 / (500 + PieceValue[MG][pt]);
 +                // Presumably a mate threat
 +                if (!(attackedBy[Us][KING] & ~(attackedBy[Them][ALL_PIECES] | pos.pieces(Us))))
 +                    kingDanger += 2000;
 +            }
 +    }
 +
 +    if (pos.check_counting())
 +        kingDanger += kingDanger * 7 / (3 + pos.checks_remaining(Them));
 +
 +    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, the squares
      // which they attack twice in that flank, and the squares that we defend.
      int sf = me->scale_factor(pos, strongSide);
  
      // If scale is not already specific, scale down the endgame via general heuristics
 -    if (sf == SCALE_FACTOR_NORMAL)
 +    if (sf == SCALE_FACTOR_NORMAL && !pos.captures_to_hand())
      {
-         if (   pos.opposite_bishops()
-             && pos.non_pawn_material() == 2 * BishopValueMg)
-             sf = 22;
+         if (pos.opposite_bishops())
+         {
+             if (   pos.non_pawn_material(WHITE) == BishopValueMg
+                 && pos.non_pawn_material(BLACK) == BishopValueMg)
+                 sf = 22;
+             else
+                 sf = 22 + 3 * pos.count<ALL_PIECES>(strongSide);
+         }
          else
-             sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * (pos.count<PAWN>(strongSide) + pos.count<SOLDIER>(strongSide)));
 -            sf = std::min(sf, 36 + 7 * pos.count<PAWN>(strongSide));
++            sf = std::min(sf, 36 + 7 * (pos.count<PAWN>(strongSide) + pos.count<SOLDIER>(strongSide)));
  
          sf = std::max(0, sf - (pos.rule50_count() - 12) / 4);
      }
diff --cc src/pawns.cpp
@@@ -268,9 -244,9 +268,9 @@@ Score Entry::do_king_safety(const Posit
  
    // In endgame we like to bring our king near our closest pawn
    Bitboard pawns = pos.pieces(Us, PAWN);
-   int minPawnDist = pawns ? 8 : 0;
+   int minPawnDist = 6;
  
 -  if (pawns & PseudoAttacks[KING][ksq])
 +  if (pawns & PseudoAttacks[Us][KING][ksq])
        minPawnDist = 1;
    else while (pawns)
        minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns)));
diff --cc src/search.cpp
@@@ -708,14 -650,11 +708,14 @@@ namespace 
  
      if (!rootNode)
      {
 +        Value variantResult;
 +        if (pos.is_game_end(variantResult, ss->ply))
 +            return variantResult;
 +
          // Step 2. Check for aborted search and immediate draw
          if (   Threads.stop.load(std::memory_order_relaxed)
 -            || pos.is_draw(ss->ply)
              || ss->ply >= MAX_PLY)
-             return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos)
+             return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos)
                                                      : value_draw(pos.this_thread());
  
          // Step 3. Mate distance pruning. Even if we mate at the next move our score
                  probCutCount++;
  
                  ss->currentMove = move;
-                 ss->continuationHistory = &thisThread->continuationHistory[inCheck]
+                 ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
                                                                            [captureOrPromotion]
 -                                                                          [pos.moved_piece(move)]
 +                                                                          [history_slot(pos.moved_piece(move))]
                                                                            [to_sq(move)];
  
                  pos.do_move(move, st);
@@@ -1107,13 -1030,11 +1106,13 @@@ moves_loop: // When in check, search st
  
                // Futility pruning: parent node (~5 Elo)
                if (   lmrDepth < 6
-                   && !inCheck
+                   && !ss->inCheck
 -                  && ss->staticEval + 235 + 172 * lmrDepth <= alpha
 -                  &&  (*contHist[0])[movedPiece][to_sq(move)]
 -                    + (*contHist[1])[movedPiece][to_sq(move)]
 -                    + (*contHist[3])[movedPiece][to_sq(move)] < 27400)
 +                  && !(   pos.extinction_value() == -VALUE_MATE
 +                       && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end())
 +                  && ss->staticEval + (235 + 172 * lmrDepth) * (1 + pos.check_counting()) <= alpha
 +                  &&  (*contHist[0])[history_slot(movedPiece)][to_sq(move)]
 +                    + (*contHist[1])[history_slot(movedPiece)][to_sq(move)]
 +                    + (*contHist[3])[history_slot(movedPiece)][to_sq(move)] < 27400)
                    continue;
  
                // Prune moves with negative SEE (~20 Elo)
                    && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0)
                    continue;
  
+               // Futility pruning for captures
+               if (   !givesCheck
+                   && lmrDepth < 6
+                   && !ss->inCheck
+                   && ss->staticEval + 270 + 384 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha)
+                   continue;
                // See based pruning
 -              if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo)
 +              if (!pos.see_ge(move, Value(-194 - 120 * pos.captures_to_hand()) * depth)) // (~25 Elo)
                    continue;
            }
        }
  
        // Update the current move (this must be done after singular extension search)
        ss->currentMove = move;
-       ss->continuationHistory = &thisThread->continuationHistory[inCheck]
+       ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
                                                                  [captureOrPromotion]
 -                                                                [movedPiece]
 +                                                                [history_slot(movedPiece)]
                                                                  [to_sq(move)];
  
        // Step 15. Make the move
  
      if (!moveCount)
          bestValue = excludedMove ? alpha
-                    :     inCheck ? pos.checkmate_value(ss->ply) : pos.stalemate_value(ss->ply);
 -                   :     ss->inCheck ? mated_in(ss->ply) : VALUE_DRAW;
++                   :     ss->inCheck ? pos.checkmate_value(ss->ply) : pos.stalemate_value(ss->ply);
  
      else if (bestMove)
          update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq,
      Thread* thisThread = pos.this_thread();
      (ss+1)->ply = ss->ply + 1;
      bestMove = MOVE_NONE;
-     inCheck = pos.checkers();
+     ss->inCheck = pos.checkers();
      moveCount = 0;
  
 -    // Check for an immediate draw or maximum ply reached
 -    if (   pos.is_draw(ss->ply)
 -        || ss->ply >= MAX_PLY)
 -        return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : VALUE_DRAW;
 +    Value gameResult;
 +    if (pos.is_game_end(gameResult, ss->ply))
 +        return gameResult;
 +
 +    // Check for maximum ply reached
 +    if (ss->ply >= MAX_PLY)
-         return !inCheck ? evaluate(pos) : VALUE_DRAW;
++        return !ss->inCheck ? evaluate(pos) : VALUE_DRAW;
  
      assert(0 <= ss->ply && ss->ply < MAX_PLY);
  
        moveCount++;
  
        // Futility pruning
-       if (   !inCheck
+       if (   !ss->inCheck
            && !givesCheck
 +          && !(   pos.extinction_value() == -VALUE_MATE
 +               && pos.piece_on(to_sq(move))
 +               && pos.extinction_piece_types().find(type_of(pos.piece_on(to_sq(move)))) != pos.extinction_piece_types().end())
            &&  futilityBase > -VALUE_KNOWN_WIN
            && !pos.advanced_pawn_push(move))
        {
        }
  
        ss->currentMove = move;
-       ss->continuationHistory = &thisThread->continuationHistory[inCheck]
+       ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
                                                                  [captureOrPromotion]
 -                                                                [pos.moved_piece(move)]
 +                                                                [history_slot(pos.moved_piece(move))]
                                                                  [to_sq(move)];
  
        // Make and search the move
  
      // All legal moves have been searched. A special case: If we're in check
      // and no legal moves were found, it is checkmate.
-     if (inCheck && bestValue == -VALUE_INFINITE)
+     if (ss->inCheck && bestValue == -VALUE_INFINITE)
 -        return mated_in(ss->ply); // Plies to mate from the root
 +        return pos.checkmate_value(ss->ply); // Plies to mate from the root
  
      tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit,
                bestValue >= beta ? BOUND_LOWER :
    void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
  
      for (int i : {1, 2, 4, 6})
+     {
+         if (ss->inCheck && i > 2)
+             break;
          if (is_ok((ss-i)->currentMove))
 -            (*(ss-i)->continuationHistory)[pc][to] << bonus;
 +            (*(ss-i)->continuationHistory)[history_slot(pc)][to] << bonus;
+     }
    }
  
  
diff --cc src/search.h
Simple merge