mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 08:43:09 +00:00
Use SF Position to calculate material key
Don't reinvent the wheel. Also clarify that init_tb it is used to populate TBHash: rename it in proper way.
This commit is contained in:
parent
024fec7a2b
commit
63b39c5bff
4 changed files with 78 additions and 95 deletions
|
@ -83,26 +83,6 @@ namespace {
|
||||||
return sq;
|
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
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,8 +112,9 @@ Endgames::Endgames() {
|
||||||
|
|
||||||
template<EndgameType E, typename T>
|
template<EndgameType E, typename T>
|
||||||
void Endgames::add(const string& code) {
|
void Endgames::add(const string& code) {
|
||||||
map<T>()[key(code, WHITE)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
|
StateInfo st;
|
||||||
map<T>()[key(code, BLACK)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -357,6 +357,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
|
/// 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.
|
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,7 @@ public:
|
||||||
|
|
||||||
// FEN string input/output
|
// FEN string input/output
|
||||||
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
|
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;
|
const std::string fen() const;
|
||||||
|
|
||||||
// Position representation
|
// Position representation
|
||||||
|
|
|
@ -388,6 +388,20 @@ class HashTable {
|
||||||
|
|
||||||
Entry table[1 << TBHASHBITS][HSHMAX];
|
Entry table[1 << TBHASHBITS][HSHMAX];
|
||||||
|
|
||||||
|
void insert(Key key, TBEntry* ptr) {
|
||||||
|
Entry* entry = table[key >> (64 - TBHASHBITS)];
|
||||||
|
|
||||||
|
for (int i = 0; i < HSHMAX; ++i, ++entry)
|
||||||
|
if (!entry->ptr || entry->key == key) {
|
||||||
|
entry->key = key;
|
||||||
|
entry->ptr = ptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "HSHMAX too low!" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TBEntry* operator[](Key key) {
|
TBEntry* operator[](Key key) {
|
||||||
Entry* entry = table[key >> (64 - TBHASHBITS)];
|
Entry* entry = table[key >> (64 - TBHASHBITS)];
|
||||||
|
@ -399,21 +413,8 @@ public:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(TBEntry* ptr, Key key) {
|
|
||||||
Entry* entry = table[key >> (64 - TBHASHBITS)];
|
|
||||||
|
|
||||||
for (int i = 0; i < HSHMAX; ++i, ++entry)
|
|
||||||
if (!entry->ptr) {
|
|
||||||
entry->key = key;
|
|
||||||
entry->ptr = ptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "HSHMAX too low!" << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() { std::memset(table, 0, sizeof(table)); }
|
void clear() { std::memset(table, 0, sizeof(table)); }
|
||||||
|
void insert(const std::vector<PieceType>& pieces);
|
||||||
};
|
};
|
||||||
|
|
||||||
HashTable TBHash;
|
HashTable TBHash;
|
||||||
|
@ -519,22 +520,6 @@ Key get_key(Position& pos, bool mirror)
|
||||||
return key;
|
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.
|
|
||||||
Key get_key(uint8_t* pcs, bool mirror)
|
|
||||||
{
|
|
||||||
Key key = 0;
|
|
||||||
|
|
||||||
for (Color c = WHITE; c <= BLACK; ++c)
|
|
||||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
|
||||||
for (int cnt = 0; cnt < pcs[8 * (c ^ mirror) + pt]; ++cnt)
|
|
||||||
key ^= Zobrist::psq[c][pt][cnt];
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a position with 6 or fewer pieces, produce a text string
|
// Given a position with 6 or fewer pieces, produce a text string
|
||||||
// of the form KQPvKRP, where "KQP" represents the white pieces if
|
// of the form KQPvKRP, where "KQP" represents the white pieces if
|
||||||
// mirror == false and the black pieces if mirror == true.
|
// mirror == false and the black pieces if mirror == true.
|
||||||
|
@ -582,39 +567,32 @@ void free_dtz_entry(TBEntry* entry)
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_tb(const std::vector<PieceType>& pieces)
|
void HashTable::insert(const std::vector<PieceType>& pieces)
|
||||||
{
|
{
|
||||||
TBEntry* entry;
|
TBEntry* entry;
|
||||||
std::string fname;
|
StateInfo st;
|
||||||
Color c = BLACK;
|
Position pos;
|
||||||
uint8_t pcs[PIECE_NB] = {0};
|
std::string code;
|
||||||
int num = 0;
|
|
||||||
|
|
||||||
for (PieceType pt : pieces) {
|
for (PieceType pt : pieces)
|
||||||
if (pt == KING) {
|
code += PieceChar[pt];
|
||||||
c = ~c;
|
|
||||||
|
|
||||||
if (!fname.empty())
|
int bk = code.find('K', 1); // Black king
|
||||||
fname += 'v';
|
TBFile f(code.substr(0, bk) + 'v' + code.substr(bk) + ".rtbw");
|
||||||
}
|
|
||||||
|
|
||||||
++pcs[make_piece(c, pt)];
|
|
||||||
++num;
|
|
||||||
fname += PieceChar[pt];
|
|
||||||
}
|
|
||||||
|
|
||||||
TBFile f(fname + ".rtbw");
|
|
||||||
|
|
||||||
if (!f.is_open())
|
if (!f.is_open())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
|
pos.set(code, WHITE, &st);
|
||||||
|
|
||||||
|
int num = pos.count<ALL_PIECES>(WHITE) + pos.count<ALL_PIECES>(BLACK);
|
||||||
|
bool hasPawns = pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK);
|
||||||
|
|
||||||
if (num > Tablebases::MaxCardinality)
|
if (num > Tablebases::MaxCardinality)
|
||||||
Tablebases::MaxCardinality = num;
|
Tablebases::MaxCardinality = num;
|
||||||
|
|
||||||
bool hasPawns = pcs[W_PAWN] + pcs[B_PAWN];
|
|
||||||
|
|
||||||
if (hasPawns) {
|
if (hasPawns) {
|
||||||
if (TBnum_pawn == TBMAX_PAWN) {
|
if (TBnum_pawn == TBMAX_PAWN) {
|
||||||
std::cerr << "TBMAX_PAWN limit too low!" << std::endl;
|
std::cerr << "TBMAX_PAWN limit too low!" << std::endl;
|
||||||
|
@ -622,14 +600,16 @@ void init_tb(const std::vector<PieceType>& pieces)
|
||||||
}
|
}
|
||||||
|
|
||||||
TBEntry_pawn* ptr = &TB_pawn[TBnum_pawn++];
|
TBEntry_pawn* ptr = &TB_pawn[TBnum_pawn++];
|
||||||
ptr->pawns[0] = pcs[W_PAWN];
|
|
||||||
ptr->pawns[1] = pcs[B_PAWN];
|
|
||||||
|
|
||||||
// FIXME: What it means this one?
|
// FIXME: What it means this one?
|
||||||
if ( pcs[B_PAWN] > 0
|
if ( !pos.count<PAWN>(BLACK)
|
||||||
&& (pcs[W_PAWN] == 0 || pcs[B_PAWN] < pcs[W_PAWN])) {
|
|| ( pos.count<PAWN>(WHITE)
|
||||||
ptr->pawns[0] = pcs[B_PAWN];
|
&& pos.count<PAWN>(BLACK) >= pos.count<PAWN>(WHITE))) {
|
||||||
ptr->pawns[1] = pcs[W_PAWN];
|
ptr->pawns[0] = pos.count<PAWN>(WHITE);
|
||||||
|
ptr->pawns[1] = pos.count<PAWN>(BLACK);
|
||||||
|
} else {
|
||||||
|
ptr->pawns[0] = pos.count<PAWN>(BLACK);
|
||||||
|
ptr->pawns[1] = pos.count<PAWN>(WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = (TBEntry*)ptr;
|
entry = (TBEntry*)ptr;
|
||||||
|
@ -642,23 +622,24 @@ void init_tb(const std::vector<PieceType>& pieces)
|
||||||
TBEntry_piece* ptr = &TB_piece[TBnum_piece++];
|
TBEntry_piece* ptr = &TB_piece[TBnum_piece++];
|
||||||
int uniquePieces = 0;
|
int uniquePieces = 0;
|
||||||
|
|
||||||
for (auto n : pcs)
|
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||||
if (n == 1)
|
uniquePieces += (popcount(pos.pieces(WHITE, pt)) == 1)
|
||||||
++uniquePieces;
|
+ (popcount(pos.pieces(BLACK, pt)) == 1);
|
||||||
|
|
||||||
if (uniquePieces >= 3)
|
if (uniquePieces >= 3)
|
||||||
ptr->enc_type = 0;
|
ptr->enc_type = 0;
|
||||||
else {
|
else {
|
||||||
// W_KING and B_KING are the only unique pieces
|
// W_KING and B_KING are the only unique pieces
|
||||||
assert(uniquePieces == 2);
|
assert(uniquePieces == 2);
|
||||||
|
|
||||||
ptr->enc_type = 2;
|
ptr->enc_type = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = (TBEntry*)ptr;
|
entry = (TBEntry*)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Key key1 = get_key(pcs, 0);
|
Key key1 = pos.material_key();
|
||||||
Key key2 = get_key(pcs, 1);
|
Key key2 = pos.set(code, BLACK, &st).material_key();
|
||||||
|
|
||||||
entry->key = key1;
|
entry->key = key1;
|
||||||
entry->ready = 0;
|
entry->ready = 0;
|
||||||
|
@ -666,10 +647,8 @@ void init_tb(const std::vector<PieceType>& pieces)
|
||||||
entry->symmetric = (key1 == key2);
|
entry->symmetric = (key1 == key2);
|
||||||
entry->has_pawns = hasPawns;
|
entry->has_pawns = hasPawns;
|
||||||
|
|
||||||
TBHash.insert(entry, key1);
|
insert(key1, entry);
|
||||||
|
insert(key2, entry);
|
||||||
if (key2 != key1) // Asymmetric distribution
|
|
||||||
TBHash.insert(entry, key2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t encode_piece(TBEntry_piece* ptr, uint8_t* norm, int* pos, int* factor)
|
uint64_t encode_piece(TBEntry_piece* ptr, uint8_t* norm, int* pos, int* factor)
|
||||||
|
@ -1822,28 +1801,28 @@ void Tablebases::init(const std::string& paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PieceType p1 = PAWN; p1 < KING; ++p1) {
|
for (PieceType p1 = PAWN; p1 < KING; ++p1) {
|
||||||
init_tb({KING, p1, KING});
|
TBHash.insert({KING, p1, KING});
|
||||||
|
|
||||||
for (PieceType p2 = PAWN; p2 <= p1; ++p2) {
|
for (PieceType p2 = PAWN; p2 <= p1; ++p2) {
|
||||||
init_tb({KING, p1, p2, KING});
|
TBHash.insert({KING, p1, p2, KING});
|
||||||
init_tb({KING, p1, KING, p2});
|
TBHash.insert({KING, p1, KING, p2});
|
||||||
|
|
||||||
for (PieceType p3 = PAWN; p3 < KING; ++p3)
|
for (PieceType p3 = PAWN; p3 < KING; ++p3)
|
||||||
init_tb({KING, p1, p2, KING, p3});
|
TBHash.insert({KING, p1, p2, KING, p3});
|
||||||
|
|
||||||
for (PieceType p3 = PAWN; p3 <= p2; ++p3) {
|
for (PieceType p3 = PAWN; p3 <= p2; ++p3) {
|
||||||
init_tb({KING, p1, p2, p3, KING});
|
TBHash.insert({KING, p1, p2, p3, KING});
|
||||||
|
|
||||||
for (PieceType p4 = PAWN; p4 <= p3; ++p4)
|
for (PieceType p4 = PAWN; p4 <= p3; ++p4)
|
||||||
init_tb({KING, p1, p2, p3, p4, KING});
|
TBHash.insert({KING, p1, p2, p3, p4, KING});
|
||||||
|
|
||||||
for (PieceType p4 = PAWN; p4 < KING; ++p4)
|
for (PieceType p4 = PAWN; p4 < KING; ++p4)
|
||||||
init_tb({KING, p1, p2, p3, KING, p4});
|
TBHash.insert({KING, p1, p2, p3, KING, p4});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PieceType p3 = PAWN; p3 <= p1; ++p3)
|
for (PieceType p3 = PAWN; p3 <= p1; ++p3)
|
||||||
for (PieceType p4 = PAWN; p4 <= (p1 == p3 ? p2 : p3); ++p4)
|
for (PieceType p4 = PAWN; p4 <= (p1 == p3 ? p2 : p3); ++p4)
|
||||||
init_tb({KING, p1, p2, KING, p3, p4});
|
TBHash.insert({KING, p1, p2, KING, p3, p4});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue