Skip to content

Commit

Permalink
Rewrite syzygy in C++
Browse files Browse the repository at this point in the history
Rewrite the code in SF style, simplify and
document it.

Code is now much clear and bug free (no mem-leaks and
other small issues) and is also smaller (more than
600 lines of code removed).

All the code has been rewritten but root_probe() and
root_probe_wdl() that are completely misplaced and should
be retired altogheter. For now just leave them in the
original version.

Code is fully and deeply tested for equivalency both in
functionality and in speed with hundreds of games and
test positions and is guaranteed to be 100% equivalent
to the original.

Tested with tb_dbg branch for functional equivalency on
more than 12M positions.

stockfish.exe bench 128 1 16 syzygy.epd

Position: 2016/2016
Total 12121156 Hits 0 hit rate (%) 0
Total time (ms) : 4417851
Nodes searched : 1100151204
Nodes/second : 249024

Tested with 5,000 games match against master, 1 Thread,
128 MB Hash each, tc 40+0.4, which is almost equivalent
to LTC in Fishtest on this machine. 3-, 4- and 5-men syzygy
bases on SSD, 12-moves opening book to emphasize mid- and endgame.

Score of SF-SyzygyC++ vs SF-Master: 633 - 617 - 3750  [0.502] 5000
ELO difference: 1

No functional change.
  • Loading branch information
mcostalba committed Nov 5, 2016
1 parent 369eff4 commit c0bb041
Show file tree
Hide file tree
Showing 9 changed files with 1,652 additions and 2,261 deletions.
25 changes: 3 additions & 22 deletions src/endgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,26 +83,6 @@ namespace {
return sq;
}

// Get the material key of Position out of the given endgame key code
// like "KBPKN". The trick here is to first forge an ad-hoc FEN string
// and then let a Position object do the work for us.
Key key(const string& code, Color c) {

assert(code.length() > 0 && code.length() < 8);
assert(code[0] == 'K');

string sides[] = { code.substr(code.find('K', 1)), // Weak
code.substr(0, code.find('K', 1)) }; // Strong

std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);

string fen = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";

StateInfo st;
return Position().set(fen, false, &st, nullptr).material_key();
}

} // namespace


Expand Down Expand Up @@ -132,8 +112,9 @@ Endgames::Endgames() {

template<EndgameType E, typename T>
void Endgames::add(const string& code) {
map<T>()[key(code, WHITE)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
map<T>()[key(code, BLACK)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
StateInfo st;
map<T>()[Position().set(code, WHITE, &st).material_key()] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
map<T>()[Position().set(code, BLACK, &st).material_key()] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
}


Expand Down
38 changes: 36 additions & 2 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "thread.h"
#include "tt.h"
#include "uci.h"
#include "syzygy/tbprobe.h"

using std::string;

Expand Down Expand Up @@ -85,7 +86,7 @@ PieceType min_attacker<KING>(const Bitboard*, Square, Bitboard, Bitboard&, Bitbo

/// operator<<(Position) returns an ASCII representation of the position

std::ostream& operator<<(std::ostream& os, const Position& pos) {
std::ostream& operator<<(std::ostream& os, Position& pos) {

os << "\n +---+---+---+---+---+---+---+---+\n";

Expand All @@ -98,11 +99,22 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) {
}

os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
<< std::setfill('0') << std::setw(16) << pos.key() << std::dec << "\nCheckers: ";
<< std::setfill('0') << std::setw(16) << pos.key()
<< std::setfill(' ') << std::dec << "\nCheckers: ";

for (Bitboard b = pos.checkers(); b; )
os << UCI::square(pop_lsb(&b)) << " ";

if ( int(Tablebases::MaxCardinality) >= popcount(pos.pieces())
&& !pos.can_castle(ANY_CASTLING))
{
Tablebases::ProbeState s1, s2;
Tablebases::WDLScore wdl = Tablebases::probe_wdl(pos, &s1);
int dtz = Tablebases::probe_dtz(pos, &s2);
os << "\nTablebases WDL: " << std::setw(4) << wdl << " (" << s1 << ")"
<< "\nTablebases DTZ: " << std::setw(4) << dtz << " (" << s2 << ")";
}

return os;
}

Expand Down Expand Up @@ -357,6 +369,28 @@ void Position::set_state(StateInfo* si) const {
}


/// Position::set() is an overload to initialize the position object with
/// the given endgame code string like "KBPKN". It is manily an helper to
/// get the material key out of an endgame code. Position is not playable,
/// indeed is even not guaranteed to be legal.

Position& Position::set(const string& code, Color c, StateInfo* si) {

assert(code.length() > 0 && code.length() < 8);
assert(code[0] == 'K');

string sides[] = { code.substr(code.find('K', 1)), // Weak
code.substr(0, code.find('K', 1)) }; // Strong

std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);

string fenStr = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";

return set(fenStr, false, si, nullptr);
}


/// Position::fen() returns a FEN representation of the position. In case of
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.

Expand Down
3 changes: 2 additions & 1 deletion src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class Position {

// FEN string input/output
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
Position& set(const std::string& code, Color c, StateInfo* si);
const std::string fen() const;

// Position representation
Expand Down Expand Up @@ -188,7 +189,7 @@ class Position {
bool chess960;
};

extern std::ostream& operator<<(std::ostream& os, const Position& pos);
extern std::ostream& operator<<(std::ostream& os, Position& pos);

inline Color Position::side_to_move() const {
return sideToMove;
Expand Down
5 changes: 3 additions & 2 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,9 +664,10 @@ namespace {
&& pos.rule50_count() == 0
&& !pos.can_castle(ANY_CASTLING))
{
int found, v = Tablebases::probe_wdl(pos, &found);
TB::ProbeState err;
TB::WDLScore v = Tablebases::probe_wdl(pos, &err);

if (found)
if (err != TB::ProbeState::FAIL)
{
thisThread->tbHits++;

Expand Down

0 comments on commit c0bb041

Please sign in to comment.