Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 20 Sep 2020 10:20:05 +0000 (12:20 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 20 Sep 2020 10:20:05 +0000 (12:20 +0200)
No functional change.

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

@@@ -79,15 -78,13 +79,13 @@@ namespace 
    constexpr Value SpaceThreshold = Value(12222);
  
    // KingAttackWeights[PieceType] contains king attack weights by piece type
 -  constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 };
 +  constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10, 40 };
  
-   // Penalties for enemy's safe checks
-   constexpr int QueenSafeCheck  = 772;
-   constexpr int RookSafeCheck   = 1084;
-   constexpr int BishopSafeCheck = 645;
-   constexpr int KnightSafeCheck = 792;
-   constexpr int OtherSafeCheck  = 600;
+   // SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type,
+   // higher if multiple safe checks are possible for that piece type.
+   constexpr int SafeCheck[][2] = {
 -      {}, {}, {792, 1283}, {645, 967}, {1084, 1897}, {772, 1119}
++      {}, {600, 600}, {792, 1283}, {645, 967}, {1084, 1897}, {772, 1119}, {600, 900}
+   };
  
  #define S(mg, eg) make_score(mg, eg)
  
        S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171),
        S(110,182), S(114,182), S(114,192), S(116,219) }
    };
 +  constexpr Score MaxMobility  = S(150, 200);
 +  constexpr Score DropMobility = S(10, 10);
  
+   // KingProtector[knight/bishop] contains penalty for each distance unit to own king
+   constexpr Score KingProtector[] = { S(8, 9), S(6, 9) };
+   // Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
+   // pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
+   constexpr Score Outpost[] = { S(56, 36), S(30, 23) };
+   // PassedRank[Rank] contains a bonus according to the rank of a passed pawn
+   constexpr Score PassedRank[RANK_NB] = {
+     S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
+   };
    // RookOnFile[semiopen/open] contains bonuses for each rook when there is
    // no (friendly) pawn on the rook file.
    constexpr Score RookOnFile[] = { S(19, 7), S(48, 29) };
    constexpr Score WeakQueen           = S( 56, 15);
  
  
++  // Variant and fairy piece bonuses
++  constexpr Score KingProximity        = S(2, 4);
++  constexpr Score EndgameKingProximity = S(0, 10);
++  constexpr Score ConnectedSoldier     = S(20, 20);
++
++  constexpr int VirtualCheck = 600;
++
  #undef S
  
    // Evaluation class computes and stores attacks tables and other working data
          if (b & kingRing[Them])
          {
              kingAttackersCount[Us]++;
-             kingAttackersWeight[Us] += KingAttackWeights[std::min(int(Pt), QUEEN + 1)];
 -            kingAttackersWeight[Us] += KingAttackWeights[Pt];
++            kingAttackersWeight[Us] += KingAttackWeights[std::min(Pt, FAIRY_PIECES)];
              kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
          }
  
          else if (Pt == BISHOP && (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & kingRing[Them]))
              score += BishopOnKingRing;
  
 +        if (Pt > QUEEN)
 +             b = (b & pos.pieces()) | (pos.moves_from(Us, Pt, s) & ~pos.pieces() & pos.board_bb());
 +
          int mob = popcount(b & mobilityArea[Us]);
  
 -        mobility[Us] += MobilityBonus[Pt - 2][mob];
 +        if (Pt <= QUEEN)
 +            mobility[Us] += MobilityBonus[Pt - 2][mob];
 +        else
 +            mobility[Us] += MaxMobility * (mob - 2) / (8 + mob);
 +
 +        // Piece promotion bonus
 +        if (pos.promoted_piece_type(Pt) != NO_PIECE_TYPE)
 +        {
 +            if (promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank()) & (b | s))
 +                score += make_score(PieceValue[MG][pos.promoted_piece_type(Pt)] - PieceValue[MG][Pt],
 +                                    PieceValue[EG][pos.promoted_piece_type(Pt)] - PieceValue[EG][Pt]) / 10;
 +        }
 +        else if (pos.piece_demotion() && pos.unpromoted_piece_on(s))
 +            score -= make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)],
 +                                PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 4;
 +        else if (pos.captures_to_hand() && pos.unpromoted_piece_on(s))
 +            score += make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)],
 +                                PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 8;
 +
 +        // Penalty if the piece is far from the kings in drop variants
 +        if ((pos.captures_to_hand() || pos.two_boards()) && pos.count<KING>(Them) && pos.count<KING>(Us))
 +            score -= KingProximity * distance(s, pos.square<KING>(Us)) * distance(s, pos.square<KING>(Them));
 +
 +        else if (pos.count<KING>(Us) && (Pt == FERS || Pt == SILVER))
 +            score -= EndgameKingProximity * (distance(s, pos.square<KING>(Us)) - 2);
 +
 +        if (Pt == SOLDIER && (pos.pieces(Us, SOLDIER) & rank_bb(s) & adjacent_files_bb(s)))
-             score += make_score(20, 20);
++            score += ConnectedSoldier;
  
          if (Pt == BISHOP || Pt == KNIGHT)
          {
                  score += MinorBehindPawn;
  
              // Penalty if the piece is far from the king
 +            if (pos.count<KING>(Us))
-             score -= (Pt == KNIGHT ? KnightKingProtector
-                                    : BishopKingProtector) * distance(pos.square<KING>(Us), s);
+             score -= KingProtector[Pt == BISHOP] * distance(pos.square<KING>(Us), s);
  
              if (Pt == BISHOP)
              {
      return score;
    }
  
 +  // Evaluation::hand() scores pieces of a given color and type in hand
 +  template<Tracing T> template<Color Us>
 +  Score Evaluation<T>::hand(PieceType pt) {
 +
 +    constexpr Color Them = ~Us;
 +
 +    Score score = SCORE_ZERO;
 +
 +    if (pos.count_in_hand(Us, pt))
 +    {
 +        Bitboard b = pos.drop_region(Us, pt) & ~pos.pieces() & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]);
 +        if ((b & kingRing[Them]) && pt != SHOGI_PAWN)
 +        {
 +            kingAttackersCountInHand[Us] += pos.count_in_hand(Us, pt);
-             kingAttackersWeightInHand[Us] += KingAttackWeights[std::min(int(pt), QUEEN + 1)] * pos.count_in_hand(Us, pt);
++            kingAttackersWeightInHand[Us] += KingAttackWeights[std::min(pt, FAIRY_PIECES)] * pos.count_in_hand(Us, pt);
 +            kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
 +        }
 +        Bitboard theirHalf = pos.board_bb() & ~forward_ranks_bb(Them, relative_rank(Them, Rank((pos.max_rank() - 1) / 2), pos.max_rank()));
 +        mobility[Us] += DropMobility * popcount(b & theirHalf & ~attackedBy[Them][ALL_PIECES]);
 +        if (pos.promoted_piece_type(pt) != NO_PIECE_TYPE && pos.drop_promoted())
 +            score += make_score(std::max(PieceValue[MG][pos.promoted_piece_type(pt)] - PieceValue[MG][pt], VALUE_ZERO),
 +                                std::max(PieceValue[EG][pos.promoted_piece_type(pt)] - PieceValue[EG][pt], VALUE_ZERO)) / 4 * pos.count_in_hand(Us, pt);
 +        if (pos.enclosing_drop())
 +            mobility[Us] += make_score(500, 500) * popcount(b);
 +
 +        // Reduce score if there is a deficit of gates
 +        if (pos.seirawan_gating() && !pos.piece_drops() && pos.count_in_hand(Us, ALL_PIECES) > popcount(pos.gates(Us)))
 +            score -= make_score(200, 900) / pos.count_in_hand(Us, ALL_PIECES) * (pos.count_in_hand(Us, ALL_PIECES) - popcount(pos.gates(Us)));
 +
 +        if (pt == SHOGI_PAWN && !pos.shogi_doubled_pawn())
 +            score -= make_score(50, 20) * std::max(pos.count_with_hand(Us, SHOGI_PAWN) - pos.max_file() - 1, 0);
 +    }
 +
 +    return score;
 +  }
  
    // Evaluation::king() assigns bonuses and penalties to a king of a given color
  
      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 & attackedBy[Them][ROOK] & safe;
 -    if (rookChecks)
 -        kingDanger += SafeCheck[ROOK][more_than_one(rookChecks)];
 -    else
 -        unsafeChecks |= b1 & attackedBy[Them][ROOK];
 -
 -    // Enemy queen safe checks: count them only if the checks are from squares from
 -    // which opponent cannot give a rook check, because rook checks are more valuable.
 -    queenChecks =  (b1 | b2) & attackedBy[Them][QUEEN] & safe
 -                 & ~(attackedBy[Us][QUEEN] | rookChecks);
 -    if (queenChecks)
 -        kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)];
 -
 -    // Enemy bishops checks: count them only if they are from squares from which
 -    // opponent cannot give a queen check, because queen checks are more valuable.
 -    bishopChecks =  b2 & attackedBy[Them][BISHOP] & safe
 -                  & ~queenChecks;
 -    if (bishopChecks)
 -        kingDanger += SafeCheck[BISHOP][more_than_one(bishopChecks)];
 +    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 += more_than_one(queenChecks) ? QueenSafeCheck * 145/100
-                                                          : QueenSafeCheck;
++                kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)];
 +            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 * (more_than_one(knightChecks & safe) ? 175 : 100) / 100
-                              : pt == BISHOP ? BishopSafeCheck * (more_than_one(knightChecks & safe) ? 150 : 100) / 100
-                                             : KnightSafeCheck * (more_than_one(knightChecks & safe) ? 162 : 100) / 100;
++                kingDanger += SafeCheck[pt][more_than_one(knightChecks & safe)];
 +            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;
++                    kingDanger += SafeCheck[PAWN][more_than_one(pawnChecks & safe)];
 +                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 * (more_than_one(otherChecks & safe) ? 3 : 2) / 2;
++                kingDanger += SafeCheck[FAIRY_PIECES][more_than_one(otherChecks & safe)];
 +            else
 +                unsafeChecks |= otherChecks;
 +        }
 +    }
  
 -    else
 -        unsafeChecks |= b2 & attackedBy[Them][BISHOP];
 +    // 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]);
++                kingDanger += VirtualCheck * 500 / (500 + PieceValue[MG][pt]);
 +                // Presumably a mate threat
 +                if (!(attackedBy[Us][KING] & ~(attackedBy[Them][ALL_PIECES] | pos.pieces(Us))))
 +                    kingDanger += 2000;
 +            }
 +    }
  
 -    // Enemy knights checks
 -    knightChecks = attacks_bb<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
 -    if (knightChecks & safe)
 -        kingDanger += SafeCheck[KNIGHT][more_than_one(knightChecks & safe)];
 -    else
 -        unsafeChecks |= knightChecks;
 +    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.
 -    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 kingFlankAttack = popcount(b1) + popcount(b2);
+     int kingFlankAttack  = popcount(b1) + popcount(b2);
      int kingFlankDefense = popcount(b3);
  
      kingDanger +=        kingAttackersCount[Them] * kingAttackersWeight[Them]
diff --cc src/pawns.cpp
Simple merge
diff --cc src/types.h
@@@ -368,25 -190,11 +368,26 @@@ enum Value : int 
    MidgameLimit  = 15258, EndgameLimit  = 3915
  };
  
 +constexpr int PIECE_TYPE_BITS = 6; // PIECE_TYPE_NB = pow(2, PIECE_TYPE_BITS)
 +
  enum PieceType {
 -  NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
 +  NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN,
 +  FERS, MET = FERS, ALFIL, FERS_ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS,
 +  ARCHBISHOP, CHANCELLOR, AMAZON, KNIBIS, BISKNI, KNIROO, ROOKNI,
 +  SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, DRAGON_HORSE,
 +  CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, ATAXX_PIECE, QUIET_QUEEN, CANNON, JANGGI_CANNON,
 +  SOLDIER, HORSE, ELEPHANT, JANGGI_ELEPHANT, BANNER,
 +  WAZIR, COMMONER, CENTAUR, KING,
    ALL_PIECES = 0,
 -  PIECE_TYPE_NB = 8
++  FAIRY_PIECES = FERS,
 +
 +  PIECE_TYPE_NB = 1 << PIECE_TYPE_BITS
  };
 +static_assert(KING < PIECE_TYPE_NB, "KING exceeds PIECE_TYPE_NB.");
 +static_assert(PIECE_TYPE_BITS <= 6, "PIECE_TYPE uses more than 6 bit");
 +static_assert(!(PIECE_TYPE_NB & (PIECE_TYPE_NB - 1)), "PIECE_TYPE_NB is not a power of 2");
 +
 +static_assert(2 * SQUARE_BITS + MOVE_TYPE_BITS + 2 * PIECE_TYPE_BITS <= 32, "Move encoding uses more than 32 bits");
  
  enum Piece {
    NO_PIECE,