mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 16:53:09 +00:00
Merge branch 'master' into bishop_pin_clop
This commit is contained in:
commit
ea4e22be1d
7 changed files with 75 additions and 118 deletions
151
src/bitbase.cpp
151
src/bitbase.cpp
|
@ -26,22 +26,22 @@
|
|||
namespace {
|
||||
|
||||
// The possible pawns squares are 24, the first 4 files and ranks from 2 to 7
|
||||
const unsigned IndexMax = 24*64*64*2; // wp_sq * wk_sq * bk_sq * stm = 196608
|
||||
const unsigned IndexMax = 2*24*64*64; // stm * psq * wksq * bksq = 196608
|
||||
|
||||
// Each uint32_t stores results of 32 positions, one per bit
|
||||
uint32_t KPKBitbase[IndexMax / 32];
|
||||
|
||||
// A KPK bitbase index is an integer in [0, IndexMax] range
|
||||
//
|
||||
// Information is mapped in this way
|
||||
// Information is mapped in a way that minimizes number of iterations:
|
||||
//
|
||||
// bit 0: side to move (WHITE or BLACK)
|
||||
// bit 1- 6: black king square (from SQ_A1 to SQ_H8)
|
||||
// bit 7-12: white king square (from SQ_A1 to SQ_H8)
|
||||
// bit 0- 5: white king square (from SQ_A1 to SQ_H8)
|
||||
// bit 6-11: black king square (from SQ_A1 to SQ_H8)
|
||||
// bit 12: side to move (WHITE or BLACK)
|
||||
// bit 13-14: white pawn file (from FILE_A to FILE_D)
|
||||
// bit 15-17: white pawn 6 - rank (from 6 - RANK_7 to 6 - RANK_2)
|
||||
unsigned index(Color stm, Square bksq, Square wksq, Square psq) {
|
||||
return stm + (bksq << 1) + (wksq << 7) + (file_of(psq) << 13) + ((6 - rank_of(psq)) << 15);
|
||||
unsigned index(Color us, Square bksq, Square wksq, Square psq) {
|
||||
return wksq + (bksq << 6) + (us << 12) + (file_of(psq) << 13) + ((6 - rank_of(psq)) << 15);
|
||||
}
|
||||
|
||||
enum Result {
|
||||
|
@ -55,20 +55,15 @@ namespace {
|
|||
|
||||
struct KPKPosition {
|
||||
|
||||
void classify_leaf(unsigned idx);
|
||||
|
||||
Result classify(const std::vector<KPKPosition>& db)
|
||||
{ return stm == WHITE ? classify<WHITE>(db) : classify<BLACK>(db); }
|
||||
|
||||
operator Result() const { return res; }
|
||||
Result classify_leaf(unsigned idx);
|
||||
Result classify(const std::vector<KPKPosition>& db)
|
||||
{ return us == WHITE ? classify<WHITE>(db) : classify<BLACK>(db); }
|
||||
|
||||
private:
|
||||
template<Color Us> Bitboard k_attacks() const
|
||||
{ return StepAttacksBB[KING][Us == WHITE ? wksq : bksq]; }
|
||||
|
||||
template<Color Us> Result classify(const std::vector<KPKPosition>& db);
|
||||
|
||||
Color stm;
|
||||
Color us;
|
||||
Square bksq, wksq, psq;
|
||||
Result res;
|
||||
};
|
||||
|
@ -76,12 +71,12 @@ namespace {
|
|||
} // namespace
|
||||
|
||||
|
||||
bool Bitbases::probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm) {
|
||||
bool Bitbases::probe_kpk(Square wksq, Square wpsq, Square bksq, Color us) {
|
||||
|
||||
assert(file_of(wpsq) <= FILE_D);
|
||||
|
||||
unsigned idx = index(stm, bksq, wksq, wpsq);
|
||||
return KPKBitbase[idx / 32] & (1 << (idx & 31));
|
||||
unsigned idx = index(us, bksq, wksq, wpsq);
|
||||
return KPKBitbase[idx / 32] & (1 << (idx & 0x1F));
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,7 +89,7 @@ void Bitbases::init_kpk() {
|
|||
for (idx = 0; idx < IndexMax; idx++)
|
||||
db[idx].classify_leaf(idx);
|
||||
|
||||
// Iterate until all positions are classified (26 cycles needed)
|
||||
// Iterate until all positions are classified (15 cycles needed)
|
||||
while (repeat)
|
||||
for (repeat = idx = 0; idx < IndexMax; idx++)
|
||||
if (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN)
|
||||
|
@ -103,101 +98,61 @@ void Bitbases::init_kpk() {
|
|||
// Map 32 results into one KPKBitbase[] entry
|
||||
for (idx = 0; idx < IndexMax; idx++)
|
||||
if (db[idx] == WIN)
|
||||
KPKBitbase[idx / 32] |= 1 << (idx & 31);
|
||||
KPKBitbase[idx / 32] |= 1 << (idx & 0x1F);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void KPKPosition::classify_leaf(unsigned idx) {
|
||||
Result KPKPosition::classify_leaf(unsigned idx) {
|
||||
|
||||
stm = Color(idx & 1);
|
||||
bksq = Square((idx >> 1) & 0x3F);
|
||||
wksq = Square((idx >> 7) & 0x3F);
|
||||
wksq = Square((idx >> 0) & 0x3F);
|
||||
bksq = Square((idx >> 6) & 0x3F);
|
||||
us = Color((idx >> 12) & 0x01);
|
||||
psq = File((idx >> 13) & 3) | Rank(6 - (idx >> 15));
|
||||
|
||||
// Check if two pieces are on the same square or if a king can be captured
|
||||
if ( wksq == psq || wksq == bksq || bksq == psq
|
||||
|| (k_attacks<WHITE>() & bksq)
|
||||
|| (stm == WHITE && (StepAttacksBB[PAWN][psq] & bksq)))
|
||||
res = INVALID;
|
||||
|| (StepAttacksBB[KING][wksq] & bksq)
|
||||
|| (us == WHITE && (StepAttacksBB[PAWN][psq] & bksq)))
|
||||
return res = INVALID;
|
||||
|
||||
// The position is an immediate win if it is white to move and the white
|
||||
// pawn can be promoted without getting captured.
|
||||
else if ( rank_of(psq) == RANK_7
|
||||
&& stm == WHITE
|
||||
&& wksq != psq + DELTA_N
|
||||
&& ( square_distance(bksq, psq + DELTA_N) > 1
|
||||
||(k_attacks<WHITE>() & (psq + DELTA_N))))
|
||||
res = WIN;
|
||||
if (us == WHITE)
|
||||
{
|
||||
// Immediate win if pawn can be promoted without getting captured
|
||||
if ( rank_of(psq) == RANK_7
|
||||
&& wksq != psq + DELTA_N
|
||||
&& ( square_distance(bksq, psq + DELTA_N) > 1
|
||||
||(StepAttacksBB[KING][wksq] & (psq + DELTA_N))))
|
||||
return res = WIN;
|
||||
}
|
||||
// Immediate draw if is stalemate or king captures undefended pawn
|
||||
else if ( !(StepAttacksBB[KING][bksq] & ~(StepAttacksBB[KING][wksq] | StepAttacksBB[PAWN][psq]))
|
||||
|| (StepAttacksBB[KING][bksq] & psq & ~StepAttacksBB[KING][wksq]))
|
||||
return res = DRAW;
|
||||
|
||||
// Check for known draw positions
|
||||
//
|
||||
// Case 1: Stalemate
|
||||
else if ( stm == BLACK
|
||||
&& !(k_attacks<BLACK>() & ~(k_attacks<WHITE>() | StepAttacksBB[PAWN][psq])))
|
||||
res = DRAW;
|
||||
|
||||
// Case 2: King can capture undefended pawn
|
||||
else if ( stm == BLACK
|
||||
&& (k_attacks<BLACK>() & psq & ~k_attacks<WHITE>()))
|
||||
res = DRAW;
|
||||
|
||||
// Case 3: Black king in front of white pawn
|
||||
else if ( bksq == psq + DELTA_N
|
||||
&& rank_of(psq) < RANK_7)
|
||||
res = DRAW;
|
||||
|
||||
// Case 4: White king in front of pawn and black has opposition
|
||||
else if ( stm == WHITE
|
||||
&& wksq == psq + DELTA_N
|
||||
&& bksq == wksq + DELTA_N + DELTA_N
|
||||
&& rank_of(psq) < RANK_5)
|
||||
res = DRAW;
|
||||
|
||||
// Case 5: Stalemate with rook pawn
|
||||
else if ( bksq == SQ_A8
|
||||
&& file_of(psq) == FILE_A)
|
||||
res = DRAW;
|
||||
|
||||
// Case 6: White king trapped on the rook file
|
||||
else if ( file_of(wksq) == FILE_A
|
||||
&& file_of(psq) == FILE_A
|
||||
&& rank_of(wksq) > rank_of(psq)
|
||||
&& bksq == wksq + 2)
|
||||
res = DRAW;
|
||||
|
||||
else
|
||||
res = UNKNOWN;
|
||||
return res = UNKNOWN;
|
||||
}
|
||||
|
||||
template<Color Us>
|
||||
Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
|
||||
|
||||
// White to Move: If one move leads to a position classified as RESULT_WIN,
|
||||
// the result of the current position is RESULT_WIN. If all moves lead to
|
||||
// positions classified as RESULT_DRAW, the current position is classified
|
||||
// RESULT_DRAW otherwise the current position is classified as RESULT_UNKNOWN.
|
||||
// White to Move: If one move leads to a position classified as WIN, the result
|
||||
// of the current position is WIN. If all moves lead to positions classified
|
||||
// as DRAW, the current position is classified DRAW otherwise the current
|
||||
// position is classified as UNKNOWN.
|
||||
//
|
||||
// Black to Move: If one move leads to a position classified as RESULT_DRAW,
|
||||
// the result of the current position is RESULT_DRAW. If all moves lead to
|
||||
// positions classified as RESULT_WIN, the position is classified RESULT_WIN.
|
||||
// Otherwise, the current position is classified as RESULT_UNKNOWN.
|
||||
// Black to Move: If one move leads to a position classified as DRAW, the result
|
||||
// of the current position is DRAW. If all moves lead to positions classified
|
||||
// as WIN, the position is classified WIN otherwise the current position is
|
||||
// classified UNKNOWN.
|
||||
|
||||
Result r = INVALID;
|
||||
Bitboard b = k_attacks<Us>();
|
||||
Bitboard b = StepAttacksBB[KING][Us == WHITE ? wksq : bksq];
|
||||
|
||||
while (b)
|
||||
{
|
||||
r |= Us == WHITE ? db[index(BLACK, bksq, pop_lsb(&b), psq)]
|
||||
: db[index(WHITE, pop_lsb(&b), wksq, psq)];
|
||||
|
||||
if (Us == WHITE && (r & WIN))
|
||||
return res = WIN;
|
||||
|
||||
if (Us == BLACK && (r & DRAW))
|
||||
return res = DRAW;
|
||||
}
|
||||
r |= Us == WHITE ? db[index(~Us, bksq, pop_lsb(&b), psq)]
|
||||
: db[index(~Us, pop_lsb(&b), wksq, psq)];
|
||||
|
||||
if (Us == WHITE && rank_of(psq) < RANK_7)
|
||||
{
|
||||
|
@ -206,12 +161,12 @@ namespace {
|
|||
|
||||
if (rank_of(s) == RANK_3 && s != wksq && s != bksq)
|
||||
r |= db[index(BLACK, bksq, wksq, s + DELTA_N)]; // Double push
|
||||
|
||||
if (r & WIN)
|
||||
return res = WIN;
|
||||
}
|
||||
|
||||
return res = r & UNKNOWN ? UNKNOWN : Us == WHITE ? DRAW : WIN;
|
||||
if (Us == WHITE)
|
||||
return res = r & WIN ? WIN : r & UNKNOWN ? UNKNOWN : DRAW;
|
||||
else
|
||||
return res = r & DRAW ? DRAW : r & UNKNOWN ? UNKNOWN : WIN;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -33,7 +33,7 @@ void print(Bitboard b);
|
|||
namespace Bitbases {
|
||||
|
||||
void init_kpk();
|
||||
bool probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm);
|
||||
bool probe_kpk(Square wksq, Square wpsq, Square bksq, Color us);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -199,21 +199,21 @@ Value Endgame<KPK>::operator()(const Position& pos) const {
|
|||
assert(pos.piece_count(weakerSide, PAWN) == 0);
|
||||
|
||||
Square wksq, bksq, wpsq;
|
||||
Color stm;
|
||||
Color us;
|
||||
|
||||
if (strongerSide == WHITE)
|
||||
{
|
||||
wksq = pos.king_square(WHITE);
|
||||
bksq = pos.king_square(BLACK);
|
||||
wpsq = pos.piece_list(WHITE, PAWN)[0];
|
||||
stm = pos.side_to_move();
|
||||
us = pos.side_to_move();
|
||||
}
|
||||
else
|
||||
{
|
||||
wksq = ~pos.king_square(BLACK);
|
||||
bksq = ~pos.king_square(WHITE);
|
||||
wpsq = ~pos.piece_list(BLACK, PAWN)[0];
|
||||
stm = ~pos.side_to_move();
|
||||
us = ~pos.side_to_move();
|
||||
}
|
||||
|
||||
if (file_of(wpsq) >= FILE_E)
|
||||
|
@ -223,7 +223,7 @@ Value Endgame<KPK>::operator()(const Position& pos) const {
|
|||
wpsq = mirror(wpsq);
|
||||
}
|
||||
|
||||
if (!Bitbases::probe_kpk(wksq, wpsq, bksq, stm))
|
||||
if (!Bitbases::probe_kpk(wksq, wpsq, bksq, us))
|
||||
return VALUE_DRAW;
|
||||
|
||||
Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(wpsq));
|
||||
|
@ -920,14 +920,14 @@ ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
|
|||
Square wksq = pos.king_square(strongerSide);
|
||||
Square bksq = pos.king_square(weakerSide);
|
||||
Square wpsq = pos.piece_list(strongerSide, PAWN)[0];
|
||||
Color stm = pos.side_to_move();
|
||||
Color us = pos.side_to_move();
|
||||
|
||||
if (strongerSide == BLACK)
|
||||
{
|
||||
wksq = ~wksq;
|
||||
bksq = ~bksq;
|
||||
wpsq = ~wpsq;
|
||||
stm = ~stm;
|
||||
us = ~us;
|
||||
}
|
||||
|
||||
if (file_of(wpsq) >= FILE_E)
|
||||
|
@ -945,5 +945,5 @@ ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
|
|||
|
||||
// Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
|
||||
// it's probably at least a draw even with the pawn.
|
||||
return Bitbases::probe_kpk(wksq, wpsq, bksq, stm) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
|
||||
return Bitbases::probe_kpk(wksq, wpsq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
|
||||
}
|
||||
|
|
|
@ -498,7 +498,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
|
||||
// Init king safety tables only if we are going to use them
|
||||
if ( pos.piece_count(Us, QUEEN)
|
||||
&& pos.non_pawn_material(Us) >= QueenValueMg + RookValueMg)
|
||||
&& pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
|
||||
{
|
||||
ei.kingRing[Them] = (b | (Us == WHITE ? b >> 8 : b << 8));
|
||||
b &= ei.attackedBy[Us][PAWN];
|
||||
|
|
|
@ -278,11 +278,11 @@ void Position::set(const string& fenStr, bool isChess960, Thread* th) {
|
|||
}
|
||||
|
||||
// 5-6. Halfmove clock and fullmove number
|
||||
ss >> std::skipws >> st->rule50 >> startPosPly;
|
||||
ss >> std::skipws >> st->rule50 >> gamePly;
|
||||
|
||||
// Convert from fullmove starting from 1 to ply starting from 0,
|
||||
// handle also common incorrect FEN with fullmove = 0.
|
||||
startPosPly = std::max(2 * (startPosPly - 1), 0) + int(sideToMove == BLACK);
|
||||
gamePly = std::max(2 * (gamePly - 1), 0) + int(sideToMove == BLACK);
|
||||
|
||||
st->key = compute_key();
|
||||
st->pawnKey = compute_pawn_key();
|
||||
|
@ -373,7 +373,7 @@ const string Position::fen() const {
|
|||
ss << '-';
|
||||
|
||||
ss << (ep_square() == SQ_NONE ? " - " : " " + square_to_string(ep_square()) + " ")
|
||||
<< st->rule50 << " " << 1 + (startPosPly - int(sideToMove == BLACK)) / 2;
|
||||
<< st->rule50 << " " << 1 + (gamePly - int(sideToMove == BLACK)) / 2;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
@ -735,8 +735,9 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
|
|||
// Update side to move
|
||||
k ^= Zobrist::side;
|
||||
|
||||
// Increment the 50 moves rule draw counter. Resetting it to zero in the
|
||||
// case of a capture or a pawn move is taken care of later.
|
||||
// Increment ply counters.In particular rule50 will be later reset it to zero
|
||||
// in case of a capture or a pawn move.
|
||||
gamePly++;
|
||||
st->rule50++;
|
||||
st->pliesFromNull++;
|
||||
|
||||
|
@ -1054,6 +1055,7 @@ void Position::undo_move(Move m) {
|
|||
|
||||
// Finally point our state pointer back to the previous state
|
||||
st = st->previous;
|
||||
gamePly--;
|
||||
|
||||
assert(pos_is_ok());
|
||||
}
|
||||
|
@ -1417,7 +1419,7 @@ void Position::flip() {
|
|||
thisThread = pos.this_thread();
|
||||
nodes = pos.nodes_searched();
|
||||
chess960 = pos.is_chess960();
|
||||
startPosPly = pos.startpos_ply_counter();
|
||||
gamePly = pos.game_ply();
|
||||
|
||||
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
||||
if (!pos.is_empty(s))
|
||||
|
|
|
@ -174,7 +174,7 @@ public:
|
|||
|
||||
// Other properties of the position
|
||||
Color side_to_move() const;
|
||||
int startpos_ply_counter() const;
|
||||
int game_ply() const;
|
||||
bool is_chess960() const;
|
||||
Thread* this_thread() const;
|
||||
int64_t nodes_searched() const;
|
||||
|
@ -218,7 +218,7 @@ private:
|
|||
Bitboard castlePath[COLOR_NB][CASTLING_SIDE_NB];
|
||||
StateInfo startState;
|
||||
int64_t nodes;
|
||||
int startPosPly;
|
||||
int gamePly;
|
||||
Color sideToMove;
|
||||
Thread* thisThread;
|
||||
StateInfo* st;
|
||||
|
@ -376,8 +376,8 @@ inline bool Position::is_passed_pawn_push(Move m) const {
|
|||
&& pawn_is_passed(sideToMove, to_sq(m));
|
||||
}
|
||||
|
||||
inline int Position::startpos_ply_counter() const {
|
||||
return startPosPly + st->pliesFromNull; // HACK
|
||||
inline int Position::game_ply() const {
|
||||
return gamePly;
|
||||
}
|
||||
|
||||
inline bool Position::opposite_bishops() const {
|
||||
|
|
|
@ -182,7 +182,7 @@ void Search::think() {
|
|||
static PolyglotBook book; // Defined static to initialize the PRNG only once
|
||||
|
||||
RootColor = RootPos.side_to_move();
|
||||
TimeMgr.init(Limits, RootPos.startpos_ply_counter(), RootColor);
|
||||
TimeMgr.init(Limits, RootPos.game_ply(), RootColor);
|
||||
|
||||
if (RootMoves.empty())
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue