]> git.sesse.net Git - stockfish/commitdiff
Merge remote-tracking branch 'upstream/master' into HEAD
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 3 Aug 2020 10:27:33 +0000 (12:27 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 3 Aug 2020 10:27:33 +0000 (12:27 +0200)
1  2 
src/Makefile
src/main.cpp
src/misc.cpp
src/position.cpp
src/syzygy/tbprobe.cpp
src/ucioption.cpp

diff --combined src/Makefile
index 06c95faf2cb7d552ede947f77c3b1e43aa3a7992,c3660a20fa674739009e3fe65eb9ba9a06e2d8fa..9b10a195aed31e9f992bf36469178b7c1f5f8772
@@@ -35,12 -35,14 +35,17 @@@ BINDIR = $(PREFIX)/bi
  ### Built-in benchmark for pgo-builds
  PGOBENCH = ./$(EXE) bench
  
- ### Object files
- OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
-       material.o misc.o movegen.o movepick.o pawns.o position.o psqt.o \
-       search.o thread.o timeman.o tt.o uci.o ucioption.o syzygy/tbprobe.o \
-       hashprobe.grpc.pb.o hashprobe.pb.o
- CLIOBJS = client.o hashprobe.grpc.pb.o hashprobe.pb.o uci.o
+ ### Source and object files
+ SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \
+       material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \
 -      search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp
++      search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
++      hashprobe.grpc.pb.cc hashprobe.pb.cc
++CLISRCS = client.cpp hashprobe.grpc.pb.cc hashprobe.pb.cc uci.cpp
+ OBJS = $(notdir $(SRCS:.cpp=.o))
++CLIOBJS = $(notdir $(CLISRCS:.cpp=.o))
+ VPATH = syzygy
  
  ### Establish the operating system name
  KERNEL = $(shell uname -s)
@@@ -52,7 -54,7 +57,7 @@@ endi
  ### Section 2. High-level Configuration
  ### ==========================================================================
  #
- # flag                --- Comp switch --- Description
+ # flag                --- Comp switch      --- Description
  # ----------------------------------------------------------------------------
  #
  # debug = yes/no      --- -DNDEBUG         --- Enable/Disable debug mode
  optimize = yes
  debug = no
  sanitize = no
- bits = 32
+ bits = 64
  prefetch = no
  popcnt = no
  sse = no
  pext = no
  
  ### 2.2 Architecture specific
  ifeq ($(ARCH),general-32)
        arch = any
+       bits = 32
  endif
  
  ifeq ($(ARCH),x86-32-old)
        arch = i386
+       bits = 32
  endif
  
  ifeq ($(ARCH),x86-32)
        arch = i386
+       bits = 32
        prefetch = yes
        sse = yes
  endif
  
  ifeq ($(ARCH),general-64)
        arch = any
-       bits = 64
  endif
  
  ifeq ($(ARCH),x86-64)
        arch = x86_64
-       bits = 64
        prefetch = yes
        sse = yes
  endif
  
  ifeq ($(ARCH),x86-64-modern)
        arch = x86_64
-       bits = 64
        prefetch = yes
        popcnt = yes
        sse = yes
@@@ -119,7 -120,6 +123,6 @@@ endi
  
  ifeq ($(ARCH),x86-64-bmi2)
        arch = x86_64
-       bits = 64
        prefetch = yes
        popcnt = yes
        sse = yes
@@@ -129,26 -129,31 +132,31 @@@ endi
  ifeq ($(ARCH),armv7)
        arch = armv7
        prefetch = yes
+       bits = 32
+ endif
+ ifeq ($(ARCH),armv8)
+       arch = armv8-a
+       prefetch = yes
+       popcnt = yes
  endif
  
  ifeq ($(ARCH),ppc-32)
        arch = ppc
+       bits = 32
  endif
  
  ifeq ($(ARCH),ppc-64)
        arch = ppc64
-       bits = 64
        popcnt = yes
        prefetch = yes
  endif
  
  ### ==========================================================================
- ### Section 3. Low-level configuration
+ ### Section 3. Low-level Configuration
  ### ==========================================================================
  
  ### 3.1 Selecting compiler (default = gcc)
  CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++11 $(EXTRACXXFLAGS)
  DEPENDFLAGS += -std=c++11
  LDFLAGS += $(EXTRALDFLAGS)
@@@ -160,9 -165,9 +168,9 @@@ endi
  ifeq ($(COMP),gcc)
        comp=gcc
        CXX=g++
 -      CXXFLAGS += -pedantic -Wextra -Wshadow
 +      CXXFLAGS += -pedantic -Wextra
  
-       ifeq ($(ARCH),armv7)
+       ifeq ($(ARCH),$(filter $(ARCH),armv7 armv8))
                ifeq ($(OS),Android)
                        CXXFLAGS += -m$(bits)
                        LDFLAGS += -m$(bits)
@@@ -219,7 -224,7 +227,7 @@@ ifeq ($(COMP),clang
        endif
        endif
  
-       ifeq ($(ARCH),armv7)
+       ifeq ($(ARCH),$(filter $(ARCH),armv7 armv8))
                ifeq ($(OS),Android)
                        CXXFLAGS += -m$(bits)
                        LDFLAGS += -m$(bits)
@@@ -285,7 -290,7 +293,7 @@@ endi
  ### 3.3 Optimization
  ifeq ($(optimize),yes)
  
 -      CXXFLAGS += -O3
 +      CXXFLAGS += -O3 -g
  
        ifeq ($(comp),gcc)
                ifeq ($(OS), Android)
@@@ -317,7 -322,7 +325,7 @@@ endi
  
  ### 3.6 popcnt
  ifeq ($(popcnt),yes)
-       ifeq ($(arch),ppc64)
+       ifeq ($(arch),$(filter $(arch),ppc64 armv8-a))
                CXXFLAGS += -DUSE_POPCNT
        else ifeq ($(comp),icc)
                CXXFLAGS += -msse3 -DUSE_POPCNT
@@@ -334,7 -339,7 +342,7 @@@ ifeq ($(pext),yes
        endif
  endif
  
- ### 3.8 Link Time Optimization, it works since gcc 4.5 but not on mingw under Windows.
+ ### 3.8 Link Time Optimization
  ### This is a mix of compile and link time options because the lto link phase
  ### needs access to the optimization flags.
  ifeq ($(optimize),yes)
@@@ -344,6 -349,9 +352,9 @@@ ifeq ($(debug), no
                LDFLAGS += $(CXXFLAGS)
        endif
  
+ # To use LTO and static linking on windows, the tool chain requires a recent gcc:
+ # gcc version 10.1 in msys2 or TDM-GCC version 9.2 are know to work, older might not.
+ # So, only enable it for a cross from Linux by default.
        ifeq ($(comp),mingw)
        ifeq ($(KERNEL),Linux)
                CXXFLAGS += -flto
@@@ -360,9 -368,8 +371,8 @@@ ifeq ($(OS), Android
        LDFLAGS += -fPIE -pie
  endif
  
  ### ==========================================================================
- ### Section 4. Public targets
+ ### Section 4. Public Targets
  ### ==========================================================================
  
  help:
        @echo "ppc-64                  > PPC 64-bit"
        @echo "ppc-32                  > PPC 32-bit"
        @echo "armv7                   > ARMv7 32-bit"
+       @echo "armv8                   > ARMv8 64-bit"
        @echo "general-64              > unspecified 64-bit"
        @echo "general-32              > unspecified 32-bit"
        @echo ""
        @echo ""
  
  
- .PHONY: help build profile-build strip install clean objclean profileclean help \
+ .PHONY: help build profile-build strip install clean objclean profileclean \
          config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \
          clang-profile-use clang-profile-make
  
@@@ -452,17 -460,17 +463,17 @@@ objclean
  # clean auxiliary profiling files
  profileclean:
        @rm -rf profdir
-       @rm -f bench.txt *.gcda ./syzygy/*.gcda *.gcno ./syzygy/*.gcno
+       @rm -f bench.txt *.gcda *.gcno
        @rm -f stockfish.profdata *.profraw
  
  default:
        help
  
  ### ==========================================================================
- ### Section 5. Private targets
+ ### Section 5. Private Targets
  ### ==========================================================================
  
 -all: $(EXE) .depend
 +all: $(EXE) client .depend
  
  config-sanity:
        @echo ""
        @test "$(sanitize)" = "undefined" || test "$(sanitize)" = "thread" || test "$(sanitize)" = "address" || test "$(sanitize)" = "no"
        @test "$(optimize)" = "yes" || test "$(optimize)" = "no"
        @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
-        test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"
+        test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || \
+        test "$(arch)" = "armv7" || test "$(arch)" = "armv8-a"
        @test "$(bits)" = "32" || test "$(bits)" = "64"
        @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
        @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@@@ -537,34 -546,7 +549,33 @@@ icc-profile-use
        EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
        all
  
 +### GRPC
 +
 +PROTOS_PATH = .
 +PROTOC = protoc
 +GRPC_CPP_PLUGIN = grpc_cpp_plugin
 +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
 +
 +%.grpc.pb.h %.grpc.pb.cc: %.proto
 +      $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
 +
 +# oh my
 +%.cpp: %.cc
 +      cp $< $@
 +
 +%.pb.h %.pb.cc: %.proto
 +      $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
 +
 +#LDFLAGS += -Wl,-Bstatic -Wl,-\( -lprotobuf -lgrpc++_unsecure -lgrpc_unsecure -lgrpc -lz -Wl,-\) -Wl,-Bdynamic -ldl
 +LDFLAGS += /usr/lib/x86_64-linux-gnu/libprotobuf.a /usr/lib/x86_64-linux-gnu/libgrpc++_unsecure.a /usr/lib/x86_64-linux-gnu/libgrpc_unsecure.a /usr/lib/x86_64-linux-gnu/libgrpc.a /usr/lib/x86_64-linux-gnu/libcares.a -ldl -lz
 +#LDFLAGS += /usr/lib/x86_64-linux-gnu/libprotobuf.a /usr/lib/libgrpc++_unsecure.a /usr/lib/libgrpc_unsecure.a /usr/lib/libgrpc.a /usr/lib/x86_64-linux-gnu/libcares.a -ldl -lz
 +
 +client: $(CLIOBJS)
 +      $(CXX) -o $@ $(CLIOBJS) $(LDFLAGS)
 +
 +# Other stuff
 +
  .depend:
-       -@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) $(OBJS:.o=.cc) > $@ 2> /dev/null
+       -@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
  
  -include .depend
diff --combined src/main.cpp
index dc8487e994b73098308c7eae72512de066f22ef0,fafefee2bc02bd0fb0d716749a45c9468e044a05..98cbfc978f45142b0ae8638491c478ceb2684939
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  
 +#include <deque>
  #include <iostream>
 +#include <stack>
 +#include <thread>
  
  #include "bitboard.h"
+ #include "endgame.h"
  #include "position.h"
  #include "search.h"
  #include "thread.h"
  #include "tt.h"
  #include "uci.h"
- #include "endgame.h"
  #include "syzygy/tbprobe.h"
  
 +#include <grpc/grpc.h>
 +#include <grpc++/server.h>
 +#include <grpc++/server_builder.h>
 +#include "hashprobe.h"
 +#include "hashprobe.grpc.pb.h"
 +#include "tt.h"
 +
 +using grpc::Server;
 +using grpc::ServerBuilder;
 +using grpc::ServerContext;
 +using grpc::Status;
 +using grpc::StatusCode;
 +using namespace hashprobe;
 +
 +Status HashProbeImpl::Probe(ServerContext* context,
 +                            const HashProbeRequest* request,
 +                          HashProbeResponse *response) {
 +      Position pos;
 +      StateInfo st;
 +      pos.set(request->fen(), /*isChess960=*/false, &st, Threads.main());
 +      if (!pos.pos_is_ok()) {
 +              return Status(StatusCode::INVALID_ARGUMENT, "Invalid FEN");
 +      }
 +
 +      bool invert = (pos.side_to_move() == BLACK);
 +      StateListPtr setup_states = StateListPtr(new std::deque<StateInfo>(1));
 +
 +      ProbeMove(&pos, setup_states.get(), invert, response->mutable_root());
 +
 +      MoveList<LEGAL> moves(pos);
 +      for (const ExtMove* em = moves.begin(); em != moves.end(); ++em) {
 +              HashProbeLine *line = response->add_line();
 +              FillMove(&pos, em->move, line->mutable_move());
 +              setup_states->push_back(StateInfo());
 +              pos.do_move(em->move, setup_states->back());
 +              ProbeMove(&pos, setup_states.get(), !invert, line);
 +              pos.undo_move(em->move);
 +      }
 +
 +      return Status::OK;
 +}
 +
 +void HashProbeImpl::FillMove(Position *pos, Move move, HashProbeMove* decoded) {
 +      if (!is_ok(move)) return;
 +
 +      Square from = from_sq(move);
 +      Square to = to_sq(move);
 +
 +      if (type_of(move) == CASTLING) {
 +              to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
 +      }
 +
 +      Piece moved_piece = pos->moved_piece(move);
 +      std::string pretty;
 +      if (type_of(move) == CASTLING) {
 +              if (to > from) {
 +                      pretty = "O-O";
 +              } else {
 +                      pretty = "O-O-O";
 +              }
 +      } else if (type_of(moved_piece) == PAWN) {
 +              if (type_of(move) == ENPASSANT || pos->piece_on(to) != NO_PIECE) {
 +                      // Capture.
 +                      pretty = char('a' + file_of(from));
 +                      pretty += "x";
 +              }
 +              pretty += UCI::square(to);
 +              if (type_of(move) == PROMOTION) {
 +                      pretty += "=";
 +                      pretty += " PNBRQK"[promotion_type(move)];
 +              }
 +      } else {
 +              pretty = " PNBRQK"[type_of(moved_piece)];
 +              Bitboard attackers = pos->attackers_to(to) & pos->pieces(color_of(moved_piece), type_of(moved_piece));
 +              if (more_than_one(attackers)) {
 +                      // Remove all illegal moves to disambiguate.
 +                      Bitboard att_copy = attackers;
 +                      while (att_copy) {
 +                              Square s = pop_lsb(&att_copy);
 +                              Move m = make_move(s, to);
 +                              if (!pos->pseudo_legal(m) || !pos->legal(m)) {
 +                                      attackers &= ~SquareBB[s];
 +                              }
 +                      }
 +              }
 +              if (more_than_one(attackers)) {
 +                      // Disambiguate by file if possible.
 +                      Bitboard attackers_this_file = attackers & file_bb(file_of(from));
 +                      if (attackers != attackers_this_file) {
 +                              pretty += char('a' + file_of(from));
 +                              attackers = attackers_this_file;
 +                      }
 +                      if (more_than_one(attackers)) {
 +                              // Still ambiguous, so need to disambiguate by rank.
 +                              pretty += char('1' + rank_of(from));
 +                      }
 +              }
 +
 +              if (type_of(move) == ENPASSANT || pos->piece_on(to) != NO_PIECE) {
 +                      pretty += "x";
 +              }
 +
 +              pretty += UCI::square(to);
 +      }
 +
 +      if (pos->gives_check(move)) {
 +              // Check if mate.
 +              StateInfo si;
 +              pos->do_move(move, si, true);
 +              if (MoveList<LEGAL>(*pos).size() > 0) {
 +                      pretty += "+";
 +              } else {
 +                      pretty += "#";
 +              }
 +              pos->undo_move(move);
 +      }
 +
 +      decoded->set_pretty(pretty);
 +}
 +
 +void HashProbeImpl::ProbeMove(Position* pos, std::deque<StateInfo>* setup_states, bool invert, HashProbeLine* response) {
 +      bool found;
 +      TTEntry *entry = TT.probe(pos->key(), found);
 +      response->set_found(found);
 +      if (found) {
 +              Value value = entry->value();
 +              Value eval = entry->eval();
 +              Bound bound = entry->bound();
 +
 +              if (invert) {
 +                      value = -value;
 +                      eval = -eval;
 +                      if (bound == BOUND_UPPER) {
 +                              bound = BOUND_LOWER;
 +                      } else if (bound == BOUND_LOWER) {
 +                              bound = BOUND_UPPER;
 +                      }
 +              }
 +
 +              response->set_depth(entry->depth());
 +              FillValue(eval, response->mutable_eval());
 +              if (entry->depth() > DEPTH_NONE) {
 +                      FillValue(value, response->mutable_value());
 +              }
 +              response->set_bound(HashProbeLine::ValueBound(bound));
 +
 +              // Follow the PV until we hit an illegal move.
 +              std::stack<Move> pv;
 +              std::set<Key> seen;
 +              while (found && is_ok(entry->move()) &&
 +                     pos->pseudo_legal(entry->move()) &&
 +                     pos->legal(entry->move())) {
 +                      FillMove(pos, entry->move(), response->add_pv());
 +                      if (seen.count(pos->key())) break;
 +                      pv.push(entry->move());
 +                      seen.insert(pos->key());
 +                      setup_states->push_back(StateInfo());
 +                      pos->do_move(entry->move(), setup_states->back());
 +                      entry = TT.probe(pos->key(), found);
 +              }
 +
 +              // Unroll the PV back again, so the Position object remains unchanged.
 +              while (!pv.empty()) {
 +                      pos->undo_move(pv.top());
 +                      pv.pop();
 +              }
 +      }
 +}
 +
 +void HashProbeImpl::FillValue(Value value, HashProbeScore* score) {
 +      if (abs(value) < VALUE_MATE - MAX_PLY) {
 +              score->set_score_type(HashProbeScore::SCORE_CP);
 +              score->set_score_cp(value * 100 / PawnValueEg);
 +      } else {
 +              score->set_score_type(HashProbeScore::SCORE_MATE);
 +              score->set_score_mate((value > 0 ? VALUE_MATE - value + 1 : -VALUE_MATE - value) / 2);
 +      }
 +}
 +
 +HashProbeThread::HashProbeThread(const std::string &server_address) {
 +      builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
 +      builder.RegisterService(&service);
 +      server = std::move(builder.BuildAndStart());
 +      std::cout << "Server listening on " << server_address << std::endl;
 +      std::thread([this]{ server->Wait(); }).detach();
 +}
 +
 +void HashProbeThread::Shutdown() {
 +      server->Shutdown();
 +}
 +
  namespace PSQT {
    void init();
  }
@@@ -232,12 -38,13 +232,13 @@@ int main(int argc, char* argv[]) 
    std::cout << engine_info() << std::endl;
  
    UCI::init(Options);
+   Tune::init();
    PSQT::init();
    Bitboards::init();
    Position::init();
    Bitbases::init();
    Endgames::init();
-   Threads.set(Options["Threads"]);
+   Threads.set(size_t(Options["Threads"]));
    Search::clear(); // After threads are up
  
    UCI::loop(argc, argv);
diff --combined src/misc.cpp
index 6ed0bdd0d9108a5633fde87664559bac1f2c40e3,2bc05c5b736556cd496fdfac94a67f34f06407be..d9c0679bf4e3704de73bcd99c94ffe54db39351a
@@@ -47,6 -47,11 +47,11 @@@ typedef bool(*fun3_t)(HANDLE, CONST GRO
  #include <sstream>
  #include <vector>
  
+ #if defined(__linux__) && !defined(__ANDROID__)
+ #include <stdlib.h>
+ #include <sys/mman.h>
+ #endif
  #include "misc.h"
  #include "thread.h"
  
@@@ -56,7 -61,7 +61,7 @@@ namespace 
  
  /// Version number. If Version is left empty, then compile date in the format
  /// DD-MM-YY and show in engine_info.
- const string Version = "11";
+ const string Version = "";
  
  /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
  /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
@@@ -140,7 -145,6 +145,7 @@@ const string engine_info(bool to_uci) 
    {
        date >> month >> day >> year;
        ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
 +      ss << "-asn";
    }
  
    ss << (Is64Bit ? " 64" : "")
  
  const std::string compiler_info() {
  
-   #define STRINGIFY2(x) #x
-   #define STRINGIFY(x) STRINGIFY2(x)
-   #define VER_STRING(major, minor, patch) STRINGIFY(major) "." STRINGIFY(minor) "." STRINGIFY(patch)
+   #define stringify2(x) #x
+   #define stringify(x) stringify2(x)
+   #define make_version_string(major, minor, patch) stringify(major) "." stringify(minor) "." stringify(patch)
  
  /// Predefined macros hell:
  ///
  
    #ifdef __clang__
       compiler += "clang++ ";
-      compiler += VER_STRING(__clang_major__, __clang_minor__, __clang_patchlevel__);
+      compiler += make_version_string(__clang_major__, __clang_minor__, __clang_patchlevel__);
    #elif __INTEL_COMPILER
       compiler += "Intel compiler ";
       compiler += "(version ";
-      compiler += STRINGIFY(__INTEL_COMPILER) " update " STRINGIFY(__INTEL_COMPILER_UPDATE);
+      compiler += stringify(__INTEL_COMPILER) " update " stringify(__INTEL_COMPILER_UPDATE);
       compiler += ")";
    #elif _MSC_VER
       compiler += "MSVC ";
       compiler += "(version ";
-      compiler += STRINGIFY(_MSC_FULL_VER) "." STRINGIFY(_MSC_BUILD);
+      compiler += stringify(_MSC_FULL_VER) "." stringify(_MSC_BUILD);
       compiler += ")";
    #elif __GNUC__
       compiler += "g++ (GNUC) ";
-      compiler += VER_STRING(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+      compiler += make_version_string(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
    #else
       compiler += "Unknown compiler ";
       compiler += "(unknown version)";
    #endif
  
-   #if defined(__APPLE__) 
+   #if defined(__APPLE__)
       compiler += " on Apple";
    #elif defined(__CYGWIN__)
       compiler += " on Cygwin";
@@@ -289,6 -293,133 +294,133 @@@ void prefetch(void* addr) 
  
  #endif
  
+ /// aligned_ttmem_alloc() will return suitably aligned memory, and if possible use large pages.
+ /// The returned pointer is the aligned one, while the mem argument is the one that needs
+ /// to be passed to free. With c++17 some of this functionality could be simplified.
+ #if defined(__linux__) && !defined(__ANDROID__)
+ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) {
+   constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page sizes
+   size_t size = ((allocSize + alignment - 1) / alignment) * alignment; // multiple of alignment
+   if (posix_memalign(&mem, alignment, size))
+      mem = nullptr;
+   madvise(mem, allocSize, MADV_HUGEPAGE);
+   return mem;
+ }
+ #elif defined(_WIN64)
+ static void* aligned_ttmem_alloc_large_pages(size_t allocSize) {
+   HANDLE hProcessToken { };
+   LUID luid { };
+   void* mem = nullptr;
+   const size_t largePageSize = GetLargePageMinimum();
+   if (!largePageSize)
+       return nullptr;
+   // We need SeLockMemoryPrivilege, so try to enable it for the process
+   if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken))
+       return nullptr;
+   if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
+   {
+       TOKEN_PRIVILEGES tp { };
+       TOKEN_PRIVILEGES prevTp { };
+       DWORD prevTpLen = 0;
+       tp.PrivilegeCount = 1;
+       tp.Privileges[0].Luid = luid;
+       tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+       // Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds,
+       // we still need to query GetLastError() to ensure that the privileges were actually obtained.
+       if (AdjustTokenPrivileges(
+               hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) &&
+           GetLastError() == ERROR_SUCCESS)
+       {
+           // Round up size to full pages and allocate
+           allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
+           mem = VirtualAlloc(
+               NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+           // Privilege no longer needed, restore previous state
+           AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL);
+       }
+   }
+   CloseHandle(hProcessToken);
+   return mem;
+ }
+ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) {
+   static bool firstCall = true;
+   // Try to allocate large pages
+   mem = aligned_ttmem_alloc_large_pages(allocSize);
+   // Suppress info strings on the first call. The first call occurs before 'uci'
+   // is received and in that case this output confuses some GUIs.
+   if (!firstCall)
+   {
+       if (mem)
+           sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl;
+       else
+           sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl;
+   }
+   firstCall = false;
+   // Fall back to regular, page aligned, allocation if necessary
+   if (!mem)
+       mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+   return mem;
+ }
+ #else
+ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) {
+   constexpr size_t alignment = 64; // assumed cache line size
+   size_t size = allocSize + alignment - 1; // allocate some extra space
+   mem = malloc(size);
+   void* ret = reinterpret_cast<void*>((uintptr_t(mem) + alignment - 1) & ~uintptr_t(alignment - 1));
+   return ret;
+ }
+ #endif
+ /// aligned_ttmem_free() will free the previously allocated ttmem
+ #if defined(_WIN64)
+ void aligned_ttmem_free(void* mem) {
+   if (mem && !VirtualFree(mem, 0, MEM_RELEASE))
+   {
+       DWORD err = GetLastError();
+       std::cerr << "Failed to free transposition table. Error code: 0x" <<
+           std::hex << err << std::dec << std::endl;
+       exit(EXIT_FAILURE);
+   }
+ }
+ #else
+ void aligned_ttmem_free(void *mem) {
+   free(mem);
+ }
+ #endif
  namespace WinProcGroup {
  
  #ifndef _WIN32
diff --combined src/position.cpp
index 09a574a5c23d901f4d10f73d9f04463235459422,396bff5f545c0f92bde33d12f23810e9d6d98745..57f731d4f257b9cd26deb0842042423bc7953ab0
@@@ -64,10 -64,11 +64,11 @@@ std::ostream& operator<<(std::ostream& 
        for (File f = FILE_A; f <= FILE_H; ++f)
            os << " | " << PieceToChar[pos.piece_on(make_square(f, r))];
  
-       os << " |\n +---+---+---+---+---+---+---+---+\n";
+       os << " | " << (1 + r) << "\n +---+---+---+---+---+---+---+---+\n";
    }
  
-   os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
+   os << "   a   b   c   d   e   f   g   h\n"
+      << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
       << std::setfill('0') << std::setw(16) << pos.key()
       << std::setfill(' ') << std::dec << "\nCheckers: ";
  
@@@ -104,8 -105,7 +105,7 @@@ Key cuckoo[8192]
  Move cuckooMove[8192];
  
  
- /// Position::init() initializes at startup the various arrays used to compute
- /// hash keys.
+ /// Position::init() initializes at startup the various arrays used to compute hash keys
  
  void Position::init() {
  
        Zobrist::enpassant[f] = rng.rand<Key>();
  
    for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr)
-   {
-       Zobrist::castling[cr] = 0;
-       Bitboard b = cr;
-       while (b)
-       {
-           Key k = Zobrist::castling[1ULL << pop_lsb(&b)];
-           Zobrist::castling[cr] ^= k ? k : rng.rand<Key>();
-       }
-   }
+       Zobrist::castling[cr] = rng.rand<Key>();
  
    Zobrist::side = rng.rand<Key>();
    Zobrist::noPawns = rng.rand<Key>();
    for (Piece pc : Pieces)
        for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
            for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
-               if (PseudoAttacks[type_of(pc)][s1] & s2)
+               if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2))
                {
                    Move move = make_move(s1, s2);
                    Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
@@@ -186,9 -178,9 +178,9 @@@ Position& Position::set(const string& f
  
     4) En passant target square (in algebraic notation). If there's no en passant
        target square, this is "-". If a pawn has just made a 2-square move, this
-       is the position "behind" the pawn. This is recorded only if there is a pawn
-       in position to make an en passant capture, and if there really is a pawn
-       that might have advanced two squares.
+       is the position "behind" the pawn. Following X-FEN standard, this is recorded only
+       if there is a pawn in position to make an en passant capture, and if there really
+       is a pawn that might have advanced two squares.
  
     5) Halfmove clock. This is the number of halfmoves since the last pawn advance
        or capture. This is used to determine if a draw can be claimed under the
        set_castling_right(c, rsq);
    }
  
-   // 4. En passant square. Ignore if no pawn capture is possible
+   // 4. En passant square.
+   // Ignore if square is invalid or not on side to move relative rank 6.
+   bool enpassant = false;
    if (   ((ss >> col) && (col >= 'a' && col <= 'h'))
-       && ((ss >> row) && (row == '3' || row == '6')))
+       && ((ss >> row) && (row == (sideToMove == WHITE ? '6' : '3'))))
    {
        st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
  
-       if (   !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))
-           || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove))))
-           st->epSquare = SQ_NONE;
+       // En passant square will be considered only if
+       // a) side to move have a pawn threatening epSquare
+       // b) there is an enemy pawn in front of epSquare
+       // c) there is no piece on epSquare or behind epSquare
+       enpassant = pawn_attacks_bb(~sideToMove, st->epSquare) & pieces(sideToMove, PAWN)
+                && (pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))
+                && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove))));
    }
-   else
+   if (!enpassant)
        st->epSquare = SQ_NONE;
  
    // 5-6. Halfmove clock and fullmove number
    thisThread = th;
    set_state(st);
  
 -  assert(pos_is_ok());
 -
    return *this;
  }
  
@@@ -304,7 -306,7 +304,7 @@@ void Position::set_castling_right(Colo
    Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1);
  
    castlingPath[cr] =   (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto)
-                     & ~(square_bb(kfrom) | rfrom);
+                     & ~(kfrom | rfrom);
  }
  
  
@@@ -317,10 -319,10 +317,10 @@@ void Position::set_check_info(StateInfo
  
    Square ksq = square<KING>(~sideToMove);
  
-   si->checkSquares[PAWN]   = attacks_from<PAWN>(ksq, ~sideToMove);
-   si->checkSquares[KNIGHT] = attacks_from<KNIGHT>(ksq);
-   si->checkSquares[BISHOP] = attacks_from<BISHOP>(ksq);
-   si->checkSquares[ROOK]   = attacks_from<ROOK>(ksq);
+   si->checkSquares[PAWN]   = pawn_attacks_bb(~sideToMove, ksq);
+   si->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
+   si->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
+   si->checkSquares[ROOK]   = attacks_bb<ROOK>(ksq, pieces());
    si->checkSquares[QUEEN]  = si->checkSquares[BISHOP] | si->checkSquares[ROOK];
    si->checkSquares[KING]   = 0;
  }
@@@ -373,11 -375,13 +373,13 @@@ void Position::set_state(StateInfo* si
  
  Position& Position::set(const string& code, Color c, StateInfo* si) {
  
-   assert(code.length() > 0 && code.length() < 8);
    assert(code[0] == 'K');
  
    string sides[] = { code.substr(code.find('K', 1)),      // Weak
-                      code.substr(0, code.find('K', 1)) }; // Strong
+                      code.substr(0, std::min(code.find('v'), code.find('K', 1))) }; // Strong
+   assert(sides[0].length() > 0 && sides[0].length() < 8);
+   assert(sides[1].length() > 0 && sides[1].length() < 8);
  
    std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
  
@@@ -451,8 -455,8 +453,8 @@@ Bitboard Position::slider_blockers(Bitb
    pinners = 0;
  
    // Snipers are sliders that attack 's' when a piece and other snipers are removed
-   Bitboard snipers = (  (PseudoAttacks[  ROOK][s] & pieces(QUEEN, ROOK))
-                       | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
+   Bitboard snipers = (  (attacks_bb<  ROOK>(s) & pieces(QUEEN, ROOK))
+                       | (attacks_bb<BISHOP>(s) & pieces(QUEEN, BISHOP))) & sliders;
    Bitboard occupancy = pieces() ^ snipers;
  
    while (snipers)
  
  Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
  
-   return  (attacks_from<PAWN>(s, BLACK)    & pieces(WHITE, PAWN))
-         | (attacks_from<PAWN>(s, WHITE)    & pieces(BLACK, PAWN))
-         | (attacks_from<KNIGHT>(s)         & pieces(KNIGHT))
+   return  (pawn_attacks_bb(BLACK, s)       & pieces(WHITE, PAWN))
+         | (pawn_attacks_bb(WHITE, s)       & pieces(BLACK, PAWN))
+         | (attacks_bb<KNIGHT>(s)           & pieces(KNIGHT))
          | (attacks_bb<  ROOK>(s, occupied) & pieces(  ROOK, QUEEN))
          | (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
-         | (attacks_from<KING>(s)           & pieces(KING));
+         | (attacks_bb<KING>(s)             & pieces(KING));
  }
  
  
@@@ -584,15 -588,15 +586,15 @@@ bool Position::pseudo_legal(const Move 
        if ((Rank8BB | Rank1BB) & to)
            return false;
  
-       if (   !(attacks_from<PAWN>(from, us) & pieces(~us) & to) // Not a capture
+       if (   !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture
            && !((from + pawn_push(us) == to) && empty(to))       // Not a single push
            && !(   (from + 2 * pawn_push(us) == to)              // Not a double push
-                && (rank_of(from) == relative_rank(us, RANK_2))
+                && (relative_rank(us, from) == RANK_2)
                 && empty(to)
                 && empty(to - pawn_push(us))))
            return false;
    }
-   else if (!(attacks_from(type_of(pc), from) & to))
+   else if (!(attacks_bb(type_of(pc), from, pieces()) & to))
        return false;
  
    // Evasions generator already takes care to avoid some kind of illegal moves
@@@ -631,11 -635,11 +633,11 @@@ bool Position::gives_check(Move m) cons
    Square to = to_sq(m);
  
    // Is there a direct check?
-   if (st->checkSquares[type_of(piece_on(from))] & to)
+   if (check_squares(type_of(piece_on(from))) & to)
        return true;
  
    // Is there a discovered check?
-   if (   (st->blockersForKing[~sideToMove] & from)
+   if (   (blockers_for_king(~sideToMove) & from)
        && !aligned(from, to, square<KING>(~sideToMove)))
        return true;
  
    case CASTLING:
    {
        Square kfrom = from;
-       Square rfrom = to; // Castling is encoded as 'King captures the rook'
+       Square rfrom = to; // Castling is encoded as 'king captures the rook'
        Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1);
        Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1);
  
-       return   (PseudoAttacks[ROOK][rto] & square<KING>(~sideToMove))
+       return   (attacks_bb<ROOK>(rto) & square<KING>(~sideToMove))
              && (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square<KING>(~sideToMove));
    }
    default:
@@@ -741,8 -745,6 +743,6 @@@ void Position::do_move(Move m, StateInf
                assert(relative_rank(us, to) == RANK_6);
                assert(piece_on(to) == NO_PIECE);
                assert(piece_on(capsq) == make_piece(them, PAWN));
-               board[capsq] = NO_PIECE; // Not done by remove_piece()
            }
  
            st->pawnKey ^= Zobrist::psq[captured][capsq];
            st->nonPawnMaterial[them] -= PieceValue[MG][captured];
  
        // Update board and piece lists
-       remove_piece(captured, capsq);
+       remove_piece(capsq);
+       if (type_of(m) == ENPASSANT)
+           board[capsq] = NO_PIECE;
  
        // Update material hash key and prefetch access to materialTable
        k ^= Zobrist::psq[captured][capsq];
    // Update castling rights if needed
    if (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];
    }
  
    // Move the piece. The tricky Chess960 castling is handled earlier
    if (type_of(m) != CASTLING)
-       move_piece(pc, from, to);
+       move_piece(from, to);
  
    // If the moving piece is a pawn do some special extra work
    if (type_of(pc) == PAWN)
    {
        // Set en-passant square if the moved pawn can be captured
        if (   (int(to) ^ int(from)) == 16
-           && (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
+           && (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)))
        {
            st->epSquare = to - pawn_push(us);
            k ^= Zobrist::enpassant[file_of(st->epSquare)];
            assert(relative_rank(us, to) == RANK_8);
            assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
  
-           remove_piece(pc, to);
+           remove_piece(to);
            put_piece(promotion, to);
  
            // Update hash keys
@@@ -882,7 -887,7 +885,7 @@@ void Position::undo_move(Move m) 
        assert(type_of(pc) == promotion_type(m));
        assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN);
  
-       remove_piece(pc, to);
+       remove_piece(to);
        pc = make_piece(us, PAWN);
        put_piece(pc, to);
    }
    }
    else
    {
-       move_piece(pc, to, from); // Put the piece back at the source square
+       move_piece(to, from); // Put the piece back at the source square
  
        if (st->capturedPiece)
        {
@@@ -934,9 -939,9 +937,9 @@@ void Position::do_castling(Color us, Sq
    to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
  
    // Remove both pieces first since squares could overlap in Chess960
-   remove_piece(make_piece(us, KING), Do ? from : to);
-   remove_piece(make_piece(us, ROOK), Do ? rfrom : rto);
-   board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
+   remove_piece(Do ? from : to);
+   remove_piece(Do ? rfrom : rto);
+   board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do this for us
    put_piece(make_piece(us, KING), Do ? to : from);
    put_piece(make_piece(us, ROOK), Do ? rto : rfrom);
  }
@@@ -1106,6 -1111,7 +1109,7 @@@ bool Position::see_ge(Move m, Value thr
    return bool(res);
  }
  
  /// Position::is_draw() tests whether the position is drawn by 50-move rule
  /// or by repetition. It does not detect stalemates.
  
@@@ -1116,10 -1122,7 +1120,7 @@@ bool Position::is_draw(int ply) const 
  
    // Return a draw score if a position repeats once earlier but strictly
    // after the root, or repeats twice before or at the root.
-   if (st->repetition && st->repetition < ply)
-       return true;
-   return false;
+   return st->repetition && st->repetition < ply;
  }
  
  
diff --combined src/syzygy/tbprobe.cpp
index b9a3359511ae53ecd1d988331d6ac7f317f3c879,95d58945d72449adfbfc8f7c6def1f10ca8db546..764574f75e2976758bbeb2fc415afe3b47978840
@@@ -60,13 -60,12 +60,12 @@@ namespace 
  constexpr int TBPIECES = 7; // Max number of supported pieces
  
  enum { BigEndian, LittleEndian };
- enum TBType { KEY, WDL, DTZ }; // Used as template parameter
+ enum TBType { WDL, DTZ }; // Used as template parameter
  
  // Each table has a set of flags: all of them refer to DTZ tables, the last one to WDL tables
  enum TBFlag { STM = 1, Mapped = 2, WinPlies = 4, LossPlies = 8, Wide = 16, SingleValue = 128 };
  
  inline WDLScore operator-(WDLScore d) { return WDLScore(-int(d)); }
- inline Square operator^=(Square& s, int i) { return s = Square(int(s) ^ i); }
  inline Square operator^(Square s, int i) { return Square(int(s) ^ i); }
  
  const std::string PieceToChar = " PNBRQK  pnbrqk";
@@@ -76,7 -75,7 +75,7 @@@ int MapB1H1H7[SQUARE_NB]
  int MapA1D1D4[SQUARE_NB];
  int MapKK[10][SQUARE_NB]; // [MapA1D1D4][SQUARE_NB]
  
 -int Binomial[6][SQUARE_NB];    // [k][n] k elements from a set of n elements
 +int Binomial[7][SQUARE_NB];    // [k][n] k elements from a set of n elements
  int LeadPawnIdx[6][SQUARE_NB]; // [leadPawnsCnt][SQUARE_NB]
  int LeadPawnsSize[6][4];       // [leadPawnsCnt][FILE_A..FILE_D]
  
@@@ -404,7 -403,17 +403,17 @@@ TBTable<DTZ>::TBTable(const TBTable<WDL
  // at init time, accessed at probe time.
  class TBTables {
  
-     typedef std::tuple<Key, TBTable<WDL>*, TBTable<DTZ>*> Entry;
+     struct Entry
+     {
+         Key key;
+         TBTable<WDL>* wdl;
+         TBTable<DTZ>* dtz;
+         template <TBType Type>
+         TBTable<Type>* get() const {
+             return (TBTable<Type>*)(Type == WDL ? (void*)wdl : (void*)dtz);
+         }
+     };
  
      static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb
      static constexpr int Overflow = 1;  // Number of elements allowed to map to the last bucket
  
      void insert(Key key, TBTable<WDL>* wdl, TBTable<DTZ>* dtz) {
          uint32_t homeBucket = (uint32_t)key & (Size - 1);
-         Entry entry = std::make_tuple(key, wdl, dtz);
+         Entry entry{ key, wdl, dtz };
  
          // Ensure last element is empty to avoid overflow when looking up
          for (uint32_t bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket) {
-             Key otherKey = std::get<KEY>(hashTable[bucket]);
-             if (otherKey == key || !std::get<WDL>(hashTable[bucket])) {
+             Key otherKey = hashTable[bucket].key;
+             if (otherKey == key || !hashTable[bucket].get<WDL>()) {
                  hashTable[bucket] = entry;
                  return;
              }
              // insert here and search for a new spot for the other element instead.
              uint32_t otherHomeBucket = (uint32_t)otherKey & (Size - 1);
              if (otherHomeBucket > homeBucket) {
-                 swap(entry, hashTable[bucket]);
+                 std::swap(entry, hashTable[bucket]);
                  key = otherKey;
                  homeBucket = otherHomeBucket;
              }
@@@ -443,8 -452,8 +452,8 @@@ public
      template<TBType Type>
      TBTable<Type>* get(Key key) {
          for (const Entry* entry = &hashTable[(uint32_t)key & (Size - 1)]; ; ++entry) {
-             if (std::get<KEY>(*entry) == key || !std::get<Type>(*entry))
-                 return std::get<Type>(*entry);
+             if (entry->key == key || !entry->get<Type>())
+                 return entry->get<Type>();
          }
      }
  
@@@ -521,7 -530,7 +530,7 @@@ int decompress_pairs(PairsData* d, uint
      //       I(k) = k * d->span + d->span / 2      (1)
  
      // First step is to get the 'k' of the I(k) nearest to our idx, using definition (1)
-     uint32_t k = idx / d->span;
+     uint32_t k = uint32_t(idx / d->span);
  
      // Then we read the corresponding SparseIndex[] entry
      uint32_t block = number<uint32_t, LittleEndian>(&d->sparseIndex[k].block);
          // All the symbols of a given length are consecutive integers (numerical
          // sequence property), so we can compute the offset of our symbol of
          // length len, stored at the beginning of buf64.
-         sym = (buf64 - d->base64[len]) >> (64 - len - d->minSymLen);
+         sym = Sym((buf64 - d->base64[len]) >> (64 - len - d->minSymLen));
  
          // Now add the value of the lowest symbol of length len to get our symbol
          sym += number<Sym, LittleEndian>(&d->lowestSym[len]);
@@@ -706,7 -715,7 +715,7 @@@ Ret do_probe_table(const Position& pos
  
          std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp));
  
-         tbFile = map_to_queenside(file_of(squares[0]));
+         tbFile = File(edge_distance(file_of(squares[0])));
      }
  
      // DTZ tables are one-sided, i.e. they store positions only for white to
      // the triangle A1-D1-D4.
      if (file_of(squares[0]) > FILE_D)
          for (int i = 0; i < size; ++i)
-             squares[i] ^= 7; // Horizontal flip: SQ_H1 -> SQ_A1
+             squares[i] = flip_file(squares[i]);
  
      // Encode leading pawns starting with the one with minimum MapPawns[] and
      // proceeding in ascending order.
      // piece is below RANK_5.
      if (rank_of(squares[0]) > RANK_4)
          for (int i = 0; i < size; ++i)
-             squares[i] ^= SQ_A8; // Vertical flip: SQ_A8 -> SQ_A1
+             squares[i] = flip_rank(squares[i]);
  
      // Look for the first piece of the leading group not on the A1-D4 diagonal
      // and ensure it is mapped below the diagonal.
          if (!off_A1H8(squares[i]))
              continue;
  
-         if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C3
+         if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C1
              for (int j = i; j < size; ++j)
                  squares[j] = Square(((squares[j] >> 3) | (squares[j] << 3)) & 63);
          break;
@@@ -975,7 -984,7 +984,7 @@@ uint8_t* set_sizes(PairsData* d, uint8_
  
      d->sizeofBlock = 1ULL << *data++;
      d->span = 1ULL << *data++;
-     d->sparseIndexSize = (tbSize + d->span - 1) / d->span; // Round up
+     d->sparseIndexSize = size_t((tbSize + d->span - 1) / d->span); // Round up
      auto padding = number<uint8_t, LittleEndian>(data++);
      d->blocksNum = number<uint32_t, LittleEndian>(data); data += sizeof(uint32_t);
      d->blockLengthSize = d->blocksNum + padding; // Padded to ensure SparseIndex[]
@@@ -1191,7 -1200,7 +1200,7 @@@ WDLScore search(Position& pos, ProbeSta
      auto moveList = MoveList<LEGAL>(pos);
      size_t totalCount = moveList.size(), moveCount = 0;
  
-     for (const Move& move : moveList)
+     for (const Move move : moveList)
      {
          if (   !pos.capture(move)
              && (!CheckZeroingMoves || type_of(pos.moved_piece(move)) != PAWN))
@@@ -1311,7 -1320,7 +1320,7 @@@ void Tablebases::init(const std::string
      Binomial[0][0] = 1;
  
      for (int n = 1; n < 64; n++) // Squares
 -        for (int k = 0; k < 6 && k <= n; ++k) // Pieces
 +        for (int k = 0; k < 7 && k <= n; ++k) // Pieces
              Binomial[k][n] =  (k > 0 ? Binomial[k - 1][n - 1] : 0)
                              + (k < n ? Binomial[k    ][n - 1] : 0);
  
                  if (leadPawnsCnt == 1)
                  {
                      MapPawns[sq] = availableSquares--;
-                     MapPawns[sq ^ 7] = availableSquares--; // Horizontal flip
+                     MapPawns[flip_file(sq)] = availableSquares--;
                  }
                  LeadPawnIdx[leadPawnsCnt][sq] = idx;
                  idx += Binomial[leadPawnsCnt - 1][MapPawns[sq]];
              LeadPawnsSize[leadPawnsCnt][f] = idx;
          }
  
-     // Add entries in TB tables if the corresponding ".rtbw" file exsists
+     // Add entries in TB tables if the corresponding ".rtbw" file exists
      for (PieceType p1 = PAWN; p1 < KING; ++p1) {
          TBTables.add({KING, p1, KING});
  
@@@ -1460,7 -1469,7 +1469,7 @@@ int Tablebases::probe_dtz(Position& pos
      StateInfo st;
      int minDTZ = 0xFFFF;
  
-     for (const Move& move : MoveList<LEGAL>(pos))
+     for (const Move move : MoveList<LEGAL>(pos))
      {
          bool zeroing = pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN;
  
diff --combined src/ucioption.cpp
index 78e3d46547c55435222e9f6fad6828fb0ed9a6f7,ef54ef4e5be50f9fb2b0c535a2546815ea407b20..5982f26a14832c6817f0a303a2b7022b5dfc1abc
  #include "thread.h"
  #include "tt.h"
  #include "uci.h"
 +#include "hashprobe.h"
  #include "syzygy/tbprobe.h"
  
  using std::string;
  
  UCI::OptionsMap Options; // Global object
 +std::unique_ptr<HashProbeThread> hash_probe_thread;
  
  namespace UCI {
  
  /// 'On change' actions, triggered by an option's value change
  void on_clear_hash(const Option&) { Search::clear(); }
- void on_hash_size(const Option& o) { TT.resize(o); }
+ void on_hash_size(const Option& o) { TT.resize(size_t(o)); }
  void on_logger(const Option& o) { start_logger(o); }
- void on_threads(const Option& o) { Threads.set(o); }
+ void on_threads(const Option& o) { Threads.set(size_t(o)); }
  void on_tb_path(const Option& o) { Tablebases::init(o); }
 -
 +void on_rpc_server_address(const Option& o) {
 +      if (hash_probe_thread) {
 +              hash_probe_thread->Shutdown();
 +      }
 +      std::string addr = o;
 +      hash_probe_thread.reset(new HashProbeThread(addr));
 +}
  
  /// Our case insensitive less() function as required by UCI protocol
  bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
  }
  
  
- /// init() initializes the UCI options to their hard-coded default values
+ /// UCI::init() initializes the UCI options to their hard-coded default values
  
  void init(OptionsMap& o) {
  
-   // at most 2^32 clusters.
-   constexpr int MaxHashMB = Is64Bit ? 131072 : 2048;
+   constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
  
    o["Debug Log File"]        << Option("", on_logger);
    o["Contempt"]              << Option(24, -100, 100);
    o["Ponder"]                << Option(false);
    o["MultiPV"]               << Option(1, 1, 500);
    o["Skill Level"]           << Option(20, 0, 20);
-   o["Move Overhead"]         << Option(30, 0, 5000);
-   o["Minimum Thinking Time"] << Option(20, 0, 5000);
-   o["Slow Mover"]            << Option(84, 10, 1000);
+   o["Move Overhead"]         << Option(10, 0, 5000);
+   o["Slow Mover"]            << Option(100, 10, 1000);
    o["nodestime"]             << Option(0, 0, 10000);
    o["UCI_Chess960"]          << Option(false);
    o["UCI_AnalyseMode"]       << Option(false);
    o["UCI_LimitStrength"]     << Option(false);
    o["UCI_Elo"]               << Option(1350, 1350, 2850);
+   o["UCI_ShowWDL"]           << Option(false);
    o["SyzygyPath"]            << Option("<empty>", on_tb_path);
    o["SyzygyProbeDepth"]      << Option(1, 1, 100);
    o["Syzygy50MoveRule"]      << Option(true);
    o["SyzygyProbeLimit"]      << Option(7, 0, 7);
 +  o["RPCServerAddress"]      << Option("<empty>", on_rpc_server_address);
  }