|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <cassert> |
|
#include <vector> |
|
#include <bitset> |
|
|
|
#include "bitboard.h" |
|
#include "types.h" |
|
|
|
namespace Stockfish { |
|
|
|
namespace { |
|
|
|
|
|
|
|
constexpr unsigned MAX_INDEX = 2*24*64*64; |
|
|
|
std::bitset<MAX_INDEX> KPKBitbase; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned index(Color stm, Square bksq, Square wksq, Square psq) { |
|
return int(wksq) | (bksq << 6) | (stm << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15); |
|
} |
|
|
|
enum Result { |
|
INVALID = 0, |
|
UNKNOWN = 1, |
|
DRAW = 2, |
|
WIN = 4 |
|
}; |
|
|
|
Result& operator|=(Result& r, Result v) { return r = Result(r | v); } |
|
|
|
struct KPKPosition { |
|
KPKPosition() = default; |
|
explicit KPKPosition(unsigned idx); |
|
operator Result() const { return result; } |
|
Result classify(const std::vector<KPKPosition>& db); |
|
|
|
Color stm; |
|
Square ksq[COLOR_NB], psq; |
|
Result result; |
|
}; |
|
|
|
} |
|
|
|
bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) { |
|
|
|
assert(file_of(wpsq) <= FILE_D); |
|
|
|
return KPKBitbase[index(stm, bksq, wksq, wpsq)]; |
|
} |
|
|
|
|
|
void Bitbases::init() { |
|
|
|
std::vector<KPKPosition> db(MAX_INDEX); |
|
unsigned idx, repeat = 1; |
|
|
|
|
|
for (idx = 0; idx < MAX_INDEX; ++idx) |
|
db[idx] = KPKPosition(idx); |
|
|
|
|
|
|
|
while (repeat) |
|
for (repeat = idx = 0; idx < MAX_INDEX; ++idx) |
|
repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN); |
|
|
|
|
|
for (idx = 0; idx < MAX_INDEX; ++idx) |
|
if (db[idx] == WIN) |
|
KPKBitbase.set(idx); |
|
} |
|
|
|
namespace { |
|
|
|
KPKPosition::KPKPosition(unsigned idx) { |
|
|
|
ksq[WHITE] = Square((idx >> 0) & 0x3F); |
|
ksq[BLACK] = Square((idx >> 6) & 0x3F); |
|
stm = Color ((idx >> 12) & 0x01); |
|
psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7))); |
|
|
|
|
|
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1 |
|
|| ksq[WHITE] == psq |
|
|| ksq[BLACK] == psq |
|
|| (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK]))) |
|
result = INVALID; |
|
|
|
|
|
else if ( stm == WHITE |
|
&& rank_of(psq) == RANK_7 |
|
&& ksq[WHITE] != psq + NORTH |
|
&& ( distance(ksq[BLACK], psq + NORTH) > 1 |
|
|| (distance(ksq[WHITE], psq + NORTH) == 1))) |
|
result = WIN; |
|
|
|
|
|
else if ( stm == BLACK |
|
&& ( !(attacks_bb<KING>(ksq[BLACK]) & ~(attacks_bb<KING>(ksq[WHITE]) | pawn_attacks_bb(WHITE, psq))) |
|
|| (attacks_bb<KING>(ksq[BLACK]) & ~attacks_bb<KING>(ksq[WHITE]) & psq))) |
|
result = DRAW; |
|
|
|
|
|
else |
|
result = UNKNOWN; |
|
} |
|
|
|
Result KPKPosition::classify(const std::vector<KPKPosition>& db) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Result Good = (stm == WHITE ? WIN : DRAW); |
|
const Result Bad = (stm == WHITE ? DRAW : WIN); |
|
|
|
Result r = INVALID; |
|
Bitboard b = attacks_bb<KING>(ksq[stm]); |
|
|
|
while (b) |
|
r |= stm == WHITE ? db[index(BLACK, ksq[BLACK], pop_lsb(b), psq)] |
|
: db[index(WHITE, pop_lsb(b), ksq[WHITE], psq)]; |
|
|
|
if (stm == WHITE) |
|
{ |
|
if (rank_of(psq) < RANK_7) |
|
r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH)]; |
|
|
|
if ( rank_of(psq) == RANK_2 |
|
&& psq + NORTH != ksq[WHITE] |
|
&& psq + NORTH != ksq[BLACK]) |
|
r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH + NORTH)]; |
|
} |
|
|
|
return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad; |
|
} |
|
|
|
} |
|
|
|
} |
|
|