Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sat, 19 Sep 2020 12:49:12 +0000 (14:49 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sat, 19 Sep 2020 12:49:12 +0000 (14:49 +0200)
bench: 4665603

1  2 
Readme.md
src/Makefile
src/evaluate.cpp
src/position.cpp
src/psqt.cpp
src/search.cpp
src/search.h
src/types.h
src/uci.cpp
src/uci.h
src/ucioption.cpp

diff --cc Readme.md
Simple merge
diff --cc src/Makefile
Simple merge
@@@ -1154,8 -781,18 +1153,18 @@@ namespace 
              else
                  sf = 22 + 3 * pos.count<ALL_PIECES>(strongSide);
          }
+         else if (  pos.non_pawn_material(WHITE) == RookValueMg
+                 && pos.non_pawn_material(BLACK) == RookValueMg
+                 && !pe->passed_pawns(strongSide)
+                 && pos.count<PAWN>(strongSide) - pos.count<PAWN>(~strongSide) <= 1
+                 && bool(KingSide & pos.pieces(strongSide, PAWN)) != bool(QueenSide & pos.pieces(strongSide, PAWN))
+                 && (attacks_bb<KING>(pos.square<KING>(~strongSide)) & pos.pieces(~strongSide, PAWN)))
+             sf = 36;
+         else if (pos.count<QUEEN>() == 1)
+             sf = 37 + 3 * (pos.count<QUEEN>(WHITE) == 1 ? pos.count<BISHOP>(BLACK) + pos.count<KNIGHT>(BLACK)
+                                                         : pos.count<BISHOP>(WHITE) + pos.count<KNIGHT>(WHITE));
          else
 -            sf = std::min(sf, 36 + 7 * pos.count<PAWN>(strongSide));
 +            sf = std::min(sf, 36 + 7 * (pos.count<PAWN>(strongSide) + pos.count<SOLDIER>(strongSide)));
      }
  
      // Interpolate between the middlegame and (scaled by 'sf') endgame score
@@@ -1309,79 -770,15 +1301,79 @@@ void Position::do_move(Move m, StateInf
    }
  
    // Update castling rights if needed
 -  if (st->castlingRights && (castlingRightsMask[from] | castlingRightsMask[to]))
 +  if (type_of(m) != DROP && st->castlingRights && (castlingRightsMask[from] | castlingRightsMask[to]))
    {
-       int cr = castlingRightsMask[from] | castlingRightsMask[to];
-       k ^= Zobrist::castling[st->castlingRights & cr];
-       st->castlingRights &= ~cr;
+       k ^= Zobrist::castling[st->castlingRights];
+       st->castlingRights &= ~(castlingRightsMask[from] | castlingRightsMask[to]);
+       k ^= Zobrist::castling[st->castlingRights];
    }
  
 +  // Flip enclosed pieces
 +  st->flippedPieces = 0;
 +  if (flip_enclosed_pieces() && !is_pass(m))
 +  {
 +      // Find end of rows to be flipped
 +      if (flip_enclosed_pieces() == REVERSI)
 +      {
 +          Bitboard b = attacks_bb(us, QUEEN, to, board_bb() & ~pieces(~us)) & ~PseudoAttacks[us][KING][to] & pieces(us);
 +          while(b)
 +              st->flippedPieces |= between_bb(to, pop_lsb(&b));
 +      }
 +      else
 +      {
 +          assert(flip_enclosed_pieces() == ATAXX);
 +          st->flippedPieces = PseudoAttacks[us][KING][to] & pieces(~us);
 +      }
 +
 +      // Flip pieces
 +      Bitboard to_flip = st->flippedPieces;
 +      while(to_flip)
 +      {
 +          Square s = pop_lsb(&to_flip);
 +          Piece flipped = piece_on(s);
 +          Piece resulting = ~flipped;
 +
 +          // remove opponent's piece
 +          remove_piece(s);
 +          k ^= Zobrist::psq[flipped][s];
 +          st->materialKey ^= Zobrist::psq[flipped][pieceCount[flipped]];
 +          st->nonPawnMaterial[them] -= PieceValue[MG][flipped];
 +
 +          // add our piece
 +          put_piece(resulting, s);
 +          k ^= Zobrist::psq[resulting][s];
 +          st->materialKey ^= Zobrist::psq[resulting][pieceCount[resulting]-1];
 +          st->nonPawnMaterial[us] += PieceValue[MG][resulting];
 +      }
 +  }
 +
    // Move the piece. The tricky Chess960 castling is handled earlier
 -  if (type_of(m) != CASTLING)
 +  if (type_of(m) == DROP)
 +  {
 +      drop_piece(make_piece(us, in_hand_piece_type(m)), pc, to);
 +      st->materialKey ^= Zobrist::psq[pc][pieceCount[pc]-1];
 +      if (type_of(pc) != PAWN)
 +          st->nonPawnMaterial[us] += PieceValue[MG][pc];
 +      // Set castling rights for dropped king or rook
 +      if (castling_dropped_piece() && rank_of(to) == castling_rank(us))
 +      {
 +          if (type_of(pc) == KING && file_of(to) == FILE_E)
 +          {
 +              Bitboard castling_rooks =  pieces(us, castling_rook_piece())
 +                                       & rank_bb(castling_rank(us))
 +                                       & (file_bb(FILE_A) | file_bb(max_file()));
 +              while (castling_rooks)
 +                  set_castling_right(us, pop_lsb(&castling_rooks));
 +          }
 +          else if (type_of(pc) == castling_rook_piece())
 +          {
 +              if (   (file_of(to) == FILE_A || file_of(to) == max_file())
 +                  && piece_on(make_square(FILE_E, castling_rank(us))) == make_piece(us, KING))
 +                  set_castling_right(us, to);
 +          }
 +      }
 +  }
 +  else if (type_of(m) != CASTLING)
        move_piece(from, to);
  
    // If the moving piece is a pawn do some special extra work
diff --cc src/psqt.cpp
Simple merge
diff --cc src/search.cpp
Simple merge
diff --cc src/search.h
@@@ -91,10 -91,10 +91,10 @@@ struct LimitsType 
    }
  
    bool use_time_management() const {
-     return !(mate | movetime | depth | nodes | perft | infinite);
+     return time[WHITE] || time[BLACK];
    }
  
 -  std::vector<Move> searchmoves;
 +  std::vector<Move> searchmoves, banmoves;
    TimePoint time[COLOR_NB], inc[COLOR_NB], npmsec, movetime, startTime;
    int movestogo, depth, mate, perft, infinite;
    int64_t nodes;
diff --cc src/types.h
@@@ -778,27 -447,19 +778,32 @@@ constexpr Move reverse_move(Move m) 
  }
  
  template<MoveType T>
 -constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
 -  return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
 +constexpr Move make_gating(Square from, Square to, PieceType pt, Square gate) {
 +  return Move((gate << (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) + (pt << (2 * SQUARE_BITS + MOVE_TYPE_BITS)) + T + (from << SQUARE_BITS) + to);
 +}
 +
 +constexpr PieceType dropped_piece_type(Move m) {
 +  return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS)) & (PIECE_TYPE_NB - 1));
 +}
 +
 +constexpr PieceType in_hand_piece_type(Move m) {
 +  return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) & (PIECE_TYPE_NB - 1));
 +}
 +
 +inline bool is_ok(Move m) {
 +  return from_sq(m) != to_sq(m) || type_of(m) == PROMOTION || type_of(m) == SPECIAL; // Catch MOVE_NULL and MOVE_NONE
  }
  
 -constexpr bool is_ok(Move m) {
 -  return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
 +inline int dist(Direction d) {
 +  return std::abs(d % NORTH) < NORTH / 2 ? std::max(std::abs(d / NORTH), int(std::abs(d % NORTH)))
 +      : std::max(std::abs(d / NORTH) + 1, int(NORTH - std::abs(d % NORTH)));
  }
  
+ /// Based on a congruential pseudo random number generator
+ constexpr Key make_key(uint64_t seed) {
+   return seed * 6364136223846793005ULL + 1442695040888963407ULL;
+ }
  #endif // #ifndef TYPES_H_INCLUDED
  
  #include "tune.h" // Global visibility to tuning setup
diff --cc src/uci.cpp
@@@ -201,26 -183,28 +202,48 @@@ namespace 
           << "\nNodes/second    : " << 1000 * nodes / elapsed << endl;
    }
  
+   // The win rate model returns the probability (per mille) of winning given an eval
+   // and a game-ply. The model fits rather accurately the LTC fishtest statistics.
+   int win_rate_model(Value v, int ply) {
+      // The model captures only up to 240 plies, so limit input (and rescale)
+      double m = std::min(240, ply) / 64.0;
+      // Coefficients of a 3rd order polynomial fit based on fishtest data
+      // for two parameters needed to transform eval to the argument of a
+      // logistic function.
+      double as[] = {-8.24404295, 64.23892342, -95.73056462, 153.86478679};
+      double bs[] = {-3.37154371, 28.44489198, -56.67657741,  72.05858751};
+      double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3];
+      double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3];
+      // Transform eval to centipawns with limited range
+      double x = Utility::clamp(double(100 * v) / PawnValueEg, -1000.0, 1000.0);
+      // Return win rate in per mille (rounded to nearest)
+      return int(0.5 + 1000 / (1 + std::exp((a - x) / b)));
+   }
 +  // load() is called when engine receives the "load" command.
 +  // The function reads variant configuration files.
 +
 +  void load(istringstream& is) {
 +
 +    string token;
 +    while (is >> token)
 +        Options["VariantPath"] = token;
 +  }
 +
 +  // check() is called when engine receives the "check" command.
 +  // The function reads variant configuration files and validates them.
 +
 +  void check(istringstream& is) {
 +
 +    string token;
 +    while (is >> token)
 +        variants.parse<true>(token);
 +  }
 +
  } // namespace
  
  
@@@ -342,36 -292,26 +365,52 @@@ string UCI::value(Value v) 
  }
  
  
+ /// UCI::wdl() report WDL statistics given an evaluation and a game ply, based on
+ /// data gathered for fishtest LTC games.
+ string UCI::wdl(Value v, int ply) {
+   stringstream ss;
+   int wdl_w = win_rate_model( v, ply);
+   int wdl_l = win_rate_model(-v, ply);
+   int wdl_d = 1000 - wdl_w - wdl_l;
+   ss << " wdl " << wdl_w << " " << wdl_d << " " << wdl_l;
+   return ss.str();
+ }
  /// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.)
  
 -std::string UCI::square(Square s) {
 -  return std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) };
 +std::string UCI::square(const Position& pos, Square s) {
 +#ifdef LARGEBOARDS
 +  if (Options["Protocol"] == "usi")
 +      return rank_of(s) < RANK_10 ? std::string{ char('1' + pos.max_file() - file_of(s)), char('a' + pos.max_rank() - rank_of(s)) }
 +                                  : std::string{ char('0' + (pos.max_file() - file_of(s) + 1) / 10),
 +                                                 char('0' + (pos.max_file() - file_of(s) + 1) % 10),
 +                                                 char('a' + pos.max_rank() - rank_of(s)) };
 +  else if ((Options["Protocol"] == "xboard" || Options["Protocol"] == "ucci") && pos.max_rank() == RANK_10)
 +      return std::string{ char('a' + file_of(s)), char('0' + rank_of(s)) };
 +  else
 +      return rank_of(s) < RANK_10 ? std::string{ char('a' + file_of(s)), char('1' + (rank_of(s) % 10)) }
 +                                  : std::string{ char('a' + file_of(s)), char('0' + ((rank_of(s) + 1) / 10)),
 +                                                 char('0' + ((rank_of(s) + 1) % 10)) };
 +#else
 +  return Options["Protocol"] == "usi" ? std::string{ char('1' + pos.max_file() - file_of(s)), char('a' + pos.max_rank() - rank_of(s)) }
 +                                      : std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) };
 +#endif
 +}
 +
 +/// UCI::dropped_piece() generates a piece label string from a Move.
 +
 +string UCI::dropped_piece(const Position& pos, Move m) {
 +  assert(type_of(m) == DROP);
 +  if (dropped_piece_type(m) == pos.promoted_piece_type(in_hand_piece_type(m)))
 +      // Dropping as promoted piece
 +      return std::string{'+', pos.piece_to_char()[in_hand_piece_type(m)]};
 +  else
 +      return std::string{pos.piece_to_char()[dropped_piece_type(m)]};
  }
  
  
diff --cc src/uci.h
+++ b/src/uci.h
@@@ -76,10 -70,10 +76,11 @@@ private
  void init(OptionsMap&);
  void loop(int argc, char* argv[]);
  std::string value(Value v);
 -std::string square(Square s);
 -std::string move(Move m, bool chess960);
 +std::string square(const Position& pos, Square s);
 +std::string dropped_piece(const Position& pos, Move m);
 +std::string move(const Position& pos, Move m);
  std::string pv(const Position& pos, Depth depth, Value alpha, Value beta);
+ std::string wdl(Value v, int ply);
  Move to_move(const Position& pos, std::string& str);
  
  } // namespace UCI
Simple merge