Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sat, 18 Jul 2020 10:44:36 +0000 (12:44 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sat, 18 Jul 2020 10:44:36 +0000 (12:44 +0200)
bench: 5126336

1  2 
src/benchmark.cpp
src/bitboard.h
src/endgame.cpp
src/evaluate.cpp
src/pawns.cpp
src/psqt.cpp
src/syzygy/tbprobe.cpp
src/types.h

Simple merge
diff --cc src/bitboard.h
@@@ -352,23 -255,8 +352,25 @@@ template<> inline int distance<File>(Sq
  template<> inline int distance<Rank>(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); }
  template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
  
 -inline File edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
 -inline Rank edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); }
++inline File edge_distance(File f, File maxFile = FILE_H) { return std::min(f, File(maxFile - f)); }
++inline Rank edge_distance(Rank r, Rank maxRank = RANK_8) { return std::min(r, Rank(maxRank - r)); }
 +
 +
 +template<RiderType R>
 +inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) {
 +
 +  assert(R == RIDER_BISHOP || R == RIDER_ROOK_H || R == RIDER_ROOK_V || R == RIDER_CANNON_H || R == RIDER_CANNON_V
 +         || R == RIDER_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT);
 +  const Magic& m =  R == RIDER_ROOK_H ? RookMagicsH[s]
 +                  : R == RIDER_ROOK_V ? RookMagicsV[s]
 +                  : R == RIDER_CANNON_H ? CannonMagicsH[s]
 +                  : R == RIDER_CANNON_V ? CannonMagicsV[s]
 +                  : R == RIDER_HORSE ? HorseMagics[s]
 +                  : R == RIDER_ELEPHANT ? ElephantMagics[s]
 +                  : R == RIDER_JANGGI_ELEPHANT ? JanggiElephantMagics[s]
 +                  : BishopMagics[s];
 +  return m.attacks[m.index(occupied)];
 +}
  
  /// attacks_bb() returns a bitboard representing all the squares attacked by a
  /// piece of type Pt (bishop or rook) placed on 's'.
diff --cc src/endgame.cpp
@@@ -28,44 -28,17 +28,24 @@@ using std::string
  
  namespace {
  
-   // Table used to drive the king towards the edge of the board
+   // Used to drive the king towards the edge of the board
    // in KX vs K and KQ vs KR endgames.
-   constexpr int PushToEdges[SQUARE_NB] = {
-     100, 90, 80, 70, 70, 80, 90, 100,
-      90, 70, 60, 50, 50, 60, 70,  90,
-      80, 60, 40, 30, 30, 40, 60,  80,
-      70, 50, 30, 20, 20, 30, 50,  70,
-      70, 50, 30, 20, 20, 30, 50,  70,
-      80, 60, 40, 30, 30, 40, 60,  80,
-      90, 70, 60, 50, 50, 60, 70,  90,
-     100, 90, 80, 70, 70, 80, 90, 100
-   };
-   // Table used to drive the king towards a corner square of the
-   // right color in KBN vs K endgames.
-   constexpr int PushToCorners[SQUARE_NB] = {
-      6400, 6080, 5760, 5440, 5120, 4800, 4480, 4160,
-      6080, 5760, 5440, 5120, 4800, 4480, 4160, 4480,
-      5760, 5440, 4960, 4480, 4480, 4000, 4480, 4800,
-      5440, 5120, 4480, 3840, 3520, 4480, 4800, 5120,
-      5120, 4800, 4480, 3520, 3840, 4480, 5120, 5440,
-      4800, 4480, 4000, 4480, 4480, 4960, 5440, 5760,
-      4480, 4160, 4480, 4800, 5120, 5440, 5760, 6080,
-      4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400
-   };
-   // Table used to drive the king towards the edge of the board
 -  inline int push_to_edge(Square s) {
 -      int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s));
++  inline int push_to_edge(Square s, const Position& pos) {
++      int rd = edge_distance(rank_of(s), pos.max_rank()), fd = edge_distance(file_of(s), pos.max_file());
+       return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2);
+   }
+   // Used to drive the king towards A1H8 corners in KBN vs K endgames.
 -  inline int push_to_corner(Square s) {
 -      return abs(7 - rank_of(s) - file_of(s));
++  inline int push_to_corner(Square s, const Position& pos) {
++      return abs((pos.max_file() + pos.max_rank()) / 2 - rank_of(s) - file_of(s));
++  }
++
++  // Used to drive the king towards the edge of the board
 +  // in KSF vs K.
-   constexpr int PushToOpposingSideEdges[SQUARE_NB] = {
-      20, 10,  5,  0,  0,  5, 10,  20,
-      20, 10,  5,  0,  0,  5, 10,  20,
-      30, 20, 10,  0,  0, 10, 20,  30,
-      50, 40, 20, 10, 10, 20, 40,  50,
-      60, 50, 40, 30, 30, 40, 50,  60,
-      70, 60, 50, 40, 40, 50, 60,  70,
-      90, 70, 60, 50, 50, 60, 70,  90,
-     100, 90, 80, 70, 70, 80, 90, 100
-   };
++  inline int push_to_opposing_edge(Square s, const Position& pos) {
++      int rd = rank_of(s), fd = edge_distance(file_of(s), pos.max_file());
++      return 20 - (7 * fd * fd / 2 - 7 * rd * rd / 4);
+   }
  
    // Drive a piece close to or away from another piece
    inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); }
  
      assert(pos.count<PAWN>(strongSide) == 1);
  
 -    if (file_of(pos.square<PAWN>(strongSide)) >= FILE_E)
 -        sq = flip_file(sq);
 +    if (file_of(pos.square<PAWN>(strongSide)) > pos.max_file() / 2)
 +        sq = flip_file(sq, pos.max_file());
  
 -    return strongSide == WHITE ? sq : flip_rank(sq);
 +    return strongSide == WHITE ? sq : flip_rank(sq, pos.max_rank());
    }
  
-   // Map the square to an 8x8 board
-   Square map_to_standard_board(const Position& pos, Square s) {
-     File f = file_of(s) > pos.max_file() / 2 ? File(FILE_H - pos.max_file() + file_of(s)) : file_of(s);
-     Rank r = rank_of(s) > pos.max_rank() / 2 ? Rank(RANK_8 - pos.max_rank() + rank_of(s)) : rank_of(s);
-     return Square(r * 8 + f);
-   }
  } // namespace
  
  
@@@ -154,7 -112,7 +127,7 @@@ Value Endgame<KXK>::operator()(const Po
  
    Value result =  pos.non_pawn_material(strongSide)
                  + pos.count<PAWN>(strongSide) * PawnValueEg
-                 + PushToEdges[map_to_standard_board(pos, loserKSq)]
 -                + push_to_edge(loserKSq)
++                + push_to_edge(loserKSq, pos)
                  + push_close(winnerKSq, loserKSq);
  
    if (   pos.count<QUEEN>(strongSide)
@@@ -190,9 -141,9 +163,9 @@@ Value Endgame<KBNK>::operator()(const P
    // If our bishop does not attack A1/H8, we flip the enemy king square
    // to drive to opposite corners (A8/H1).
  
-   Value result =  VALUE_KNOWN_WIN
+   Value result =  (VALUE_KNOWN_WIN + 3520)
                  + push_close(winnerKSq, loserKSq)
-                 + PushToCorners[map_to_standard_board(pos, relative_square(opposite_colors(bishopSq, SQ_A1) ? BLACK : WHITE, loserKSq, pos.max_rank()))];
 -                + 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq) : loserKSq);
++                + 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq, pos.max_file()) : loserKSq, pos);
  
    assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
    return strongSide == pos.side_to_move() ? result : -result;
@@@ -286,7 -226,7 +259,7 @@@ Value Endgame<KRKB>::operator()(const P
    assert(verify_material(pos, strongSide, RookValueMg, 0));
    assert(verify_material(pos, weakSide, BishopValueMg, 0));
  
-   Value result = Value(PushToEdges[map_to_standard_board(pos, pos.square<KING>(weakSide))]);
 -  Value result = Value(push_to_edge(pos.square<KING>(weakSide)));
++  Value result = Value(push_to_edge(pos.square<KING>(weakSide), pos));
    return strongSide == pos.side_to_move() ? result : -result;
  }
  
@@@ -301,7 -241,7 +274,7 @@@ Value Endgame<KRKN>::operator()(const P
  
    Square bksq = pos.square<KING>(weakSide);
    Square bnsq = pos.square<KNIGHT>(weakSide);
-   Value result = Value(PushToEdges[map_to_standard_board(pos, bksq)] + push_away(bksq, bnsq));
 -  Value result = Value(push_to_edge(bksq) + push_away(bksq, bnsq));
++  Value result = Value(push_to_edge(bksq, pos) + push_away(bksq, bnsq));
    return strongSide == pos.side_to_move() ? result : -result;
  }
  
@@@ -346,7 -286,7 +319,7 @@@ Value Endgame<KQKR>::operator()(const P
  
    Value result =  QueenValueEg
                  - RookValueEg
-                 + PushToEdges[map_to_standard_board(pos, loserKSq)]
 -                + push_to_edge(loserKSq)
++                + push_to_edge(loserKSq, pos)
                  + push_close(winnerKSq, loserKSq);
  
    return strongSide == pos.side_to_move() ? result : -result;
@@@ -362,7 -302,7 +335,7 @@@ Value Endgame<KNNKP>::operator()(const 
    assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
  
    Value result =      PawnValueEg
-                +  2 * PushToEdges[map_to_standard_board(pos, pos.square<KING>(weakSide))]
 -               +  2 * push_to_edge(pos.square<KING>(weakSide))
++               +  2 * push_to_edge(pos.square<KING>(weakSide), pos)
                 - 10 * relative_rank(weakSide, pos.square<PAWN>(weakSide));
  
    return strongSide == pos.side_to_move() ? result : -result;
  template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
  
  
 +/// KFsPs vs K.
 +template<>
 +Value Endgame<KFsPsK>::operator()(const Position& pos) const {
 +
 +  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
 +
 +  Square winnerKSq = pos.square<KING>(strongSide);
 +  Square loserKSq = pos.square<KING>(weakSide);
 +
 +  Value result =  pos.non_pawn_material(strongSide)
 +                + pos.count<PAWN>(strongSide) * PawnValueEg
-                 + PushToEdges[map_to_standard_board(pos, loserKSq)]
++                + push_to_edge(loserKSq, pos)
 +                + push_close(winnerKSq, loserKSq);
 +
 +  if (   pos.count<FERS>(strongSide) >= 3
 +      && ( DarkSquares & pos.pieces(strongSide, FERS))
 +      && (~DarkSquares & pos.pieces(strongSide, FERS)))
 +      result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
 +  else if (pos.count<FERS>(strongSide) + pos.count<PAWN>(strongSide) < 3)
 +      return VALUE_DRAW;
 +  else
 +  {
 +      bool dark  =  DarkSquares & pos.pieces(strongSide, FERS);
 +      bool light = ~DarkSquares & pos.pieces(strongSide, FERS);
 +
 +      // Determine the color of ferzes from promoting pawns
 +      Bitboard b = pos.pieces(strongSide, PAWN);
 +      while (b && (!dark || !light))
 +      {
 +          if (file_of(pop_lsb(&b)) % 2 != relative_rank(strongSide, pos.promotion_rank(), pos.max_rank()) % 2)
 +              light = true;
 +          else
 +              dark = true;
 +      }
 +      if (!dark || !light)
 +          return VALUE_DRAW; // we can not checkmate with same colored ferzes
 +  }
 +
 +  return strongSide == pos.side_to_move() ? result : -result;
 +}
 +
 +
 +/// Mate with KNS vs K.
 +template<>
 +Value Endgame<KNSK>::operator()(const Position& pos) const {
 +
 +  assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg, 0));
 +  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
 +
 +  Square winnerKSq = pos.square<KING>(strongSide);
 +  Square loserKSq = pos.square<KING>(weakSide);
 +
 +  Value result =  VALUE_KNOWN_WIN
 +                + push_close(winnerKSq, loserKSq)
-                 + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
++                + push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
 +
 +  return strongSide == pos.side_to_move() ? result : -result;
 +}
 +
 +
 +/// KNF vs K. Can only be won if the weaker side's king
 +/// is close to a corner of the same color as the fers.
 +template<>
 +Value Endgame<KNFK>::operator()(const Position& pos) const {
 +
 +  assert(verify_material(pos, strongSide, KnightValueMg + FersValueMg, 0));
 +  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
 +
 +  Square winnerKSq = pos.square<KING>(strongSide);
 +  Square loserKSq = pos.square<KING>(weakSide);
 +  Square fersSq = pos.square<FERS>(strongSide);
 +
 +  // tries to drive toward corners A1 or H8. If we have a
 +  // fers that cannot reach the above squares, we flip the kings in order
 +  // to drive the enemy toward corners A8 or H1.
 +  if (opposite_colors(fersSq, SQ_A1))
 +  {
 +      winnerKSq = relative_square(BLACK, winnerKSq, pos.max_rank());
 +      loserKSq  = relative_square(BLACK, loserKSq, pos.max_rank());
 +  }
 +
 +  Value result =  Value(push_close(winnerKSq, loserKSq))
-                 + (PushToCorners[map_to_standard_board(pos, loserKSq)] - 3000) / 10;
++                + 50 * push_to_corner(loserKSq, pos);
 +
 +  return strongSide == pos.side_to_move() ? result : -result;
 +}
 +
 +
 +/// KNSFKR vs K.
 +template<>
 +Value Endgame<KNSFKR>::operator()(const Position& pos) const {
 +
 +  assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg + FersValueMg, 0));
 +  assert(verify_material(pos, weakSide, RookValueMg, 0));
 +
 +  Square winnerKSq = pos.square<KING>(strongSide);
 +  Square loserKSq = pos.square<KING>(weakSide);
 +
 +  Value result =  KnightValueEg + SilverValueEg + FersValueEg - RookValueEg
 +                + push_close(winnerKSq, loserKSq)
-                 + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
++                + push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
 +
 +  return strongSide == pos.side_to_move() ? result : -result;
 +}
 +
 +
 +/// Mate with KSF vs K.
 +template<>
 +Value Endgame<KSFK>::operator()(const Position& pos) const {
 +
 +  assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0));
 +  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
 +
 +  Square winnerKSq = pos.square<KING>(strongSide);
 +  Square loserKSq = pos.square<KING>(weakSide);
 +
 +  Value result =  VALUE_KNOWN_WIN
 +                + push_close(winnerKSq, loserKSq)
-                 + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
++                + push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
 +
 +  return strongSide == pos.side_to_move() ? result : -result;
 +}
 +
 +
 +/// Mate with KSF vs KF.
 +template<>
 +Value Endgame<KSFKF>::operator()(const Position& pos) const {
 +
 +  assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0));
 +  assert(verify_material(pos, weakSide, FersValueMg, 0));
 +
 +  Square winnerKSq = pos.square<KING>(strongSide);
 +  Square loserKSq = pos.square<KING>(weakSide);
 +  Square fersSq = pos.square<FERS>(weakSide);
 +
 +  Value result =  SilverValueEg
 +                + push_close(winnerKSq, loserKSq)
 +                + push_away(fersSq, loserKSq)
-                 + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
++                + push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
 +
 +  return strongSide == pos.side_to_move() ? result : -result;
 +}
 +
 +
 +/// KR vs KS
 +template<>
 +Value Endgame<KRKS>::operator()(const Position& pos) const {
 +
 +  assert(verify_material(pos, strongSide, RookValueMg, 0));
 +  assert(verify_material(pos, weakSide, SilverValueMg, 0));
 +
 +  Square winnerKSq = pos.square<KING>(strongSide);
 +  Square loserKSq = pos.square<KING>(weakSide);
 +
 +  Value result =  RookValueEg
 +                - SilverValueEg
-                 + PushToEdges[map_to_standard_board(pos, loserKSq)]
++                + push_to_edge(loserKSq, pos)
 +                + push_close(winnerKSq, loserKSq);
 +
 +  return strongSide == pos.side_to_move() ? result : -result;
 +}
 +
 +
  /// KB and one or more pawns vs K. It checks for draws with rook pawns and
  /// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
  /// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
@@@ -820,36 -643,7 +820,36 @@@ namespace 
              || (pos.pieces(PAWN) & (s + Up)))
              bonus = bonus / 2;
  
-         score += bonus - PassedFile * std::min(file_of(s), File(pos.max_file() - file_of(s)));
 -        score += bonus - PassedFile * edge_distance(file_of(s));
++        score += bonus - PassedFile * edge_distance(file_of(s), pos.max_file());
 +    }
 +
 +    // Scale by maximum promotion piece value
 +    Value maxMg = VALUE_ZERO, maxEg = VALUE_ZERO;
 +    for (PieceType pt : pos.promotion_piece_types())
 +    {
 +        maxMg = std::max(maxMg, PieceValue[MG][pt]);
 +        maxEg = std::max(maxEg, PieceValue[EG][pt]);
 +    }
 +    score = make_score(mg_value(score) * int(maxMg - PawnValueMg) / (QueenValueMg - PawnValueMg),
 +                       eg_value(score) * int(maxEg - PawnValueEg) / (QueenValueEg - PawnValueEg));
 +
 +    // Score passed shogi pawns
 +    const Square* pl = pos.squares(Us, SHOGI_PAWN);
 +    Square s;
 +
 +    PieceType pt = pos.promoted_piece_type(SHOGI_PAWN);
 +    if (pt != NO_PIECE_TYPE)
 +    {
 +        while ((s = *pl++) != SQ_NONE)
 +        {
 +            if ((pos.pieces(Them, SHOGI_PAWN) & forward_file_bb(Us, s)) || relative_rank(Us, s, pos.max_rank()) == pos.max_rank())
 +                continue;
 +
 +            Square blockSq = s + Up;
 +            int d = std::max(pos.promotion_rank() - relative_rank(Us, s, pos.max_rank()), 1);
 +            d += !!(attackedBy[Them][ALL_PIECES] & ~attackedBy2[Us] & blockSq);
 +            score += make_score(PieceValue[MG][pt], PieceValue[EG][pt]) / (4 * d * d);
 +        }
      }
  
      if (T)
diff --cc src/pawns.cpp
@@@ -220,14 -197,13 +220,14 @@@ Score Entry::evaluate_shelter(const Pos
    for (File f = File(center - 1); f <= File(center + 1); ++f)
    {
        b = ourPawns & file_bb(f);
 -      int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
 +      int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0;
  
        b = theirPawns & file_bb(f);
 -      int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
 +      int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0;
  
-       int d = std::min(std::min(f, File(pos.max_file() - f)), FILE_D);
 -      File d = edge_distance(f);
 -      bonus += make_score(ShelterStrength[d][ourRank], 0);
++      int d = std::min(edge_distance(f, pos.max_file()), FILE_D);
 +      bonus += make_score(ShelterStrength[d][ourRank], 0) * (1 + (pos.captures_to_hand() && ourRank <= RANK_2)
 +                                                               + (pos.check_counting() && d == 0 && ourRank == RANK_2));
  
        if (ourRank && (ourRank == theirRank - 1))
            bonus -= BlockedStorm * int(theirRank == RANK_3);
diff --cc src/psqt.cpp
@@@ -21,8 -21,7 +21,9 @@@
  #include <algorithm>
  
  #include "types.h"
+ #include "bitboard.h"
 +#include "piece.h"
 +#include "variant.h"
  
  namespace PSQT {
  
@@@ -106,99 -104,19 +107,99 @@@ Score psq[PIECE_NB][SQUARE_NB + 1]
  // init() initializes piece-square tables: the white halves of the tables are
  // copied from Bonus[] adding the piece value, then the black halves of the
  // tables are initialized by flipping and changing the sign of the white scores.
 -void init() {
 +void init(const Variant* v) {
  
 -  for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
 +  PieceType strongestPiece = NO_PIECE_TYPE;
 +  for (PieceType pt : v->pieceTypes)
 +      if (PieceValue[MG][pt] > PieceValue[MG][strongestPiece])
 +          strongestPiece = pt;
 +
 +  Value maxPromotion = VALUE_ZERO;
 +  for (PieceType pt : v->promotionPieceTypes)
 +      maxPromotion = std::max(maxPromotion, PieceValue[EG][pt]);
 +
 +  for (PieceType pt = PAWN; pt <= KING; ++pt)
    {
 +      Piece pc = make_piece(WHITE, pt);
 +
        Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
  
 -      for (Square s = SQ_A1; s <= SQ_H8; ++s)
 +      // Consider promotion types in pawn score
 +      if (pt == PAWN)
 +          score -= make_score(0, (QueenValueEg - maxPromotion) / 100);
 +
 +      // Scale slider piece values with board size
 +      const PieceInfo* pi = pieceMap.find(pt)->second;
 +      bool isSlider = pi->sliderQuiet.size() || pi->sliderCapture.size() || pi->hopperQuiet.size() || pi->hopperCapture.size();
 +      bool isPawn = !isSlider && pi->stepsQuiet.size() && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return d < SOUTH / 2; });
 +      bool isSlowLeaper = !isSlider && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return dist(d) > 1; });
 +
 +      if (isSlider)
 +      {
 +          constexpr int lc = 5;
 +          constexpr int rm = 5;
 +          constexpr int r0 = rm + RANK_8;
 +          int r1 = rm + (v->maxRank + v->maxFile) / 2;
 +          int leaper = pi->stepsQuiet.size() + pi->stepsCapture.size();
 +          int slider = pi->sliderQuiet.size() + pi->sliderCapture.size() + pi->hopperQuiet.size() + pi->hopperCapture.size();
 +          score = make_score(mg_value(score) * (lc * leaper + r1 * slider) / (lc * leaper + r0 * slider),
 +                             eg_value(score) * (lc * leaper + r1 * slider) / (lc * leaper + r0 * slider));
 +      }
 +
 +      // Increase leapers' value in makpong
 +      if (v->makpongRule)
 +      {
 +          if (std::any_of(pi->stepsCapture.begin(), pi->stepsCapture.end(), [](Direction d) { return dist(d) > 1; })
 +                  && !pi->lameLeaper)
 +              score = make_score(mg_value(score) * 4200 / (3500 + mg_value(score)),
 +                                 eg_value(score) * 4700 / (3500 + mg_value(score)));
 +      }
 +
 +      // For drop variants, halve the piece values
 +      if (v->capturesToHand)
 +          score = make_score(mg_value(score) * 3500 / (7000 + mg_value(score)),
 +                             eg_value(score) * 3500 / (7000 + eg_value(score)));
 +      else if (!v->checking)
 +          score = make_score(mg_value(score) * 2000 / (3500 + mg_value(score)),
 +                             eg_value(score) * 2200 / (3500 + eg_value(score)));
 +      else if (v->twoBoards)
 +          score = make_score(mg_value(score) * 7000 / (7000 + mg_value(score)),
 +                             eg_value(score) * 7000 / (7000 + eg_value(score)));
 +      else if (v->checkCounting)
 +          score = make_score(mg_value(score) * (40000 + mg_value(score)) / 41000,
 +                             eg_value(score) * (30000 + eg_value(score)) / 31000);
 +      else if (pt == strongestPiece)
 +              score += make_score(std::max(QueenValueMg - PieceValue[MG][pt], VALUE_ZERO) / 20,
 +                                  std::max(QueenValueEg - PieceValue[EG][pt], VALUE_ZERO) / 20);
 +
 +      // For antichess variants, use negative piece values
 +      if (   v->extinctionValue == VALUE_MATE
 +          && v->extinctionPieceTypes.find(ALL_PIECES) != v->extinctionPieceTypes.end())
 +          score = -make_score(mg_value(score) / 8, eg_value(score) / 8 / (1 + !pi->sliderCapture.size()));
 +
 +      for (Square s = SQ_A1; s <= SQ_MAX; ++s)
        {
-           File f = std::max(std::min(file_of(s), File(v->maxFile - file_of(s))), FILE_A);
 -          File f = edge_distance(file_of(s));
 -          psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
 -                                                      : Bonus[pc][rank_of(s)][f]);
 -          psq[~pc][flip_rank(s)] = -psq[pc][s];
++          File f = std::max(edge_distance(file_of(s), v->maxFile), FILE_A);
 +          Rank r = rank_of(s);
 +          psq[ pc][ s] = score + (  pt == PAWN  ? PBonus[std::min(r, RANK_8)][std::min(file_of(s), FILE_H)]
 +                                  : pt == KING  ? KingBonus[std::min(r, RANK_8)][std::min(f, FILE_D)] * (1 + v->capturesToHand)
 +                                  : pt <= QUEEN ? Bonus[pc][std::min(r, RANK_8)][std::min(f, FILE_D)]
 +                                  : pt == HORSE ? Bonus[KNIGHT][std::min(r, RANK_8)][std::min(f, FILE_D)]
 +                                  : isSlider    ? make_score(5, 5) * (2 * f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile - 1)
 +                                  : isPawn      ? make_score(5, 5) * (2 * f - v->maxFile)
 +                                                : make_score(10, 10) * (1 + isSlowLeaper) * (f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile / 2));
 +          if (pt == SOLDIER && r < v->soldierPromotionRank)
 +              psq[pc][s] -= score * (v->soldierPromotionRank - r) / (4 + f);
 +          if (v->enclosingDrop)
 +          {
 +              if (f == FILE_A && (r == RANK_1 || r == v->maxRank))
 +                  psq[pc][s] += make_score(1000, 1000);
 +          }
 +          psq[~pc][rank_of(s) <= v->maxRank ? flip_rank(s, v->maxRank) : s] = -psq[pc][s];
        }
 +      // pieces in pocket
 +      psq[ pc][SQ_NONE] = score + make_score(45, 10);
 +      psq[~pc][SQ_NONE] = -psq[pc][SQ_NONE];
    }
  }
  
Simple merge
diff --cc src/types.h
@@@ -656,13 -367,9 +656,9 @@@ constexpr Square flip_file(Square s, Fi
  }
  
  constexpr Piece operator~(Piece pc) {
 -  return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
 +  return Piece(pc ^ PIECE_TYPE_NB); // Swap color of piece BLACK KNIGHT -> WHITE KNIGHT
  }
  
- inline File map_to_queenside(File f) {
-   return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA
- }
  constexpr CastlingRights operator&(Color c, CastlingRights cr) {
    return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr);
  }