diff --git a/DroidFish/jni/stockfish/Android.mk b/DroidFish/jni/stockfish/Android.mk
index 3b5a175..c7b8595 100644
--- a/DroidFish/jni/stockfish/Android.mk
+++ b/DroidFish/jni/stockfish/Android.mk
@@ -4,10 +4,10 @@ include $(CLEAR_VARS)
LOCAL_MODULE := stockfish
LOCAL_SRC_FILES := \
- benchmark.cpp book.cpp main.cpp movegen.cpp pawns.cpp thread.cpp uci.cpp \
+ benchmark.cpp main.cpp movegen.cpp pawns.cpp thread.cpp uci.cpp \
bitbase.cpp endgame.cpp material.cpp movepick.cpp position.cpp timeman.cpp ucioption.cpp \
- bitboard.cpp evaluate.cpp misc.cpp notation.cpp search.cpp tt.cpp
+ bitboard.cpp evaluate.cpp misc.cpp notation.cpp search.cpp tt.cpp tbprobe.cpp
-LOCAL_CFLAGS := -DNO_PREFETCH=1 -O2
+LOCAL_CFLAGS := -std=c++11 -O2
include $(BUILD_EXECUTABLE)
diff --git a/DroidFish/jni/stockfish/benchmark.cpp b/DroidFish/jni/stockfish/benchmark.cpp
index 2f943c4..3161c4c 100644
--- a/DroidFish/jni/stockfish/benchmark.cpp
+++ b/DroidFish/jni/stockfish/benchmark.cpp
@@ -17,6 +17,7 @@
along with this program. If not, see .
*/
+#include
#include
#include
#include
@@ -81,7 +82,7 @@ void benchmark(const Position& current, istream& is) {
vector fens;
// Assign default values to missing arguments
- string ttSize = (is >> token) ? token : "32";
+ string ttSize = (is >> token) ? token : "16";
string threads = (is >> token) ? token : "1";
string limit = (is >> token) ? token : "13";
string fenFile = (is >> token) ? token : "default";
@@ -137,22 +138,9 @@ void benchmark(const Position& current, istream& is) {
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
- if (limitType == "divide")
- for (MoveList it(pos); *it; ++it)
- {
- StateInfo si;
- pos.do_move(*it, si);
- uint64_t cnt = limits.depth > 1 ? Search::perft(pos, (limits.depth - 1) * ONE_PLY) : 1;
- pos.undo_move(*it);
- cerr << move_to_uci(*it, pos.is_chess960()) << ": " << cnt << endl;
- nodes += cnt;
- }
- else if (limitType == "perft")
- {
- uint64_t cnt = Search::perft(pos, limits.depth * ONE_PLY);
- cerr << "\nPerft " << limits.depth << " leaf nodes: " << cnt << endl;
- nodes += cnt;
- }
+ if (limitType == "perft")
+ nodes += Search::perft(pos, limits.depth * ONE_PLY);
+
else
{
Threads.start_thinking(pos, limits, st);
@@ -161,7 +149,7 @@ void benchmark(const Position& current, istream& is) {
}
}
- elapsed = Time::now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
+ elapsed = std::max(Time::now() - elapsed, Time::point(1)); // Avoid a 'divide by zero'
dbg_print(); // Just before to exit
diff --git a/DroidFish/jni/stockfish/bitbase.cpp b/DroidFish/jni/stockfish/bitbase.cpp
index 6094f50..0f274c8 100644
--- a/DroidFish/jni/stockfish/bitbase.cpp
+++ b/DroidFish/jni/stockfish/bitbase.cpp
@@ -107,11 +107,11 @@ namespace {
KPKPosition::KPKPosition(unsigned idx) {
- wksq = Square((idx >> 0) & 0x3F);
- bksq = Square((idx >> 6) & 0x3F);
- us = Color ((idx >> 12) & 0x01);
- psq = make_square(File((idx >> 13) & 0x03), Rank(RANK_7 - (idx >> 15)));
- result = UNKNOWN;
+ wksq = Square((idx >> 0) & 0x3F);
+ bksq = Square((idx >> 6) & 0x3F);
+ us = Color ((idx >> 12) & 0x01);
+ psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
+ result = UNKNOWN;
// Check if two pieces are on the same square or if a king can be captured
if ( square_distance(wksq, bksq) <= 1
diff --git a/DroidFish/jni/stockfish/bitboard.cpp b/DroidFish/jni/stockfish/bitboard.cpp
index d4b433f..b3dbd00 100644
--- a/DroidFish/jni/stockfish/bitboard.cpp
+++ b/DroidFish/jni/stockfish/bitboard.cpp
@@ -149,7 +149,10 @@ const std::string Bitboards::pretty(Bitboard b) {
void Bitboards::init() {
for (Square s = SQ_A1; s <= SQ_H8; ++s)
- BSFTable[bsf_index(SquareBB[s] = 1ULL << s)] = s;
+ {
+ SquareBB[s] = 1ULL << s;
+ BSFTable[bsf_index(SquareBB[s])] = s;
+ }
for (Bitboard b = 1; b < 256; ++b)
MS1BTable[b] = more_than_one(b) ? MS1BTable[b - 1] : lsb(b);
@@ -251,9 +254,8 @@ namespace {
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) {
- int MagicBoosters[][8] = { { 969, 1976, 2850, 542, 2069, 2852, 1708, 164 },
- { 3101, 552, 3555, 926, 834, 26, 2131, 1117 } };
-
+ int MagicBoosters[][RANK_NB] = { { 969, 1976, 2850, 542, 2069, 2852, 1708, 164 },
+ { 3101, 552, 3555, 926, 834, 26, 2131, 1117 } };
RKISS rk;
Bitboard occupancy[4096], reference[4096], edges, b;
int i, size, booster;
@@ -301,7 +303,8 @@ namespace {
// Find a magic for square 's' picking up an (almost) random number
// until we find the one that passes the verification test.
do {
- do magics[s] = rk.magic_rand(booster);
+ do
+ magics[s] = rk.magic_rand(booster);
while (popcount((magics[s] * masks[s]) >> 56) < 6);
std::memset(attacks[s], 0, size * sizeof(Bitboard));
diff --git a/DroidFish/jni/stockfish/bitboard.h b/DroidFish/jni/stockfish/bitboard.h
index 9814268..6a1755b 100644
--- a/DroidFish/jni/stockfish/bitboard.h
+++ b/DroidFish/jni/stockfish/bitboard.h
@@ -21,6 +21,8 @@
#ifndef BITBOARD_H_INCLUDED
#define BITBOARD_H_INCLUDED
+#include
+
#include "types.h"
namespace Bitboards {
diff --git a/DroidFish/jni/stockfish/bitcount.h b/DroidFish/jni/stockfish/bitcount.h
index f84c51c..9feed19 100644
--- a/DroidFish/jni/stockfish/bitcount.h
+++ b/DroidFish/jni/stockfish/bitcount.h
@@ -96,8 +96,7 @@ inline int popcount(Bitboard b) {
#else
- __asm__("popcnt %1, %0" : "=r" (b) : "r" (b));
- return b;
+ return __builtin_popcountll(b);
#endif
}
diff --git a/DroidFish/jni/stockfish/book.cpp b/DroidFish/jni/stockfish/book.cpp
deleted file mode 100644
index fbbc3fe..0000000
--- a/DroidFish/jni/stockfish/book.cpp
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
- Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
-
- Stockfish is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Stockfish is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-/*
- The code in this file is based on the opening book code in PolyGlot
- by Fabien Letouzey. PolyGlot is available under the GNU General
- Public License, and can be downloaded from http://wbec-ridderkerk.nl
-*/
-
-#include
-#include
-
-#include "book.h"
-#include "misc.h"
-#include "movegen.h"
-
-using namespace std;
-
-namespace {
-
- // A Polyglot book is a series of "entries" of 16 bytes. All integers are
- // stored in big-endian format, with the highest byte first (regardless of
- // size). The entries are ordered according to the key in ascending order.
- struct Entry {
- uint64_t key;
- uint16_t move;
- uint16_t count;
- uint32_t learn;
- };
-
- // Random numbers from PolyGlot, used to compute book hash keys
- const union {
- Key PolyGlotRandoms[781];
- struct {
- Key psq[12][64]; // [piece][square]
- Key castling[4]; // [castling flag]
- Key enpassant[8]; // [file]
- Key turn;
- } Zobrist;
- } PG = {{
- 0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
- 0x9C15F73E62A76AE2ULL, 0x75834465489C0C89ULL, 0x3290AC3A203001BFULL,
- 0x0FBBAD1F61042279ULL, 0xE83A908FF2FB60CAULL, 0x0D7E765D58755C10ULL,
- 0x1A083822CEAFE02DULL, 0x9605D5F0E25EC3B0ULL, 0xD021FF5CD13A2ED5ULL,
- 0x40BDF15D4A672E32ULL, 0x011355146FD56395ULL, 0x5DB4832046F3D9E5ULL,
- 0x239F8B2D7FF719CCULL, 0x05D1A1AE85B49AA1ULL, 0x679F848F6E8FC971ULL,
- 0x7449BBFF801FED0BULL, 0x7D11CDB1C3B7ADF0ULL, 0x82C7709E781EB7CCULL,
- 0xF3218F1C9510786CULL, 0x331478F3AF51BBE6ULL, 0x4BB38DE5E7219443ULL,
- 0xAA649C6EBCFD50FCULL, 0x8DBD98A352AFD40BULL, 0x87D2074B81D79217ULL,
- 0x19F3C751D3E92AE1ULL, 0xB4AB30F062B19ABFULL, 0x7B0500AC42047AC4ULL,
- 0xC9452CA81A09D85DULL, 0x24AA6C514DA27500ULL, 0x4C9F34427501B447ULL,
- 0x14A68FD73C910841ULL, 0xA71B9B83461CBD93ULL, 0x03488B95B0F1850FULL,
- 0x637B2B34FF93C040ULL, 0x09D1BC9A3DD90A94ULL, 0x3575668334A1DD3BULL,
- 0x735E2B97A4C45A23ULL, 0x18727070F1BD400BULL, 0x1FCBACD259BF02E7ULL,
- 0xD310A7C2CE9B6555ULL, 0xBF983FE0FE5D8244ULL, 0x9F74D14F7454A824ULL,
- 0x51EBDC4AB9BA3035ULL, 0x5C82C505DB9AB0FAULL, 0xFCF7FE8A3430B241ULL,
- 0x3253A729B9BA3DDEULL, 0x8C74C368081B3075ULL, 0xB9BC6C87167C33E7ULL,
- 0x7EF48F2B83024E20ULL, 0x11D505D4C351BD7FULL, 0x6568FCA92C76A243ULL,
- 0x4DE0B0F40F32A7B8ULL, 0x96D693460CC37E5DULL, 0x42E240CB63689F2FULL,
- 0x6D2BDCDAE2919661ULL, 0x42880B0236E4D951ULL, 0x5F0F4A5898171BB6ULL,
- 0x39F890F579F92F88ULL, 0x93C5B5F47356388BULL, 0x63DC359D8D231B78ULL,
- 0xEC16CA8AEA98AD76ULL, 0x5355F900C2A82DC7ULL, 0x07FB9F855A997142ULL,
- 0x5093417AA8A7ED5EULL, 0x7BCBC38DA25A7F3CULL, 0x19FC8A768CF4B6D4ULL,
- 0x637A7780DECFC0D9ULL, 0x8249A47AEE0E41F7ULL, 0x79AD695501E7D1E8ULL,
- 0x14ACBAF4777D5776ULL, 0xF145B6BECCDEA195ULL, 0xDABF2AC8201752FCULL,
- 0x24C3C94DF9C8D3F6ULL, 0xBB6E2924F03912EAULL, 0x0CE26C0B95C980D9ULL,
- 0xA49CD132BFBF7CC4ULL, 0xE99D662AF4243939ULL, 0x27E6AD7891165C3FULL,
- 0x8535F040B9744FF1ULL, 0x54B3F4FA5F40D873ULL, 0x72B12C32127FED2BULL,
- 0xEE954D3C7B411F47ULL, 0x9A85AC909A24EAA1ULL, 0x70AC4CD9F04F21F5ULL,
- 0xF9B89D3E99A075C2ULL, 0x87B3E2B2B5C907B1ULL, 0xA366E5B8C54F48B8ULL,
- 0xAE4A9346CC3F7CF2ULL, 0x1920C04D47267BBDULL, 0x87BF02C6B49E2AE9ULL,
- 0x092237AC237F3859ULL, 0xFF07F64EF8ED14D0ULL, 0x8DE8DCA9F03CC54EULL,
- 0x9C1633264DB49C89ULL, 0xB3F22C3D0B0B38EDULL, 0x390E5FB44D01144BULL,
- 0x5BFEA5B4712768E9ULL, 0x1E1032911FA78984ULL, 0x9A74ACB964E78CB3ULL,
- 0x4F80F7A035DAFB04ULL, 0x6304D09A0B3738C4ULL, 0x2171E64683023A08ULL,
- 0x5B9B63EB9CEFF80CULL, 0x506AACF489889342ULL, 0x1881AFC9A3A701D6ULL,
- 0x6503080440750644ULL, 0xDFD395339CDBF4A7ULL, 0xEF927DBCF00C20F2ULL,
- 0x7B32F7D1E03680ECULL, 0xB9FD7620E7316243ULL, 0x05A7E8A57DB91B77ULL,
- 0xB5889C6E15630A75ULL, 0x4A750A09CE9573F7ULL, 0xCF464CEC899A2F8AULL,
- 0xF538639CE705B824ULL, 0x3C79A0FF5580EF7FULL, 0xEDE6C87F8477609DULL,
- 0x799E81F05BC93F31ULL, 0x86536B8CF3428A8CULL, 0x97D7374C60087B73ULL,
- 0xA246637CFF328532ULL, 0x043FCAE60CC0EBA0ULL, 0x920E449535DD359EULL,
- 0x70EB093B15B290CCULL, 0x73A1921916591CBDULL, 0x56436C9FE1A1AA8DULL,
- 0xEFAC4B70633B8F81ULL, 0xBB215798D45DF7AFULL, 0x45F20042F24F1768ULL,
- 0x930F80F4E8EB7462ULL, 0xFF6712FFCFD75EA1ULL, 0xAE623FD67468AA70ULL,
- 0xDD2C5BC84BC8D8FCULL, 0x7EED120D54CF2DD9ULL, 0x22FE545401165F1CULL,
- 0xC91800E98FB99929ULL, 0x808BD68E6AC10365ULL, 0xDEC468145B7605F6ULL,
- 0x1BEDE3A3AEF53302ULL, 0x43539603D6C55602ULL, 0xAA969B5C691CCB7AULL,
- 0xA87832D392EFEE56ULL, 0x65942C7B3C7E11AEULL, 0xDED2D633CAD004F6ULL,
- 0x21F08570F420E565ULL, 0xB415938D7DA94E3CULL, 0x91B859E59ECB6350ULL,
- 0x10CFF333E0ED804AULL, 0x28AED140BE0BB7DDULL, 0xC5CC1D89724FA456ULL,
- 0x5648F680F11A2741ULL, 0x2D255069F0B7DAB3ULL, 0x9BC5A38EF729ABD4ULL,
- 0xEF2F054308F6A2BCULL, 0xAF2042F5CC5C2858ULL, 0x480412BAB7F5BE2AULL,
- 0xAEF3AF4A563DFE43ULL, 0x19AFE59AE451497FULL, 0x52593803DFF1E840ULL,
- 0xF4F076E65F2CE6F0ULL, 0x11379625747D5AF3ULL, 0xBCE5D2248682C115ULL,
- 0x9DA4243DE836994FULL, 0x066F70B33FE09017ULL, 0x4DC4DE189B671A1CULL,
- 0x51039AB7712457C3ULL, 0xC07A3F80C31FB4B4ULL, 0xB46EE9C5E64A6E7CULL,
- 0xB3819A42ABE61C87ULL, 0x21A007933A522A20ULL, 0x2DF16F761598AA4FULL,
- 0x763C4A1371B368FDULL, 0xF793C46702E086A0ULL, 0xD7288E012AEB8D31ULL,
- 0xDE336A2A4BC1C44BULL, 0x0BF692B38D079F23ULL, 0x2C604A7A177326B3ULL,
- 0x4850E73E03EB6064ULL, 0xCFC447F1E53C8E1BULL, 0xB05CA3F564268D99ULL,
- 0x9AE182C8BC9474E8ULL, 0xA4FC4BD4FC5558CAULL, 0xE755178D58FC4E76ULL,
- 0x69B97DB1A4C03DFEULL, 0xF9B5B7C4ACC67C96ULL, 0xFC6A82D64B8655FBULL,
- 0x9C684CB6C4D24417ULL, 0x8EC97D2917456ED0ULL, 0x6703DF9D2924E97EULL,
- 0xC547F57E42A7444EULL, 0x78E37644E7CAD29EULL, 0xFE9A44E9362F05FAULL,
- 0x08BD35CC38336615ULL, 0x9315E5EB3A129ACEULL, 0x94061B871E04DF75ULL,
- 0xDF1D9F9D784BA010ULL, 0x3BBA57B68871B59DULL, 0xD2B7ADEEDED1F73FULL,
- 0xF7A255D83BC373F8ULL, 0xD7F4F2448C0CEB81ULL, 0xD95BE88CD210FFA7ULL,
- 0x336F52F8FF4728E7ULL, 0xA74049DAC312AC71ULL, 0xA2F61BB6E437FDB5ULL,
- 0x4F2A5CB07F6A35B3ULL, 0x87D380BDA5BF7859ULL, 0x16B9F7E06C453A21ULL,
- 0x7BA2484C8A0FD54EULL, 0xF3A678CAD9A2E38CULL, 0x39B0BF7DDE437BA2ULL,
- 0xFCAF55C1BF8A4424ULL, 0x18FCF680573FA594ULL, 0x4C0563B89F495AC3ULL,
- 0x40E087931A00930DULL, 0x8CFFA9412EB642C1ULL, 0x68CA39053261169FULL,
- 0x7A1EE967D27579E2ULL, 0x9D1D60E5076F5B6FULL, 0x3810E399B6F65BA2ULL,
- 0x32095B6D4AB5F9B1ULL, 0x35CAB62109DD038AULL, 0xA90B24499FCFAFB1ULL,
- 0x77A225A07CC2C6BDULL, 0x513E5E634C70E331ULL, 0x4361C0CA3F692F12ULL,
- 0xD941ACA44B20A45BULL, 0x528F7C8602C5807BULL, 0x52AB92BEB9613989ULL,
- 0x9D1DFA2EFC557F73ULL, 0x722FF175F572C348ULL, 0x1D1260A51107FE97ULL,
- 0x7A249A57EC0C9BA2ULL, 0x04208FE9E8F7F2D6ULL, 0x5A110C6058B920A0ULL,
- 0x0CD9A497658A5698ULL, 0x56FD23C8F9715A4CULL, 0x284C847B9D887AAEULL,
- 0x04FEABFBBDB619CBULL, 0x742E1E651C60BA83ULL, 0x9A9632E65904AD3CULL,
- 0x881B82A13B51B9E2ULL, 0x506E6744CD974924ULL, 0xB0183DB56FFC6A79ULL,
- 0x0ED9B915C66ED37EULL, 0x5E11E86D5873D484ULL, 0xF678647E3519AC6EULL,
- 0x1B85D488D0F20CC5ULL, 0xDAB9FE6525D89021ULL, 0x0D151D86ADB73615ULL,
- 0xA865A54EDCC0F019ULL, 0x93C42566AEF98FFBULL, 0x99E7AFEABE000731ULL,
- 0x48CBFF086DDF285AULL, 0x7F9B6AF1EBF78BAFULL, 0x58627E1A149BBA21ULL,
- 0x2CD16E2ABD791E33ULL, 0xD363EFF5F0977996ULL, 0x0CE2A38C344A6EEDULL,
- 0x1A804AADB9CFA741ULL, 0x907F30421D78C5DEULL, 0x501F65EDB3034D07ULL,
- 0x37624AE5A48FA6E9ULL, 0x957BAF61700CFF4EULL, 0x3A6C27934E31188AULL,
- 0xD49503536ABCA345ULL, 0x088E049589C432E0ULL, 0xF943AEE7FEBF21B8ULL,
- 0x6C3B8E3E336139D3ULL, 0x364F6FFA464EE52EULL, 0xD60F6DCEDC314222ULL,
- 0x56963B0DCA418FC0ULL, 0x16F50EDF91E513AFULL, 0xEF1955914B609F93ULL,
- 0x565601C0364E3228ULL, 0xECB53939887E8175ULL, 0xBAC7A9A18531294BULL,
- 0xB344C470397BBA52ULL, 0x65D34954DAF3CEBDULL, 0xB4B81B3FA97511E2ULL,
- 0xB422061193D6F6A7ULL, 0x071582401C38434DULL, 0x7A13F18BBEDC4FF5ULL,
- 0xBC4097B116C524D2ULL, 0x59B97885E2F2EA28ULL, 0x99170A5DC3115544ULL,
- 0x6F423357E7C6A9F9ULL, 0x325928EE6E6F8794ULL, 0xD0E4366228B03343ULL,
- 0x565C31F7DE89EA27ULL, 0x30F5611484119414ULL, 0xD873DB391292ED4FULL,
- 0x7BD94E1D8E17DEBCULL, 0xC7D9F16864A76E94ULL, 0x947AE053EE56E63CULL,
- 0xC8C93882F9475F5FULL, 0x3A9BF55BA91F81CAULL, 0xD9A11FBB3D9808E4ULL,
- 0x0FD22063EDC29FCAULL, 0xB3F256D8ACA0B0B9ULL, 0xB03031A8B4516E84ULL,
- 0x35DD37D5871448AFULL, 0xE9F6082B05542E4EULL, 0xEBFAFA33D7254B59ULL,
- 0x9255ABB50D532280ULL, 0xB9AB4CE57F2D34F3ULL, 0x693501D628297551ULL,
- 0xC62C58F97DD949BFULL, 0xCD454F8F19C5126AULL, 0xBBE83F4ECC2BDECBULL,
- 0xDC842B7E2819E230ULL, 0xBA89142E007503B8ULL, 0xA3BC941D0A5061CBULL,
- 0xE9F6760E32CD8021ULL, 0x09C7E552BC76492FULL, 0x852F54934DA55CC9ULL,
- 0x8107FCCF064FCF56ULL, 0x098954D51FFF6580ULL, 0x23B70EDB1955C4BFULL,
- 0xC330DE426430F69DULL, 0x4715ED43E8A45C0AULL, 0xA8D7E4DAB780A08DULL,
- 0x0572B974F03CE0BBULL, 0xB57D2E985E1419C7ULL, 0xE8D9ECBE2CF3D73FULL,
- 0x2FE4B17170E59750ULL, 0x11317BA87905E790ULL, 0x7FBF21EC8A1F45ECULL,
- 0x1725CABFCB045B00ULL, 0x964E915CD5E2B207ULL, 0x3E2B8BCBF016D66DULL,
- 0xBE7444E39328A0ACULL, 0xF85B2B4FBCDE44B7ULL, 0x49353FEA39BA63B1ULL,
- 0x1DD01AAFCD53486AULL, 0x1FCA8A92FD719F85ULL, 0xFC7C95D827357AFAULL,
- 0x18A6A990C8B35EBDULL, 0xCCCB7005C6B9C28DULL, 0x3BDBB92C43B17F26ULL,
- 0xAA70B5B4F89695A2ULL, 0xE94C39A54A98307FULL, 0xB7A0B174CFF6F36EULL,
- 0xD4DBA84729AF48ADULL, 0x2E18BC1AD9704A68ULL, 0x2DE0966DAF2F8B1CULL,
- 0xB9C11D5B1E43A07EULL, 0x64972D68DEE33360ULL, 0x94628D38D0C20584ULL,
- 0xDBC0D2B6AB90A559ULL, 0xD2733C4335C6A72FULL, 0x7E75D99D94A70F4DULL,
- 0x6CED1983376FA72BULL, 0x97FCAACBF030BC24ULL, 0x7B77497B32503B12ULL,
- 0x8547EDDFB81CCB94ULL, 0x79999CDFF70902CBULL, 0xCFFE1939438E9B24ULL,
- 0x829626E3892D95D7ULL, 0x92FAE24291F2B3F1ULL, 0x63E22C147B9C3403ULL,
- 0xC678B6D860284A1CULL, 0x5873888850659AE7ULL, 0x0981DCD296A8736DULL,
- 0x9F65789A6509A440ULL, 0x9FF38FED72E9052FULL, 0xE479EE5B9930578CULL,
- 0xE7F28ECD2D49EECDULL, 0x56C074A581EA17FEULL, 0x5544F7D774B14AEFULL,
- 0x7B3F0195FC6F290FULL, 0x12153635B2C0CF57ULL, 0x7F5126DBBA5E0CA7ULL,
- 0x7A76956C3EAFB413ULL, 0x3D5774A11D31AB39ULL, 0x8A1B083821F40CB4ULL,
- 0x7B4A38E32537DF62ULL, 0x950113646D1D6E03ULL, 0x4DA8979A0041E8A9ULL,
- 0x3BC36E078F7515D7ULL, 0x5D0A12F27AD310D1ULL, 0x7F9D1A2E1EBE1327ULL,
- 0xDA3A361B1C5157B1ULL, 0xDCDD7D20903D0C25ULL, 0x36833336D068F707ULL,
- 0xCE68341F79893389ULL, 0xAB9090168DD05F34ULL, 0x43954B3252DC25E5ULL,
- 0xB438C2B67F98E5E9ULL, 0x10DCD78E3851A492ULL, 0xDBC27AB5447822BFULL,
- 0x9B3CDB65F82CA382ULL, 0xB67B7896167B4C84ULL, 0xBFCED1B0048EAC50ULL,
- 0xA9119B60369FFEBDULL, 0x1FFF7AC80904BF45ULL, 0xAC12FB171817EEE7ULL,
- 0xAF08DA9177DDA93DULL, 0x1B0CAB936E65C744ULL, 0xB559EB1D04E5E932ULL,
- 0xC37B45B3F8D6F2BAULL, 0xC3A9DC228CAAC9E9ULL, 0xF3B8B6675A6507FFULL,
- 0x9FC477DE4ED681DAULL, 0x67378D8ECCEF96CBULL, 0x6DD856D94D259236ULL,
- 0xA319CE15B0B4DB31ULL, 0x073973751F12DD5EULL, 0x8A8E849EB32781A5ULL,
- 0xE1925C71285279F5ULL, 0x74C04BF1790C0EFEULL, 0x4DDA48153C94938AULL,
- 0x9D266D6A1CC0542CULL, 0x7440FB816508C4FEULL, 0x13328503DF48229FULL,
- 0xD6BF7BAEE43CAC40ULL, 0x4838D65F6EF6748FULL, 0x1E152328F3318DEAULL,
- 0x8F8419A348F296BFULL, 0x72C8834A5957B511ULL, 0xD7A023A73260B45CULL,
- 0x94EBC8ABCFB56DAEULL, 0x9FC10D0F989993E0ULL, 0xDE68A2355B93CAE6ULL,
- 0xA44CFE79AE538BBEULL, 0x9D1D84FCCE371425ULL, 0x51D2B1AB2DDFB636ULL,
- 0x2FD7E4B9E72CD38CULL, 0x65CA5B96B7552210ULL, 0xDD69A0D8AB3B546DULL,
- 0x604D51B25FBF70E2ULL, 0x73AA8A564FB7AC9EULL, 0x1A8C1E992B941148ULL,
- 0xAAC40A2703D9BEA0ULL, 0x764DBEAE7FA4F3A6ULL, 0x1E99B96E70A9BE8BULL,
- 0x2C5E9DEB57EF4743ULL, 0x3A938FEE32D29981ULL, 0x26E6DB8FFDF5ADFEULL,
- 0x469356C504EC9F9DULL, 0xC8763C5B08D1908CULL, 0x3F6C6AF859D80055ULL,
- 0x7F7CC39420A3A545ULL, 0x9BFB227EBDF4C5CEULL, 0x89039D79D6FC5C5CULL,
- 0x8FE88B57305E2AB6ULL, 0xA09E8C8C35AB96DEULL, 0xFA7E393983325753ULL,
- 0xD6B6D0ECC617C699ULL, 0xDFEA21EA9E7557E3ULL, 0xB67C1FA481680AF8ULL,
- 0xCA1E3785A9E724E5ULL, 0x1CFC8BED0D681639ULL, 0xD18D8549D140CAEAULL,
- 0x4ED0FE7E9DC91335ULL, 0xE4DBF0634473F5D2ULL, 0x1761F93A44D5AEFEULL,
- 0x53898E4C3910DA55ULL, 0x734DE8181F6EC39AULL, 0x2680B122BAA28D97ULL,
- 0x298AF231C85BAFABULL, 0x7983EED3740847D5ULL, 0x66C1A2A1A60CD889ULL,
- 0x9E17E49642A3E4C1ULL, 0xEDB454E7BADC0805ULL, 0x50B704CAB602C329ULL,
- 0x4CC317FB9CDDD023ULL, 0x66B4835D9EAFEA22ULL, 0x219B97E26FFC81BDULL,
- 0x261E4E4C0A333A9DULL, 0x1FE2CCA76517DB90ULL, 0xD7504DFA8816EDBBULL,
- 0xB9571FA04DC089C8ULL, 0x1DDC0325259B27DEULL, 0xCF3F4688801EB9AAULL,
- 0xF4F5D05C10CAB243ULL, 0x38B6525C21A42B0EULL, 0x36F60E2BA4FA6800ULL,
- 0xEB3593803173E0CEULL, 0x9C4CD6257C5A3603ULL, 0xAF0C317D32ADAA8AULL,
- 0x258E5A80C7204C4BULL, 0x8B889D624D44885DULL, 0xF4D14597E660F855ULL,
- 0xD4347F66EC8941C3ULL, 0xE699ED85B0DFB40DULL, 0x2472F6207C2D0484ULL,
- 0xC2A1E7B5B459AEB5ULL, 0xAB4F6451CC1D45ECULL, 0x63767572AE3D6174ULL,
- 0xA59E0BD101731A28ULL, 0x116D0016CB948F09ULL, 0x2CF9C8CA052F6E9FULL,
- 0x0B090A7560A968E3ULL, 0xABEEDDB2DDE06FF1ULL, 0x58EFC10B06A2068DULL,
- 0xC6E57A78FBD986E0ULL, 0x2EAB8CA63CE802D7ULL, 0x14A195640116F336ULL,
- 0x7C0828DD624EC390ULL, 0xD74BBE77E6116AC7ULL, 0x804456AF10F5FB53ULL,
- 0xEBE9EA2ADF4321C7ULL, 0x03219A39EE587A30ULL, 0x49787FEF17AF9924ULL,
- 0xA1E9300CD8520548ULL, 0x5B45E522E4B1B4EFULL, 0xB49C3B3995091A36ULL,
- 0xD4490AD526F14431ULL, 0x12A8F216AF9418C2ULL, 0x001F837CC7350524ULL,
- 0x1877B51E57A764D5ULL, 0xA2853B80F17F58EEULL, 0x993E1DE72D36D310ULL,
- 0xB3598080CE64A656ULL, 0x252F59CF0D9F04BBULL, 0xD23C8E176D113600ULL,
- 0x1BDA0492E7E4586EULL, 0x21E0BD5026C619BFULL, 0x3B097ADAF088F94EULL,
- 0x8D14DEDB30BE846EULL, 0xF95CFFA23AF5F6F4ULL, 0x3871700761B3F743ULL,
- 0xCA672B91E9E4FA16ULL, 0x64C8E531BFF53B55ULL, 0x241260ED4AD1E87DULL,
- 0x106C09B972D2E822ULL, 0x7FBA195410E5CA30ULL, 0x7884D9BC6CB569D8ULL,
- 0x0647DFEDCD894A29ULL, 0x63573FF03E224774ULL, 0x4FC8E9560F91B123ULL,
- 0x1DB956E450275779ULL, 0xB8D91274B9E9D4FBULL, 0xA2EBEE47E2FBFCE1ULL,
- 0xD9F1F30CCD97FB09ULL, 0xEFED53D75FD64E6BULL, 0x2E6D02C36017F67FULL,
- 0xA9AA4D20DB084E9BULL, 0xB64BE8D8B25396C1ULL, 0x70CB6AF7C2D5BCF0ULL,
- 0x98F076A4F7A2322EULL, 0xBF84470805E69B5FULL, 0x94C3251F06F90CF3ULL,
- 0x3E003E616A6591E9ULL, 0xB925A6CD0421AFF3ULL, 0x61BDD1307C66E300ULL,
- 0xBF8D5108E27E0D48ULL, 0x240AB57A8B888B20ULL, 0xFC87614BAF287E07ULL,
- 0xEF02CDD06FFDB432ULL, 0xA1082C0466DF6C0AULL, 0x8215E577001332C8ULL,
- 0xD39BB9C3A48DB6CFULL, 0x2738259634305C14ULL, 0x61CF4F94C97DF93DULL,
- 0x1B6BACA2AE4E125BULL, 0x758F450C88572E0BULL, 0x959F587D507A8359ULL,
- 0xB063E962E045F54DULL, 0x60E8ED72C0DFF5D1ULL, 0x7B64978555326F9FULL,
- 0xFD080D236DA814BAULL, 0x8C90FD9B083F4558ULL, 0x106F72FE81E2C590ULL,
- 0x7976033A39F7D952ULL, 0xA4EC0132764CA04BULL, 0x733EA705FAE4FA77ULL,
- 0xB4D8F77BC3E56167ULL, 0x9E21F4F903B33FD9ULL, 0x9D765E419FB69F6DULL,
- 0xD30C088BA61EA5EFULL, 0x5D94337FBFAF7F5BULL, 0x1A4E4822EB4D7A59ULL,
- 0x6FFE73E81B637FB3ULL, 0xDDF957BC36D8B9CAULL, 0x64D0E29EEA8838B3ULL,
- 0x08DD9BDFD96B9F63ULL, 0x087E79E5A57D1D13ULL, 0xE328E230E3E2B3FBULL,
- 0x1C2559E30F0946BEULL, 0x720BF5F26F4D2EAAULL, 0xB0774D261CC609DBULL,
- 0x443F64EC5A371195ULL, 0x4112CF68649A260EULL, 0xD813F2FAB7F5C5CAULL,
- 0x660D3257380841EEULL, 0x59AC2C7873F910A3ULL, 0xE846963877671A17ULL,
- 0x93B633ABFA3469F8ULL, 0xC0C0F5A60EF4CDCFULL, 0xCAF21ECD4377B28CULL,
- 0x57277707199B8175ULL, 0x506C11B9D90E8B1DULL, 0xD83CC2687A19255FULL,
- 0x4A29C6465A314CD1ULL, 0xED2DF21216235097ULL, 0xB5635C95FF7296E2ULL,
- 0x22AF003AB672E811ULL, 0x52E762596BF68235ULL, 0x9AEBA33AC6ECC6B0ULL,
- 0x944F6DE09134DFB6ULL, 0x6C47BEC883A7DE39ULL, 0x6AD047C430A12104ULL,
- 0xA5B1CFDBA0AB4067ULL, 0x7C45D833AFF07862ULL, 0x5092EF950A16DA0BULL,
- 0x9338E69C052B8E7BULL, 0x455A4B4CFE30E3F5ULL, 0x6B02E63195AD0CF8ULL,
- 0x6B17B224BAD6BF27ULL, 0xD1E0CCD25BB9C169ULL, 0xDE0C89A556B9AE70ULL,
- 0x50065E535A213CF6ULL, 0x9C1169FA2777B874ULL, 0x78EDEFD694AF1EEDULL,
- 0x6DC93D9526A50E68ULL, 0xEE97F453F06791EDULL, 0x32AB0EDB696703D3ULL,
- 0x3A6853C7E70757A7ULL, 0x31865CED6120F37DULL, 0x67FEF95D92607890ULL,
- 0x1F2B1D1F15F6DC9CULL, 0xB69E38A8965C6B65ULL, 0xAA9119FF184CCCF4ULL,
- 0xF43C732873F24C13ULL, 0xFB4A3D794A9A80D2ULL, 0x3550C2321FD6109CULL,
- 0x371F77E76BB8417EULL, 0x6BFA9AAE5EC05779ULL, 0xCD04F3FF001A4778ULL,
- 0xE3273522064480CAULL, 0x9F91508BFFCFC14AULL, 0x049A7F41061A9E60ULL,
- 0xFCB6BE43A9F2FE9BULL, 0x08DE8A1C7797DA9BULL, 0x8F9887E6078735A1ULL,
- 0xB5B4071DBFC73A66ULL, 0x230E343DFBA08D33ULL, 0x43ED7F5A0FAE657DULL,
- 0x3A88A0FBBCB05C63ULL, 0x21874B8B4D2DBC4FULL, 0x1BDEA12E35F6A8C9ULL,
- 0x53C065C6C8E63528ULL, 0xE34A1D250E7A8D6BULL, 0xD6B04D3B7651DD7EULL,
- 0x5E90277E7CB39E2DULL, 0x2C046F22062DC67DULL, 0xB10BB459132D0A26ULL,
- 0x3FA9DDFB67E2F199ULL, 0x0E09B88E1914F7AFULL, 0x10E8B35AF3EEAB37ULL,
- 0x9EEDECA8E272B933ULL, 0xD4C718BC4AE8AE5FULL, 0x81536D601170FC20ULL,
- 0x91B534F885818A06ULL, 0xEC8177F83F900978ULL, 0x190E714FADA5156EULL,
- 0xB592BF39B0364963ULL, 0x89C350C893AE7DC1ULL, 0xAC042E70F8B383F2ULL,
- 0xB49B52E587A1EE60ULL, 0xFB152FE3FF26DA89ULL, 0x3E666E6F69AE2C15ULL,
- 0x3B544EBE544C19F9ULL, 0xE805A1E290CF2456ULL, 0x24B33C9D7ED25117ULL,
- 0xE74733427B72F0C1ULL, 0x0A804D18B7097475ULL, 0x57E3306D881EDB4FULL,
- 0x4AE7D6A36EB5DBCBULL, 0x2D8D5432157064C8ULL, 0xD1E649DE1E7F268BULL,
- 0x8A328A1CEDFE552CULL, 0x07A3AEC79624C7DAULL, 0x84547DDC3E203C94ULL,
- 0x990A98FD5071D263ULL, 0x1A4FF12616EEFC89ULL, 0xF6F7FD1431714200ULL,
- 0x30C05B1BA332F41CULL, 0x8D2636B81555A786ULL, 0x46C9FEB55D120902ULL,
- 0xCCEC0A73B49C9921ULL, 0x4E9D2827355FC492ULL, 0x19EBB029435DCB0FULL,
- 0x4659D2B743848A2CULL, 0x963EF2C96B33BE31ULL, 0x74F85198B05A2E7DULL,
- 0x5A0F544DD2B1FB18ULL, 0x03727073C2E134B1ULL, 0xC7F6AA2DE59AEA61ULL,
- 0x352787BAA0D7C22FULL, 0x9853EAB63B5E0B35ULL, 0xABBDCDD7ED5C0860ULL,
- 0xCF05DAF5AC8D77B0ULL, 0x49CAD48CEBF4A71EULL, 0x7A4C10EC2158C4A6ULL,
- 0xD9E92AA246BF719EULL, 0x13AE978D09FE5557ULL, 0x730499AF921549FFULL,
- 0x4E4B705B92903BA4ULL, 0xFF577222C14F0A3AULL, 0x55B6344CF97AAFAEULL,
- 0xB862225B055B6960ULL, 0xCAC09AFBDDD2CDB4ULL, 0xDAF8E9829FE96B5FULL,
- 0xB5FDFC5D3132C498ULL, 0x310CB380DB6F7503ULL, 0xE87FBB46217A360EULL,
- 0x2102AE466EBB1148ULL, 0xF8549E1A3AA5E00DULL, 0x07A69AFDCC42261AULL,
- 0xC4C118BFE78FEAAEULL, 0xF9F4892ED96BD438ULL, 0x1AF3DBE25D8F45DAULL,
- 0xF5B4B0B0D2DEEEB4ULL, 0x962ACEEFA82E1C84ULL, 0x046E3ECAAF453CE9ULL,
- 0xF05D129681949A4CULL, 0x964781CE734B3C84ULL, 0x9C2ED44081CE5FBDULL,
- 0x522E23F3925E319EULL, 0x177E00F9FC32F791ULL, 0x2BC60A63A6F3B3F2ULL,
- 0x222BBFAE61725606ULL, 0x486289DDCC3D6780ULL, 0x7DC7785B8EFDFC80ULL,
- 0x8AF38731C02BA980ULL, 0x1FAB64EA29A2DDF7ULL, 0xE4D9429322CD065AULL,
- 0x9DA058C67844F20CULL, 0x24C0E332B70019B0ULL, 0x233003B5A6CFE6ADULL,
- 0xD586BD01C5C217F6ULL, 0x5E5637885F29BC2BULL, 0x7EBA726D8C94094BULL,
- 0x0A56A5F0BFE39272ULL, 0xD79476A84EE20D06ULL, 0x9E4C1269BAA4BF37ULL,
- 0x17EFEE45B0DEE640ULL, 0x1D95B0A5FCF90BC6ULL, 0x93CBE0B699C2585DULL,
- 0x65FA4F227A2B6D79ULL, 0xD5F9E858292504D5ULL, 0xC2B5A03F71471A6FULL,
- 0x59300222B4561E00ULL, 0xCE2F8642CA0712DCULL, 0x7CA9723FBB2E8988ULL,
- 0x2785338347F2BA08ULL, 0xC61BB3A141E50E8CULL, 0x150F361DAB9DEC26ULL,
- 0x9F6A419D382595F4ULL, 0x64A53DC924FE7AC9ULL, 0x142DE49FFF7A7C3DULL,
- 0x0C335248857FA9E7ULL, 0x0A9C32D5EAE45305ULL, 0xE6C42178C4BBB92EULL,
- 0x71F1CE2490D20B07ULL, 0xF1BCC3D275AFE51AULL, 0xE728E8C83C334074ULL,
- 0x96FBF83A12884624ULL, 0x81A1549FD6573DA5ULL, 0x5FA7867CAF35E149ULL,
- 0x56986E2EF3ED091BULL, 0x917F1DD5F8886C61ULL, 0xD20D8C88C8FFE65FULL,
- 0x31D71DCE64B2C310ULL, 0xF165B587DF898190ULL, 0xA57E6339DD2CF3A0ULL,
- 0x1EF6E6DBB1961EC9ULL, 0x70CC73D90BC26E24ULL, 0xE21A6B35DF0C3AD7ULL,
- 0x003A93D8B2806962ULL, 0x1C99DED33CB890A1ULL, 0xCF3145DE0ADD4289ULL,
- 0xD0E4427A5514FB72ULL, 0x77C621CC9FB3A483ULL, 0x67A34DAC4356550BULL,
- 0xF8D626AAAF278509ULL
- }};
-
- // polyglot_key() returns the PolyGlot hash key of the given position
- Key polyglot_key(const Position& pos) {
-
- Key key = 0;
- Bitboard b = pos.pieces();
-
- while (b)
- {
- Square s = pop_lsb(&b);
- Piece pc = pos.piece_on(s);
-
- // PolyGlot pieces are: BP = 0, WP = 1, BN = 2, ... BK = 10, WK = 11
- key ^= PG.Zobrist.psq[2 * (type_of(pc) - 1) + (color_of(pc) == WHITE)][s];
- }
-
- b = pos.can_castle(ANY_CASTLING);
-
- while (b)
- key ^= PG.Zobrist.castling[pop_lsb(&b)];
-
- if (pos.ep_square() != SQ_NONE)
- key ^= PG.Zobrist.enpassant[file_of(pos.ep_square())];
-
- if (pos.side_to_move() == WHITE)
- key ^= PG.Zobrist.turn;
-
- return key;
- }
-
-} // namespace
-
-PolyglotBook::PolyglotBook() : rkiss(Time::now() % 10000) {}
-
-PolyglotBook::~PolyglotBook() { if (is_open()) close(); }
-
-
-/// operator>>() reads sizeof(T) chars from the file's binary byte stream and
-/// converts them into a number of type T. A Polyglot book stores numbers in
-/// big-endian format.
-
-template PolyglotBook& PolyglotBook::operator>>(T& n) {
-
- n = 0;
- for (size_t i = 0; i < sizeof(T); ++i)
- n = T((n << 8) + ifstream::get());
-
- return *this;
-}
-
-template<> PolyglotBook& PolyglotBook::operator>>(Entry& e) {
- return *this >> e.key >> e.move >> e.count >> e.learn;
-}
-
-
-/// open() tries to open a book file with the given name after closing any
-/// existing one.
-
-bool PolyglotBook::open(const char* fName) {
-
- if (is_open()) // Cannot close an already closed file
- close();
-
- ifstream::open(fName, ifstream::in | ifstream::binary);
-
- fileName = is_open() ? fName : "";
- ifstream::clear(); // Reset any error flag to allow a retry ifstream::open()
- return !fileName.empty();
-}
-
-
-/// probe() tries to find a book move for the given position. If no move is
-/// found, it returns MOVE_NONE. If pickBest is true, then it always returns
-/// the highest-rated move, otherwise it randomly chooses one based on the
-/// move score.
-
-Move PolyglotBook::probe(const Position& pos, const string& fName, bool pickBest) {
-
- if (fileName != fName && !open(fName.c_str()))
- return MOVE_NONE;
-
- Entry e;
- uint16_t best = 0;
- unsigned sum = 0;
- Move move = MOVE_NONE;
- Key key = polyglot_key(pos);
-
- seekg(find_first(key) * sizeof(Entry), ios_base::beg);
-
- while (*this >> e, e.key == key && good())
- {
- best = max(best, e.count);
- sum += e.count;
-
- // Choose book move according to its score. If a move has a very high
- // score it has a higher probability of being choosen than a move with
- // a lower score. Note that first entry is always chosen.
- if ( (!pickBest && sum && rkiss.rand() % sum < e.count)
- || (pickBest && e.count == best))
- move = Move(e.move);
- }
-
- if (!move)
- return MOVE_NONE;
-
- // A PolyGlot book move is encoded as follows:
- //
- // bit 0- 5: destination square (from 0 to 63)
- // bit 6-11: origin square (from 0 to 63)
- // bit 12-14: promotion piece (from KNIGHT == 1 to QUEEN == 4)
- //
- // Castling moves follow the "king captures rook" representation. If a book
- // move is a promotion, we have to convert it to our representation and in
- // all other cases, we can directly compare with a Move after having masked
- // out the special Move flags (bit 14-15) that are not supported by PolyGlot.
- int pt = (move >> 12) & 7;
- if (pt)
- move = make(from_sq(move), to_sq(move), PieceType(pt + 1));
-
- // Add 'special move' flags and verify it is legal
- for (MoveList it(pos); *it; ++it)
- if (move == (*it ^ type_of(*it)))
- return *it;
-
- return MOVE_NONE;
-}
-
-
-/// find_first() takes a book key as input, and does a binary search through
-/// the book file for the given key. Returns the index of the leftmost book
-/// entry with the same key as the input.
-
-size_t PolyglotBook::find_first(Key key) {
-
- seekg(0, ios::end); // Move pointer to end, so tellg() gets file's size
-
- size_t low = 0, mid, high = (size_t)tellg() / sizeof(Entry) - 1;
- Entry e;
-
- assert(low <= high);
-
- while (low < high && good())
- {
- mid = (low + high) / 2;
-
- assert(mid >= low && mid < high);
-
- seekg(mid * sizeof(Entry), ios_base::beg);
- *this >> e;
-
- if (key <= e.key)
- high = mid;
- else
- low = mid + 1;
- }
-
- assert(low == high);
-
- return low;
-}
diff --git a/DroidFish/jni/stockfish/book.h b/DroidFish/jni/stockfish/book.h
deleted file mode 100644
index fc84e09..0000000
--- a/DroidFish/jni/stockfish/book.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
- Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
-
- Stockfish is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Stockfish is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifndef BOOK_H_INCLUDED
-#define BOOK_H_INCLUDED
-
-#include
-#include
-
-#include "position.h"
-#include "rkiss.h"
-
-class PolyglotBook : private std::ifstream {
-public:
- PolyglotBook();
- ~PolyglotBook();
- Move probe(const Position& pos, const std::string& fName, bool pickBest);
-
-private:
- template PolyglotBook& operator>>(T& n);
-
- bool open(const char* fName);
- size_t find_first(Key key);
-
- RKISS rkiss;
- std::string fileName;
-};
-
-#endif // #ifndef BOOK_H_INCLUDED
diff --git a/DroidFish/jni/stockfish/evaluate.cpp b/DroidFish/jni/stockfish/evaluate.cpp
index 64b1bf4..69df762 100644
--- a/DroidFish/jni/stockfish/evaluate.cpp
+++ b/DroidFish/jni/stockfish/evaluate.cpp
@@ -76,7 +76,7 @@ namespace {
namespace Tracing {
enum Terms { // First 8 entries are for PieceType
- PST = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERMS_NB
+ MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERMS_NB
};
Score terms[COLOR_NB][TERMS_NB];
@@ -89,23 +89,15 @@ namespace {
std::string do_trace(const Position& pos);
}
- // Evaluation weights, initialized from UCI options
- enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem };
- struct Weight { int mg, eg; } Weights[6];
+ // Evaluation weights, indexed by evaluation term
+ enum { Mobility, PawnStructure, PassedPawns, Space, KingSafety };
+ const struct Weight { int mg, eg; } Weights[] = {
+ {289, 344}, {233, 201}, {221, 273}, {46, 0}, {318, 0}
+ };
typedef Value V;
#define S(mg, eg) make_score(mg, eg)
- // Internal evaluation weights. These are applied on top of the evaluation
- // weights read from UCI parameters. The purpose is to be able to change
- // the evaluation weights while keeping the default values of the UCI
- // parameters at 100, which looks prettier.
- //
- // Values modified by Joona Kiiski
- const Score WeightsInternal[] = {
- S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(271, 0), S(307, 0)
- };
-
// MobilityBonus[PieceType][attacked] contains bonuses for middle and end
// game, indexed by piece type and number of attacked squares not occupied by
// friendly pieces.
@@ -155,27 +147,27 @@ namespace {
// ThreatenedByPawn[PieceType] contains a penalty according to which piece
// type is attacked by an enemy pawn.
const Score ThreatenedByPawn[] = {
- S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118)
+ S(0, 0), S(0, 0), S(80, 119), S(80, 119), S(117, 199), S(127, 218)
};
- // Hanging[side to move] contains a bonus for each enemy hanging piece
- const Score Hanging[2] = { S(23, 20) , S(35, 45) };
-
- #undef S
-
- const Score Tempo = make_score(24, 11);
- const Score RookOnPawn = make_score(10, 28);
- const Score RookOpenFile = make_score(43, 21);
- const Score RookSemiopenFile = make_score(19, 10);
- const Score BishopPawns = make_score( 8, 12);
- const Score MinorBehindPawn = make_score(16, 0);
- const Score TrappedRook = make_score(90, 0);
- const Score Unstoppable = make_score( 0, 20);
+ // Assorted bonuses and penalties used by evaluation
+ const Score KingOnOne = S(2 , 58);
+ const Score KingOnMany = S(6 ,125);
+ const Score RookOnPawn = S(10, 28);
+ const Score RookOpenFile = S(43, 21);
+ const Score RookSemiOpenFile = S(19, 10);
+ const Score BishopPawns = S( 8, 12);
+ const Score MinorBehindPawn = S(16, 0);
+ const Score TrappedRook = S(92, 0);
+ const Score Unstoppable = S( 0, 20);
+ const Score Hanging = S(23, 20);
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
// happen in Chess960 games.
- const Score TrappedBishopA1H1 = make_score(50, 50);
+ const Score TrappedBishopA1H1 = S(50, 50);
+
+ #undef S
// SpaceMask[Color] contains the area of the board which is considered
// by the space evaluation. In the middlegame, each side is given a bonus
@@ -202,10 +194,11 @@ namespace {
const int BishopCheck = 2;
const int KnightCheck = 3;
- // KingDanger[Color][attackUnits] contains the actual king danger weighted
- // scores, indexed by color and by a calculated integer number.
- Score KingDanger[COLOR_NB][128];
+ // KingDanger[attackUnits] contains the actual king danger weighted
+ // scores, indexed by a calculated integer number.
+ Score KingDanger[128];
+ const int ScalePawnSpan[2] = { 38, 56 };
// apply_weight() weighs score 'v' by weight 'w' trying to prevent overflow
Score apply_weight(Score v, const Weight& w) {
@@ -213,17 +206,6 @@ namespace {
}
- // weight_option() computes the value of an evaluation weight, by combining
- // two UCI-configurable weights (midgame and endgame) with an internal weight.
-
- Weight weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
-
- Weight w = { Options[mgOpt] * mg_value(internalWeight) / 100,
- Options[egOpt] * eg_value(internalWeight) / 100 };
- return w;
- }
-
-
// init_eval_info() initializes king bitboards for given color adding
// pawn attacks. To be done at the beginning of the evaluation.
@@ -239,7 +221,7 @@ namespace {
ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
// Init king safety tables only if we are going to use them
- if (pos.count(Us) && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
+ if (pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
{
ei.kingRing[Them] = b | shift_bb(b);
b &= ei.attackedBy[Us][PAWN];
@@ -251,10 +233,10 @@ namespace {
}
- // evaluate_outposts() evaluates bishop and knight outpost squares
+ // evaluate_outpost() evaluates bishop and knight outpost squares
template
- Score evaluate_outposts(const Position& pos, EvalInfo& ei, Square s) {
+ Score evaluate_outpost(const Position& pos, const EvalInfo& ei, Square s) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
@@ -274,7 +256,7 @@ namespace {
bonus += bonus / 2;
}
- return make_score(bonus, bonus);
+ return make_score(bonus * 2, bonus / 2);
}
@@ -335,9 +317,9 @@ namespace {
if (Pt == BISHOP)
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
- // Bishop and knight outposts squares
+ // Bishop and knight outpost square
if (!(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s)))
- score += evaluate_outposts(pos, ei, s);
+ score += evaluate_outpost(pos, ei, s);
// Bishop or knight behind a pawn
if ( relative_rank(Us, s) < RANK_5
@@ -357,7 +339,7 @@ namespace {
// Give a bonus for a rook on a open or semi-open file
if (ei.pi->semiopen_file(Us, file_of(s)))
- score += ei.pi->semiopen_file(Them, file_of(s)) ? RookOpenFile : RookSemiopenFile;
+ score += ei.pi->semiopen_file(Them, file_of(s)) ? RookOpenFile : RookSemiOpenFile;
if (mob > 3 || ei.pi->semiopen_file(Us, file_of(s)))
continue;
@@ -369,7 +351,7 @@ namespace {
if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq)))
&& (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1)
&& !ei.pi->semiopen_side(Us, file_of(ksq), file_of(s) < file_of(ksq)))
- score -= (TrappedRook - make_score(mob * 8, 0)) * (1 + !pos.can_castle(Us));
+ score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us));
}
// An important Chess960 pattern: A cornered bishop blocked by a friendly
@@ -432,7 +414,8 @@ namespace {
attackUnits = std::min(20, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount(undefended))
+ 2 * (ei.pinnedPieces[Us] != 0)
- - mg_value(score) / 32;
+ - mg_value(score) / 32
+ - !pos.count(Them) * 15;
// Analyse the enemy's safe queen contact checks. Firstly, find the
// undefended squares around the king that are attacked by the enemy's
@@ -445,9 +428,7 @@ namespace {
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
if (b)
- attackUnits += QueenContactCheck
- * popcount(b)
- * (Them == pos.side_to_move() ? 2 : 1);
+ attackUnits += QueenContactCheck * popcount(b);
}
// Analyse the enemy's safe rook contact checks. Firstly, find the
@@ -465,9 +446,7 @@ namespace {
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]);
if (b)
- attackUnits += RookContactCheck
- * popcount(b)
- * (Them == pos.side_to_move() ? 2 : 1);
+ attackUnits += RookContactCheck * popcount(b);
}
// Analyse the enemy's safe distance checks for sliders and knights
@@ -501,7 +480,7 @@ namespace {
// Finally, extract the king danger score from the KingDanger[]
// array and subtract the score from evaluation.
- score -= KingDanger[Us == Search::RootColor][attackUnits];
+ score -= KingDanger[attackUnits];
}
if (Trace)
@@ -519,8 +498,17 @@ namespace {
const Color Them = (Us == WHITE ? BLACK : WHITE);
- Bitboard b, weakEnemies;
+ Bitboard b, weakEnemies, protectedEnemies;
Score score = SCORE_ZERO;
+ enum { Minor, Major };
+
+ // Protected enemies
+ protectedEnemies = (pos.pieces(Them) ^ pos.pieces(Them,PAWN))
+ & ei.attackedBy[Them][PAWN]
+ & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+
+ if (protectedEnemies)
+ score += Threat[Minor][type_of(pos.piece_on(lsb(protectedEnemies)))];
// Enemies not defended by a pawn and under our attack
weakEnemies = pos.pieces(Them)
@@ -530,18 +518,21 @@ namespace {
// Add a bonus according if the attacking pieces are minor or major
if (weakEnemies)
{
- b = weakEnemies & (ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+ b = weakEnemies & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
if (b)
- score += Threat[0][type_of(pos.piece_on(lsb(b)))];
+ score += Threat[Minor][type_of(pos.piece_on(lsb(b)))];
b = weakEnemies & (ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]);
if (b)
- score += Threat[1][type_of(pos.piece_on(lsb(b)))];
+ score += Threat[Major][type_of(pos.piece_on(lsb(b)))];
b = weakEnemies & ~ei.attackedBy[Them][ALL_PIECES];
if (b)
- score += more_than_one(b) ? Hanging[Us != pos.side_to_move()] * popcount(b)
- : Hanging[Us == pos.side_to_move()];
+ score += more_than_one(b) ? Hanging * popcount(b) : Hanging;
+
+ b = weakEnemies & ei.attackedBy[Us][KING];
+ if (b)
+ score += more_than_one(b) ? KingOnMany : KingOnOne;
}
if (Trace)
@@ -590,22 +581,18 @@ namespace {
// If the pawn is free to advance, then increase the bonus
if (pos.empty(blockSq))
{
- squaresToQueen = forward_bb(Us, s);
+ // If there is a rook or queen attacking/defending the pawn from behind,
+ // consider all the squaresToQueen. Otherwise consider only the squares
+ // in the pawn's path attacked or occupied by the enemy.
+ defendedSquares = unsafeSquares = squaresToQueen = forward_bb(Us, s);
- // If there is an enemy rook or queen attacking the pawn from behind,
- // add all X-ray attacks by the rook or queen. Otherwise consider only
- // the squares in the pawn's path attacked or occupied by the enemy.
- if ( unlikely(forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN))
- && (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN) & pos.attacks_from(s)))
- unsafeSquares = squaresToQueen;
- else
- unsafeSquares = squaresToQueen & (ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
+ Bitboard bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from(s);
- if ( unlikely(forward_bb(Them, s) & pos.pieces(Us, ROOK, QUEEN))
- && (forward_bb(Them, s) & pos.pieces(Us, ROOK, QUEEN) & pos.attacks_from(s)))
- defendedSquares = squaresToQueen;
- else
- defendedSquares = squaresToQueen & ei.attackedBy[Us][ALL_PIECES];
+ if (!(pos.pieces(Us) & bb))
+ defendedSquares &= ei.attackedBy[Us][ALL_PIECES];
+
+ if (!(pos.pieces(Them) & bb))
+ unsafeSquares &= ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them);
// If there aren't any enemy attacks, assign a big bonus. Otherwise
// assign a smaller bonus if the block square isn't attacked.
@@ -621,6 +608,8 @@ namespace {
mbonus += k * rr, ebonus += k * rr;
}
+ else if (pos.pieces(Us) & blockSq)
+ mbonus += rr * 3 + r * 2 + 3, ebonus += rr + r * 2;
} // rr != 0
if (pos.count(Us) < pos.count(Them))
@@ -637,18 +626,15 @@ namespace {
}
- // evaluate_unstoppable_pawns() scores the most advanced among the passed and
- // candidate pawns. In case opponent has no pieces but pawns, this is somewhat
- // related to the possibility that pawns are unstoppable.
+ // evaluate_unstoppable_pawns() scores the most advanced passed pawn. In case
+ // both players have no pieces but pawns, this is somewhat related to the
+ // possibility that pawns are unstoppable.
- Score evaluate_unstoppable_pawns(const Position& pos, Color us, const EvalInfo& ei) {
+ Score evaluate_unstoppable_pawns(Color us, const EvalInfo& ei) {
- Bitboard b = ei.pi->passed_pawns(us) | ei.pi->candidate_pawns(us);
+ Bitboard b = ei.pi->passed_pawns(us);
- if (!b || pos.non_pawn_material(~us))
- return SCORE_ZERO;
-
- return Unstoppable * int(relative_rank(us, frontmost_sq(us, b)));
+ return b ? Unstoppable * int(relative_rank(us, frontmost_sq(us, b))) : SCORE_ZERO;
}
@@ -696,9 +682,9 @@ namespace {
Thread* thisThread = pos.this_thread();
// Initialize score by reading the incrementally updated scores included
- // in the position object (material + piece square tables) and adding a
- // Tempo bonus. Score is computed from the point of view of white.
- score = pos.psq_score() + (pos.side_to_move() == WHITE ? Tempo : -Tempo);
+ // in the position object (material + piece square tables).
+ // Score is computed from the point of view of white.
+ score = pos.psq_score();
// Probe the material hash table
ei.mi = Material::probe(pos, thisThread->materialTable, thisThread->endgames);
@@ -741,10 +727,10 @@ namespace {
score += evaluate_passed_pawns(pos, ei)
- evaluate_passed_pawns(pos, ei);
- // If one side has only a king, score for potential unstoppable pawns
- if (!pos.non_pawn_material(WHITE) || !pos.non_pawn_material(BLACK))
- score += evaluate_unstoppable_pawns(pos, WHITE, ei)
- - evaluate_unstoppable_pawns(pos, BLACK, ei);
+ // If both sides have only pawns, score for potential unstoppable pawns
+ if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK))
+ score += evaluate_unstoppable_pawns(WHITE, ei)
+ - evaluate_unstoppable_pawns(BLACK, ei);
// Evaluate space for both sides, only in middlegame
if (ei.mi->space_weight())
@@ -754,29 +740,35 @@ namespace {
}
// Scale winning side if position is more drawish than it appears
- ScaleFactor sf = eg_value(score) > VALUE_DRAW ? ei.mi->scale_factor(pos, WHITE)
- : ei.mi->scale_factor(pos, BLACK);
+ Color strongSide = eg_value(score) > VALUE_DRAW ? WHITE : BLACK;
+ ScaleFactor sf = ei.mi->scale_factor(pos, strongSide);
- // If we don't already have an unusual scale factor, check for opposite
- // colored bishop endgames, and use a lower scale for those.
+ // If we don't already have an unusual scale factor, check for certain
+ // types of endgames, and use a lower scale for those.
if ( ei.mi->game_phase() < PHASE_MIDGAME
- && pos.opposite_bishops()
&& (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN))
{
- // Ignoring any pawns, do both sides only have a single bishop and no
- // other pieces?
- if ( pos.non_pawn_material(WHITE) == BishopValueMg
- && pos.non_pawn_material(BLACK) == BishopValueMg)
- {
- // Check for KBP vs KB with only a single pawn that is almost
- // certainly a draw or at least two pawns.
- bool one_pawn = (pos.count(WHITE) + pos.count(BLACK) == 1);
- sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
+ if (pos.opposite_bishops()) {
+ // Ignoring any pawns, do both sides only have a single bishop and no
+ // other pieces?
+ if ( pos.non_pawn_material(WHITE) == BishopValueMg
+ && pos.non_pawn_material(BLACK) == BishopValueMg)
+ {
+ // Check for KBP vs KB with only a single pawn that is almost
+ // certainly a draw or at least two pawns.
+ bool one_pawn = (pos.count(WHITE) + pos.count(BLACK) == 1);
+ sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
+ }
+ else
+ // Endgame with opposite-colored bishops, but also other pieces. Still
+ // a bit drawish, but not as drawish as with only the two bishops.
+ sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL);
+ } else if ( abs(eg_value(score)) <= BishopValueEg
+ && ei.pi->pawn_span(strongSide) <= 1
+ && !pos.pawn_passed(~strongSide, pos.king_square(~strongSide))) {
+ // Endings where weaker side can be place his king in front of the opponent's pawns are drawish.
+ sf = ScaleFactor(ScalePawnSpan[ei.pi->pawn_span(strongSide)]);
}
- else
- // Endgame with opposite-colored bishops, but also other pieces. Still
- // a bit drawish, but not as drawish as with only the two bishops.
- sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL);
}
// Interpolate between a middlegame and a (scaled by 'sf') endgame score
@@ -788,7 +780,7 @@ namespace {
// In case of tracing add all single evaluation contributions for both white and black
if (Trace)
{
- Tracing::add_term(Tracing::PST, pos.psq_score());
+ Tracing::add_term(Tracing::MATERIAL, pos.psq_score());
Tracing::add_term(Tracing::IMBALANCE, ei.mi->material_value());
Tracing::add_term(PAWN, ei.pi->pawns_value());
Tracing::add_term(Tracing::MOBILITY, apply_weight(mobility[WHITE], Weights[Mobility])
@@ -821,13 +813,13 @@ namespace {
Score bScore = terms[BLACK][idx];
switch (idx) {
- case PST: case IMBALANCE: case PAWN: case TOTAL:
- ss << std::setw(20) << name << " | --- --- | --- --- | "
+ case MATERIAL: case IMBALANCE: case PAWN: case TOTAL:
+ ss << std::setw(15) << name << " | --- --- | --- --- | "
<< std::setw(5) << to_cp(mg_value(wScore - bScore)) << " "
<< std::setw(5) << to_cp(eg_value(wScore - bScore)) << " \n";
break;
default:
- ss << std::setw(20) << name << " | " << std::noshowpos
+ ss << std::setw(15) << name << " | " << std::noshowpos
<< std::setw(5) << to_cp(mg_value(wScore)) << " "
<< std::setw(5) << to_cp(eg_value(wScore)) << " | "
<< std::setw(5) << to_cp(mg_value(bScore)) << " "
@@ -846,12 +838,12 @@ namespace {
std::stringstream ss;
ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
- << " Eval term | White | Black | Total \n"
- << " | MG EG | MG EG | MG EG \n"
- << "---------------------+-------------+-------------+-------------\n";
+ << " Eval term | White | Black | Total \n"
+ << " | MG EG | MG EG | MG EG \n"
+ << "----------------+-------------+-------------+-------------\n";
- format_row(ss, "Material, PST, Tempo", PST);
- format_row(ss, "Material imbalance", IMBALANCE);
+ format_row(ss, "Material", MATERIAL);
+ format_row(ss, "Imbalance", IMBALANCE);
format_row(ss, "Pawns", PAWN);
format_row(ss, "Knights", KNIGHT);
format_row(ss, "Bishops", BISHOP);
@@ -863,7 +855,7 @@ namespace {
format_row(ss, "Passed pawns", PASSED);
format_row(ss, "Space", SPACE);
- ss << "---------------------+-------------+-------------+-------------\n";
+ ss << "----------------+-------------+-------------+-------------\n";
format_row(ss, "Total", TOTAL);
ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n";
@@ -880,7 +872,7 @@ namespace Eval {
/// of the position always from the point of view of the side to move.
Value evaluate(const Position& pos) {
- return do_evaluate(pos);
+ return do_evaluate(pos) + Tempo;
}
@@ -898,22 +890,13 @@ namespace Eval {
void init() {
- Weights[Mobility] = weight_option("Mobility (Midgame)", "Mobility (Endgame)", WeightsInternal[Mobility]);
- Weights[PawnStructure] = weight_option("Pawn Structure (Midgame)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]);
- Weights[PassedPawns] = weight_option("Passed Pawns (Midgame)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
- Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]);
- Weights[KingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
- Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);
-
const double MaxSlope = 30;
const double Peak = 1280;
for (int t = 0, i = 1; i < 100; ++i)
{
t = int(std::min(Peak, std::min(0.4 * i * i, t + MaxSlope)));
-
- KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
- KingDanger[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
+ KingDanger[i] = apply_weight(make_score(t, 0), Weights[KingSafety]);
}
}
diff --git a/DroidFish/jni/stockfish/evaluate.h b/DroidFish/jni/stockfish/evaluate.h
index 73df76a..fff2476 100644
--- a/DroidFish/jni/stockfish/evaluate.h
+++ b/DroidFish/jni/stockfish/evaluate.h
@@ -26,6 +26,8 @@ class Position;
namespace Eval {
+const Value Tempo = Value(17); // Must be visible to search
+
extern void init();
extern Value evaluate(const Position& pos);
extern std::string trace(const Position& pos);
diff --git a/DroidFish/jni/stockfish/main.cpp b/DroidFish/jni/stockfish/main.cpp
index cbb260f..69d29c2 100644
--- a/DroidFish/jni/stockfish/main.cpp
+++ b/DroidFish/jni/stockfish/main.cpp
@@ -23,6 +23,7 @@
#include "evaluate.h"
#include "position.h"
#include "search.h"
+#include "tbprobe.h"
#include "thread.h"
#include "tt.h"
#include "ucioption.h"
@@ -36,10 +37,10 @@ int main(int argc, char* argv[]) {
Position::init();
Bitbases::init_kpk();
Search::init();
- Pawns::init();
Eval::init();
Threads.init();
TT.resize(Options["Hash"]);
+ Tablebases::init(Options["SyzygyPath"]);
UCI::loop(argc, argv);
diff --git a/DroidFish/jni/stockfish/material.cpp b/DroidFish/jni/stockfish/material.cpp
index 9a12066..b7db134 100644
--- a/DroidFish/jni/stockfish/material.cpp
+++ b/DroidFish/jni/stockfish/material.cpp
@@ -29,10 +29,10 @@ namespace {
// Polynomial material balance parameters
- // pair pawn knight bishop rook queen
- const int LinearCoefficients[6] = { 1852, -162, -1122, -183, 249, -154 };
+ // pair pawn knight bishop rook queen
+ const int Linear[6] = { 1852, -162, -1122, -183, 249, -154 };
- const int QuadraticCoefficientsSameSide[][PIECE_TYPE_NB] = {
+ const int QuadraticSameSide[][PIECE_TYPE_NB] = {
// OUR PIECES
// pair pawn knight bishop rook queen
{ 0 }, // Bishop pair
@@ -43,7 +43,7 @@ namespace {
{-177, 25, 129, 142, -137, 0 } // Queen
};
- const int QuadraticCoefficientsOppositeSide[][PIECE_TYPE_NB] = {
+ const int QuadraticOppositeSide[][PIECE_TYPE_NB] = {
// THEIR PIECES
// pair pawn knight bishop rook queen
{ 0 }, // Bishop pair
@@ -66,8 +66,7 @@ namespace {
// Helper templates used to detect a given material distribution
template bool is_KXK(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
- return !pos.count(Them)
- && pos.non_pawn_material(Them) == VALUE_ZERO
+ return !more_than_one(pos.pieces(Them))
&& pos.non_pawn_material(Us) >= RookValueMg;
}
@@ -94,26 +93,24 @@ namespace {
const Color Them = (Us == WHITE ? BLACK : WHITE);
- int pt1, pt2, pc, v;
- int value = 0;
+ int bonus = 0;
// Second-degree polynomial material imbalance by Tord Romstad
- for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
+ for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
{
- pc = pieceCount[Us][pt1];
- if (!pc)
+ if (!pieceCount[Us][pt1])
continue;
- v = LinearCoefficients[pt1];
+ int v = Linear[pt1];
- for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
- v += QuadraticCoefficientsSameSide[pt1][pt2] * pieceCount[Us][pt2]
- + QuadraticCoefficientsOppositeSide[pt1][pt2] * pieceCount[Them][pt2];
+ for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
+ v += QuadraticSameSide[pt1][pt2] * pieceCount[Us][pt2]
+ + QuadraticOppositeSide[pt1][pt2] * pieceCount[Them][pt2];
- value += pc * v;
+ bonus += pieceCount[Us][pt1] * v;
}
- return value;
+ return bonus;
}
} // namespace
@@ -139,7 +136,7 @@ Entry* probe(const Position& pos, Table& entries, Endgames& endgames) {
std::memset(e, 0, sizeof(Entry));
e->key = key;
e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
- e->gamePhase = game_phase(pos);
+ e->gamePhase = pos.game_phase();
// Let's look if we have a specialized evaluation function for this particular
// material configuration. Firstly we look for a fixed configuration one, then
@@ -248,18 +245,4 @@ Entry* probe(const Position& pos, Table& entries, Endgames& endgames) {
return e;
}
-
-/// Material::game_phase() calculates the phase given the current
-/// position. Because the phase is strictly a function of the material, it
-/// is stored in MaterialEntry.
-
-Phase game_phase(const Position& pos) {
-
- Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
-
- return npm >= MidgameLimit ? PHASE_MIDGAME
- : npm <= EndgameLimit ? PHASE_ENDGAME
- : Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
-}
-
} // namespace Material
diff --git a/DroidFish/jni/stockfish/material.h b/DroidFish/jni/stockfish/material.h
index 9116361..f05541c 100644
--- a/DroidFish/jni/stockfish/material.h
+++ b/DroidFish/jni/stockfish/material.h
@@ -68,7 +68,6 @@ struct Entry {
typedef HashTable Table;
Entry* probe(const Position& pos, Table& entries, Endgames& endgames);
-Phase game_phase(const Position& pos);
} // namespace Material
diff --git a/DroidFish/jni/stockfish/misc.cpp b/DroidFish/jni/stockfish/misc.cpp
index ebbb778..3519611 100644
--- a/DroidFish/jni/stockfish/misc.cpp
+++ b/DroidFish/jni/stockfish/misc.cpp
@@ -17,6 +17,7 @@
along with this program. If not, see .
*/
+#include
#include
#include
#include
@@ -28,7 +29,7 @@ using namespace std;
/// Version number. If Version is left empty, then compile date in the format
/// DD-MM-YY and show in engine_info.
-static const string Version = "5";
+static const string Version = "121014";
/// engine_info() returns the full name of the current Stockfish version. This
diff --git a/DroidFish/jni/stockfish/misc.h b/DroidFish/jni/stockfish/misc.h
index 92bde8f..970f335 100644
--- a/DroidFish/jni/stockfish/misc.h
+++ b/DroidFish/jni/stockfish/misc.h
@@ -20,7 +20,7 @@
#ifndef MISC_H_INCLUDED
#define MISC_H_INCLUDED
-#include
+#include
#include
#include
@@ -37,12 +37,6 @@ extern void dbg_mean_of(int v);
extern void dbg_print();
-struct Log : public std::ofstream {
- Log(const std::string& f = "log.txt") : std::ofstream(f.c_str(), std::ios::out | std::ios::app) {}
- ~Log() { if (is_open()) close(); }
-};
-
-
namespace Time {
typedef int64_t point;
inline point now() { return system_time_to_msec(); }
diff --git a/DroidFish/jni/stockfish/notation.cpp b/DroidFish/jni/stockfish/notation.cpp
index cace78b..7e8765f 100644
--- a/DroidFish/jni/stockfish/notation.cpp
+++ b/DroidFish/jni/stockfish/notation.cpp
@@ -18,9 +18,7 @@
*/
#include
-#include
#include
-#include
#include "movegen.h"
#include "notation.h"
@@ -42,7 +40,7 @@ string score_to_uci(Value v, Value alpha, Value beta) {
stringstream ss;
- if (abs(v) < VALUE_MATE_IN_MAX_PLY)
+ if (abs(v) < VALUE_MATE - MAX_PLY)
ss << "cp " << v * 100 / PawnValueEg;
else
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
@@ -95,162 +93,3 @@ Move move_from_uci(const Position& pos, string& str) {
return MOVE_NONE;
}
-
-
-/// move_to_san() takes a position and a legal Move as input and returns its
-/// short algebraic notation representation.
-
-const string move_to_san(Position& pos, Move m) {
-
- if (m == MOVE_NONE)
- return "(none)";
-
- if (m == MOVE_NULL)
- return "(null)";
-
- assert(MoveList(pos).contains(m));
-
- Bitboard others, b;
- string san;
- Color us = pos.side_to_move();
- Square from = from_sq(m);
- Square to = to_sq(m);
- Piece pc = pos.piece_on(from);
- PieceType pt = type_of(pc);
-
- if (type_of(m) == CASTLING)
- san = to > from ? "O-O" : "O-O-O";
- else
- {
- if (pt != PAWN)
- {
- san = PieceToChar[WHITE][pt]; // Upper case
-
- // A disambiguation occurs if we have more then one piece of type 'pt'
- // that can reach 'to' with a legal move.
- others = b = (pos.attacks_from(pc, to) & pos.pieces(us, pt)) ^ from;
-
- while (b)
- {
- Square s = pop_lsb(&b);
- if (!pos.legal(make_move(s, to), pos.pinned_pieces(us)))
- others ^= s;
- }
-
- if (!others)
- { /* Disambiguation is not needed */ }
-
- else if (!(others & file_bb(from)))
- san += to_char(file_of(from));
-
- else if (!(others & rank_bb(from)))
- san += to_char(rank_of(from));
-
- else
- san += to_string(from);
- }
- else if (pos.capture(m))
- san = to_char(file_of(from));
-
- if (pos.capture(m))
- san += 'x';
-
- san += to_string(to);
-
- if (type_of(m) == PROMOTION)
- san += string("=") + PieceToChar[WHITE][promotion_type(m)];
- }
-
- if (pos.gives_check(m, CheckInfo(pos)))
- {
- StateInfo st;
- pos.do_move(m, st);
- san += MoveList(pos).size() ? "+" : "#";
- pos.undo_move(m);
- }
-
- return san;
-}
-
-
-/// pretty_pv() formats human-readable search information, typically to be
-/// appended to the search log file. It uses the two helpers below to pretty
-/// format the time and score respectively.
-
-static string format(int64_t msecs) {
-
- const int MSecMinute = 1000 * 60;
- const int MSecHour = 1000 * 60 * 60;
-
- int64_t hours = msecs / MSecHour;
- int64_t minutes = (msecs % MSecHour) / MSecMinute;
- int64_t seconds = ((msecs % MSecHour) % MSecMinute) / 1000;
-
- stringstream ss;
-
- if (hours)
- ss << hours << ':';
-
- ss << setfill('0') << setw(2) << minutes << ':' << setw(2) << seconds;
-
- return ss.str();
-}
-
-static string format(Value v) {
-
- stringstream ss;
-
- if (v >= VALUE_MATE_IN_MAX_PLY)
- ss << "#" << (VALUE_MATE - v + 1) / 2;
-
- else if (v <= VALUE_MATED_IN_MAX_PLY)
- ss << "-#" << (VALUE_MATE + v) / 2;
-
- else
- ss << setprecision(2) << fixed << showpos << double(v) / PawnValueEg;
-
- return ss.str();
-}
-
-string pretty_pv(Position& pos, int depth, Value value, int64_t msecs, Move pv[]) {
-
- const uint64_t K = 1000;
- const uint64_t M = 1000000;
-
- std::stack st;
- Move* m = pv;
- string san, str, padding;
- stringstream ss;
-
- ss << setw(2) << depth << setw(8) << format(value) << setw(8) << format(msecs);
-
- if (pos.nodes_searched() < M)
- ss << setw(8) << pos.nodes_searched() / 1 << " ";
-
- else if (pos.nodes_searched() < K * M)
- ss << setw(7) << pos.nodes_searched() / K << "K ";
-
- else
- ss << setw(7) << pos.nodes_searched() / M << "M ";
-
- str = ss.str();
- padding = string(str.length(), ' ');
-
- while (*m != MOVE_NONE)
- {
- san = move_to_san(pos, *m) + ' ';
-
- if ((str.length() + san.length()) % 80 <= san.length()) // Exceed 80 cols
- str += "\n" + padding;
-
- str += san;
-
- st.push(StateInfo());
- pos.do_move(*m++, st.top());
- }
-
- while (m != pv)
- pos.undo_move(*--m);
-
- return str;
-}
diff --git a/DroidFish/jni/stockfish/notation.h b/DroidFish/jni/stockfish/notation.h
index 730e841..251a0ca 100644
--- a/DroidFish/jni/stockfish/notation.h
+++ b/DroidFish/jni/stockfish/notation.h
@@ -29,7 +29,18 @@ class Position;
std::string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
Move move_from_uci(const Position& pos, std::string& str);
const std::string move_to_uci(Move m, bool chess960);
-const std::string move_to_san(Position& pos, Move m);
-std::string pretty_pv(Position& pos, int depth, Value score, int64_t msecs, Move pv[]);
+
+inline char to_char(File f, bool tolower = true) {
+ return char(f - FILE_A + (tolower ? 'a' : 'A'));
+}
+
+inline char to_char(Rank r) {
+ return char(r - RANK_1 + '1');
+}
+
+inline const std::string to_string(Square s) {
+ char ch[] = { to_char(file_of(s)), to_char(rank_of(s)), 0 };
+ return ch;
+}
#endif // #ifndef NOTATION_H_INCLUDED
diff --git a/DroidFish/jni/stockfish/pawns.cpp b/DroidFish/jni/stockfish/pawns.cpp
index 5768eb3..4693e15 100644
--- a/DroidFish/jni/stockfish/pawns.cpp
+++ b/DroidFish/jni/stockfish/pawns.cpp
@@ -49,13 +49,13 @@ namespace {
{ S(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28) } };
- // Connected pawn bonus by file and rank (initialized by formula)
- Score Connected[FILE_NB][RANK_NB];
+ // Connected bonus by rank
+ const int Connected[RANK_NB] = {0, 6, 15, 10, 57, 75, 135, 258};
- // Candidate passed pawn bonus by rank
- const Score CandidatePassed[RANK_NB] = {
- S( 0, 0), S( 6, 13), S(6,13), S(14,29),
- S(34,68), S(83,166), S(0, 0), S( 0, 0) };
+ // Levers bonus by rank
+ const Score Lever[RANK_NB] = {
+ S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
+ S(20,20), S(40,40), S(0, 0), S(0, 0) };
// Bonus for file distance of the two outermost pawns
const Score PawnsFileSpan = S(0, 15);
@@ -69,7 +69,7 @@ namespace {
// Danger of enemy pawns moving toward our king indexed by
// [no friendly pawn | pawn unblocked | pawn blocked][rank of enemy pawn]
- const Value StormDanger[3][RANK_NB] = {
+ const Value StormDanger[][RANK_NB] = {
{ V( 0), V(64), V(128), V(51), V(26) },
{ V(26), V(32), V( 96), V(38), V(20) },
{ V( 0), V( 0), V(160), V(25), V(13) } };
@@ -91,15 +91,15 @@ namespace {
Bitboard b, p, doubled;
Square s;
- File f;
- bool passed, isolated, opposed, connected, backward, candidate, unsupported;
+ bool passed, isolated, opposed, connected, backward, unsupported, lever;
Score value = SCORE_ZERO;
const Square* pl = pos.list(Us);
+ const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)];
- Bitboard ourPawns = pos.pieces(Us, PAWN);
+ Bitboard ourPawns = pos.pieces(Us , PAWN);
Bitboard theirPawns = pos.pieces(Them, PAWN);
- e->passedPawns[Us] = e->candidatePawns[Us] = 0;
+ e->passedPawns[Us] = 0;
e->kingSquares[Us] = SQ_NONE;
e->semiopenFiles[Us] = 0xFF;
e->pawnAttacks[Us] = shift_bb(ourPawns) | shift_bb(ourPawns);
@@ -111,7 +111,8 @@ namespace {
{
assert(pos.piece_on(s) == make_piece(Us, PAWN));
- f = file_of(s);
+ Rank r = rank_of(s), rr = relative_rank(Us, s);
+ File f = file_of(s);
// This file cannot be semi-open
e->semiopenFiles[Us] &= ~(1 << f);
@@ -130,6 +131,7 @@ namespace {
doubled = ourPawns & forward_bb(Us, s);
opposed = theirPawns & forward_bb(Us, s);
passed = !(theirPawns & passed_pawn_mask(Us, s));
+ lever = theirPawns & pawnAttacksBB[s];
// Test for backward pawn.
// If the pawn is passed, isolated, or connected it cannot be
@@ -155,14 +157,6 @@ namespace {
assert(opposed | passed | (pawn_attack_span(Us, s) & theirPawns));
- // A not-passed pawn is a candidate to become passed, if it is free to
- // advance and if the number of friendly pawns beside or behind this
- // pawn on adjacent files is higher than or equal to the number of
- // enemy pawns in the forward direction on the adjacent files.
- candidate = !(opposed | passed | backward | isolated)
- && (b = pawn_attack_span(Them, s + pawn_push(Us)) & ourPawns) != 0
- && popcount(b) >= popcount(pawn_attack_span(Us, s) & theirPawns);
-
// Passed pawns will be properly scored in evaluation because we need
// full attack info to evaluate passed pawns. Only the frontmost passed
// pawn on each file is considered a true passed pawn.
@@ -182,25 +176,23 @@ namespace {
if (backward)
value -= Backward[opposed][f];
- if (connected)
- value += Connected[f][relative_rank(Us, s)];
-
- if (candidate)
- {
- value += CandidatePassed[relative_rank(Us, s)];
-
- if (!doubled)
- e->candidatePawns[Us] |= s;
+ if (connected) {
+ int bonus = Connected[rr];
+ if (ourPawns & adjacent_files_bb(f) & rank_bb(r))
+ bonus += (Connected[rr+1] - Connected[rr]) / 2;
+ value += make_score(bonus / 2, bonus >> opposed);
}
+
+ if (lever)
+ value += Lever[rr];
}
+ b = e->semiopenFiles[Us] ^ 0xFF;
+ e->pawnSpan[Us] = b ? int(msb(b) - lsb(b)) : 0;
+
// In endgame it's better to have pawns on both wings. So give a bonus according
// to file distance between left and right outermost pawns.
- if (pos.count(Us) > 1)
- {
- b = e->semiopenFiles[Us] ^ 0xFF;
- value += PawnsFileSpan * int(msb(b) - lsb(b));
- }
+ value += PawnsFileSpan * e->pawnSpan[Us];
return value;
}
@@ -209,24 +201,8 @@ namespace {
namespace Pawns {
-/// init() initializes some tables by formula instead of hard-coding their values
-
-void init() {
-
- const int bonusesByFile[8] = { 1, 3, 3, 4, 4, 3, 3, 1 };
- int bonus;
-
- for (Rank r = RANK_1; r < RANK_8; ++r)
- for (File f = FILE_A; f <= FILE_H; ++f)
- {
- bonus = r * (r-1) * (r-2) + bonusesByFile[f] * (r/2 + 1);
- Connected[f][r] = make_score(bonus, bonus);
- }
-}
-
-
-/// probe() takes a position object as input, computes a Entry object, and returns
-/// a pointer to it. The result is also stored in a hash table, so we don't have
+/// probe() takes a position as input, computes a Entry object, and returns a
+/// pointer to it. The result is also stored in a hash table, so we don't have
/// to recompute everything when the same pawn structure occurs again.
Entry* probe(const Position& pos, Table& entries) {
@@ -250,30 +226,30 @@ template
Value Entry::shelter_storm(const Position& pos, Square ksq) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
- static const Bitboard MiddleEdges = (FileABB | FileHBB) & (Rank2BB | Rank3BB);
+ const Bitboard Edges = (FileABB | FileHBB) & (Rank2BB | Rank3BB);
- Value safety = MaxSafetyBonus;
Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq));
Bitboard ourPawns = b & pos.pieces(Us);
Bitboard theirPawns = b & pos.pieces(Them);
- Rank rkUs, rkThem;
+ Value safety = MaxSafetyBonus;
File kf = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
for (File f = kf - File(1); f <= kf + File(1); ++f)
{
b = ourPawns & file_bb(f);
- rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
+ Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
b = theirPawns & file_bb(f);
- rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
+ Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
- if ( (MiddleEdges & make_square(f, rkThem))
+ if ( (Edges & make_square(f, rkThem))
&& file_of(ksq) == f
&& relative_rank(Us, ksq) == rkThem - 1)
safety += 200;
else
- safety -= ShelterWeakness[rkUs]
- + StormDanger[rkUs == RANK_1 ? 0 : rkThem == rkUs + 1 ? 2 : 1][rkThem];
+ safety -= ShelterWeakness[rkUs]
+ + StormDanger[rkUs == RANK_1 ? 0 :
+ rkThem != rkUs + 1 ? 1 : 2][rkThem];
}
return safety;
diff --git a/DroidFish/jni/stockfish/pawns.h b/DroidFish/jni/stockfish/pawns.h
index 28fe1c0..f24fb75 100644
--- a/DroidFish/jni/stockfish/pawns.h
+++ b/DroidFish/jni/stockfish/pawns.h
@@ -35,7 +35,6 @@ struct Entry {
Score pawns_value() const { return value; }
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
- Bitboard candidate_pawns(Color c) const { return candidatePawns[c]; }
int semiopen_file(Color c, File f) const {
return semiopenFiles[c] & (1 << f);
@@ -45,6 +44,10 @@ struct Entry {
return semiopenFiles[c] & (leftSide ? (1 << f) - 1 : ~((1 << (f + 1)) - 1));
}
+ int pawn_span(Color c) const {
+ return pawnSpan[c];
+ }
+
int pawns_on_same_color_squares(Color c, Square s) const {
return pawnsOnSquares[c][!!(DarkSquares & s)];
}
@@ -64,19 +67,18 @@ struct Entry {
Key key;
Score value;
Bitboard passedPawns[COLOR_NB];
- Bitboard candidatePawns[COLOR_NB];
Bitboard pawnAttacks[COLOR_NB];
Square kingSquares[COLOR_NB];
Score kingSafety[COLOR_NB];
int minKPdistance[COLOR_NB];
int castlingRights[COLOR_NB];
int semiopenFiles[COLOR_NB];
+ int pawnSpan[COLOR_NB];
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
};
typedef HashTable Table;
-void init();
Entry* probe(const Position& pos, Table& entries);
} // namespace Pawns
diff --git a/DroidFish/jni/stockfish/position.cpp b/DroidFish/jni/stockfish/position.cpp
index 982352c..cbaa07e 100644
--- a/DroidFish/jni/stockfish/position.cpp
+++ b/DroidFish/jni/stockfish/position.cpp
@@ -226,7 +226,7 @@ void Position::set(const string& fenStr, bool isChess960, Thread* th) {
incremented after Black's move.
*/
- char col, row, token;
+ unsigned char col, row, token;
size_t idx;
Square sq = SQ_A8;
std::istringstream ss(fenStr);
@@ -430,17 +430,12 @@ const string Position::fen() const {
}
-/// Position::pretty() returns an ASCII representation of the position to be
-/// printed to the standard output together with the move's san notation.
+/// Position::pretty() returns an ASCII representation of the position
-const string Position::pretty(Move m) const {
+const string Position::pretty() const {
std::ostringstream ss;
- if (m)
- ss << "\nMove: " << (sideToMove == BLACK ? ".." : "")
- << move_to_san(*const_cast(this), m);
-
ss << "\n +---+---+---+---+---+---+---+---+\n";
for (Rank r = RANK_8; r >= RANK_1; --r)
@@ -457,14 +452,23 @@ const string Position::pretty(Move m) const {
for (Bitboard b = checkers(); b; )
ss << to_string(pop_lsb(&b)) << " ";
- ss << "\nLegal moves: ";
- for (MoveList it(*this); *it; ++it)
- ss << move_to_san(*const_cast(this), *it) << " ";
-
return ss.str();
}
+/// Position::game_phase() calculates the game phase interpolating total non-pawn
+/// material between endgame and midgame limits.
+
+Phase Position::game_phase() const {
+
+ Value npm = st->npMaterial[WHITE] + st->npMaterial[BLACK];
+
+ npm = std::max(EndgameLimit, std::min(npm, MidgameLimit));
+
+ return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
+}
+
+
/// Position::check_blockers() returns a bitboard of all the pieces with color
/// 'c' that are blocking check on the king with color 'kingColor'. A piece
/// blocks a check if removing that piece from the board would result in a
@@ -803,9 +807,6 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
st->castlingRights &= ~cr;
}
- // Prefetch TT access as soon as we know the new hash key
- prefetch((char*)TT.first_entry(k));
-
// Move the piece. The tricky Chess960 castling is handled earlier
if (type_of(m) != CASTLING)
move_piece(from, to, us, pt);
@@ -1012,6 +1013,26 @@ void Position::undo_null_move() {
}
+/// Position::key_after() computes the new hash key after the given moven. Needed
+/// for speculative prefetch. It doesn't recognize special moves like castling,
+/// en-passant and promotions.
+
+Key Position::key_after(Move m) const {
+
+ Color us = sideToMove;
+ Square from = from_sq(m);
+ Square to = to_sq(m);
+ PieceType pt = type_of(piece_on(from));
+ PieceType captured = type_of(piece_on(to));
+ Key k = st->key ^ Zobrist::side;
+
+ if (captured)
+ k ^= Zobrist::psq[~us][captured][to];
+
+ return k ^ Zobrist::psq[us][pt][to] ^ Zobrist::psq[us][pt][from];
+}
+
+
/// Position::see() is a static exchange evaluator: It tries to estimate the
/// material gain or loss resulting from a move.
@@ -1113,10 +1134,6 @@ Value Position::see(Move m) const {
bool Position::is_draw() const {
- if ( !pieces(PAWN)
- && (non_pawn_material(WHITE) + non_pawn_material(BLACK) <= BishopValueMg))
- return true;
-
if (st->rule50 > 99 && (!checkers() || MoveList(*this).size()))
return true;
diff --git a/DroidFish/jni/stockfish/position.h b/DroidFish/jni/stockfish/position.h
index 0f88944..7f7d2c5 100644
--- a/DroidFish/jni/stockfish/position.h
+++ b/DroidFish/jni/stockfish/position.h
@@ -24,9 +24,9 @@
#include
#include "bitboard.h"
+#include "bitcount.h"
#include "types.h"
-
/// The checkInfo struct is initialized at c'tor time and keeps info used
/// to detect if a move gives check.
class Position;
@@ -83,7 +83,7 @@ public:
// Text input/output
void set(const std::string& fenStr, bool isChess960, Thread* th);
const std::string fen() const;
- const std::string pretty(Move m = MOVE_NONE) const;
+ const std::string pretty() const;
// Position representation
Bitboard pieces() const;
@@ -98,6 +98,7 @@ public:
bool empty(Square s) const;
template int count(Color c) const;
template const Square* list(Color c) const;
+ int total_piece_count() const;
// Castling
int can_castle(Color c) const;
@@ -146,6 +147,7 @@ public:
// Accessing hash keys
Key key() const;
+ Key key_after(Move m) const;
Key exclusion_key() const;
Key pawn_key() const;
Key material_key() const;
@@ -156,12 +158,14 @@ public:
// Other properties of the position
Color side_to_move() const;
+ Phase game_phase() const;
int game_ply() const;
bool is_chess960() const;
Thread* this_thread() const;
uint64_t nodes_searched() const;
void set_nodes_searched(uint64_t n);
bool is_draw() const;
+ int rule50_count() const;
// Position consistency check, for debugging
bool pos_is_ok(int* step = NULL) const;
@@ -348,6 +352,14 @@ inline int Position::game_ply() const {
return gamePly;
}
+inline int Position::rule50_count() const {
+ return st->rule50;
+}
+
+inline int Position::total_piece_count() const {
+ return HasPopCnt ? popcount(pieces()) : pieceCount[WHITE][ALL_PIECES];
+}
+
inline bool Position::opposite_bishops() const {
return pieceCount[WHITE][BISHOP] == 1
@@ -398,6 +410,8 @@ inline void Position::put_piece(Square s, Color c, PieceType pt) {
byColorBB[c] |= s;
index[s] = pieceCount[c][pt]++;
pieceList[c][pt][index[s]] = s;
+ if (!HasPopCnt)
+ pieceCount[WHITE][ALL_PIECES]++;
}
inline void Position::move_piece(Square from, Square to, Color c, PieceType pt) {
@@ -428,6 +442,8 @@ inline void Position::remove_piece(Square s, Color c, PieceType pt) {
index[lastSquare] = index[s];
pieceList[c][pt][index[lastSquare]] = lastSquare;
pieceList[c][pt][pieceCount[c][pt]] = SQ_NONE;
+ if (!HasPopCnt)
+ pieceCount[WHITE][ALL_PIECES]--;
}
#endif // #ifndef POSITION_H_INCLUDED
diff --git a/DroidFish/jni/stockfish/search.cpp b/DroidFish/jni/stockfish/search.cpp
index 4ac4c08..64233d2 100644
--- a/DroidFish/jni/stockfish/search.cpp
+++ b/DroidFish/jni/stockfish/search.cpp
@@ -19,18 +19,18 @@
#include
#include
-#include
#include
#include
#include
#include
-#include "book.h"
#include "evaluate.h"
#include "movegen.h"
#include "movepick.h"
#include "notation.h"
+#include "rkiss.h"
#include "search.h"
+#include "tbprobe.h"
#include "timeman.h"
#include "thread.h"
#include "tt.h"
@@ -42,9 +42,14 @@ namespace Search {
LimitsType Limits;
std::vector RootMoves;
Position RootPos;
- Color RootColor;
Time::point SearchTime;
StateStackPtr SetupStates;
+ int TBCardinality;
+ uint64_t TBHits;
+ bool RootInTB;
+ bool TB50MoveRule;
+ Depth TBProbeDepth;
+ Value TBScore;
}
using std::string;
@@ -53,31 +58,27 @@ using namespace Search;
namespace {
- // Set to true to force running with one thread. Used for debugging
- const bool FakeSplit = false;
-
// Different node types, used as template parameter
enum NodeType { Root, PV, NonPV };
// Dynamic razoring margin based on depth
- inline Value razor_margin(Depth d) { return Value(512 + 16 * d); }
+ inline Value razor_margin(Depth d) { return Value(512 + 32 * d); }
// Futility lookup tables (initialized at startup) and their access functions
int FutilityMoveCounts[2][32]; // [improving][depth]
inline Value futility_margin(Depth d) {
- return Value(100 * d);
+ return Value(200 * d);
}
// Reduction lookup tables (initialized at startup) and their access function
int8_t Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber]
template inline Depth reduction(bool i, Depth d, int mn) {
-
- return (Depth) Reductions[PvNode][i][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)];
+ return (Depth) Reductions[PvNode][i][std::min(int(d), 63)][std::min(mn, 63)];
}
- size_t MultiPV, PVIdx;
+ size_t PVIdx;
TimeManager TimeMgr;
double BestMoveChanges;
Value DrawValue[COLOR_NB];
@@ -98,18 +99,21 @@ namespace {
string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
struct Skill {
- Skill(int l) : level(l), best(MOVE_NONE) {}
+ Skill(int l, size_t rootSize) : level(l),
+ candidates(l < 20 ? std::min(4, (int)rootSize) : 0),
+ best(MOVE_NONE) {}
~Skill() {
- if (enabled()) // Swap best PV line with the sub-optimal one
+ if (candidates) // Swap best PV line with the sub-optimal one
std::swap(RootMoves[0], *std::find(RootMoves.begin(),
RootMoves.end(), best ? best : pick_move()));
}
- bool enabled() const { return level < 20; }
+ size_t candidates_size() const { return candidates; }
bool time_to_pick(int depth) const { return depth == 1 + level; }
Move pick_move();
int level;
+ size_t candidates;
Move best;
};
@@ -129,50 +133,55 @@ void Search::init() {
{
double pvRed = 0.00 + log(double(hd)) * log(double(mc)) / 3.00;
double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25;
- Reductions[1][1][hd][mc] = int8_t( pvRed >= 1.0 ? pvRed * int(ONE_PLY) : 0);
- Reductions[0][1][hd][mc] = int8_t(nonPVRed >= 1.0 ? nonPVRed * int(ONE_PLY) : 0);
+
+ Reductions[1][1][hd][mc] = int8_t( pvRed >= 1.0 ? pvRed + 0.5: 0);
+ Reductions[0][1][hd][mc] = int8_t(nonPVRed >= 1.0 ? nonPVRed + 0.5: 0);
Reductions[1][0][hd][mc] = Reductions[1][1][hd][mc];
Reductions[0][0][hd][mc] = Reductions[0][1][hd][mc];
- if (Reductions[0][0][hd][mc] > 2 * ONE_PLY)
- Reductions[0][0][hd][mc] += ONE_PLY;
-
- else if (Reductions[0][0][hd][mc] > 1 * ONE_PLY)
- Reductions[0][0][hd][mc] += ONE_PLY / 2;
+ if (Reductions[0][0][hd][mc] >= 2)
+ Reductions[0][0][hd][mc] += 1;
}
// Init futility move count array
for (d = 0; d < 32; ++d)
{
- FutilityMoveCounts[0][d] = int(2.4 + 0.222 * pow(d + 0.00, 1.8));
- FutilityMoveCounts[1][d] = int(3.0 + 0.300 * pow(d + 0.98, 1.8));
+ FutilityMoveCounts[0][d] = int(2.4 + 0.773 * pow(d + 0.00, 1.8));
+ FutilityMoveCounts[1][d] = int(2.9 + 1.045 * pow(d + 0.49, 1.8));
}
}
/// Search::perft() is our utility to verify move generation. All the leaf nodes
/// up to the given depth are generated and counted and the sum returned.
-
-static uint64_t perft(Position& pos, Depth depth) {
+template
+uint64_t Search::perft(Position& pos, Depth depth) {
StateInfo st;
- uint64_t cnt = 0;
+ uint64_t cnt, nodes = 0;
CheckInfo ci(pos);
- const bool leaf = depth == 2 * ONE_PLY;
+ const bool leaf = (depth == 2 * ONE_PLY);
for (MoveList it(pos); *it; ++it)
{
- pos.do_move(*it, st, ci, pos.gives_check(*it, ci));
- cnt += leaf ? MoveList(pos).size() : ::perft(pos, depth - ONE_PLY);
- pos.undo_move(*it);
+ if (Root && depth <= ONE_PLY)
+ cnt = 1, nodes++;
+ else
+ {
+ pos.do_move(*it, st, ci, pos.gives_check(*it, ci));
+ cnt = leaf ? MoveList(pos).size() : perft(pos, depth - ONE_PLY);
+ nodes += cnt;
+ pos.undo_move(*it);
+ }
+ if (Root)
+ sync_cout << move_to_uci(*it, pos.is_chess960()) << ": " << cnt << sync_endl;
}
- return cnt;
+ return nodes;
}
-uint64_t Search::perft(Position& pos, Depth depth) {
- return depth > ONE_PLY ? ::perft(pos, depth) : MoveList(pos).size();
-}
+template uint64_t Search::perft(Position& pos, Depth depth);
+
/// Search::think() is the external interface to Stockfish's search, and is
/// called by the main thread when the program receives the UCI 'go' command. It
@@ -180,14 +189,14 @@ uint64_t Search::perft(Position& pos, Depth depth) {
void Search::think() {
- static PolyglotBook book; // Defined static to initialize the PRNG only once
+ TimeMgr.init(Limits, RootPos.game_ply(), RootPos.side_to_move());
+ int piecesCnt;
+ TBHits = TBCardinality = 0;
+ RootInTB = false;
- RootColor = RootPos.side_to_move();
- TimeMgr.init(Limits, RootPos.game_ply(), RootColor);
-
- int cf = Options["Contempt Factor"] * PawnValueEg / 100; // From centipawns
- DrawValue[ RootColor] = VALUE_DRAW - Value(cf);
- DrawValue[~RootColor] = VALUE_DRAW + Value(cf);
+ int cf = Options["Contempt"] * PawnValueEg / 100; // From centipawns
+ DrawValue[ RootPos.side_to_move()] = VALUE_DRAW - Value(cf);
+ DrawValue[~RootPos.side_to_move()] = VALUE_DRAW + Value(cf);
if (RootMoves.empty())
{
@@ -199,27 +208,55 @@ void Search::think() {
goto finalize;
}
- if (Options["OwnBook"] && !Limits.infinite && !Limits.mate)
+ piecesCnt = RootPos.total_piece_count();
+ TBCardinality = Options["SyzygyProbeLimit"];
+ TBProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY;
+ if (TBCardinality > Tablebases::TBLargest)
{
- Move bookMove = book.probe(RootPos, Options["Book File"], Options["Best Book Move"]);
-
- if (bookMove && std::count(RootMoves.begin(), RootMoves.end(), bookMove))
- {
- std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), bookMove));
- goto finalize;
- }
+ TBCardinality = Tablebases::TBLargest;
+ TBProbeDepth = 0 * ONE_PLY;
}
+ TB50MoveRule = Options["Syzygy50MoveRule"];
- if (Options["Write Search Log"])
+ if (piecesCnt <= TBCardinality)
{
- Log log(Options["Search Log Filename"]);
- log << "\nSearching: " << RootPos.fen()
- << "\ninfinite: " << Limits.infinite
- << " ponder: " << Limits.ponder
- << " time: " << Limits.time[RootColor]
- << " increment: " << Limits.inc[RootColor]
- << " moves to go: " << Limits.movestogo
- << "\n" << std::endl;
+ TBHits = RootMoves.size();
+
+ // If the current root position is in the tablebases then RootMoves
+ // contains only moves that preserve the draw or win.
+ RootInTB = Tablebases::root_probe(RootPos, TBScore);
+
+ if (RootInTB)
+ {
+ TBCardinality = 0; // Do not probe tablebases during the search
+
+ // It might be a good idea to mangle the hash key (xor it
+ // with a fixed value) in order to "clear" the hash table of
+ // the results of previous probes. However, that would have to
+ // be done from within the Position class, so we skip it for now.
+
+ // Optional: decrease target time.
+ }
+ else // If DTZ tables are missing, use WDL tables as a fallback
+ {
+ // Filter out moves that do not preserve a draw or win
+ RootInTB = Tablebases::root_probe_wdl(RootPos, TBScore);
+
+ // Only probe during search if winning
+ if (TBScore <= VALUE_DRAW)
+ TBCardinality = 0;
+ }
+
+ if (!RootInTB)
+ {
+ TBHits = 0;
+ }
+ else if (!TB50MoveRule)
+ {
+ TBScore = TBScore > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1
+ : TBScore < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1
+ : TBScore;
+ }
}
// Reset the threads, still sleeping: will wake up at split time
@@ -233,25 +270,16 @@ void Search::think() {
Threads.timer->run = false; // Stop the timer
- if (Options["Write Search Log"])
+ if (RootInTB)
{
- Time::point elapsed = Time::now() - SearchTime + 1;
-
- Log log(Options["Search Log Filename"]);
- log << "Nodes: " << RootPos.nodes_searched()
- << "\nNodes/second: " << RootPos.nodes_searched() * 1000 / elapsed
- << "\nBest move: " << move_to_san(RootPos, RootMoves[0].pv[0]);
-
- StateInfo st;
- RootPos.do_move(RootMoves[0].pv[0], st);
- log << "\nPonder move: " << move_to_san(RootPos, RootMoves[0].pv[1]) << std::endl;
- RootPos.undo_move(RootMoves[0].pv[0]);
+ // If we mangled the hash key, unmangle it here
}
finalize:
// When search is stopped this info is not printed
sync_cout << "info nodes " << RootPos.nodes_searched()
+ << " tbhits " << TBHits
<< " time " << Time::now() - SearchTime + 1 << sync_endl;
// When we reach the maximum depth, we can arrive here without a raise of
@@ -285,7 +313,6 @@ namespace {
Value bestValue, alpha, beta, delta;
std::memset(ss-2, 0, 5 * sizeof(Stack));
- (ss-1)->currentMove = MOVE_NULL; // Hack to skip update gains
depth = 0;
BestMoveChanges = 0;
@@ -298,15 +325,12 @@ namespace {
Countermoves.clear();
Followupmoves.clear();
- MultiPV = Options["MultiPV"];
- Skill skill(Options["Skill Level"]);
+ size_t multiPV = Options["MultiPV"];
+ Skill skill(Options["Skill Level"], RootMoves.size());
// Do we have to play with skill handicap? In this case enable MultiPV search
// that we will use behind the scenes to retrieve a set of possible moves.
- if (skill.enabled() && MultiPV < 4)
- MultiPV = 4;
-
- MultiPV = std::min(MultiPV, RootMoves.size());
+ multiPV = std::max(multiPV, skill.candidates_size());
// Iterative deepening loop until requested to stop or target depth reached
while (++depth <= MAX_PLY && !Signals.stop && (!Limits.depth || depth <= Limits.depth))
@@ -320,7 +344,7 @@ namespace {
RootMoves[i].prevScore = RootMoves[i].score;
// MultiPV loop. We perform a full root search for each PV line
- for (PVIdx = 0; PVIdx < MultiPV && !Signals.stop; ++PVIdx)
+ for (PVIdx = 0; PVIdx < std::min(multiPV, RootMoves.size()) && !Signals.stop; ++PVIdx)
{
// Reset aspiration window starting size
if (depth >= 5)
@@ -377,7 +401,7 @@ namespace {
else
break;
- delta += delta / 2;
+ delta += 3 * delta / 8;
assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
}
@@ -385,25 +409,14 @@ namespace {
// Sort the PV lines searched so far and update the GUI
std::stable_sort(RootMoves.begin(), RootMoves.begin() + PVIdx + 1);
- if (PVIdx + 1 == MultiPV || Time::now() - SearchTime > 3000)
+ if (PVIdx + 1 == std::min(multiPV, RootMoves.size()) || Time::now() - SearchTime > 3000)
sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
}
// If skill levels are enabled and time is up, pick a sub-optimal best move
- if (skill.enabled() && skill.time_to_pick(depth))
+ if (skill.candidates_size() && skill.time_to_pick(depth))
skill.pick_move();
- if (Options["Write Search Log"])
- {
- RootMove& rm = RootMoves[0];
- if (skill.best != MOVE_NONE)
- rm = *std::find(RootMoves.begin(), RootMoves.end(), skill.best);
-
- Log log(Options["Search Log Filename"]);
- log << pretty_pv(pos, depth, rm.score, Time::now() - SearchTime, &rm.pv[0])
- << std::endl;
- }
-
// Have we found a "mate in x"?
if ( Limits.mate
&& bestValue >= VALUE_MATE_IN_MAX_PLY
@@ -414,7 +427,7 @@ namespace {
if (Limits.use_time_management() && !Signals.stop && !Signals.stopOnPonderhit)
{
// Take some extra time if the best move has changed
- if (depth > 4 && depth < 50 && MultiPV == 1)
+ if (depth > 4 && multiPV == 1)
TimeMgr.pv_instability(BestMoveChanges);
// Stop the search if only one legal move is available or all
@@ -540,6 +553,37 @@ namespace {
return ttValue;
}
+ // Step 4a. Tablebase probe
+ if ( !RootNode
+ && pos.total_piece_count() <= TBCardinality
+ && ( pos.total_piece_count() < TBCardinality || depth >= TBProbeDepth )
+ && pos.rule50_count() == 0)
+ {
+ int found, v = Tablebases::probe_wdl(pos, &found);
+
+ if (found)
+ {
+ TBHits++;
+
+ if (TB50MoveRule) {
+ value = v < -1 ? -VALUE_MATE + MAX_PLY + ss->ply
+ : v > 1 ? VALUE_MATE - MAX_PLY - ss->ply
+ : VALUE_DRAW + 2 * v;
+ }
+ else
+ {
+ value = v < 0 ? -VALUE_MATE + MAX_PLY + ss->ply
+ : v > 0 ? VALUE_MATE - MAX_PLY - ss->ply
+ : VALUE_DRAW;
+ }
+
+ TT.store(posKey, value_to_tt(value, ss->ply), BOUND_EXACT,
+ depth + 6 * ONE_PLY, MOVE_NONE, VALUE_NONE);
+
+ return value;
+ }
+ }
+
// Step 5. Evaluate the position statically and update parent's gain statistics
if (inCheck)
{
@@ -560,7 +604,9 @@ namespace {
}
else
{
- eval = ss->staticEval = evaluate(pos);
+ eval = ss->staticEval =
+ (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval + 2 * Eval::Tempo;
+
TT.store(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->staticEval);
}
@@ -568,6 +614,7 @@ namespace {
&& ss->staticEval != VALUE_NONE
&& (ss-1)->staticEval != VALUE_NONE
&& (move = (ss-1)->currentMove) != MOVE_NULL
+ && move != MOVE_NONE
&& type_of(move) == NORMAL)
{
Square to = to_sq(move);
@@ -579,7 +626,6 @@ namespace {
&& depth < 4 * ONE_PLY
&& eval + razor_margin(depth) <= alpha
&& ttMove == MOVE_NONE
- && abs(beta) < VALUE_MATE_IN_MAX_PLY
&& !pos.pawn_on_7th(pos.side_to_move()))
{
if ( depth <= ONE_PLY
@@ -597,8 +643,7 @@ namespace {
&& !ss->skipNullMove
&& depth < 7 * ONE_PLY
&& eval - futility_margin(depth) >= beta
- && abs(beta) < VALUE_MATE_IN_MAX_PLY
- && abs(eval) < VALUE_KNOWN_WIN
+ && eval < VALUE_KNOWN_WIN // Do not return unproven wins
&& pos.non_pawn_material(pos.side_to_move()))
return eval - futility_margin(depth);
@@ -607,7 +652,6 @@ namespace {
&& !ss->skipNullMove
&& depth >= 2 * ONE_PLY
&& eval >= beta
- && abs(beta) < VALUE_MATE_IN_MAX_PLY
&& pos.non_pawn_material(pos.side_to_move()))
{
ss->currentMove = MOVE_NULL;
@@ -615,9 +659,7 @@ namespace {
assert(eval - beta >= 0);
// Null move dynamic reduction based on depth and value
- Depth R = 3 * ONE_PLY
- + depth / 4
- + int(eval - beta) / PawnValueMg * ONE_PLY;
+ Depth R = (3 + depth / 4 + std::min(int(eval - beta) / PawnValueMg, 3)) * ONE_PLY;
pos.do_null_move(st);
(ss+1)->skipNullMove = true;
@@ -632,7 +674,7 @@ namespace {
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
nullValue = beta;
- if (depth < 12 * ONE_PLY)
+ if (depth < 12 * ONE_PLY && abs(beta) < VALUE_KNOWN_WIN)
return nullValue;
// Do verification search at high depths
@@ -682,10 +724,9 @@ namespace {
&& !ttMove
&& (PvNode || ss->staticEval + 256 >= beta))
{
- Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4);
-
+ Depth d = 2 * (depth - 2 * ONE_PLY) - (PvNode ? DEPTH_ZERO : depth / 2);
ss->skipNullMove = true;
- search(pos, ss, alpha, beta, d, true);
+ search(pos, ss, alpha, beta, d / 2, true);
ss->skipNullMove = false;
tte = TT.probe(posKey);
@@ -713,6 +754,8 @@ moves_loop: // When in check and at SpNode search starts from here
&& !SpNode
&& depth >= 8 * ONE_PLY
&& ttMove != MOVE_NONE
+ /* && ttValue != VALUE_NONE Already implicit in the next condition */
+ && abs(ttValue) < VALUE_KNOWN_WIN
&& !excludedMove // Recursive singular search is not allowed
&& (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 3 * ONE_PLY;
@@ -749,7 +792,7 @@ moves_loop: // When in check and at SpNode search starts from here
Signals.firstRootMove = (moveCount == 1);
if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
- sync_cout << "info depth " << depth / ONE_PLY
+ sync_cout << "info depth " << depth
<< " currmove " << move_to_uci(move, pos.is_chess960())
<< " currmovenumber " << moveCount + PVIdx << sync_endl;
}
@@ -777,12 +820,9 @@ moves_loop: // When in check and at SpNode search starts from here
if ( singularExtensionNode
&& move == ttMove
&& !ext
- && pos.legal(move, ci.pinned)
- && abs(ttValue) < VALUE_KNOWN_WIN)
+ && pos.legal(move, ci.pinned))
{
- assert(ttValue != VALUE_NONE);
-
- Value rBeta = ttValue - int(depth);
+ Value rBeta = ttValue - int(2 * depth);
ss->excludedMove = move;
ss->skipNullMove = true;
value = search(pos, ss, rBeta - 1, rBeta, depth / 2, cutNode);
@@ -806,7 +846,7 @@ moves_loop: // When in check and at SpNode search starts from here
{
// Move count based pruning
if ( depth < 16 * ONE_PLY
- && moveCount >= FutilityMoveCounts[improving][depth] )
+ && moveCount >= FutilityMoveCounts[improving][depth])
{
if (SpNode)
splitPoint->mutex.lock();
@@ -819,8 +859,8 @@ moves_loop: // When in check and at SpNode search starts from here
// Futility pruning: parent node
if (predictedDepth < 7 * ONE_PLY)
{
- futilityValue = ss->staticEval + futility_margin(predictedDepth)
- + 128 + Gains[pos.moved_piece(move)][to_sq(move)];
+ futilityValue = ss->staticEval + futility_margin(predictedDepth)
+ + 128 + Gains[pos.moved_piece(move)][to_sq(move)];
if (futilityValue <= alpha)
{
@@ -846,6 +886,9 @@ moves_loop: // When in check and at SpNode search starts from here
}
}
+ // Speculative prefetch as early as possible
+ prefetch((char*)TT.first_entry(pos.key_after(move)));
+
// Check for legality just before making the move
if (!RootNode && !SpNode && !pos.legal(move, ci.pinned))
{
@@ -872,15 +915,20 @@ moves_loop: // When in check and at SpNode search starts from here
{
ss->reduction = reduction(improving, depth, moveCount);
- if (!PvNode && cutNode)
+ if ( (!PvNode && cutNode)
+ || History[pos.piece_on(to_sq(move))][to_sq(move)] < 0)
ss->reduction += ONE_PLY;
- else if (History[pos.piece_on(to_sq(move))][to_sq(move)] < 0)
- ss->reduction += ONE_PLY / 2;
-
if (move == countermoves[0] || move == countermoves[1])
ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY);
+ // Decrease reduction for moves that escape a capture
+ if ( ss->reduction
+ && type_of(move) == NORMAL
+ && type_of(pos.piece_on(to_sq(move))) != PAWN
+ && pos.see(make_move(to_sq(move), from_sq(move))) < 0)
+ ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY);
+
Depth d = std::max(newDepth - ss->reduction, ONE_PLY);
if (SpNode)
alpha = splitPoint->alpha;
@@ -906,20 +954,20 @@ moves_loop: // When in check and at SpNode search starts from here
if (SpNode)
alpha = splitPoint->alpha;
- value = newDepth < ONE_PLY ?
- givesCheck ? -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
- : -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
- : - search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
+ value = newDepth < ONE_PLY ?
+ givesCheck ? -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
+ : -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
+ : - search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
}
// For PV nodes only, do a full PV search on the first move or after a fail
// high (in the latter case search only if value < beta), otherwise let the
// parent node fail low with value <= alpha and to try another move.
if (PvNode && (pvMove || (value > alpha && (RootNode || value < beta))))
- value = newDepth < ONE_PLY ?
- givesCheck ? -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
- : -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
- : - search(pos, ss+1, -beta, -alpha, newDepth, false);
+ value = newDepth < ONE_PLY ?
+ givesCheck ? -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
+ : -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
+ : - search(pos, ss+1, -beta, -alpha, newDepth, false);
// Step 17. Undo move
pos.undo_move(move);
@@ -994,8 +1042,8 @@ moves_loop: // When in check and at SpNode search starts from here
{
assert(bestValue > -VALUE_INFINITE && bestValue < beta);
- thisThread->split(pos, ss, alpha, beta, &bestValue, &bestMove,
- depth, moveCount, &mp, NT, cutNode);
+ thisThread->split(pos, ss, alpha, beta, &bestValue, &bestMove,
+ depth, moveCount, &mp, NT, cutNode);
if (Signals.stop || thisThread->cutoff_occurred())
return VALUE_ZERO;
@@ -1116,7 +1164,8 @@ moves_loop: // When in check and at SpNode search starts from here
bestValue = ttValue;
}
else
- ss->staticEval = bestValue = evaluate(pos);
+ ss->staticEval = bestValue =
+ (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval + 2 * Eval::Tempo;
// Stand pat. Return immediately if static value is at least beta
if (bestValue >= beta)
@@ -1189,6 +1238,9 @@ moves_loop: // When in check and at SpNode search starts from here
&& pos.see_sign(move) < VALUE_ZERO)
continue;
+ // Speculative prefetch as early as possible
+ prefetch((char*)TT.first_entry(pos.key_after(move)));
+
// Check for legality just before making the move
if (!pos.legal(move, ci.pinned))
continue;
@@ -1279,7 +1331,7 @@ moves_loop: // When in check and at SpNode search starts from here
// Increase history value of the cut-off move and decrease all the other
// played quiet moves.
- Value bonus = Value(int(depth) * int(depth));
+ Value bonus = Value(4 * int(depth) * int(depth));
History.update(pos.moved_piece(move), to_sq(move), bonus);
for (int i = 0; i < quietsCnt; ++i)
{
@@ -1301,8 +1353,8 @@ moves_loop: // When in check and at SpNode search starts from here
}
- // When playing with a strength handicap, choose best move among the MultiPV
- // set using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
+ // When playing with a strength handicap, choose best move among the first 'candidates'
+ // RootMoves using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
Move Skill::pick_move() {
@@ -1313,7 +1365,7 @@ moves_loop: // When in check and at SpNode search starts from here
rk.rand();
// RootMoves are already sorted by score in descending order
- int variance = std::min(RootMoves[0].score - RootMoves[MultiPV - 1].score, PawnValueMg);
+ int variance = std::min(RootMoves[0].score - RootMoves[candidates - 1].score, PawnValueMg);
int weakness = 120 - 2 * level;
int max_s = -VALUE_INFINITE;
best = MOVE_NONE;
@@ -1321,12 +1373,12 @@ moves_loop: // When in check and at SpNode search starts from here
// Choose best move. For each move score we add two terms both dependent on
// weakness. One deterministic and bigger for weaker moves, and one random,
// then we choose the move with the resulting highest score.
- for (size_t i = 0; i < MultiPV; ++i)
+ for (size_t i = 0; i < candidates; ++i)
{
int s = RootMoves[i].score;
// Don't allow crazy blunders even at very low skills
- if (i > 0 && RootMoves[i-1].score > s + 2 * PawnValueMg)
+ if (i > 0 && RootMoves[i - 1].score > s + 2 * PawnValueMg)
break;
// This is our magic formula
@@ -1368,14 +1420,24 @@ moves_loop: // When in check and at SpNode search starts from here
int d = updated ? depth : depth - 1;
Value v = updated ? RootMoves[i].score : RootMoves[i].prevScore;
+ bool tb = RootInTB;
+ if (tb)
+ {
+ if (abs(v) >= VALUE_MATE - MAX_PLY)
+ tb = false;
+ else
+ v = TBScore;
+ }
+
if (ss.rdbuf()->in_avail()) // Not at first line
ss << "\n";
ss << "info depth " << d
<< " seldepth " << selDepth
- << " score " << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v))
+ << " score " << ((!tb && i == PVIdx) ? score_to_uci(v, alpha, beta) : score_to_uci(v))
<< " nodes " << pos.nodes_searched()
<< " nps " << pos.nodes_searched() * 1000 / elapsed
+ << " tbhits " << TBHits
<< " time " << elapsed
<< " multipv " << i + 1
<< " pv";
@@ -1463,46 +1525,13 @@ void Thread::idle_loop() {
assert(!this_sp || (this_sp->masterThread == this && searching));
- while (true)
+ while (!exit)
{
- // If we are not searching, wait for a condition to be signaled instead of
- // wasting CPU time polling for work.
- while (!searching || exit)
- {
- if (exit)
- {
- assert(!this_sp);
- return;
- }
-
- // Grab the lock to avoid races with Thread::notify_one()
- mutex.lock();
-
- // If we are master and all slaves have finished then exit idle_loop
- if (this_sp && this_sp->slavesMask.none())
- {
- mutex.unlock();
- break;
- }
-
- // Do sleep after retesting sleep conditions under lock protection. In
- // particular we need to avoid a deadlock in case a master thread has,
- // in the meanwhile, allocated us and sent the notify_one() call before
- // we had the chance to grab the lock.
- if (!searching && !exit)
- sleepCondition.wait(mutex);
-
- mutex.unlock();
- }
-
// If this thread has been assigned work, launch a search
- if (searching)
+ while (searching)
{
- assert(!exit);
-
Threads.mutex.lock();
- assert(searching);
assert(activeSplitPoint);
SplitPoint* sp = activeSplitPoint;
@@ -1559,7 +1588,7 @@ void Thread::idle_loop() {
if (Threads.size() > 2)
for (size_t i = 0; i < Threads.size(); ++i)
{
- int size = Threads[i]->splitPointsSize; // Local copy
+ const int size = Threads[i]->splitPointsSize; // Local copy
sp = size ? &Threads[i]->splitPoints[size - 1] : NULL;
if ( sp
@@ -1586,16 +1615,23 @@ void Thread::idle_loop() {
}
}
- // If this thread is the master of a split point and all slaves have finished
- // their work at this split point, return from the idle loop.
+ // Grab the lock to avoid races with Thread::notify_one()
+ mutex.lock();
+
+ // If we are master and all slaves have finished then exit idle_loop
if (this_sp && this_sp->slavesMask.none())
{
- this_sp->mutex.lock();
- bool finished = this_sp->slavesMask.none(); // Retest under lock protection
- this_sp->mutex.unlock();
- if (finished)
- return;
+ assert(!searching);
+ mutex.unlock();
+ break;
}
+
+ // If we are not searching, wait for a condition to be signaled instead of
+ // wasting CPU time polling for work.
+ if (!searching && !exit)
+ sleepCondition.wait(mutex);
+
+ mutex.unlock();
}
}
diff --git a/DroidFish/jni/stockfish/search.h b/DroidFish/jni/stockfish/search.h
index a9f21fa..4fe5a5b 100644
--- a/DroidFish/jni/stockfish/search.h
+++ b/DroidFish/jni/stockfish/search.h
@@ -45,7 +45,7 @@ struct Stack {
Move killers[2];
Depth reduction;
Value staticEval;
- int skipNullMove;
+ bool skipNullMove;
};
@@ -101,13 +101,12 @@ extern volatile SignalsType Signals;
extern LimitsType Limits;
extern std::vector RootMoves;
extern Position RootPos;
-extern Color RootColor;
extern Time::point SearchTime;
extern StateStackPtr SetupStates;
extern void init();
-extern uint64_t perft(Position& pos, Depth depth);
extern void think();
+template uint64_t perft(Position& pos, Depth depth);
} // namespace Search
diff --git a/DroidFish/jni/stockfish/tbcore.cpp b/DroidFish/jni/stockfish/tbcore.cpp
new file mode 100644
index 0000000..6a2e814
--- /dev/null
+++ b/DroidFish/jni/stockfish/tbcore.cpp
@@ -0,0 +1,1620 @@
+/*
+ Copyright (c) 2011-2013 Ronald de Man
+ This file may be redistributed and/or modified without restrictions.
+
+ tbcore.c contains engine-independent routines of the tablebase probing code.
+ This file should not need to much adaptation to add tablebase probing to
+ a particular engine, provided the engine is written in C or C++.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifndef __WIN32__
+#include
+#endif
+#include "tbcore.h"
+#include
+
+#define TBMAX_PIECE 254
+#define TBMAX_PAWN 256
+#define HSHMAX 4
+
+// for variants where kings can connect and/or captured
+// #define CONNECTED_KINGS
+
+#define Swap(a,b) {int tmp=a;a=b;b=tmp;}
+
+#define TB_PAWN 1
+#define TB_KNIGHT 2
+#define TB_BISHOP 3
+#define TB_ROOK 4
+#define TB_QUEEN 5
+#define TB_KING 6
+
+#define TB_WPAWN TB_PAWN
+#define TB_BPAWN (TB_PAWN | 8)
+
+static std::mutex TB_mutex;
+
+static bool initialized = false;
+static int num_paths = 0;
+static char *path_string = NULL;
+static char **paths = NULL;
+
+static int TBnum_piece, TBnum_pawn;
+static struct TBEntry_piece TB_piece[TBMAX_PIECE];
+static struct TBEntry_pawn TB_pawn[TBMAX_PAWN];
+
+static struct TBHashEntry WDL_hash[1 << TBHASHBITS][HSHMAX];
+static struct DTZTableEntry DTZ_hash[1 << TBHASHBITS][HSHMAX];
+
+static void init_indices(void);
+static uint64_t calc_key_from_pcs(const int *pcs, bool mirror);
+static void free_wdl_entry(struct TBEntry *entry);
+static void free_dtz_entry(struct TBEntry *entry);
+
+static FD open_tb(const char *str, const char *suffix)
+{
+ for (int i = 0; i < num_paths; i++) {
+ std::string file(paths[i]);
+ file += '/';
+ file += str;
+ file += suffix;
+#ifndef __WIN32__
+ FD fd = open(file.c_str(), O_RDONLY);
+#else
+ FD fd = CreateFile(file.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+#endif
+ if (fd != FD_ERR) return fd;
+ }
+ return FD_ERR;
+}
+
+static void close_tb(FD fd)
+{
+#ifndef __WIN32__
+ close(fd);
+#else
+ CloseHandle(fd);
+#endif
+}
+
+static char *map_file(const char *name, const char *suffix, uint64_t *mapping)
+{
+ FD fd = open_tb(name, suffix);
+ if (fd == FD_ERR)
+ return NULL;
+#ifndef __WIN32__
+ struct stat statbuf;
+ fstat(fd, &statbuf);
+ *mapping = statbuf.st_size;
+ char *data = (char *)mmap(NULL, statbuf.st_size, PROT_READ,
+ MAP_SHARED, fd, 0);
+ if (data == (char *)(-1)) {
+ std::cout << "Could not mmap() " << name << std::endl;
+ close_tb(fd);
+ return NULL;
+ }
+#else
+ DWORD size_low, size_high;
+ size_low = GetFileSize(fd, &size_high);
+ // *size = ((uint64_t)size_high) << 32 | ((uint64_t)size_low);
+ HANDLE map = CreateFileMapping(fd, NULL, PAGE_READONLY, size_high, size_low,
+ NULL);
+ if (map == NULL) {
+ std::cout << "CreateFileMapping() failed" << std::endl;
+ close_tb(fd);
+ return NULL;
+ }
+ *mapping = (uint64_t)map;
+ char *data = (char *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
+ if (data == NULL) {
+ std::cout << "MapViewOfFile() failed, name = " << name << suffix << ", error = " << GetLastError() << std::endl;
+ close_tb(fd);
+ return NULL;
+ }
+#endif
+ close_tb(fd);
+ return data;
+}
+
+#ifndef __WIN32__
+static void unmap_file(char *data, uint64_t size)
+{
+ if (!data) return;
+ munmap(data, size);
+}
+#else
+static void unmap_file(char *data, uint64_t mapping)
+{
+ if (!data) return;
+ UnmapViewOfFile(data);
+ CloseHandle((HANDLE)mapping);
+}
+#endif
+
+static void add_to_hash(struct TBEntry *ptr, uint64_t key)
+{
+ int i, hshidx;
+
+ hshidx = key >> (64 - TBHASHBITS);
+ i = 0;
+ while (i < HSHMAX && WDL_hash[hshidx][i].ptr)
+ i++;
+ assert(i < HSHMAX);
+ WDL_hash[hshidx][i].key = key;
+ WDL_hash[hshidx][i].ptr = ptr;
+}
+
+static void add_to_dtz_hash(uint64_t key1, uint64_t key2)
+{
+ int i, hshidx;
+
+ hshidx = key1 >> (64 - TBHASHBITS);
+ i = 0;
+ while (i < HSHMAX && DTZ_hash[hshidx][i].key1)
+ i++;
+ assert(i < HSHMAX);
+ DTZ_hash[hshidx][i].key1 = key1;
+ DTZ_hash[hshidx][i].key2 = key2;
+ DTZ_hash[hshidx][i].entry = NULL;
+}
+
+static char pchr[] = {'K', 'Q', 'R', 'B', 'N', 'P'};
+
+static void init_tb(char *str)
+{
+ FD fd;
+ struct TBEntry *entry;
+ int i, j, pcs[16];
+ uint64_t key, key2;
+ int color;
+ char *s;
+
+ fd = open_tb(str, WDLSUFFIX);
+ if (fd == FD_ERR) return;
+ close_tb(fd);
+
+ for (i = 0; i < 16; i++)
+ pcs[i] = 0;
+ color = 0;
+ for (s = str; *s; s++)
+ switch (*s) {
+ case 'P':
+ pcs[TB_PAWN | color]++;
+ break;
+ case 'N':
+ pcs[TB_KNIGHT | color]++;
+ break;
+ case 'B':
+ pcs[TB_BISHOP | color]++;
+ break;
+ case 'R':
+ pcs[TB_ROOK | color]++;
+ break;
+ case 'Q':
+ pcs[TB_QUEEN | color]++;
+ break;
+ case 'K':
+ pcs[TB_KING | color]++;
+ break;
+ case 'v':
+ color = 0x08;
+ break;
+ }
+ for (i = 0; i < 8; i++)
+ if (pcs[i] != pcs[i+8])
+ break;
+ key = calc_key_from_pcs(pcs, false);
+ key2 = calc_key_from_pcs(pcs, true);
+ if (pcs[TB_WPAWN] + pcs[TB_BPAWN] == 0) {
+ assert(TBnum_piece < TBMAX_PIECE);
+ entry = (struct TBEntry *)&TB_piece[TBnum_piece++];
+ } else {
+ assert(TBnum_pawn < TBMAX_PAWN);
+ entry = (struct TBEntry *)&TB_pawn[TBnum_pawn++];
+ }
+ entry->key = key;
+ entry->ready = 0;
+ entry->num = 0;
+ for (i = 0; i < 16; i++)
+ entry->num += pcs[i];
+ entry->symmetric = (key == key2);
+ entry->has_pawns = (pcs[TB_WPAWN] + pcs[TB_BPAWN] > 0);
+ if (entry->num > Tablebases::TBLargest)
+ Tablebases::TBLargest = entry->num;
+
+ if (entry->has_pawns) {
+ struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
+ ptr->pawns[0] = pcs[TB_WPAWN];
+ ptr->pawns[1] = pcs[TB_BPAWN];
+ if (pcs[TB_BPAWN] > 0
+ && (pcs[TB_WPAWN] == 0 || pcs[TB_BPAWN] < pcs[TB_WPAWN])) {
+ ptr->pawns[0] = pcs[TB_BPAWN];
+ ptr->pawns[1] = pcs[TB_WPAWN];
+ }
+ } else {
+ struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
+ for (i = 0, j = 0; i < 16; i++)
+ if (pcs[i] == 1) j++;
+ if (j >= 3) ptr->enc_type = 0;
+ else if (j == 2) ptr->enc_type = 2;
+ else { /* only for suicide */
+ j = 16;
+ for (i = 0; i < 16; i++) {
+ if (pcs[i] < j && pcs[i] > 1) j = pcs[i];
+ ptr->enc_type = 1 + j;
+ }
+ }
+ }
+ add_to_hash(entry, key);
+ if (key2 != key) add_to_hash(entry, key2);
+ add_to_dtz_hash(key, key2);
+}
+
+void Tablebases::init(const std::string& path)
+{
+ char str[16];
+ int i, j, k, l;
+
+ { // The probing code currently expects a little-endian architecture
+ static_assert(sizeof(uint32_t) == 4, "Unsupported architecture");
+ uint32_t test = 0x01020304;
+ unsigned char* p = (unsigned char*)&test;
+ if (p[0] != 4 || p[1] != 3 || p[2] != 2 || p[3] != 1)
+ return;
+ }
+
+ if (initialized) {
+ free(path_string); path_string = NULL;
+ free(paths); paths = NULL;
+ struct TBEntry *entry;
+ for (i = 0; i < TBnum_piece; i++) {
+ entry = (struct TBEntry *)&TB_piece[i];
+ free_wdl_entry(entry);
+ }
+ for (i = 0; i < TBnum_pawn; i++) {
+ entry = (struct TBEntry *)&TB_pawn[i];
+ free_wdl_entry(entry);
+ }
+ for (i = 0; i < (1 << TBHASHBITS); i++)
+ for (j = 0; j < HSHMAX; j++) {
+ if (DTZ_hash[i][j].entry) {
+ free_dtz_entry(DTZ_hash[i][j].entry);
+ DTZ_hash[i][j].entry = NULL;
+ }
+ }
+ TBnum_piece = TBnum_pawn = 0;
+ TBLargest = 0;
+ } else {
+ init_indices();
+ initialized = true;
+ }
+
+ const char *p = path.c_str();
+ if (strlen(p) == 0)
+ return;
+ path_string = (char *)malloc(strlen(p) + 1);
+ strcpy(path_string, p);
+ num_paths = 0;
+ for (i = 0;; i++) {
+ if (path_string[i] && path_string[i] != SEP_CHAR)
+ num_paths++;
+ while (path_string[i] && path_string[i] != SEP_CHAR)
+ i++;
+ if (!path_string[i]) break;
+ path_string[i] = 0;
+ }
+ paths = (char **)malloc(num_paths * sizeof(char *));
+ for (i = j = 0; i < num_paths; i++) {
+ while (!path_string[j]) j++;
+ paths[i] = &path_string[j];
+ while (path_string[j]) j++;
+ }
+
+ for (i = 0; i < (1 << TBHASHBITS); i++)
+ for (j = 0; j < HSHMAX; j++) {
+ WDL_hash[i][j].key = 0ULL;
+ WDL_hash[i][j].ptr = NULL;
+ }
+
+ for (i = 0; i < (1 << TBHASHBITS); i++)
+ for (j = 0; j < HSHMAX; j++) {
+ DTZ_hash[i][j].key1 = 0ULL;
+ DTZ_hash[i][j].key2 = 0ULL;
+ DTZ_hash[i][j].entry = NULL;
+ }
+
+ for (i = 1; i < 6; i++) {
+ sprintf(str, "K%cvK", pchr[i]);
+ init_tb(str);
+ }
+
+ for (i = 1; i < 6; i++)
+ for (j = i; j < 6; j++) {
+ sprintf(str, "K%cvK%c", pchr[i], pchr[j]);
+ init_tb(str);
+ }
+
+ for (i = 1; i < 6; i++)
+ for (j = i; j < 6; j++) {
+ sprintf(str, "K%c%cvK", pchr[i], pchr[j]);
+ init_tb(str);
+ }
+
+ for (i = 1; i < 6; i++)
+ for (j = i; j < 6; j++)
+ for (k = 1; k < 6; k++) {
+ sprintf(str, "K%c%cvK%c", pchr[i], pchr[j], pchr[k]);
+ init_tb(str);
+ }
+
+ for (i = 1; i < 6; i++)
+ for (j = i; j < 6; j++)
+ for (k = j; k < 6; k++) {
+ sprintf(str, "K%c%c%cvK", pchr[i], pchr[j], pchr[k]);
+ init_tb(str);
+ }
+
+ // 6-piece tables are only supported for 64-bit, because tables are mmap()ed into memory
+ if (sizeof(char*) >= 8) {
+ for (i = 1; i < 6; i++)
+ for (j = i; j < 6; j++)
+ for (k = i; k < 6; k++)
+ for (l = (i == k) ? j : k; l < 6; l++) {
+ sprintf(str, "K%c%cvK%c%c", pchr[i], pchr[j], pchr[k], pchr[l]);
+ init_tb(str);
+ }
+
+ for (i = 1; i < 6; i++)
+ for (j = i; j < 6; j++)
+ for (k = j; k < 6; k++)
+ for (l = 1; l < 6; l++) {
+ sprintf(str, "K%c%c%cvK%c", pchr[i], pchr[j], pchr[k], pchr[l]);
+ init_tb(str);
+ }
+
+ for (i = 1; i < 6; i++)
+ for (j = i; j < 6; j++)
+ for (k = j; k < 6; k++)
+ for (l = k; l < 6; l++) {
+ sprintf(str, "K%c%c%c%cvK", pchr[i], pchr[j], pchr[k], pchr[l]);
+ init_tb(str);
+ }
+ }
+
+ std::cout << "info string Found " << (TBnum_piece + TBnum_pawn) << " syzygy tablebases" << std::endl;
+}
+
+static const signed char offdiag[] = {
+ 0,-1,-1,-1,-1,-1,-1,-1,
+ 1, 0,-1,-1,-1,-1,-1,-1,
+ 1, 1, 0,-1,-1,-1,-1,-1,
+ 1, 1, 1, 0,-1,-1,-1,-1,
+ 1, 1, 1, 1, 0,-1,-1,-1,
+ 1, 1, 1, 1, 1, 0,-1,-1,
+ 1, 1, 1, 1, 1, 1, 0,-1,
+ 1, 1, 1, 1, 1, 1, 1, 0
+};
+
+static const ubyte triangle[] = {
+ 6, 0, 1, 2, 2, 1, 0, 6,
+ 0, 7, 3, 4, 4, 3, 7, 0,
+ 1, 3, 8, 5, 5, 8, 3, 1,
+ 2, 4, 5, 9, 9, 5, 4, 2,
+ 2, 4, 5, 9, 9, 5, 4, 2,
+ 1, 3, 8, 5, 5, 8, 3, 1,
+ 0, 7, 3, 4, 4, 3, 7, 0,
+ 6, 0, 1, 2, 2, 1, 0, 6
+};
+
+static const ubyte invtriangle[] = {
+ 1, 2, 3, 10, 11, 19, 0, 9, 18, 27
+};
+
+static const ubyte invdiag[] = {
+ 0, 9, 18, 27, 36, 45, 54, 63,
+ 7, 14, 21, 28, 35, 42, 49, 56
+};
+
+static const ubyte flipdiag[] = {
+ 0, 8, 16, 24, 32, 40, 48, 56,
+ 1, 9, 17, 25, 33, 41, 49, 57,
+ 2, 10, 18, 26, 34, 42, 50, 58,
+ 3, 11, 19, 27, 35, 43, 51, 59,
+ 4, 12, 20, 28, 36, 44, 52, 60,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 7, 15, 23, 31, 39, 47, 55, 63
+};
+
+static const ubyte lower[] = {
+ 28, 0, 1, 2, 3, 4, 5, 6,
+ 0, 29, 7, 8, 9, 10, 11, 12,
+ 1, 7, 30, 13, 14, 15, 16, 17,
+ 2, 8, 13, 31, 18, 19, 20, 21,
+ 3, 9, 14, 18, 32, 22, 23, 24,
+ 4, 10, 15, 19, 22, 33, 25, 26,
+ 5, 11, 16, 20, 23, 25, 34, 27,
+ 6, 12, 17, 21, 24, 26, 27, 35
+};
+
+static const ubyte diag[] = {
+ 0, 0, 0, 0, 0, 0, 0, 8,
+ 0, 1, 0, 0, 0, 0, 9, 0,
+ 0, 0, 2, 0, 0, 10, 0, 0,
+ 0, 0, 0, 3, 11, 0, 0, 0,
+ 0, 0, 0, 12, 4, 0, 0, 0,
+ 0, 0, 13, 0, 0, 5, 0, 0,
+ 0, 14, 0, 0, 0, 0, 6, 0,
+ 15, 0, 0, 0, 0, 0, 0, 7
+};
+
+static const ubyte flap[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 6, 12, 18, 18, 12, 6, 0,
+ 1, 7, 13, 19, 19, 13, 7, 1,
+ 2, 8, 14, 20, 20, 14, 8, 2,
+ 3, 9, 15, 21, 21, 15, 9, 3,
+ 4, 10, 16, 22, 22, 16, 10, 4,
+ 5, 11, 17, 23, 23, 17, 11, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const ubyte ptwist[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 47, 35, 23, 11, 10, 22, 34, 46,
+ 45, 33, 21, 9, 8, 20, 32, 44,
+ 43, 31, 19, 7, 6, 18, 30, 42,
+ 41, 29, 17, 5, 4, 16, 28, 40,
+ 39, 27, 15, 3, 2, 14, 26, 38,
+ 37, 25, 13, 1, 0, 12, 24, 36,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const ubyte invflap[] = {
+ 8, 16, 24, 32, 40, 48,
+ 9, 17, 25, 33, 41, 49,
+ 10, 18, 26, 34, 42, 50,
+ 11, 19, 27, 35, 43, 51
+};
+
+static const ubyte invptwist[] = {
+ 52, 51, 44, 43, 36, 35, 28, 27, 20, 19, 12, 11,
+ 53, 50, 45, 42, 37, 34, 29, 26, 21, 18, 13, 10,
+ 54, 49, 46, 41, 38, 33, 30, 25, 22, 17, 14, 9,
+ 55, 48, 47, 40, 39, 32, 31, 24, 23, 16, 15, 8
+};
+
+static const ubyte file_to_file[] = {
+ 0, 1, 2, 3, 3, 2, 1, 0
+};
+
+#ifndef CONNECTED_KINGS
+static const short KK_idx[10][64] = {
+ { -1, -1, -1, 0, 1, 2, 3, 4,
+ -1, -1, -1, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57 },
+ { 58, -1, -1, -1, 59, 60, 61, 62,
+ 63, -1, -1, -1, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99,
+ 100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,115},
+ {116,117, -1, -1, -1,118,119,120,
+ 121,122, -1, -1, -1,123,124,125,
+ 126,127,128,129,130,131,132,133,
+ 134,135,136,137,138,139,140,141,
+ 142,143,144,145,146,147,148,149,
+ 150,151,152,153,154,155,156,157,
+ 158,159,160,161,162,163,164,165,
+ 166,167,168,169,170,171,172,173 },
+ {174, -1, -1, -1,175,176,177,178,
+ 179, -1, -1, -1,180,181,182,183,
+ 184, -1, -1, -1,185,186,187,188,
+ 189,190,191,192,193,194,195,196,
+ 197,198,199,200,201,202,203,204,
+ 205,206,207,208,209,210,211,212,
+ 213,214,215,216,217,218,219,220,
+ 221,222,223,224,225,226,227,228 },
+ {229,230, -1, -1, -1,231,232,233,
+ 234,235, -1, -1, -1,236,237,238,
+ 239,240, -1, -1, -1,241,242,243,
+ 244,245,246,247,248,249,250,251,
+ 252,253,254,255,256,257,258,259,
+ 260,261,262,263,264,265,266,267,
+ 268,269,270,271,272,273,274,275,
+ 276,277,278,279,280,281,282,283 },
+ {284,285,286,287,288,289,290,291,
+ 292,293, -1, -1, -1,294,295,296,
+ 297,298, -1, -1, -1,299,300,301,
+ 302,303, -1, -1, -1,304,305,306,
+ 307,308,309,310,311,312,313,314,
+ 315,316,317,318,319,320,321,322,
+ 323,324,325,326,327,328,329,330,
+ 331,332,333,334,335,336,337,338 },
+ { -1, -1,339,340,341,342,343,344,
+ -1, -1,345,346,347,348,349,350,
+ -1, -1,441,351,352,353,354,355,
+ -1, -1, -1,442,356,357,358,359,
+ -1, -1, -1, -1,443,360,361,362,
+ -1, -1, -1, -1, -1,444,363,364,
+ -1, -1, -1, -1, -1, -1,445,365,
+ -1, -1, -1, -1, -1, -1, -1,446 },
+ { -1, -1, -1,366,367,368,369,370,
+ -1, -1, -1,371,372,373,374,375,
+ -1, -1, -1,376,377,378,379,380,
+ -1, -1, -1,447,381,382,383,384,
+ -1, -1, -1, -1,448,385,386,387,
+ -1, -1, -1, -1, -1,449,388,389,
+ -1, -1, -1, -1, -1, -1,450,390,
+ -1, -1, -1, -1, -1, -1, -1,451 },
+ {452,391,392,393,394,395,396,397,
+ -1, -1, -1, -1,398,399,400,401,
+ -1, -1, -1, -1,402,403,404,405,
+ -1, -1, -1, -1,406,407,408,409,
+ -1, -1, -1, -1,453,410,411,412,
+ -1, -1, -1, -1, -1,454,413,414,
+ -1, -1, -1, -1, -1, -1,455,415,
+ -1, -1, -1, -1, -1, -1, -1,456 },
+ {457,416,417,418,419,420,421,422,
+ -1,458,423,424,425,426,427,428,
+ -1, -1, -1, -1, -1,429,430,431,
+ -1, -1, -1, -1, -1,432,433,434,
+ -1, -1, -1, -1, -1,435,436,437,
+ -1, -1, -1, -1, -1,459,438,439,
+ -1, -1, -1, -1, -1, -1,460,440,
+ -1, -1, -1, -1, -1, -1, -1,461 }
+};
+#else
+static const short PP_idx[10][64] = {
+ { 0, -1, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46,
+ -1, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61 },
+ { 62, -1, -1, 63, 64, 65, -1, 66,
+ -1, 67, 68, 69, 70, 71, 72, -1,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ -1, 97, 98, 99,100,101,102,103,
+ -1,104,105,106,107,108,109, -1,
+ 110, -1,111,112,113,114, -1,115 },
+ {116, -1, -1, -1,117, -1, -1,118,
+ -1,119,120,121,122,123,124, -1,
+ -1,125,126,127,128,129,130, -1,
+ 131,132,133,134,135,136,137,138,
+ -1,139,140,141,142,143,144,145,
+ -1,146,147,148,149,150,151, -1,
+ -1,152,153,154,155,156,157, -1,
+ 158, -1, -1,159,160, -1, -1,161 },
+ {162, -1, -1, -1, -1, -1, -1,163,
+ -1,164, -1,165,166,167,168, -1,
+ -1,169,170,171,172,173,174, -1,
+ -1,175,176,177,178,179,180, -1,
+ -1,181,182,183,184,185,186, -1,
+ -1, -1,187,188,189,190,191, -1,
+ -1,192,193,194,195,196,197, -1,
+ 198, -1, -1, -1, -1, -1, -1,199 },
+ {200, -1, -1, -1, -1, -1, -1,201,
+ -1,202, -1, -1,203, -1,204, -1,
+ -1, -1,205,206,207,208, -1, -1,
+ -1,209,210,211,212,213,214, -1,
+ -1, -1,215,216,217,218,219, -1,
+ -1, -1,220,221,222,223, -1, -1,
+ -1,224, -1,225,226, -1,227, -1,
+ 228, -1, -1, -1, -1, -1, -1,229 },
+ {230, -1, -1, -1, -1, -1, -1,231,
+ -1,232, -1, -1, -1, -1,233, -1,
+ -1, -1,234, -1,235,236, -1, -1,
+ -1, -1,237,238,239,240, -1, -1,
+ -1, -1, -1,241,242,243, -1, -1,
+ -1, -1,244,245,246,247, -1, -1,
+ -1,248, -1, -1, -1, -1,249, -1,
+ 250, -1, -1, -1, -1, -1, -1,251 },
+ { -1, -1, -1, -1, -1, -1, -1,259,
+ -1,252, -1, -1, -1, -1,260, -1,
+ -1, -1,253, -1, -1,261, -1, -1,
+ -1, -1, -1,254,262, -1, -1, -1,
+ -1, -1, -1, -1,255, -1, -1, -1,
+ -1, -1, -1, -1, -1,256, -1, -1,
+ -1, -1, -1, -1, -1, -1,257, -1,
+ -1, -1, -1, -1, -1, -1, -1,258 },
+ { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,268, -1,
+ -1, -1,263, -1, -1,269, -1, -1,
+ -1, -1, -1,264,270, -1, -1, -1,
+ -1, -1, -1, -1,265, -1, -1, -1,
+ -1, -1, -1, -1, -1,266, -1, -1,
+ -1, -1, -1, -1, -1, -1,267, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 },
+ { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,274, -1, -1,
+ -1, -1, -1,271,275, -1, -1, -1,
+ -1, -1, -1, -1,272, -1, -1, -1,
+ -1, -1, -1, -1, -1,273, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 },
+ { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,277, -1, -1, -1,
+ -1, -1, -1, -1,276, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 }
+};
+
+static const ubyte test45[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const ubyte mtwist[] = {
+ 15, 63, 55, 47, 40, 48, 56, 12,
+ 62, 11, 39, 31, 24, 32, 8, 57,
+ 54, 38, 7, 23, 16, 4, 33, 49,
+ 46, 30, 22, 3, 0, 17, 25, 41,
+ 45, 29, 21, 2, 1, 18, 26, 42,
+ 53, 37, 6, 20, 19, 5, 34, 50,
+ 61, 10, 36, 28, 27, 35, 9, 58,
+ 14, 60, 52, 44, 43, 51, 59, 13
+};
+#endif
+
+static int binomial[5][64];
+static int pawnidx[5][24];
+static int pfactor[5][4];
+#ifdef CONNECTED_KINGS
+static int multidx[5][10];
+static int mfactor[5];
+#endif
+
+static void init_indices(void)
+{
+ int i, j, k;
+
+ // binomial[k-1][n] = Bin(n, k)
+ for (i = 0; i < 5; i++)
+ for (j = 0; j < 64; j++) {
+ int f = j;
+ int l = 1;
+ for (k = 1; k <= i; k++) {
+ f *= (j - k);
+ l *= (k + 1);
+ }
+ binomial[i][j] = f / l;
+ }
+
+ for (i = 0; i < 5; i++) {
+ int s = 0;
+ for (j = 0; j < 6; j++) {
+ pawnidx[i][j] = s;
+ s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
+ }
+ pfactor[i][0] = s;
+ s = 0;
+ for (; j < 12; j++) {
+ pawnidx[i][j] = s;
+ s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
+ }
+ pfactor[i][1] = s;
+ s = 0;
+ for (; j < 18; j++) {
+ pawnidx[i][j] = s;
+ s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
+ }
+ pfactor[i][2] = s;
+ s = 0;
+ for (; j < 24; j++) {
+ pawnidx[i][j] = s;
+ s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
+ }
+ pfactor[i][3] = s;
+ }
+
+#ifdef CONNECTED_KINGS
+ for (i = 0; i < 5; i++) {
+ int s = 0;
+ for (j = 0; j < 10; j++) {
+ multidx[i][j] = s;
+ s += (i == 0) ? 1 : binomial[i - 1][mtwist[invtriangle[j]]];
+ }
+ mfactor[i] = s;
+ }
+#endif
+}
+
+#ifndef CONNECTED_KINGS
+static uint64_t encode_piece(struct TBEntry_piece *ptr, ubyte *norm, int *pos, int *factor)
+{
+ uint64_t idx = 0;
+ int i, j, k, m, l, p;
+ int n = ptr->num;
+
+ if (pos[0] & 0x04) {
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x07;
+ }
+ if (pos[0] & 0x20) {
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x38;
+ }
+
+ for (i = 0; i < n; i++)
+ if (offdiag[pos[i]]) break;
+ if (i < (ptr->enc_type == 0 ? 3 : 2) && offdiag[pos[i]] > 0)
+ for (i = 0; i < n; i++)
+ pos[i] = flipdiag[pos[i]];
+
+ switch (ptr->enc_type) {
+
+ case 0: /* 111 */
+ i = (pos[1] > pos[0]);
+ j = (pos[2] > pos[0]) + (pos[2] > pos[1]);
+
+ if (offdiag[pos[0]])
+ idx = triangle[pos[0]] * 63*62 + (pos[1] - i) * 62 + (pos[2] - j);
+ else if (offdiag[pos[1]])
+ idx = 6*63*62 + diag[pos[0]] * 28*62 + lower[pos[1]] * 62 + pos[2] - j;
+ else if (offdiag[pos[2]])
+ idx = 6*63*62 + 4*28*62 + (diag[pos[0]]) * 7*28 + (diag[pos[1]] - i) * 28 + lower[pos[2]];
+ else
+ idx = 6*63*62 + 4*28*62 + 4*7*28 + (diag[pos[0]] * 7*6) + (diag[pos[1]] - i) * 6 + (diag[pos[2]] - j);
+ i = 3;
+ break;
+
+ case 1: /* K3 */
+ j = (pos[2] > pos[0]) + (pos[2] > pos[1]);
+
+ idx = KK_idx[triangle[pos[0]]][pos[1]];
+ if (idx < 441)
+ idx = idx + 441 * (pos[2] - j);
+ else {
+ idx = 441*62 + (idx - 441) + 21 * lower[pos[2]];
+ if (!offdiag[pos[2]])
+ idx -= j * 21;
+ }
+ i = 3;
+ break;
+
+ default: /* K2 */
+ idx = KK_idx[triangle[pos[0]]][pos[1]];
+ i = 2;
+ break;
+ }
+ idx *= factor[0];
+
+ for (; i < n;) {
+ int t = norm[i];
+ for (j = i; j < i + t; j++)
+ for (k = j + 1; k < i + t; k++)
+ if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
+ int s = 0;
+ for (m = i; m < i + t; m++) {
+ p = pos[m];
+ for (l = 0, j = 0; l < i; l++)
+ j += (p > pos[l]);
+ s += binomial[m - i][p - j];
+ }
+ idx += ((uint64_t)s) * ((uint64_t)factor[i]);
+ i += t;
+ }
+
+ return idx;
+}
+#else
+static uint64_t encode_piece(struct TBEntry_piece *ptr, ubyte *norm, int *pos, int *factor)
+{
+ uint64_t idx;
+ int i, j, k, m, l, p;
+ int n = ptr->num;
+
+ if (ptr->enc_type < 3) {
+ if (pos[0] & 0x04) {
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x07;
+ }
+ if (pos[0] & 0x20) {
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x38;
+ }
+
+ for (i = 0; i < n; i++)
+ if (offdiag[pos[i]]) break;
+ if (i < (ptr->enc_type == 0 ? 3 : 2) && offdiag[pos[i]] > 0)
+ for (i = 0; i < n; i++)
+ pos[i] = flipdiag[pos[i]];
+
+ switch (ptr->enc_type) {
+
+ case 0: /* 111 */
+ i = (pos[1] > pos[0]);
+ j = (pos[2] > pos[0]) + (pos[2] > pos[1]);
+
+ if (offdiag[pos[0]])
+ idx = triangle[pos[0]] * 63*62 + (pos[1] - i) * 62 + (pos[2] - j);
+ else if (offdiag[pos[1]])
+ idx = 6*63*62 + diag[pos[0]] * 28*62 + lower[pos[1]] * 62 + pos[2] - j;
+ else if (offdiag[pos[2]])
+ idx = 6*63*62 + 4*28*62 + (diag[pos[0]]) * 7*28 + (diag[pos[1]] - i) * 28 + lower[pos[2]];
+ else
+ idx = 6*63*62 + 4*28*62 + 4*7*28 + (diag[pos[0]] * 7*6) + (diag[pos[1]] - i) * 6 + (diag[pos[2]] - j);
+ i = 3;
+ break;
+
+ case 2: /* 11 */
+ i = (pos[1] > pos[0]);
+
+ if (offdiag[pos[0]])
+ idx = triangle[pos[0]] * 63 + (pos[1] - i);
+ else if (offdiag[pos[1]])
+ idx = 6*63 + diag[pos[0]] * 28 + lower[pos[1]];
+ else
+ idx = 6*63 + 4*28 + (diag[pos[0]]) * 7 + (diag[pos[1]] - i);
+ i = 2;
+ break;
+
+ }
+ } else if (ptr->enc_type == 3) { /* 2, e.g. KKvK */
+ if (triangle[pos[0]] > triangle[pos[1]])
+ Swap(pos[0], pos[1]);
+ if (pos[0] & 0x04)
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x07;
+ if (pos[0] & 0x20)
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x38;
+ if (offdiag[pos[0]] > 0 || (offdiag[pos[0]] == 0 && offdiag[pos[1]] > 0))
+ for (i = 0; i < n; i++)
+ pos[i] = flipdiag[pos[i]];
+ if (test45[pos[1]] && triangle[pos[0]] == triangle[pos[1]]) {
+ Swap(pos[0], pos[1]);
+ for (i = 0; i < n; i++)
+ pos[i] = flipdiag[pos[i] ^ 0x38];
+ }
+ idx = PP_idx[triangle[pos[0]]][pos[1]];
+ i = 2;
+ } else { /* 3 and higher, e.g. KKKvK and KKKKvK */
+ for (i = 1; i < norm[0]; i++)
+ if (triangle[pos[0]] > triangle[pos[i]])
+ Swap(pos[0], pos[i]);
+ if (pos[0] & 0x04)
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x07;
+ if (pos[0] & 0x20)
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x38;
+ if (offdiag[pos[0]] > 0)
+ for (i = 0; i < n; i++)
+ pos[i] = flipdiag[pos[i]];
+ for (i = 1; i < norm[0]; i++)
+ for (j = i + 1; j < norm[0]; j++)
+ if (mtwist[pos[i]] > mtwist[pos[j]])
+ Swap(pos[i], pos[j]);
+
+ idx = multidx[norm[0] - 1][triangle[pos[0]]];
+ for (i = 1; i < norm[0]; i++)
+ idx += binomial[i - 1][mtwist[pos[i]]];
+ }
+ idx *= factor[0];
+
+ for (; i < n;) {
+ int t = norm[i];
+ for (j = i; j < i + t; j++)
+ for (k = j + 1; k < i + t; k++)
+ if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
+ int s = 0;
+ for (m = i; m < i + t; m++) {
+ p = pos[m];
+ for (l = 0, j = 0; l < i; l++)
+ j += (p > pos[l]);
+ s += binomial[m - i][p - j];
+ }
+ idx += ((uint64_t)s) * ((uint64_t)factor[i]);
+ i += t;
+ }
+
+ return idx;
+}
+#endif
+
+// determine file of leftmost pawn and sort pawns
+static int pawn_file(struct TBEntry_pawn *ptr, int *pos)
+{
+ int i;
+
+ for (i = 1; i < ptr->pawns[0]; i++)
+ if (flap[pos[0]] > flap[pos[i]])
+ Swap(pos[0], pos[i]);
+
+ return file_to_file[pos[0] & 0x07];
+}
+
+static uint64_t encode_pawn(struct TBEntry_pawn *ptr, ubyte *norm, int *pos, int *factor)
+{
+ uint64_t idx;
+ int i, j, k, m, s, t;
+ int n = ptr->num;
+
+ if (pos[0] & 0x04)
+ for (i = 0; i < n; i++)
+ pos[i] ^= 0x07;
+
+ for (i = 1; i < ptr->pawns[0]; i++)
+ for (j = i + 1; j < ptr->pawns[0]; j++)
+ if (ptwist[pos[i]] < ptwist[pos[j]])
+ Swap(pos[i], pos[j]);
+
+ t = ptr->pawns[0] - 1;
+ idx = pawnidx[t][flap[pos[0]]];
+ for (i = t; i > 0; i--)
+ idx += binomial[t - i][ptwist[pos[i]]];
+ idx *= factor[0];
+
+ // remaining pawns
+ i = ptr->pawns[0];
+ t = i + ptr->pawns[1];
+ if (t > i) {
+ for (j = i; j < t; j++)
+ for (k = j + 1; k < t; k++)
+ if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
+ s = 0;
+ for (m = i; m < t; m++) {
+ int p = pos[m];
+ for (k = 0, j = 0; k < i; k++)
+ j += (p > pos[k]);
+ s += binomial[m - i][p - j - 8];
+ }
+ idx += ((uint64_t)s) * ((uint64_t)factor[i]);
+ i = t;
+ }
+
+ for (; i < n;) {
+ t = norm[i];
+ for (j = i; j < i + t; j++)
+ for (k = j + 1; k < i + t; k++)
+ if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
+ s = 0;
+ for (m = i; m < i + t; m++) {
+ int p = pos[m];
+ for (k = 0, j = 0; k < i; k++)
+ j += (p > pos[k]);
+ s += binomial[m - i][p - j];
+ }
+ idx += ((uint64_t)s) * ((uint64_t)factor[i]);
+ i += t;
+ }
+
+ return idx;
+}
+
+static ubyte decompress_pairs(struct PairsData *d, uint64_t index);
+
+// place k like pieces on n squares
+static int subfactor(int k, int n)
+{
+ int i, f, l;
+
+ f = n;
+ l = 1;
+ for (i = 1; i < k; i++) {
+ f *= n - i;
+ l *= i + 1;
+ }
+
+ return f / l;
+}
+
+static uint64_t calc_factors_piece(int *factor, int num, int order, ubyte *norm, ubyte enc_type)
+{
+ int i, k, n;
+ uint64_t f;
+#ifndef CONNECTED_KINGS
+ static int pivfac[] = { 31332, 28056, 462 };
+#else
+ static int pivfac[] = { 31332, 0, 518, 278 };
+#endif
+
+ n = 64 - norm[0];
+
+ f = 1;
+ for (i = norm[0], k = 0; i < num || k == order; k++) {
+ if (k == order) {
+ factor[0] = f;
+#ifndef CONNECTED_KINGS
+ f *= pivfac[enc_type];
+#else
+ if (enc_type < 4)
+ f *= pivfac[enc_type];
+ else
+ f *= mfactor[enc_type - 2];
+#endif
+ } else {
+ factor[i] = f;
+ f *= subfactor(norm[i], n);
+ n -= norm[i];
+ i += norm[i];
+ }
+ }
+
+ return f;
+}
+
+static uint64_t calc_factors_pawn(int *factor, int num, int order, int order2, ubyte *norm, int file)
+{
+ int i, k, n;
+ uint64_t f;
+
+ i = norm[0];
+ if (order2 < 0x0f) i += norm[i];
+ n = 64 - i;
+
+ f = 1;
+ for (k = 0; i < num || k == order || k == order2; k++) {
+ if (k == order) {
+ factor[0] = f;
+ f *= pfactor[norm[0] - 1][file];
+ } else if (k == order2) {
+ factor[norm[0]] = f;
+ f *= subfactor(norm[norm[0]], 48 - norm[0]);
+ } else {
+ factor[i] = f;
+ f *= subfactor(norm[i], n);
+ n -= norm[i];
+ i += norm[i];
+ }
+ }
+
+ return f;
+}
+
+static void set_norm_piece(struct TBEntry_piece *ptr, ubyte *norm, ubyte *pieces)
+{
+ int i, j;
+
+ for (i = 0; i < ptr->num; i++)
+ norm[i] = 0;
+
+ switch (ptr->enc_type) {
+ case 0:
+ norm[0] = 3;
+ break;
+ case 2:
+ norm[0] = 2;
+ break;
+ default:
+ norm[0] = ptr->enc_type - 1;
+ break;
+ }
+
+ for (i = norm[0]; i < ptr->num; i += norm[i])
+ for (j = i; j < ptr->num && pieces[j] == pieces[i]; j++)
+ norm[i]++;
+}
+
+static void set_norm_pawn(struct TBEntry_pawn *ptr, ubyte *norm, ubyte *pieces)
+{
+ int i, j;
+
+ for (i = 0; i < ptr->num; i++)
+ norm[i] = 0;
+
+ norm[0] = ptr->pawns[0];
+ if (ptr->pawns[1]) norm[ptr->pawns[0]] = ptr->pawns[1];
+
+ for (i = ptr->pawns[0] + ptr->pawns[1]; i < ptr->num; i += norm[i])
+ for (j = i; j < ptr->num && pieces[j] == pieces[i]; j++)
+ norm[i]++;
+}
+
+static void setup_pieces_piece(struct TBEntry_piece *ptr, unsigned char *data, uint64_t *tb_size)
+{
+ int i;
+ int order;
+
+ for (i = 0; i < ptr->num; i++)
+ ptr->pieces[0][i] = data[i + 1] & 0x0f;
+ order = data[0] & 0x0f;
+ set_norm_piece(ptr, ptr->norm[0], ptr->pieces[0]);
+ tb_size[0] = calc_factors_piece(ptr->factor[0], ptr->num, order, ptr->norm[0], ptr->enc_type);
+
+ for (i = 0; i < ptr->num; i++)
+ ptr->pieces[1][i] = data[i + 1] >> 4;
+ order = data[0] >> 4;
+ set_norm_piece(ptr, ptr->norm[1], ptr->pieces[1]);
+ tb_size[1] = calc_factors_piece(ptr->factor[1], ptr->num, order, ptr->norm[1], ptr->enc_type);
+}
+
+static void setup_pieces_piece_dtz(struct DTZEntry_piece *ptr, unsigned char *data, uint64_t *tb_size)
+{
+ int i;
+ int order;
+
+ for (i = 0; i < ptr->num; i++)
+ ptr->pieces[i] = data[i + 1] & 0x0f;
+ order = data[0] & 0x0f;
+ set_norm_piece((struct TBEntry_piece *)ptr, ptr->norm, ptr->pieces);
+ tb_size[0] = calc_factors_piece(ptr->factor, ptr->num, order, ptr->norm, ptr->enc_type);
+}
+
+static void setup_pieces_pawn(struct TBEntry_pawn *ptr, unsigned char *data, uint64_t *tb_size, int f)
+{
+ int i, j;
+ int order, order2;
+
+ j = 1 + (ptr->pawns[1] > 0);
+ order = data[0] & 0x0f;
+ order2 = ptr->pawns[1] ? (data[1] & 0x0f) : 0x0f;
+ for (i = 0; i < ptr->num; i++)
+ ptr->file[f].pieces[0][i] = data[i + j] & 0x0f;
+ set_norm_pawn(ptr, ptr->file[f].norm[0], ptr->file[f].pieces[0]);
+ tb_size[0] = calc_factors_pawn(ptr->file[f].factor[0], ptr->num, order, order2, ptr->file[f].norm[0], f);
+
+ order = data[0] >> 4;
+ order2 = ptr->pawns[1] ? (data[1] >> 4) : 0x0f;
+ for (i = 0; i < ptr->num; i++)
+ ptr->file[f].pieces[1][i] = data[i + j] >> 4;
+ set_norm_pawn(ptr, ptr->file[f].norm[1], ptr->file[f].pieces[1]);
+ tb_size[1] = calc_factors_pawn(ptr->file[f].factor[1], ptr->num, order, order2, ptr->file[f].norm[1], f);
+}
+
+static void setup_pieces_pawn_dtz(struct DTZEntry_pawn *ptr, unsigned char *data, uint64_t *tb_size, int f)
+{
+ int i, j;
+ int order, order2;
+
+ j = 1 + (ptr->pawns[1] > 0);
+ order = data[0] & 0x0f;
+ order2 = ptr->pawns[1] ? (data[1] & 0x0f) : 0x0f;
+ for (i = 0; i < ptr->num; i++)
+ ptr->file[f].pieces[i] = data[i + j] & 0x0f;
+ set_norm_pawn((struct TBEntry_pawn *)ptr, ptr->file[f].norm, ptr->file[f].pieces);
+ tb_size[0] = calc_factors_pawn(ptr->file[f].factor, ptr->num, order, order2, ptr->file[f].norm, f);
+}
+
+static void calc_symlen(struct PairsData *d, int s, char *tmp)
+{
+ int s1, s2;
+
+ int w = *(int *)(d->sympat + 3 * s);
+ s2 = (w >> 12) & 0x0fff;
+ if (s2 == 0x0fff)
+ d->symlen[s] = 0;
+ else {
+ s1 = w & 0x0fff;
+ if (!tmp[s1]) calc_symlen(d, s1, tmp);
+ if (!tmp[s2]) calc_symlen(d, s2, tmp);
+ d->symlen[s] = d->symlen[s1] + d->symlen[s2] + 1;
+ }
+ tmp[s] = 1;
+}
+
+static struct PairsData *setup_pairs(unsigned char *data, uint64_t tb_size, uint64_t *size, unsigned char **next, ubyte *flags, int wdl)
+{
+ struct PairsData *d;
+ int i;
+
+ *flags = data[0];
+ if (data[0] & 0x80) {
+ d = (struct PairsData *)malloc(sizeof(struct PairsData));
+ d->idxbits = 0;
+ if (wdl)
+ d->min_len = data[1];
+ else
+ d->min_len = 0;
+ *next = data + 2;
+ size[0] = size[1] = size[2] = 0;
+ return d;
+ }
+
+ int blocksize = data[1];
+ int idxbits = data[2];
+ int real_num_blocks = *(uint32_t *)(&data[4]);
+ int num_blocks = real_num_blocks + *(ubyte *)(&data[3]);
+ int max_len = data[8];
+ int min_len = data[9];
+ int h = max_len - min_len + 1;
+ int num_syms = *(ushort *)(&data[10 + 2 * h]);
+ d = (struct PairsData *)malloc(sizeof(struct PairsData) + (h - 1) * sizeof(base_t) + num_syms);
+ d->blocksize = blocksize;
+ d->idxbits = idxbits;
+ d->offset = (ushort *)(&data[10]);
+ d->symlen = ((ubyte *)d) + sizeof(struct PairsData) + (h - 1) * sizeof(base_t);
+ d->sympat = &data[12 + 2 * h];
+ d->min_len = min_len;
+ *next = &data[12 + 2 * h + 3 * num_syms + (num_syms & 1)];
+
+ int num_indices = (tb_size + (1ULL << idxbits) - 1) >> idxbits;
+ size[0] = 6ULL * num_indices;
+ size[1] = 2ULL * num_blocks;
+ size[2] = (1ULL << blocksize) * real_num_blocks;
+
+ // char tmp[num_syms];
+ char tmp[4096];
+ for (i = 0; i < num_syms; i++)
+ tmp[i] = 0;
+ for (i = 0; i < num_syms; i++)
+ if (!tmp[i])
+ calc_symlen(d, i, tmp);
+
+ d->base[h - 1] = 0;
+ for (i = h - 2; i >= 0; i--)
+ d->base[i] = (d->base[i + 1] + d->offset[i] - d->offset[i + 1]) / 2;
+ for (i = 0; i < h; i++)
+ d->base[i] <<= 64 - (min_len + i);
+
+ d->offset -= d->min_len;
+
+ return d;
+}
+
+static int init_table_wdl(struct TBEntry *entry, const char *str)
+{
+ ubyte *next;
+ int f, s;
+ uint64_t tb_size[8];
+ uint64_t size[8 * 3];
+ ubyte flags;
+
+ // first mmap the table into memory
+
+ entry->data = map_file(str, WDLSUFFIX, &entry->mapping);
+ if (!entry->data) {
+ std::cout << "Could not find " << str << WDLSUFFIX << std::endl;
+ return 0;
+ }
+
+ ubyte *data = (ubyte *)entry->data;
+ if (((uint32_t *)data)[0] != WDL_MAGIC) {
+ std::cout << "Corrupted table" << std::endl;
+ unmap_file(entry->data, entry->mapping);
+ entry->data = 0;
+ return 0;
+ }
+
+ int split = data[4] & 0x01;
+ int files = data[4] & 0x02 ? 4 : 1;
+
+ data += 5;
+
+ if (!entry->has_pawns) {
+ struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
+ setup_pieces_piece(ptr, data, &tb_size[0]);
+ data += ptr->num + 1;
+ data += ((uintptr_t)data) & 0x01;
+
+ ptr->precomp[0] = setup_pairs(data, tb_size[0], &size[0], &next, &flags, 1);
+ data = next;
+ if (split) {
+ ptr->precomp[1] = setup_pairs(data, tb_size[1], &size[3], &next, &flags, 1);
+ data = next;
+ } else
+ ptr->precomp[1] = NULL;
+
+ ptr->precomp[0]->indextable = (char *)data;
+ data += size[0];
+ if (split) {
+ ptr->precomp[1]->indextable = (char *)data;
+ data += size[3];
+ }
+
+ ptr->precomp[0]->sizetable = (ushort *)data;
+ data += size[1];
+ if (split) {
+ ptr->precomp[1]->sizetable = (ushort *)data;
+ data += size[4];
+ }
+
+ data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
+ ptr->precomp[0]->data = data;
+ data += size[2];
+ if (split) {
+ data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
+ ptr->precomp[1]->data = data;
+ }
+ } else {
+ struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
+ s = 1 + (ptr->pawns[1] > 0);
+ for (f = 0; f < 4; f++) {
+ setup_pieces_pawn((struct TBEntry_pawn *)ptr, data, &tb_size[2 * f], f);
+ data += ptr->num + s;
+ }
+ data += ((uintptr_t)data) & 0x01;
+
+ for (f = 0; f < files; f++) {
+ ptr->file[f].precomp[0] = setup_pairs(data, tb_size[2 * f], &size[6 * f], &next, &flags, 1);
+ data = next;
+ if (split) {
+ ptr->file[f].precomp[1] = setup_pairs(data, tb_size[2 * f + 1], &size[6 * f + 3], &next, &flags, 1);
+ data = next;
+ } else
+ ptr->file[f].precomp[1] = NULL;
+ }
+
+ for (f = 0; f < files; f++) {
+ ptr->file[f].precomp[0]->indextable = (char *)data;
+ data += size[6 * f];
+ if (split) {
+ ptr->file[f].precomp[1]->indextable = (char *)data;
+ data += size[6 * f + 3];
+ }
+ }
+
+ for (f = 0; f < files; f++) {
+ ptr->file[f].precomp[0]->sizetable = (ushort *)data;
+ data += size[6 * f + 1];
+ if (split) {
+ ptr->file[f].precomp[1]->sizetable = (ushort *)data;
+ data += size[6 * f + 4];
+ }
+ }
+
+ for (f = 0; f < files; f++) {
+ data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
+ ptr->file[f].precomp[0]->data = data;
+ data += size[6 * f + 2];
+ if (split) {
+ data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
+ ptr->file[f].precomp[1]->data = data;
+ data += size[6 * f + 5];
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int init_table_dtz(struct TBEntry *entry)
+{
+ ubyte *data = (ubyte *)entry->data;
+ ubyte *next;
+ int f, s;
+ uint64_t tb_size[4];
+ uint64_t size[4 * 3];
+
+ if (!data)
+ return 0;
+
+ if (((uint32_t *)data)[0] != DTZ_MAGIC) {
+ std::cout << "Corrupted table" << std::endl;
+ return 0;
+ }
+
+ int files = data[4] & 0x02 ? 4 : 1;
+
+ data += 5;
+
+ if (!entry->has_pawns) {
+ struct DTZEntry_piece *ptr = (struct DTZEntry_piece *)entry;
+ setup_pieces_piece_dtz(ptr, data, &tb_size[0]);
+ data += ptr->num + 1;
+ data += ((uintptr_t)data) & 0x01;
+
+ ptr->precomp = setup_pairs(data, tb_size[0], &size[0], &next, &(ptr->flags), 0);
+ data = next;
+
+ ptr->map = data;
+ if (ptr->flags & 2) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ ptr->map_idx[i] = (data + 1 - ptr->map);
+ data += 1 + data[0];
+ }
+ data += ((uintptr_t)data) & 0x01;
+ }
+
+ ptr->precomp->indextable = (char *)data;
+ data += size[0];
+
+ ptr->precomp->sizetable = (ushort *)data;
+ data += size[1];
+
+ data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
+ ptr->precomp->data = data;
+ data += size[2];
+ } else {
+ struct DTZEntry_pawn *ptr = (struct DTZEntry_pawn *)entry;
+ s = 1 + (ptr->pawns[1] > 0);
+ for (f = 0; f < 4; f++) {
+ setup_pieces_pawn_dtz(ptr, data, &tb_size[f], f);
+ data += ptr->num + s;
+ }
+ data += ((uintptr_t)data) & 0x01;
+
+ for (f = 0; f < files; f++) {
+ ptr->file[f].precomp = setup_pairs(data, tb_size[f], &size[3 * f], &next, &(ptr->flags[f]), 0);
+ data = next;
+ }
+
+ ptr->map = data;
+ for (f = 0; f < files; f++) {
+ if (ptr->flags[f] & 2) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ ptr->map_idx[f][i] = (data + 1 - ptr->map);
+ data += 1 + data[0];
+ }
+ }
+ }
+ data += ((uintptr_t)data) & 0x01;
+
+ for (f = 0; f < files; f++) {
+ ptr->file[f].precomp->indextable = (char *)data;
+ data += size[3 * f];
+ }
+
+ for (f = 0; f < files; f++) {
+ ptr->file[f].precomp->sizetable = (ushort *)data;
+ data += size[3 * f + 1];
+ }
+
+ for (f = 0; f < files; f++) {
+ data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
+ ptr->file[f].precomp->data = data;
+ data += size[3 * f + 2];
+ }
+ }
+
+ return 1;
+}
+
+static ubyte decompress_pairs(struct PairsData *d, uint64_t idx)
+{
+ if (!d->idxbits)
+ return d->min_len;
+
+ uint32_t mainidx = idx >> d->idxbits;
+ int litidx = (idx & ((1 << d->idxbits) - 1)) - (1 << (d->idxbits - 1));
+ uint32_t block = *(uint32_t *)(d->indextable + 6 * mainidx);
+ litidx += *(ushort *)(d->indextable + 6 * mainidx + 4);
+ if (litidx < 0) {
+ do {
+ litidx += d->sizetable[--block] + 1;
+ } while (litidx < 0);
+ } else {
+ while (litidx > d->sizetable[block])
+ litidx -= d->sizetable[block++] + 1;
+ }
+
+ uint32_t *ptr = (uint32_t *)(d->data + (block << d->blocksize));
+
+ int m = d->min_len;
+ ushort *offset = d->offset;
+ base_t *base = d->base - m;
+ ubyte *symlen = d->symlen;
+ int sym, bitcnt;
+
+ uint64_t code = __builtin_bswap64(*((uint64_t *)ptr));
+ ptr += 2;
+ bitcnt = 0; // number of "empty bits" in code
+ for (;;) {
+ int l = m;
+ while (code < base[l]) l++;
+ sym = offset[l] + ((code - base[l]) >> (64 - l));
+ if (litidx < (int)symlen[sym] + 1) break;
+ litidx -= (int)symlen[sym] + 1;
+ code <<= l;
+ bitcnt += l;
+ if (bitcnt >= 32) {
+ bitcnt -= 32;
+ code |= ((uint64_t)(__builtin_bswap32(*ptr++))) << bitcnt;
+ }
+ }
+
+ ubyte *sympat = d->sympat;
+ while (symlen[sym] != 0) {
+ int w = *(int *)(sympat + 3 * sym);
+ int s1 = w & 0x0fff;
+ if (litidx < (int)symlen[s1] + 1)
+ sym = s1;
+ else {
+ litidx -= (int)symlen[s1] + 1;
+ sym = (w >> 12) & 0x0fff;
+ }
+ }
+
+ return *(sympat + 3 * sym);
+}
+
+TBEntry* load_dtz_table(const char* str, uint64_t key1, uint64_t key2)
+{
+ int i;
+ struct TBEntry *ptr, *ptr3;
+ struct TBHashEntry *ptr2;
+
+ // find corresponding WDL entry
+ ptr2 = WDL_hash[key1 >> (64 - TBHASHBITS)];
+ for (i = 0; i < HSHMAX; i++)
+ if (ptr2[i].key == key1) break;
+ if (i == HSHMAX) return NULL;
+ ptr = ptr2[i].ptr;
+
+ ptr3 = (struct TBEntry *)malloc(ptr->has_pawns
+ ? sizeof(struct DTZEntry_pawn)
+ : sizeof(struct DTZEntry_piece));
+
+ ptr3->data = map_file(str, DTZSUFFIX, &ptr3->mapping);
+ ptr3->key = ptr->key;
+ ptr3->num = ptr->num;
+ ptr3->symmetric = ptr->symmetric;
+ ptr3->has_pawns = ptr->has_pawns;
+ if (ptr3->has_pawns) {
+ struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr3;
+ entry->pawns[0] = ((struct TBEntry_pawn *)ptr)->pawns[0];
+ entry->pawns[1] = ((struct TBEntry_pawn *)ptr)->pawns[1];
+ } else {
+ struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr3;
+ entry->enc_type = ((struct TBEntry_piece *)ptr)->enc_type;
+ }
+ if (!init_table_dtz(ptr3)) {
+ free(ptr3);
+ return NULL;
+ }
+ return ptr3;
+}
+
+static void free_wdl_entry(struct TBEntry *entry)
+{
+ unmap_file(entry->data, entry->mapping);
+ entry->data = NULL;
+ if (!entry->has_pawns) {
+ struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
+ free(ptr->precomp[0]); ptr->precomp[0] = NULL;
+ free(ptr->precomp[1]); ptr->precomp[1] = NULL;
+ } else {
+ struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
+ int f;
+ for (f = 0; f < 4; f++) {
+ free(ptr->file[f].precomp[0]); ptr->file[f].precomp[0] = NULL;
+ free(ptr->file[f].precomp[1]); ptr->file[f].precomp[1] = NULL;
+ }
+ }
+}
+
+static void free_dtz_entry(struct TBEntry *entry)
+{
+ unmap_file(entry->data, entry->mapping);
+ entry->data = NULL;
+ if (!entry->has_pawns) {
+ struct DTZEntry_piece *ptr = (struct DTZEntry_piece *)entry;
+ free(ptr->precomp); ptr->precomp = NULL;
+ } else {
+ struct DTZEntry_pawn *ptr = (struct DTZEntry_pawn *)entry;
+ int f;
+ for (f = 0; f < 4; f++) {
+ free(ptr->file[f].precomp); ptr->file[f].precomp = NULL;
+ }
+ }
+ free(entry);
+}
+
+static int wdl_to_map[5] = { 1, 3, 0, 2, 0 };
+static ubyte pa_flags[5] = { 8, 0, 0, 0, 4 };
+
diff --git a/DroidFish/jni/stockfish/tbcore.h b/DroidFish/jni/stockfish/tbcore.h
new file mode 100644
index 0000000..f9c2d56
--- /dev/null
+++ b/DroidFish/jni/stockfish/tbcore.h
@@ -0,0 +1,142 @@
+/*
+ Copyright (c) 2011-2013 Ronald de Man
+*/
+
+#ifndef TBCORE_H
+#define TBCORE_H
+
+#ifndef __WIN32__
+#define SEP_CHAR ':'
+#define FD int
+#define FD_ERR -1
+#else
+#include
+#define SEP_CHAR ';'
+#define FD HANDLE
+#define FD_ERR INVALID_HANDLE_VALUE
+#endif
+
+#include
+#include
+
+#define WDLSUFFIX ".rtbw"
+#define DTZSUFFIX ".rtbz"
+#define TBPIECES 6
+
+#define WDL_MAGIC 0x5d23e871
+#define DTZ_MAGIC 0xa50c66d7
+
+#define TBHASHBITS 11
+
+typedef unsigned char ubyte;
+typedef unsigned short ushort;
+
+struct TBHashEntry;
+
+typedef uint64_t base_t;
+
+struct PairsData {
+ char *indextable;
+ ushort *sizetable;
+ ubyte *data;
+ ushort *offset;
+ ubyte *symlen;
+ ubyte *sympat;
+ int blocksize;
+ int idxbits;
+ int min_len;
+ base_t base[1]; // C++ complains about base[]...
+};
+
+struct TBEntry {
+ char *data;
+ uint64_t key;
+ uint64_t mapping;
+ std::atomic ready;
+ ubyte num;
+ ubyte symmetric;
+ ubyte has_pawns;
+} __attribute__((__may_alias__));
+
+struct TBEntry_piece {
+ char *data;
+ uint64_t key;
+ uint64_t mapping;
+ std::atomic ready;
+ ubyte num;
+ ubyte symmetric;
+ ubyte has_pawns;
+ ubyte enc_type;
+ struct PairsData *precomp[2];
+ int factor[2][TBPIECES];
+ ubyte pieces[2][TBPIECES];
+ ubyte norm[2][TBPIECES];
+};
+
+struct TBEntry_pawn {
+ char *data;
+ uint64_t key;
+ uint64_t mapping;
+ std::atomic ready;
+ ubyte num;
+ ubyte symmetric;
+ ubyte has_pawns;
+ ubyte pawns[2];
+ struct {
+ struct PairsData *precomp[2];
+ int factor[2][TBPIECES];
+ ubyte pieces[2][TBPIECES];
+ ubyte norm[2][TBPIECES];
+ } file[4];
+};
+
+struct DTZEntry_piece {
+ char *data;
+ uint64_t key;
+ uint64_t mapping;
+ std::atomic ready;
+ ubyte num;
+ ubyte symmetric;
+ ubyte has_pawns;
+ ubyte enc_type;
+ struct PairsData *precomp;
+ int factor[TBPIECES];
+ ubyte pieces[TBPIECES];
+ ubyte norm[TBPIECES];
+ ubyte flags; // accurate, mapped, side
+ ushort map_idx[4];
+ ubyte *map;
+};
+
+struct DTZEntry_pawn {
+ char *data;
+ uint64_t key;
+ uint64_t mapping;
+ std::atomic ready;
+ ubyte num;
+ ubyte symmetric;
+ ubyte has_pawns;
+ ubyte pawns[2];
+ struct {
+ struct PairsData *precomp;
+ int factor[TBPIECES];
+ ubyte pieces[TBPIECES];
+ ubyte norm[TBPIECES];
+ } file[4];
+ ubyte flags[4];
+ ushort map_idx[4][4];
+ ubyte *map;
+};
+
+struct TBHashEntry {
+ uint64_t key;
+ struct TBEntry *ptr;
+};
+
+struct DTZTableEntry {
+ uint64_t key1;
+ uint64_t key2;
+ std::atomic entry;
+};
+
+#endif
diff --git a/DroidFish/jni/stockfish/tbprobe.cpp b/DroidFish/jni/stockfish/tbprobe.cpp
new file mode 100644
index 0000000..fa79e51
--- /dev/null
+++ b/DroidFish/jni/stockfish/tbprobe.cpp
@@ -0,0 +1,819 @@
+/*
+ Copyright (c) 2013 Ronald de Man
+ This file may be redistributed and/or modified without restrictions.
+
+ tbprobe.cpp contains the Stockfish-specific routines of the
+ tablebase probing code. It should be relatively easy to adapt
+ this code to other chess engines.
+*/
+
+#include "position.h"
+#include "movegen.h"
+#include "bitboard.h"
+#include "search.h"
+#include "bitcount.h"
+
+#include "tbprobe.h"
+#include "tbcore.h"
+
+#include "tbcore.cpp"
+
+namespace Zobrist {
+ extern Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+}
+
+int Tablebases::TBLargest = 0;
+
+// Given a position with 6 or fewer pieces, produce a text string
+// of the form KQPvKRP, where "KQP" represents the white pieces if
+// mirror == false and the black pieces if mirror == true.
+static void prt_str(Position& pos, char *str, bool mirror)
+{
+ Color color;
+ PieceType pt;
+ int i;
+
+ color = !mirror ? WHITE : BLACK;
+ for (pt = KING; pt >= PAWN; --pt)
+ for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
+ *str++ = pchr[6 - pt];
+ *str++ = 'v';
+ color = ~color;
+ for (pt = KING; pt >= PAWN; --pt)
+ for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
+ *str++ = pchr[6 - pt];
+ *str++ = 0;
+}
+
+// Given a position, produce a 64-bit material signature key.
+// If the engine supports such a key, it should equal the engine's key.
+static uint64_t calc_key(const Position& pos, bool mirror)
+{
+ Color color;
+ PieceType pt;
+ int i;
+ uint64_t key = 0;
+
+ color = !mirror ? WHITE : BLACK;
+ for (pt = PAWN; pt <= KING; ++pt)
+ for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
+ key ^= Zobrist::psq[WHITE][pt][i - 1];
+ color = ~color;
+ for (pt = PAWN; pt <= KING; ++pt)
+ for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
+ key ^= Zobrist::psq[BLACK][pt][i - 1];
+
+ return key;
+}
+
+// Produce a 64-bit material key corresponding to the material combination
+// defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
+// pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
+// pawns, ..., kings.
+static uint64_t calc_key_from_pcs(const int *pcs, bool mirror)
+{
+ int color;
+ PieceType pt;
+ int i;
+ uint64_t key = 0;
+
+ color = !mirror ? 0 : 8;
+ for (pt = PAWN; pt <= KING; ++pt)
+ for (i = 0; i < pcs[color + pt]; i++)
+ key ^= Zobrist::psq[WHITE][pt][i];
+ color ^= 8;
+ for (pt = PAWN; pt <= KING; ++pt)
+ for (i = 0; i < pcs[color + pt]; i++)
+ key ^= Zobrist::psq[BLACK][pt][i];
+
+ return key;
+}
+
+// probe_wdl_table and probe_dtz_table require similar adaptations.
+static int probe_wdl_table(Position& pos, int *success)
+{
+ struct TBEntry *ptr;
+ struct TBHashEntry *ptr2;
+ uint64_t idx;
+ uint64_t key;
+ int i;
+ ubyte res;
+ int p[TBPIECES];
+
+ // Obtain the position's material signature key.
+ key = pos.material_key();
+
+ // Test for KvK.
+ if (key == (Zobrist::psq[WHITE][KING][0] ^ Zobrist::psq[BLACK][KING][0]))
+ return 0;
+
+ ptr2 = WDL_hash[key >> (64 - TBHASHBITS)];
+ for (i = 0; i < HSHMAX; i++)
+ if (ptr2[i].key == key) break;
+ if (i == HSHMAX) {
+ *success = 0;
+ return 0;
+ }
+
+ ptr = ptr2[i].ptr;
+ ubyte ready = ptr->ready.load(std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_acquire);
+ if (!ready) {
+ std::lock_guard L(TB_mutex);
+ ready = ptr->ready.load(std::memory_order_relaxed);
+ if (!ready) {
+ char str[16];
+ prt_str(pos, str, ptr->key != key);
+ if (!init_table_wdl(ptr, str)) {
+ ptr2[i].key = 0ULL;
+ *success = 0;
+ return 0;
+ }
+ std::atomic_thread_fence(std::memory_order_release);
+ ptr->ready.store(1, std::memory_order_relaxed);
+ }
+ }
+
+ int bside, mirror, cmirror;
+ if (!ptr->symmetric) {
+ if (key != ptr->key) {
+ cmirror = 8;
+ mirror = 0x38;
+ bside = (pos.side_to_move() == WHITE);
+ } else {
+ cmirror = mirror = 0;
+ bside = !(pos.side_to_move() == WHITE);
+ }
+ } else {
+ cmirror = pos.side_to_move() == WHITE ? 0 : 8;
+ mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
+ bside = 0;
+ }
+
+ // p[i] is to contain the square 0-63 (A1-H8) for a piece of type
+ // pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king.
+ // Pieces of the same type are guaranteed to be consecutive.
+ if (!ptr->has_pawns) {
+ struct TBEntry_piece *entry = (struct TBEntry_piece *)ptr;
+ ubyte *pc = entry->pieces[bside];
+ for (i = 0; i < entry->num;) {
+ Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
+ (PieceType)(pc[i] & 0x07));
+ do {
+ p[i++] = pop_lsb(&bb);
+ } while (bb);
+ }
+ idx = encode_piece(entry, entry->norm[bside], p, entry->factor[bside]);
+ res = decompress_pairs(entry->precomp[bside], idx);
+ } else {
+ struct TBEntry_pawn *entry = (struct TBEntry_pawn *)ptr;
+ int k = entry->file[0].pieces[0][0] ^ cmirror;
+ Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
+ i = 0;
+ do {
+ p[i++] = pop_lsb(&bb) ^ mirror;
+ } while (bb);
+ int f = pawn_file(entry, p);
+ ubyte *pc = entry->file[f].pieces[bside];
+ for (; i < entry->num;) {
+ bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
+ (PieceType)(pc[i] & 0x07));
+ do {
+ p[i++] = pop_lsb(&bb) ^ mirror;
+ } while (bb);
+ }
+ idx = encode_pawn(entry, entry->file[f].norm[bside], p, entry->file[f].factor[bside]);
+ res = decompress_pairs(entry->file[f].precomp[bside], idx);
+ }
+
+ return ((int)res) - 2;
+}
+
+static int probe_dtz_table(Position& pos, int wdl, int *success)
+{
+ uint64_t idx;
+ int i, res;
+ int p[TBPIECES];
+
+ // Obtain the position's material signature key.
+ uint64_t key = calc_key(pos, false);
+
+ DTZTableEntry* dtzTabEnt;
+ {
+ dtzTabEnt = DTZ_hash[key >> (64 - TBHASHBITS)];
+ for (i = 0; i < HSHMAX; i++)
+ if (dtzTabEnt[i].key1 == key) break;
+ if (i == HSHMAX) {
+ uint64_t key2 = calc_key(pos, true);
+ dtzTabEnt = DTZ_hash[key2 >> (64 - TBHASHBITS)];
+ for (i = 0; i < HSHMAX; i++)
+ if (dtzTabEnt[i].key2 == key) break;
+ }
+ if (i == HSHMAX) {
+ *success = 0;
+ return 0;
+ }
+ dtzTabEnt += i;
+ }
+
+ TBEntry* ptr = dtzTabEnt->entry.load(std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_acquire);
+ if (!ptr) {
+ std::lock_guard L(TB_mutex);
+ ptr = dtzTabEnt->entry.load(std::memory_order_relaxed);
+ if (!ptr) {
+ struct TBHashEntry *ptr2 = WDL_hash[key >> (64 - TBHASHBITS)];
+ for (i = 0; i < HSHMAX; i++)
+ if (ptr2[i].key == key) break;
+ if (i == HSHMAX) {
+ *success = 0;
+ return 0;
+ }
+ char str[16];
+ bool mirror = (ptr2[i].ptr->key != key);
+ prt_str(pos, str, mirror);
+ ptr = load_dtz_table(str, calc_key(pos, mirror), calc_key(pos, !mirror));
+ std::atomic_thread_fence(std::memory_order_release);
+ dtzTabEnt->entry.store(ptr, std::memory_order_relaxed);
+ }
+ }
+
+ if (!ptr) {
+ *success = 0;
+ return 0;
+ }
+
+ int bside, mirror, cmirror;
+ if (!ptr->symmetric) {
+ if (key != ptr->key) {
+ cmirror = 8;
+ mirror = 0x38;
+ bside = (pos.side_to_move() == WHITE);
+ } else {
+ cmirror = mirror = 0;
+ bside = !(pos.side_to_move() == WHITE);
+ }
+ } else {
+ cmirror = pos.side_to_move() == WHITE ? 0 : 8;
+ mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
+ bside = 0;
+ }
+
+ if (!ptr->has_pawns) {
+ struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr;
+ if ((entry->flags & 1) != bside && !entry->symmetric) {
+ *success = -1;
+ return 0;
+ }
+ ubyte *pc = entry->pieces;
+ for (i = 0; i < entry->num;) {
+ Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
+ (PieceType)(pc[i] & 0x07));
+ do {
+ p[i++] = pop_lsb(&bb);
+ } while (bb);
+ }
+ idx = encode_piece((struct TBEntry_piece *)entry, entry->norm, p, entry->factor);
+ res = decompress_pairs(entry->precomp, idx);
+
+ if (entry->flags & 2)
+ res = entry->map[entry->map_idx[wdl_to_map[wdl + 2]] + res];
+
+ if (!(entry->flags & pa_flags[wdl + 2]) || (wdl & 1))
+ res *= 2;
+ } else {
+ struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr;
+ int k = entry->file[0].pieces[0] ^ cmirror;
+ Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
+ i = 0;
+ do {
+ p[i++] = pop_lsb(&bb) ^ mirror;
+ } while (bb);
+ int f = pawn_file((struct TBEntry_pawn *)entry, p);
+ if ((entry->flags[f] & 1) != bside) {
+ *success = -1;
+ return 0;
+ }
+ ubyte *pc = entry->file[f].pieces;
+ for (; i < entry->num;) {
+ bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
+ (PieceType)(pc[i] & 0x07));
+ do {
+ p[i++] = pop_lsb(&bb) ^ mirror;
+ } while (bb);
+ }
+ idx = encode_pawn((struct TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
+ res = decompress_pairs(entry->file[f].precomp, idx);
+
+ if (entry->flags[f] & 2)
+ res = entry->map[entry->map_idx[f][wdl_to_map[wdl + 2]] + res];
+
+ if (!(entry->flags[f] & pa_flags[wdl + 2]) || (wdl & 1))
+ res *= 2;
+ }
+
+ return res;
+}
+
+// Add underpromotion captures to list of captures.
+static ExtMove *add_underprom_caps(Position& pos, ExtMove *stack, ExtMove *end)
+{
+ ExtMove *moves, *extra = end;
+
+ for (moves = stack; moves < end; moves++) {
+ Move move = moves->move;
+ if (type_of(move) == PROMOTION && !pos.empty(to_sq(move))) {
+ (*extra++).move = (Move)(move - (1 << 12));
+ (*extra++).move = (Move)(move - (2 << 12));
+ (*extra++).move = (Move)(move - (3 << 12));
+ }
+ }
+
+ return extra;
+}
+
+static int probe_ab(Position& pos, int alpha, int beta, int *success)
+{
+ int v;
+ ExtMove stack[64];
+ ExtMove *moves, *end;
+ StateInfo st;
+
+ // Generate (at least) all legal non-ep captures including (under)promotions.
+ // It is OK to generate more, as long as they are filtered out below.
+ if (!pos.checkers()) {
+ end = generate(pos, stack);
+ // Since underpromotion captures are not included, we need to add them.
+ end = add_underprom_caps(pos, stack, end);
+ } else
+ end = generate(pos, stack);
+
+ CheckInfo ci(pos);
+
+ for (moves = stack; moves < end; moves++) {
+ Move capture = moves->move;
+ if (!pos.capture(capture) || type_of(capture) == ENPASSANT
+ || !pos.legal(capture, ci.pinned))
+ continue;
+ pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
+ v = -probe_ab(pos, -beta, -alpha, success);
+ pos.undo_move(capture);
+ if (*success == 0) return 0;
+ if (v > alpha) {
+ if (v >= beta) {
+ *success = 2;
+ return v;
+ }
+ alpha = v;
+ }
+ }
+
+ v = probe_wdl_table(pos, success);
+ if (*success == 0) return 0;
+ if (alpha >= v) {
+ *success = 1 + (alpha > 0);
+ return alpha;
+ } else {
+ *success = 1;
+ return v;
+ }
+}
+
+// Probe the WDL table for a particular position.
+// If *success != 0, the probe was successful.
+// The return value is from the point of view of the side to move:
+// -2 : loss
+// -1 : loss, but draw under 50-move rule
+// 0 : draw
+// 1 : win, but draw under 50-move rule
+// 2 : win
+int Tablebases::probe_wdl(Position& pos, int *success)
+{
+ int v;
+
+ *success = 1;
+ v = probe_ab(pos, -2, 2, success);
+
+ // If en passant is not possible, we are done.
+ if (pos.ep_square() == SQ_NONE)
+ return v;
+ if (!(*success)) return 0;
+
+ // Now handle en passant.
+ int v1 = -3;
+ // Generate (at least) all legal en passant captures.
+ ExtMove stack[192];
+ ExtMove *moves, *end;
+ StateInfo st;
+
+ if (!pos.checkers())
+ end = generate(pos, stack);
+ else
+ end = generate(pos, stack);
+
+ CheckInfo ci(pos);
+
+ for (moves = stack; moves < end; moves++) {
+ Move capture = moves->move;
+ if (type_of(capture) != ENPASSANT
+ || !pos.legal(capture, ci.pinned))
+ continue;
+ pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
+ int v0 = -probe_ab(pos, -2, 2, success);
+ pos.undo_move(capture);
+ if (*success == 0) return 0;
+ if (v0 > v1) v1 = v0;
+ }
+ if (v1 > -3) {
+ if (v1 >= v) v = v1;
+ else if (v == 0) {
+ // Check whether there is at least one legal non-ep move.
+ for (moves = stack; moves < end; moves++) {
+ Move capture = moves->move;
+ if (type_of(capture) == ENPASSANT) continue;
+ if (pos.legal(capture, ci.pinned)) break;
+ }
+ if (moves == end && !pos.checkers()) {
+ end = generate(pos, end);
+ for (; moves < end; moves++) {
+ Move move = moves->move;
+ if (pos.legal(move, ci.pinned))
+ break;
+ }
+ }
+ // If not, then we are forced to play the losing ep capture.
+ if (moves == end)
+ v = v1;
+ }
+ }
+
+ return v;
+}
+
+// This routine treats a position with en passant captures as one without.
+static int probe_dtz_no_ep(Position& pos, int *success)
+{
+ int wdl, dtz;
+
+ wdl = probe_ab(pos, -2, 2, success);
+ if (*success == 0) return 0;
+
+ if (wdl == 0) return 0;
+
+ if (*success == 2)
+ return wdl == 2 ? 1 : 101;
+
+ ExtMove stack[192];
+ ExtMove *moves, *end = NULL;
+ StateInfo st;
+ CheckInfo ci(pos);
+
+ if (wdl > 0) {
+ // Generate at least all legal non-capturing pawn moves
+ // including non-capturing promotions.
+ if (!pos.checkers())
+ end = generate(pos, stack);
+ else
+ end = generate(pos, stack);
+
+ for (moves = stack; moves < end; moves++) {
+ Move move = moves->move;
+ if (type_of(pos.moved_piece(move)) != PAWN || pos.capture(move)
+ || !pos.legal(move, ci.pinned))
+ continue;
+ pos.do_move(move, st, ci, pos.gives_check(move, ci));
+ int v = -probe_ab(pos, -2, -wdl + 1, success);
+ pos.undo_move(move);
+ if (*success == 0) return 0;
+ if (v == wdl)
+ return v == 2 ? 1 : 101;
+ }
+ }
+
+ dtz = 1 + probe_dtz_table(pos, wdl, success);
+ if (*success >= 0) {
+ if (wdl & 1) dtz += 100;
+ return wdl >= 0 ? dtz : -dtz;
+ }
+
+ if (wdl > 0) {
+ int best = 0xffff;
+ for (moves = stack; moves < end; moves++) {
+ Move move = moves->move;
+ if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN
+ || !pos.legal(move, ci.pinned))
+ continue;
+ pos.do_move(move, st, ci, pos.gives_check(move, ci));
+ int v = -Tablebases::probe_dtz(pos, success);
+ pos.undo_move(move);
+ if (*success == 0) return 0;
+ if (v > 0 && v + 1 < best)
+ best = v + 1;
+ }
+ return best;
+ } else {
+ int best = -1;
+ if (!pos.checkers())
+ end = generate(pos, stack);
+ else
+ end = generate(pos, stack);
+ for (moves = stack; moves < end; moves++) {
+ int v;
+ Move move = moves->move;
+ if (!pos.legal(move, ci.pinned))
+ continue;
+ pos.do_move(move, st, ci, pos.gives_check(move, ci));
+ if (st.rule50 == 0) {
+ if (wdl == -2) v = -1;
+ else {
+ v = probe_ab(pos, 1, 2, success);
+ v = (v == 2) ? 0 : -101;
+ }
+ } else {
+ v = -Tablebases::probe_dtz(pos, success) - 1;
+ }
+ pos.undo_move(move);
+ if (*success == 0) return 0;
+ if (v < best)
+ best = v;
+ }
+ return best;
+ }
+}
+
+static int wdl_to_dtz[] = {
+ -1, -101, 0, 101, 1
+};
+
+// Probe the DTZ table for a particular position.
+// If *success != 0, the probe was successful.
+// The return value is from the point of view of the side to move:
+// n < -100 : loss, but draw under 50-move rule
+// -100 <= n < -1 : loss in n ply (assuming 50-move counter == 0)
+// 0 : draw
+// 1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
+// 100 < n : win, but draw under 50-move rule
+//
+// The return value n can be off by 1: a return value -n can mean a loss
+// in n+1 ply and a return value +n can mean a win in n+1 ply. This
+// cannot happen for tables with positions exactly on the "edge" of
+// the 50-move rule.
+//
+// This implies that if dtz > 0 is returned, the position is certainly
+// a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
+// picks moves that preserve dtz + 50-move-counter <= 99.
+//
+// If n = 100 immediately after a capture or pawn move, then the position
+// is also certainly a win, and during the whole phase until the next
+// capture or pawn move, the inequality to be preserved is
+// dtz + 50-movecounter <= 100.
+//
+// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
+// then do not accept moves leading to dtz + 50-move-counter == 100.
+//
+int Tablebases::probe_dtz(Position& pos, int *success)
+{
+ *success = 1;
+ int v = probe_dtz_no_ep(pos, success);
+
+ if (pos.ep_square() == SQ_NONE)
+ return v;
+ if (*success == 0) return 0;
+
+ // Now handle en passant.
+ int v1 = -3;
+
+ ExtMove stack[192];
+ ExtMove *moves, *end;
+ StateInfo st;
+
+ if (!pos.checkers())
+ end = generate(pos, stack);
+ else
+ end = generate(pos, stack);
+ CheckInfo ci(pos);
+
+ for (moves = stack; moves < end; moves++) {
+ Move capture = moves->move;
+ if (type_of(capture) != ENPASSANT
+ || !pos.legal(capture, ci.pinned))
+ continue;
+ pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
+ int v0 = -probe_ab(pos, -2, 2, success);
+ pos.undo_move(capture);
+ if (*success == 0) return 0;
+ if (v0 > v1) v1 = v0;
+ }
+ if (v1 > -3) {
+ v1 = wdl_to_dtz[v1 + 2];
+ if (v < -100) {
+ if (v1 >= 0)
+ v = v1;
+ } else if (v < 0) {
+ if (v1 >= 0 || v1 < 100)
+ v = v1;
+ } else if (v > 100) {
+ if (v1 > 0)
+ v = v1;
+ } else if (v > 0) {
+ if (v1 == 1)
+ v = v1;
+ } else if (v1 >= 0) {
+ v = v1;
+ } else {
+ for (moves = stack; moves < end; moves++) {
+ Move move = moves->move;
+ if (type_of(move) == ENPASSANT) continue;
+ if (pos.legal(move, ci.pinned)) break;
+ }
+ if (moves == end && !pos.checkers()) {
+ end = generate(pos, end);
+ for (; moves < end; moves++) {
+ Move move = moves->move;
+ if (pos.legal(move, ci.pinned))
+ break;
+ }
+ }
+ if (moves == end)
+ v = v1;
+ }
+ }
+
+ return v;
+}
+
+// Check whether there has been at least one repetition of positions
+// since the last capture or pawn move.
+static int has_repeated(StateInfo *st)
+{
+ while (1) {
+ int i = 4, e = std::min(st->rule50, st->pliesFromNull);
+ if (e < i)
+ return 0;
+ StateInfo *stp = st->previous->previous;
+ do {
+ stp = stp->previous->previous;
+ if (stp->key == st->key)
+ return 1;
+ i += 2;
+ } while (i <= e);
+ st = st->previous;
+ }
+}
+
+static Value wdl_to_Value[5] = {
+ -VALUE_MATE + MAX_PLY + 1,
+ VALUE_DRAW - 2,
+ VALUE_DRAW,
+ VALUE_DRAW + 2,
+ VALUE_MATE - MAX_PLY - 1
+};
+
+// Use the DTZ tables to filter out moves that don't preserve the win or draw.
+// If the position is lost, but DTZ is fairly high, only keep moves that
+// maximise DTZ.
+//
+// A return value false indicates that not all probes were successful and that
+// no moves were filtered out.
+bool Tablebases::root_probe(Position& pos, Value& TBScore)
+{
+ int success;
+
+ int dtz = probe_dtz(pos, &success);
+ if (!success) return false;
+
+ StateInfo st;
+ CheckInfo ci(pos);
+
+ // Probe each move.
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ Move move = Search::RootMoves[i].pv[0];
+ pos.do_move(move, st, ci, pos.gives_check(move, ci));
+ int v = 0;
+ if (pos.checkers() && dtz > 0) {
+ ExtMove s[192];
+ if (generate(pos, s) == s)
+ v = 1;
+ }
+ if (!v) {
+ if (st.rule50 != 0) {
+ v = -Tablebases::probe_dtz(pos, &success);
+ if (v > 0) v++;
+ else if (v < 0) v--;
+ } else {
+ v = -Tablebases::probe_wdl(pos, &success);
+ v = wdl_to_dtz[v + 2];
+ }
+ }
+ pos.undo_move(move);
+ if (!success) return false;
+ Search::RootMoves[i].score = (Value)v;
+ }
+
+ // Obtain 50-move counter for the root position.
+ // In Stockfish there seems to be no clean way, so we do it like this:
+ int cnt50 = st.previous->rule50;
+
+ // Use 50-move counter to determine whether the root position is
+ // won, lost or drawn.
+ int wdl = 0;
+ if (dtz > 0)
+ wdl = (dtz + cnt50 <= 100) ? 2 : 1;
+ else if (dtz < 0)
+ wdl = (-dtz + cnt50 <= 100) ? -2 : -1;
+
+ // Determine the score to report to the user.
+ TBScore = wdl_to_Value[wdl + 2];
+ // If the position is winning or losing, but too few moves left, adjust the
+ // score to show how close it is to winning or losing.
+ // NOTE: int(PawnValueEg) is used as scaling factor in score_to_uci().
+ if (wdl == 1 && dtz <= 100)
+ TBScore = (Value)(((200 - dtz - cnt50) * int(PawnValueEg)) / 200);
+ else if (wdl == -1 && dtz >= -100)
+ TBScore = -(Value)(((200 + dtz - cnt50) * int(PawnValueEg)) / 200);
+
+ // Now be a bit smart about filtering out moves.
+ size_t j = 0;
+ if (dtz > 0) { // winning (or 50-move rule draw)
+ int best = 0xffff;
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ int v = Search::RootMoves[i].score;
+ if (v > 0 && v < best)
+ best = v;
+ }
+ int max = best;
+ // If the current phase has not seen repetitions, then try all moves
+ // that stay safely within the 50-move budget, if there are any.
+ if (!has_repeated(st.previous) && best + cnt50 <= 99)
+ max = 99 - cnt50;
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ int v = Search::RootMoves[i].score;
+ if (v > 0 && v <= max)
+ Search::RootMoves[j++] = Search::RootMoves[i];
+ }
+ } else if (dtz < 0) { // losing (or 50-move rule draw)
+ int best = 0;
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ int v = Search::RootMoves[i].score;
+ if (v < best)
+ best = v;
+ }
+ // Try all moves, unless we approach or have a 50-move rule draw.
+ if (-best * 2 + cnt50 < 100)
+ return true;
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ if (Search::RootMoves[i].score == best)
+ Search::RootMoves[j++] = Search::RootMoves[i];
+ }
+ } else { // drawing
+ // Try all moves that preserve the draw.
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ if (Search::RootMoves[i].score == 0)
+ Search::RootMoves[j++] = Search::RootMoves[i];
+ }
+ }
+ Search::RootMoves.resize(j, Search::RootMove(MOVE_NONE));
+
+ return true;
+}
+
+// Use the WDL tables to filter out moves that don't preserve the win or draw.
+// This is a fallback for the case that some or all DTZ tables are missing.
+//
+// A return value false indicates that not all probes were successful and that
+// no moves were filtered out.
+bool Tablebases::root_probe_wdl(Position& pos, Value& TBScore)
+{
+ int success;
+
+ int wdl = Tablebases::probe_wdl(pos, &success);
+ if (!success) return false;
+ TBScore = wdl_to_Value[wdl + 2];
+
+ StateInfo st;
+ CheckInfo ci(pos);
+
+ int best = -2;
+
+ // Probe each move.
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ Move move = Search::RootMoves[i].pv[0];
+ pos.do_move(move, st, ci, pos.gives_check(move, ci));
+ int v = -Tablebases::probe_wdl(pos, &success);
+ pos.undo_move(move);
+ if (!success) return false;
+ Search::RootMoves[i].score = (Value)v;
+ if (v > best)
+ best = v;
+ }
+
+ size_t j = 0;
+ for (size_t i = 0; i < Search::RootMoves.size(); i++) {
+ if (Search::RootMoves[i].score == best)
+ Search::RootMoves[j++] = Search::RootMoves[i];
+ }
+ Search::RootMoves.resize(j, Search::RootMove(MOVE_NONE));
+
+ return true;
+}
+
diff --git a/DroidFish/jni/stockfish/tbprobe.h b/DroidFish/jni/stockfish/tbprobe.h
new file mode 100644
index 0000000..9ed6f0a
--- /dev/null
+++ b/DroidFish/jni/stockfish/tbprobe.h
@@ -0,0 +1,16 @@
+#ifndef TBPROBE_H
+#define TBPROBE_H
+
+namespace Tablebases {
+
+extern int TBLargest;
+
+void init(const std::string& path);
+int probe_wdl(Position& pos, int *success);
+int probe_dtz(Position& pos, int *success);
+bool root_probe(Position& pos, Value& TBScore);
+bool root_probe_wdl(Position& pos, Value& TBScore);
+
+}
+
+#endif
diff --git a/DroidFish/jni/stockfish/thread.cpp b/DroidFish/jni/stockfish/thread.cpp
index 344cfb7..3b98ac6 100644
--- a/DroidFish/jni/stockfish/thread.cpp
+++ b/DroidFish/jni/stockfish/thread.cpp
@@ -119,7 +119,7 @@ bool Thread::available_to(const Thread* master) const {
// Make a local copy to be sure it doesn't become zero under our feet while
// testing next condition and so leading to an out of bounds access.
- int size = splitPointsSize;
+ const int size = splitPointsSize;
// No split points means that the thread is available as a slave for any
// other thread otherwise apply the "helpful master" concept if possible.
@@ -255,7 +255,6 @@ Thread* ThreadPool::available_slave(const Thread* master) const {
// leave their idle loops and call search(). When all threads have returned from
// search() then split() returns.
-template
void Thread::split(Position& pos, const Stack* ss, Value alpha, Value beta, Value* bestValue,
Move* bestMove, Depth depth, int moveCount,
MovePicker* movePicker, int nodeType, bool cutNode) {
@@ -297,14 +296,13 @@ void Thread::split(Position& pos, const Stack* ss, Value alpha, Value beta, Valu
activeSplitPoint = &sp;
activePosition = NULL;
- if (!Fake)
- for (Thread* slave; (slave = Threads.available_slave(this)) != NULL; )
- {
- sp.slavesMask.set(slave->idx);
- slave->activeSplitPoint = &sp;
- slave->searching = true; // Slave leaves idle_loop()
- slave->notify_one(); // Could be sleeping
- }
+ for (Thread* slave; (slave = Threads.available_slave(this)) != NULL; )
+ {
+ sp.slavesMask.set(slave->idx);
+ slave->activeSplitPoint = &sp;
+ slave->searching = true; // Slave leaves idle_loop()
+ slave->notify_one(); // Could be sleeping
+ }
// Everything is set up. The master thread enters the idle loop, from which
// it will instantly launch a search, because its 'searching' flag is set.
@@ -339,11 +337,6 @@ void Thread::split(Position& pos, const Stack* ss, Value alpha, Value beta, Valu
Threads.mutex.unlock();
}
-// Explicit template instantiations
-template void Thread::split(Position&, const Stack*, Value, Value, Value*, Move*, Depth, int, MovePicker*, int, bool);
-template void Thread::split< true>(Position&, const Stack*, Value, Value, Value*, Move*, Depth, int, MovePicker*, int, bool);
-
-
// wait_for_think_finished() waits for main thread to go to sleep then returns
void ThreadPool::wait_for_think_finished() {
diff --git a/DroidFish/jni/stockfish/thread.h b/DroidFish/jni/stockfish/thread.h
index 3565431..26aed39 100644
--- a/DroidFish/jni/stockfish/thread.h
+++ b/DroidFish/jni/stockfish/thread.h
@@ -117,7 +117,6 @@ struct Thread : public ThreadBase {
bool cutoff_occurred() const;
bool available_to(const Thread* master) const;
- template
void split(Position& pos, const Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove,
Depth depth, int moveCount, MovePicker* movePicker, int nodeType, bool cutNode);
diff --git a/DroidFish/jni/stockfish/timeman.cpp b/DroidFish/jni/stockfish/timeman.cpp
index c305e61..88a52bb 100644
--- a/DroidFish/jni/stockfish/timeman.cpp
+++ b/DroidFish/jni/stockfish/timeman.cpp
@@ -78,7 +78,7 @@ void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color u
increment > 0 && movesToGo == 0 means: x basetime + z increment
increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment
- Time management is adjusted by following UCI parameters:
+ Time management is adjusted by following parameters:
emergencyMoveHorizon: Be prepared to always play at least this many moves
emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock
@@ -89,11 +89,9 @@ void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color u
int hypMTG, hypMyTime, t1, t2;
// Read uci parameters
- int emergencyMoveHorizon = Options["Emergency Move Horizon"];
- int emergencyBaseTime = Options["Emergency Base Time"];
- int emergencyMoveTime = Options["Emergency Move Time"];
- int minThinkingTime = Options["Minimum Thinking Time"];
- int slowMover = Options["Slow Mover"];
+ int moveOverhead = Options["Move Overhead"];
+ int minThinkingTime = Options["Minimum Thinking Time"];
+ int slowMover = Options["Slow Mover"];
// Initialize unstablePvFactor to 1 and search times to maximum values
unstablePvFactor = 1;
@@ -106,8 +104,7 @@ void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color u
// Calculate thinking time for hypothetical "moves to go"-value
hypMyTime = limits.time[us]
+ limits.inc[us] * (hypMTG - 1)
- - emergencyBaseTime
- - emergencyMoveTime * std::min(hypMTG, emergencyMoveHorizon);
+ - moveOverhead * (2 + std::min(hypMTG, 40));
hypMyTime = std::max(hypMyTime, 0);
diff --git a/DroidFish/jni/stockfish/tt.cpp b/DroidFish/jni/stockfish/tt.cpp
index 3d2fe48..46d891c 100644
--- a/DroidFish/jni/stockfish/tt.cpp
+++ b/DroidFish/jni/stockfish/tt.cpp
@@ -28,20 +28,19 @@ TranspositionTable TT; // Our global transposition table
/// TranspositionTable::resize() sets the size of the transposition table,
/// measured in megabytes. Transposition table consists of a power of 2 number
-/// of clusters and each cluster consists of ClusterSize number of TTEntry.
+/// of clusters and each cluster consists of TTClusterSize number of TTEntry.
-void TranspositionTable::resize(uint64_t mbSize) {
+void TranspositionTable::resize(size_t mbSize) {
- assert(msb((mbSize << 20) / sizeof(TTEntry)) < 32);
+ size_t newClusterCount = size_t(1) << msb((mbSize * 1024 * 1024) / sizeof(TTCluster));
- uint32_t size = ClusterSize << msb((mbSize << 20) / sizeof(TTEntry[ClusterSize]));
-
- if (hashMask == size - ClusterSize)
+ if (newClusterCount == clusterCount)
return;
- hashMask = size - ClusterSize;
+ clusterCount = newClusterCount;
+
free(mem);
- mem = calloc(size * sizeof(TTEntry) + CACHE_LINE_SIZE - 1, 1);
+ mem = calloc(clusterCount * sizeof(TTCluster) + CACHE_LINE_SIZE - 1, 1);
if (!mem)
{
@@ -50,7 +49,7 @@ void TranspositionTable::resize(uint64_t mbSize) {
exit(EXIT_FAILURE);
}
- table = (TTEntry*)((uintptr_t(mem) + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1));
+ table = (TTCluster*)((uintptr_t(mem) + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1));
}
@@ -60,7 +59,7 @@ void TranspositionTable::resize(uint64_t mbSize) {
void TranspositionTable::clear() {
- std::memset(table, 0, (hashMask + ClusterSize) * sizeof(TTEntry));
+ std::memset(table, 0, clusterCount * sizeof(TTCluster));
}
@@ -71,12 +70,12 @@ void TranspositionTable::clear() {
const TTEntry* TranspositionTable::probe(const Key key) const {
TTEntry* tte = first_entry(key);
- uint32_t key32 = key >> 32;
+ uint16_t key16 = key >> 48;
- for (unsigned i = 0; i < ClusterSize; ++i, ++tte)
- if (tte->key32 == key32)
+ for (unsigned i = 0; i < TTClusterSize; ++i, ++tte)
+ if (tte->key16 == key16)
{
- tte->generation8 = generation; // Refresh
+ tte->genBound8 = generation | tte->bound(); // Refresh
return tte;
}
@@ -95,13 +94,13 @@ const TTEntry* TranspositionTable::probe(const Key key) const {
void TranspositionTable::store(const Key key, Value v, Bound b, Depth d, Move m, Value statV) {
TTEntry *tte, *replace;
- uint32_t key32 = key >> 32; // Use the high 32 bits as key inside the cluster
+ uint16_t key16 = key >> 48; // Use the high 16 bits as key inside the cluster
tte = replace = first_entry(key);
- for (unsigned i = 0; i < ClusterSize; ++i, ++tte)
+ for (unsigned i = 0; i < TTClusterSize; ++i, ++tte)
{
- if (!tte->key32 || tte->key32 == key32) // Empty or overwrite old
+ if (!tte->key16 || tte->key16 == key16) // Empty or overwrite old
{
if (!m)
m = tte->move(); // Preserve any existing ttMove
@@ -111,11 +110,11 @@ void TranspositionTable::store(const Key key, Value v, Bound b, Depth d, Move m,
}
// Implement replace strategy
- if ( ( tte->generation8 == generation || tte->bound() == BOUND_EXACT)
- - (replace->generation8 == generation)
- - (tte->depth16 < replace->depth16) < 0)
+ if ( (( tte->genBound8 & 0xFC) == generation || tte->bound() == BOUND_EXACT)
+ - ((replace->genBound8 & 0xFC) == generation)
+ - (tte->depth8 < replace->depth8) < 0)
replace = tte;
}
- replace->save(key32, v, b, d, m, generation, statV);
+ replace->save(key16, v, b, d, m, generation, statV);
}
diff --git a/DroidFish/jni/stockfish/tt.h b/DroidFish/jni/stockfish/tt.h
index eeb18e3..534409f 100644
--- a/DroidFish/jni/stockfish/tt.h
+++ b/DroidFish/jni/stockfish/tt.h
@@ -23,70 +23,80 @@
#include "misc.h"
#include "types.h"
-/// The TTEntry is the 14 bytes transposition table entry, defined as below:
+/// The TTEntry is the 10 bytes transposition table entry, defined as below:
///
-/// key 32 bit
+/// key 16 bit
/// move 16 bit
-/// bound type 8 bit
-/// generation 8 bit
/// value 16 bit
-/// depth 16 bit
/// eval value 16 bit
+/// generation 6 bit
+/// bound type 2 bit
+/// depth 8 bit
struct TTEntry {
Move move() const { return (Move )move16; }
- Bound bound() const { return (Bound)bound8; }
Value value() const { return (Value)value16; }
- Depth depth() const { return (Depth)depth16; }
Value eval_value() const { return (Value)evalValue; }
+ Depth depth() const { return (Depth)depth8; }
+ Bound bound() const { return (Bound)(genBound8 & 0x3); }
private:
friend class TranspositionTable;
- void save(uint32_t k, Value v, Bound b, Depth d, Move m, uint8_t g, Value ev) {
+ void save(uint16_t k, Value v, Bound b, Depth d, Move m, uint8_t g, Value ev) {
- key32 = (uint32_t)k;
- move16 = (uint16_t)m;
- bound8 = (uint8_t)b;
- generation8 = (uint8_t)g;
- value16 = (int16_t)v;
- depth16 = (int16_t)d;
- evalValue = (int16_t)ev;
+ key16 = (uint16_t)k;
+ move16 = (uint16_t)m;
+ value16 = (int16_t)v;
+ evalValue = (int16_t)ev;
+ genBound8 = (uint8_t)(g | b);
+ depth8 = (int8_t)d;
}
- uint32_t key32;
+ uint16_t key16;
uint16_t move16;
- uint8_t bound8, generation8;
- int16_t value16, depth16, evalValue;
+ int16_t value16;
+ int16_t evalValue;
+ uint8_t genBound8;
+ int8_t depth8;
};
+/// TTCluster is a 32 bytes cluster of TT entries consisting of:
+///
+/// 3 x TTEntry (3 x 10 bytes)
+/// padding (2 bytes)
+
+const unsigned TTClusterSize = 3;
+
+struct TTCluster {
+ TTEntry entry[TTClusterSize];
+ char padding[2];
+};
/// A TranspositionTable consists of a power of 2 number of clusters and each
-/// cluster consists of ClusterSize number of TTEntry. Each non-empty entry
+/// cluster consists of TTClusterSize number of TTEntry. Each non-empty entry
/// contains information of exactly one position. The size of a cluster should
/// not be bigger than a cache line size. In case it is less, it should be padded
/// to guarantee always aligned accesses.
class TranspositionTable {
- static const unsigned ClusterSize = 4;
-
public:
~TranspositionTable() { free(mem); }
- void new_search() { ++generation; }
+ void new_search() { generation += 4; } // Lower 2 bits are used by Bound
const TTEntry* probe(const Key key) const;
TTEntry* first_entry(const Key key) const;
- void resize(uint64_t mbSize);
+ void resize(size_t mbSize);
void clear();
void store(const Key key, Value v, Bound type, Depth d, Move m, Value statV);
private:
- uint32_t hashMask;
- TTEntry* table;
+ size_t clusterCount;
+ TTCluster* table;
void* mem;
- uint8_t generation; // Size must be not bigger than TTEntry::generation8
+ uint8_t generation; // Size must be not bigger than TTEntry::genBound8
};
extern TranspositionTable TT;
@@ -94,11 +104,11 @@ extern TranspositionTable TT;
/// TranspositionTable::first_entry() returns a pointer to the first entry of
/// a cluster given a position. The lowest order bits of the key are used to
-/// get the index of the cluster.
+/// get the index of the cluster inside the table.
inline TTEntry* TranspositionTable::first_entry(const Key key) const {
- return table + ((uint32_t)key & hashMask);
+ return &table[(size_t)key & (clusterCount - 1)].entry[0];
}
#endif // #ifndef TT_H_INCLUDED
diff --git a/DroidFish/jni/stockfish/types.h b/DroidFish/jni/stockfish/types.h
index 9910f10..de0723f 100644
--- a/DroidFish/jni/stockfish/types.h
+++ b/DroidFish/jni/stockfish/types.h
@@ -136,7 +136,7 @@ enum CastlingSide {
KING_SIDE, QUEEN_SIDE, CASTLING_SIDE_NB = 2
};
-enum CastlingRight { // Defined as in PolyGlot book hash key
+enum CastlingRight {
NO_CASTLING,
WHITE_OO,
WHITE_OOO = WHITE_OO << 1,
@@ -181,8 +181,8 @@ enum Value {
VALUE_INFINITE = 32001,
VALUE_NONE = 32002,
- VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY,
- VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY,
+ VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
+ VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX,
VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN,
@@ -211,14 +211,14 @@ enum Piece {
enum Depth {
- ONE_PLY = 2,
+ ONE_PLY = 1,
- DEPTH_ZERO = 0 * ONE_PLY,
- DEPTH_QS_CHECKS = 0 * ONE_PLY,
- DEPTH_QS_NO_CHECKS = -1 * ONE_PLY,
- DEPTH_QS_RECAPTURES = -5 * ONE_PLY,
+ DEPTH_ZERO = 0,
+ DEPTH_QS_CHECKS = 0,
+ DEPTH_QS_NO_CHECKS = -1,
+ DEPTH_QS_RECAPTURES = -5,
- DEPTH_NONE = -127 * ONE_PLY
+ DEPTH_NONE = -6
};
enum Square {
@@ -267,28 +267,17 @@ enum Score {
SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN
};
-typedef union {
- uint32_t full;
- struct { int16_t eg, mg; } half;
-} ScoreView;
-
-inline Score make_score(int mg, int eg) {
- ScoreView v;
- v.half.mg = (int16_t)(mg - (uint16_t(eg) >> 15));
- v.half.eg = (int16_t)eg;
- return Score(v.full);
-}
+inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
+/// Extracting the signed lower and upper 16 bits is not so trivial because
+/// according to the standard a simple cast to short is implementation defined
+/// and so is a right shift of a signed integer.
inline Value mg_value(Score s) {
- ScoreView v;
- v.full = s;
- return Value(v.half.mg + (uint16_t(v.half.eg) >> 15));
+ return Value(((s + 0x8000) & ~0xffff) / 0x10000);
}
inline Value eg_value(Score s) {
- ScoreView v;
- v.full = s;
- return Value(v.half.eg);
+ return Value((int)(unsigned(s) & 0x7FFFU) - (int)(unsigned(s) & 0x8000U));
}
#define ENABLE_BASE_OPERATORS_ON(T) \
@@ -337,6 +326,8 @@ inline Score operator/(Score s, int i) {
return make_score(mg_value(s) / i, eg_value(s) / i);
}
+CACHE_LINE_ALIGNMENT
+
extern Value PieceValue[PHASE_NB][PIECE_NB];
struct ExtMove {
@@ -414,14 +405,6 @@ inline bool opposite_colors(Square s1, Square s2) {
return ((s >> 3) ^ s) & 1;
}
-inline char to_char(File f, bool tolower = true) {
- return char(f - FILE_A + (tolower ? 'a' : 'A'));
-}
-
-inline char to_char(Rank r) {
- return char(r - RANK_1 + '1');
-}
-
inline Square pawn_push(Color c) {
return c == WHITE ? DELTA_N : DELTA_S;
}
@@ -455,11 +438,4 @@ inline bool is_ok(Move m) {
return from_sq(m) != to_sq(m); // Catches also MOVE_NULL and MOVE_NONE
}
-#include
-
-inline const std::string to_string(Square s) {
- char ch[] = { to_char(file_of(s)), to_char(rank_of(s)), 0 };
- return ch;
-}
-
#endif // #ifndef TYPES_H_INCLUDED
diff --git a/DroidFish/jni/stockfish/uci.cpp b/DroidFish/jni/stockfish/uci.cpp
index 644fc47..6027295 100644
--- a/DroidFish/jni/stockfish/uci.cpp
+++ b/DroidFish/jni/stockfish/uci.cpp
@@ -174,7 +174,7 @@ void UCI::loop(int argc, char* argv[]) {
else
Search::Limits.ponder = false;
}
- else if (token == "perft" || token == "divide")
+ else if (token == "perft")
{
int depth;
stringstream ss;
@@ -197,12 +197,7 @@ void UCI::loop(int argc, char* argv[]) {
<< "\n" << Options
<< "\nuciok" << sync_endl;
- else if (token == "eval")
- {
- Search::RootColor = pos.side_to_move(); // Ensure it is set
- sync_cout << Eval::trace(pos) << sync_endl;
- }
- else if (token == "ucinewgame") { /* Avoid returning "Unknown command" */ }
+ else if (token == "ucinewgame") TT.clear();
else if (token == "go") go(pos, is);
else if (token == "position") position(pos, is);
else if (token == "setoption") setoption(is);
@@ -210,6 +205,7 @@ void UCI::loop(int argc, char* argv[]) {
else if (token == "bench") benchmark(pos, is);
else if (token == "d") sync_cout << pos.pretty() << sync_endl;
else if (token == "isready") sync_cout << "readyok" << sync_endl;
+ else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl;
else
sync_cout << "Unknown command: " << cmd << sync_endl;
diff --git a/DroidFish/jni/stockfish/ucioption.cpp b/DroidFish/jni/stockfish/ucioption.cpp
index d5db2c9..6ebf8d7 100644
--- a/DroidFish/jni/stockfish/ucioption.cpp
+++ b/DroidFish/jni/stockfish/ucioption.cpp
@@ -27,6 +27,7 @@
#include "thread.h"
#include "tt.h"
#include "ucioption.h"
+#include "tbprobe.h"
using std::string;
@@ -40,6 +41,7 @@ void on_eval(const Option&) { Eval::init(); }
void on_threads(const Option&) { Threads.read_uci_options(); }
void on_hash_size(const Option& o) { TT.resize(o); }
void on_clear_hash(const Option&) { TT.clear(); }
+void on_tb_path(const Option& o) { Tablebases::init(o); }
/// Our case insensitive less() function as required by UCI protocol
@@ -54,35 +56,23 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const
void init(OptionsMap& o) {
- o["Write Debug Log"] << Option(false, on_logger);
- o["Write Search Log"] << Option(false);
- o["Search Log Filename"] << Option("SearchLog.txt");
- o["Book File"] << Option("book.bin");
- o["Best Book Move"] << Option(false);
- o["Contempt Factor"] << Option(0, -50, 50);
- o["Mobility (Midgame)"] << Option(100, 0, 200, on_eval);
- o["Mobility (Endgame)"] << Option(100, 0, 200, on_eval);
- o["Pawn Structure (Midgame)"] << Option(100, 0, 200, on_eval);
- o["Pawn Structure (Endgame)"] << Option(100, 0, 200, on_eval);
- o["Passed Pawns (Midgame)"] << Option(100, 0, 200, on_eval);
- o["Passed Pawns (Endgame)"] << Option(100, 0, 200, on_eval);
- o["Space"] << Option(100, 0, 200, on_eval);
- o["Aggressiveness"] << Option(100, 0, 200, on_eval);
- o["Cowardice"] << Option(100, 0, 200, on_eval);
- o["Min Split Depth"] << Option(0, 0, 12, on_threads);
- o["Threads"] << Option(1, 1, MAX_THREADS, on_threads);
- o["Hash"] << Option(32, 1, 16384, on_hash_size);
- o["Clear Hash"] << Option(on_clear_hash);
- o["Ponder"] << Option(true);
- o["OwnBook"] << Option(false);
- o["MultiPV"] << Option(1, 1, 500);
- o["Skill Level"] << Option(20, 0, 20);
- o["Emergency Move Horizon"] << Option(40, 0, 50);
- o["Emergency Base Time"] << Option(60, 0, 30000);
- o["Emergency Move Time"] << Option(30, 0, 5000);
- o["Minimum Thinking Time"] << Option(20, 0, 5000);
- o["Slow Mover"] << Option(80, 10, 1000);
- o["UCI_Chess960"] << Option(false);
+ o["Write Debug Log"] << Option(false, on_logger);
+ o["Contempt"] << Option(0, -100, 100);
+ o["Min Split Depth"] << Option(0, 0, 12, on_threads);
+ o["Threads"] << Option(1, 1, MAX_THREADS, on_threads);
+ o["Hash"] << Option(16, 1, 1024 * 1024, on_hash_size);
+ o["Clear Hash"] << Option(on_clear_hash);
+ o["Ponder"] << Option(true);
+ 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(80, 10, 1000);
+ o["UCI_Chess960"] << Option(false);
+ o["SyzygyPath"] << Option("", on_tb_path);
+ o["SyzygyProbeDepth"] << Option(1, 1, 100);
+ o["Syzygy50MoveRule"] << Option(true);
+ o["SyzygyProbeLimit"] << Option(6, 0, 6);
}