1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-30 16:53:09 +00:00

Add pawns to encode_position()

This commit is contained in:
Marco Costalba 2016-05-05 11:18:20 +02:00
parent 16019f47c8
commit 8abce63f34

View file

@ -92,7 +92,7 @@ struct WDLEntry {
} piece[2];
struct {
uint8_t pawns[2];
uint8_t pawnCount[2];
struct {
typedef int Pawn;
@ -102,12 +102,6 @@ struct WDLEntry {
};
};
typedef decltype(WDLEntry::piece) WDLPiece;
typedef decltype(WDLEntry::pawn ) WDLPawn;
auto item(WDLPiece& e, int k, int ) -> decltype(e[k])& { return e[k]; }
auto item(WDLPawn& e, int k, int f) -> decltype(e.file[k][f])& { return e.file[k][f]; }
struct DTZEntry {
DTZEntry(const WDLEntry& wdl, Key keys[]);
~DTZEntry();
@ -134,7 +128,7 @@ struct DTZEntry {
} piece;
struct {
uint8_t pawns[2];
uint8_t pawnCount[2];
struct {
typedef int Pawn;
@ -147,11 +141,15 @@ struct DTZEntry {
};
};
typedef decltype(WDLEntry::piece) WDLPiece;
typedef decltype(DTZEntry::piece) DTZPiece;
typedef decltype(WDLEntry::pawn ) WDLPawn;
typedef decltype(DTZEntry::pawn ) DTZPawn;
auto item(DTZPiece& e, int , int = 0) -> decltype(e)& { return e; }
auto item(DTZPawn& e, int f, int = 0) -> decltype(e.file[f])& { return e.file[f]; }
auto item(WDLPiece& e, int stm, int ) -> decltype(e[stm])& { return e[stm]; }
auto item(DTZPiece& e, int , int ) -> decltype(e)& { return e; }
auto item(WDLPawn& e, int stm, int f) -> decltype(e.file[stm][f])& { return e.file[stm][f]; }
auto item(DTZPawn& e, int , int f) -> decltype(e.file[f])& { return e.file[f]; }
const uint8_t MapA1D1D4[] = {
6, 0, 1, 2, 0, 0, 0, 0,
@ -510,8 +508,8 @@ WDLEntry::WDLEntry(const Position& pos, Key keys[])
|| ( pos.count<PAWN>(WHITE)
&& pos.count<PAWN>(BLACK) >= pos.count<PAWN>(WHITE)));
pawn.pawns[0] = pos.count<PAWN>(c ? WHITE : BLACK);
pawn.pawns[1] = pos.count<PAWN>(c ? BLACK : WHITE);
pawn.pawnCount[0] = pos.count<PAWN>(c ? WHITE : BLACK);
pawn.pawnCount[1] = pos.count<PAWN>(c ? BLACK : WHITE);
} else
for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = PAWN; pt < KING; ++pt)
@ -547,8 +545,8 @@ DTZEntry::DTZEntry(const WDLEntry& wdl, Key k[])
has_pawns = wdl.has_pawns;
if (has_pawns) {
pawn.pawns[0] = wdl.pawn.pawns[0];
pawn.pawns[1] = wdl.pawn.pawns[1];
pawn.pawnCount[0] = wdl.pawn.pawnCount[0];
pawn.pawnCount[1] = wdl.pawn.pawnCount[1];
} else
piece.hasUniquePieces = wdl.piece[0].hasUniquePieces;
}
@ -612,12 +610,15 @@ void HashTable::insert(const std::vector<PieceType>& pieces)
int off_A1H8(Square sq) { return int(rank_of(sq)) - file_of(sq); }
template<typename Entry>
uint64_t encode_position(const Position& pos, Entry* entry)
uint64_t encode_position(const Position& pos, Entry* entry, PairsData** precomp2 = 0)
{
Square squares[TBPIECES];
Piece pieces[TBPIECES];
uint64_t idx;
int next, stm, flipColor = 0, flipSquares = 0, size = 0;
int stm, next = 0, flipColor = 0, flipSquares = 0, size = 0, leadPawnsCnt = 0;
bool hasUniquePieces;
PairsData* precomp;
Bitboard b, leadPawns = 0;
// A given TB entry like KRK has associated two material keys: KRvk and Kvkr.
// If both sides have the same pieces we have a symmetric material and the
@ -642,9 +643,37 @@ uint64_t encode_position(const Position& pos, Entry* entry)
stm = (pos.material_key() != entry->key) ^ pos.side_to_move();
}
// Now we are ready to get all the position pieces and directly map them
// to the correct color and square:
Bitboard b = pos.pieces();
// For pawns, TB files store separate tables according if leading pawn is on
// file a, b, c or d after reordering. To determine which of the 4 tables
// must be probed we need to extract the position's pawns then reorder them
// and finally get the correct tbFile. The new pawn order should be preserved
// because needed for next steps.
if (entry->has_pawns) {
Piece pc = Piece(item(entry->pawn, 0, 0).precomp->pieces[0] ^ flipColor);
assert(type_of(pc) == PAWN);
leadPawns = b = pos.pieces(color_of(pc), PAWN);
while (b)
squares[size++] = pop_lsb(&b) ^ flipSquares;
leadPawnsCnt = size;
for (int i = 1; i < size; ++i)
if (Flap[squares[0]] > Flap[squares[i]])
std::swap(squares[0], squares[i]);
File f = std::min(file_of(squares[0]), FILE_H - file_of(squares[0]));
precomp = item(entry->pawn, stm, f).precomp;
} else
precomp = item(entry->piece, stm, 0).precomp;
if (precomp2)
*precomp2 = precomp;
// Now we are ready to get all the position pieces (but the lead pawns) and
// directly map them to the correct color and square.
b = pos.pieces() ^ leadPawns;
for ( ; b; ++size) {
Square sq = pop_lsb(&b);
squares[size] = sq ^ flipSquares;
@ -652,12 +681,11 @@ uint64_t encode_position(const Position& pos, Entry* entry)
}
// Then we reorder the pieces to have the same sequence as the one stored
// in entry->piece[stm].precomp->pieces[i], this is important for the next
// step. The sequence stored is the one that ensures the best compression.
const uint8_t* tbPieces = item(entry->piece, stm, 0).precomp->pieces;
for (int i = 0; i < size; ++i)
// in precomp->pieces[i], this is important for the next step. The sequence
// stored is the one that ensures the best compression.
for (int i = leadPawnsCnt; i < size; ++i)
for (int j = i; j < size; ++j)
if (tbPieces[i] == pieces[j])
if (precomp->pieces[i] == pieces[j])
{
std::swap(pieces[i], pieces[j]);
std::swap(squares[i], squares[j]);
@ -671,13 +699,28 @@ uint64_t encode_position(const Position& pos, Entry* entry)
for (int i = 0; i < size; ++i)
squares[i] ^= 7; // Horizontal flip: SQ_H1 -> SQ_A1
// Positions with pawns have a special ordering
if (entry->has_pawns) {
for (int i = 1; i < leadPawnsCnt; ++i)
for (int j = i + 1; j < leadPawnsCnt; ++j)
if (Ptwist[squares[i]] < Ptwist[squares[j]])
std::swap(squares[i], squares[j]);
idx = Pawnidx[leadPawnsCnt - 1][Flap[squares[0]]];
for (int i = leadPawnsCnt - 1; i > 0; --i)
idx += Binomial[leadPawnsCnt - i][Ptwist[squares[i]]];
goto tail;
}
if (rank_of(squares[0]) > RANK_4)
for (int i = 0; i < size; ++i)
squares[i] ^= 070; // Vertical flip: SQ_A8 -> SQ_A1
// Look for the first piece not on the A1-D4 diagonal and ensure it is
// mapped below the diagonal.
bool hasUniquePieces = item(entry->piece, stm, 0).hasUniquePieces;
hasUniquePieces = item(entry->piece, stm, 0).hasUniquePieces;
for (int i = 0; i < size; ++i) {
if (!off_A1H8(squares[i]))
@ -756,9 +799,34 @@ uint64_t encode_position(const Position& pos, Entry* entry)
next = 2;
}
PairsData* precomp = item(entry->piece, stm, 0).precomp;
tail:
idx *= precomp->factor[0];
// Order remainig pawns
if (entry->has_pawns) {
next = leadPawnsCnt;
int pawnsCnt = pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK);
if (pawnsCnt > next) {
std::sort(&squares[next], &squares[pawnsCnt]);
uint64_t s = 0;
for (int m = next; m < pawnsCnt; ++m) {
int j = 0;
for (int k = 0; k < next; ++k)
j += squares[m] > squares[k];
s += Binomial[m - next + 1][squares[m] - j - 8];
}
idx += s * precomp->factor[next];
next = pawnsCnt;
}
}
// Order remainig pieces
while (next < size) {
int t = precomp->norm[next];
@ -796,72 +864,6 @@ File pawn_file(uint8_t pawns[], Square *pos)
return file_to_file[pos[0] & 7];
}
uint64_t encode_pawn(uint8_t pawns[], PairsData* precomp, Square *pos, int n)
{
int i;
if (pos[0] & 4)
for (i = 0; i < n; ++i)
pos[i] ^= 7;
for (i = 1; i < pawns[0]; ++i)
for (int j = i + 1; j < pawns[0]; ++j)
if (Ptwist[pos[i]] < Ptwist[pos[j]])
std::swap(pos[i], pos[j]);
int t = pawns[0] - 1;
uint64_t idx = Pawnidx[t][Flap[pos[0]]];
for (i = t; i > 0; --i)
idx += Binomial[t - i + 1][Ptwist[pos[i]]];
idx *= precomp->factor[0];
// remaining pawns
i = pawns[0];
t = i + pawns[1];
if (t > i) {
std::sort(&pos[i], &pos[t]);
uint64_t s = 0;
for (int m = i; m < t; ++m) {
int j = 0;
for (int k = 0; k < i; ++k)
j += pos[m] > pos[k];
s += Binomial[m - i + 1][pos[m] - j - 8];
}
idx += s * precomp->factor[i];
i = t;
}
while (i < n) {
t = precomp->norm[i];
std::sort(&pos[i], &pos[i + t]);
uint64_t s = 0;
for (int l = i; l < i + t; ++l) {
int j = 0;
for (int k = 0; k < i; ++k)
j += pos[l] > pos[k];
s += Binomial[l - i + 1][pos[l] - j];
}
idx += s * precomp->factor[i];
i += t;
}
return idx;
}
template<typename T>
int get_pfactor(const T& p, File, typename T::Piece = 0)
{ return p.hasUniquePieces ? 31332 : 462; }
@ -993,9 +995,9 @@ void WDLEntry::do_init(T& e, uint8_t* data)
assert(!!has_pawns == !!(flags & HasPawns));
assert(!!symmetric != !!(flags & Split));
bool pp = (flags & HasPawns) && pawn.pawns[1]; // Pawns on both sides
bool pp = (flags & HasPawns) && pawn.pawnCount[1]; // Pawns on both sides
assert(!pp || pawn.pawns[0]);
assert(!pp || pawn.pawnCount[0]);
for (File f = FILE_A; f <= maxFile; ++f) {
@ -1014,7 +1016,7 @@ void WDLEntry::do_init(T& e, uint8_t* data)
uint8_t pn[] = { uint8_t(piece[0].hasUniquePieces ? 3 : 2), 0 };
for (int i = 0; i < 2; ++i) {
set_norms(item(e, i, f).precomp, num, (flags & HasPawns) ? pawn.pawns : pn);
set_norms(item(e, i, f).precomp, num, (flags & HasPawns) ? pawn.pawnCount : pn);
tb_size[2 * f + i] = set_factors(item(e, i, f), num, order[i], f);
}
}
@ -1070,25 +1072,25 @@ void DTZEntry::do_init(T& e, uint8_t* data)
assert(!!has_pawns == !!(flags & HasPawns));
assert(!!symmetric != !!(flags & Split));
bool pp = (flags & HasPawns) && pawn.pawns[1]; // Pawns on both sides
bool pp = (flags & HasPawns) && pawn.pawnCount[1]; // Pawns on both sides
assert(!pp || pawn.pawns[0]);
assert(!pp || pawn.pawnCount[0]);
for (File f = FILE_A; f <= maxFile; ++f) {
item(e, f).precomp = new PairsData();
item(e, 0, f).precomp = new PairsData();
int order[][2] = { { *data & 0xF, pp ? *(data + 1) & 0xF : 0xF },
{ *data >> 4, pp ? *(data + 1) >> 4 : 0xF } };
data += 1 + pp;
for (int i = 0; i < num; ++i, ++data)
item(e, f).precomp->pieces[i] = *data & 0xF;
item(e, 0, f).precomp->pieces[i] = *data & 0xF;
uint8_t pn[] = { uint8_t(piece.hasUniquePieces ? 3 : 2), 0 };
set_norms(item(e, f).precomp, num, (flags & HasPawns) ? pawn.pawns : pn);
tb_size[f] = set_factors(item(e, f), num, order[0], f);
set_norms(item(e, 0, f).precomp, num, (flags & HasPawns) ? pawn.pawnCount : pn);
tb_size[f] = set_factors(item(e, 0, f), num, order[0], f);
}
data += (uintptr_t)data & 1; // Word alignment
@ -1096,16 +1098,16 @@ void DTZEntry::do_init(T& e, uint8_t* data)
for (File f = FILE_A; f <= maxFile; ++f) {
assert(!(*data & 0x80));
item(e, f).flags = *data;
data = set_sizes(item(e, f).precomp, data, tb_size[f]);
item(e, 0, f).flags = *data;
data = set_sizes(item(e, 0, f).precomp, data, tb_size[f]);
}
e.map = data;
for (File f = FILE_A; f <= maxFile; ++f) {
if (item(e, f).flags & 2)
if (item(e, 0, f).flags & 2)
for (int i = 0; i < 4; ++i) { // Sequence like 3,x,x,x,1,x,0,2,x,x
item(e, f).map_idx[i] = (uint16_t)(data - e.map + 1);
item(e, 0, f).map_idx[i] = (uint16_t)(data - e.map + 1);
data += *data + 1;
}
}
@ -1113,18 +1115,18 @@ void DTZEntry::do_init(T& e, uint8_t* data)
data += (uintptr_t)data & 1;
for (File f = FILE_A; f <= maxFile; ++f) {
(d = item(e, f).precomp)->indextable = data;
(d = item(e, 0, f).precomp)->indextable = data;
data += 6ULL * d->num_indices;
}
for (File f = FILE_A; f <= maxFile; ++f) {
(d = item(e, f).precomp)->sizetable = (uint16_t*)data;
(d = item(e, 0, f).precomp)->sizetable = (uint16_t*)data;
data += 2ULL * d->num_blocks;
}
for (File f = FILE_A; f <= maxFile; ++f) {
data = (uint8_t*)(((uintptr_t)data + 0x3F) & ~0x3F); // 64 byte alignment
(d = item(e, f).precomp)->data = data;
(d = item(e, 0, f).precomp)->data = data;
data += (1ULL << d->blocksize) * d->real_num_blocks;
}
}
@ -1235,53 +1237,16 @@ WDLScore probe_wdl_table(Position& pos, int* success)
}
}
Square squares[TBPIECES];
int bside, smirror, cmirror;
assert(key == entry->key || !entry->symmetric);
// Entries are stored from point of view of white, so in case of a symmetric
// material distribution, we just need to lookup the relative TB entry in
// case we are black. Instead in case of asymmetric distribution, because
// stored entry is the same for both keys, we have first to verify if the
// entry is stored according to our key, otherwise we have to lookup
// the relative entry.
if (entry->symmetric) {
cmirror = pos.side_to_move() * 8;
smirror = pos.side_to_move() * 070;
bside = WHITE;
} else {
cmirror = (key != entry->key) * 8; // Switch color
smirror = (key != entry->key) * 070; // Vertical flip SQ_A1 -> SQ_A8
bside = (key != entry->key) ^ pos.side_to_move();
}
PairsData* precomp;
// squares[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 (!entry->has_pawns) {
uint64_t idx = encode_position(pos, entry);
return WDLScore(decompress_pairs(entry->piece[bside].precomp, idx) - 2);
uint64_t idx = encode_position(pos, entry, &precomp);
return WDLScore(decompress_pairs(precomp, idx) - 2);
} else {
Piece pc = Piece(entry->pawn.file[0][0].precomp->pieces[0] ^ cmirror);
Bitboard b = pos.pieces(color_of(pc), type_of(pc));
int i = 0;
do
squares[i++] = pop_lsb(&b) ^ smirror;
while (b);
File f = pawn_file(entry->pawn.pawns, squares);
for ( ; i < entry->num; ) {
pc = Piece(entry->pawn.file[bside][f].precomp->pieces[i] ^ cmirror);
b = pos.pieces(color_of(pc), type_of(pc));
do
squares[i++] = pop_lsb(&b) ^ smirror;
while (b);
}
uint64_t idx = encode_pawn(entry->pawn.pawns, entry->pawn.file[bside][f].precomp, squares, entry->num);
return WDLScore(decompress_pairs(entry->pawn.file[bside][f].precomp, idx) - 2);
uint64_t idx = encode_position(pos, entry, &precomp);
return WDLScore(decompress_pairs(precomp, idx) - 2);
}
}
@ -1387,25 +1352,14 @@ int probe_dtz_table(const Position& pos, int wdl, int *success)
squares[i++] = pop_lsb(&bb) ^ mirror;
} while (bb);
File f = pawn_file(ptr->pawn.pawns, squares);
File f = pawn_file(ptr->pawn.pawnCount, squares);
if ((ptr->pawn.file[f].flags & 1) != bside) {
*success = -1;
return 0;
}
uint8_t *pc = ptr->pawn.file[f].precomp->pieces;
for (; i < ptr->num;) {
bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
(PieceType)(pc[i] & 7));
do {
squares[i++] = pop_lsb(&bb) ^ mirror;
} while (bb);
}
idx = encode_pawn(ptr->pawn.pawns, ptr->pawn.file[f].precomp, squares, ptr->num);
idx = encode_position(pos, ptr);
res = decompress_pairs(ptr->pawn.file[f].precomp, idx);
if (ptr->pawn.file[f].flags & 2)