Skip to content

Commit

Permalink
Consolidate all attacks bitboards
Browse files Browse the repository at this point in the history
This is a non-functional simplification that simplifies getting attacks bitboards.

* consolidates all attacks to attacks_bb (remove Position::attacks_from(..)).
* attacks_bb<PieceType>(square) gets pseudo attacks
* attacks_bb<PieceType>(square, bitboard) gets attacks considering occupied squares in the bitboard).
* pawn_attacks_bb(Color, Square) gets pawn attacks like other pawn attack bitboards.
* Wraps all access to PawnAttacks arrays and PseudoAttacks arrays and adds asserts as appropriate.

Passed STC
LLR: 2.95 (-2.94,2.94) {-1.50,0.50}
Total: 90208 W: 17533 L: 17482 D: 55193
Ptnml(0-2): 1412, 10232, 21798, 10217, 1445
https://tests.stockfishchess.org/tests/view/5ece996275787cc0c05d9790

closes #2703

No functional change
  • Loading branch information
protonspring authored and vondele committed May 30, 2020
1 parent fb80957 commit a5e3b4e
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 72 deletions.
10 changes: 5 additions & 5 deletions src/bitbase.cpp
Expand Up @@ -112,21 +112,21 @@ namespace {
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|| ksq[WHITE] == psq
|| ksq[BLACK] == psq
|| (stm == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK])))
|| (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK])))
result = INVALID;

// Immediate win if a pawn can be promoted without getting captured
else if ( stm == WHITE
&& rank_of(psq) == RANK_7
&& ksq[stm] != psq + NORTH
&& ( distance(ksq[~stm], psq + NORTH) > 1
|| (PseudoAttacks[KING][ksq[stm]] & (psq + NORTH))))
|| (attacks_bb<KING>(ksq[stm]) & (psq + NORTH))))
result = WIN;

// Immediate draw if it is a stalemate or a king captures undefended pawn
else if ( stm == BLACK
&& ( !(PseudoAttacks[KING][ksq[stm]] & ~(PseudoAttacks[KING][ksq[~stm]] | PawnAttacks[~stm][psq]))
|| (PseudoAttacks[KING][ksq[stm]] & psq & ~PseudoAttacks[KING][ksq[~stm]])))
&& ( !(attacks_bb<KING>(ksq[stm]) & ~(attacks_bb<KING>(ksq[~stm]) | pawn_attacks_bb(~stm, psq)))
|| (attacks_bb<KING>(ksq[stm]) & psq & ~attacks_bb<KING>(ksq[~stm]))))
result = DRAW;

// Position will be classified later
Expand All @@ -149,7 +149,7 @@ namespace {
const Result Bad = (stm == WHITE ? DRAW : WIN);

Result r = INVALID;
Bitboard b = PseudoAttacks[KING][ksq[stm]];
Bitboard b = attacks_bb<KING>(ksq[stm]);

while (b)
r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(&b), psq)]
Expand Down
35 changes: 30 additions & 5 deletions src/bitboard.h
Expand Up @@ -176,6 +176,12 @@ constexpr Bitboard pawn_attacks_bb(Bitboard b) {
: shift<SOUTH_WEST>(b) | shift<SOUTH_EAST>(b);
}

inline Bitboard pawn_attacks_bb(Color c, Square s) {

assert(is_ok(s));
return PawnAttacks[c][s];
}


/// pawn_double_attacks_bb() returns the squares doubly attacked by pawns of the
/// given color from the squares in the given bitboard.
Expand Down Expand Up @@ -266,19 +272,38 @@ inline Bitboard safe_destination(Square s, int step)
return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
}

/// attacks_bb() returns a bitboard representing all the squares attacked by a
/// piece of type Pt (bishop or rook) placed on 's'.
/// attacks_bb(Square) returns the pseudo attacks of the give piece type
/// assuming an empty board.

template<PieceType Pt>
inline Bitboard attacks_bb(Square s) {

assert((Pt != PAWN) && (is_ok(s)));

return PseudoAttacks[Pt][s];
}

/// attacks_bb(Square, Bitboard) returns the attacks by the given piece
/// assuming the board is occupied according to the passed Bitboard.
/// Sliding piece attacks do not continue passed an occupied square.

template<PieceType Pt>
inline Bitboard attacks_bb(Square s, Bitboard occupied) {

const Magic& m = Pt == ROOK ? RookMagics[s] : BishopMagics[s];
return m.attacks[m.index(occupied)];
assert((Pt != PAWN) && (is_ok(s)));

switch (Pt)
{
case BISHOP: return BishopMagics[s].attacks[BishopMagics[s].index(occupied)];
case ROOK : return RookMagics[s].attacks[ RookMagics[s].index(occupied)];
case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
default : return PseudoAttacks[Pt][s];
}
}

inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {

assert(pt != PAWN);
assert((pt != PAWN) && (is_ok(s)));

switch (pt)
{
Expand Down
10 changes: 5 additions & 5 deletions src/endgame.cpp
Expand Up @@ -391,8 +391,8 @@ ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
&& relative_rank(weakSide, pos.square<KING>(strongSide)) >= RANK_4
&& relative_rank(weakSide, rsq) == RANK_3
&& ( pos.pieces(weakSide, PAWN)
& pos.attacks_from<KING>(kingSq)
& pos.attacks_from<PAWN>(rsq, strongSide)))
& attacks_bb<KING>(kingSq)
& pawn_attacks_bb(strongSide, rsq)))
return SCALE_FACTOR_DRAW;

return SCALE_FACTOR_NONE;
Expand Down Expand Up @@ -535,7 +535,7 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
// the corner
if ( rk == RANK_6
&& distance(psq + 2 * push, ksq) <= 1
&& (PseudoAttacks[BISHOP][bsq] & (psq + push))
&& (attacks_bb<BISHOP>(bsq) & (psq + push))
&& distance<File>(bsq, psq) >= 2)
return ScaleFactor(8);
}
Expand Down Expand Up @@ -670,14 +670,14 @@ ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
if ( ksq == blockSq1
&& opposite_colors(ksq, wbsq)
&& ( bbsq == blockSq2
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(weakSide, BISHOP))
|| (attacks_bb<BISHOP>(blockSq2, pos.pieces()) & pos.pieces(weakSide, BISHOP))
|| distance<Rank>(psq1, psq2) >= 2))
return SCALE_FACTOR_DRAW;

else if ( ksq == blockSq2
&& opposite_colors(ksq, wbsq)
&& ( bbsq == blockSq1
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(weakSide, BISHOP))))
|| (attacks_bb<BISHOP>(blockSq1, pos.pieces()) & pos.pieces(weakSide, BISHOP))))
return SCALE_FACTOR_DRAW;
else
return SCALE_FACTOR_NONE;
Expand Down
16 changes: 8 additions & 8 deletions src/evaluate.cpp
Expand Up @@ -235,15 +235,15 @@ namespace {
mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them));

// Initialize attackedBy[] for king and pawns
attackedBy[Us][KING] = pos.attacks_from<KING>(ksq);
attackedBy[Us][KING] = attacks_bb<KING>(ksq);
attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]);

// Init our king safety tables
Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G),
Utility::clamp(rank_of(ksq), RANK_2, RANK_7));
kingRing[Us] = PseudoAttacks[KING][s] | s;
kingRing[Us] = attacks_bb<KING>(s) | s;

kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
Expand Down Expand Up @@ -273,7 +273,7 @@ namespace {
// Find attacked squares, including x-ray attacks for bishops and rooks
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
: Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
: pos.attacks_from<Pt>(s);
: attacks_bb<Pt>(s, pos.pieces());

if (pos.blockers_for_king(Us) & s)
b &= LineBB[pos.square<KING>(Us)][s];
Expand Down Expand Up @@ -323,7 +323,7 @@ namespace {
* (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles));

// Penalty for all enemy pawns x-rayed
score -= BishopXRayPawns * popcount(PseudoAttacks[BISHOP][s] & pos.pieces(Them, PAWN));
score -= BishopXRayPawns * popcount(attacks_bb<BISHOP>(s) & pos.pieces(Them, PAWN));

// Bonus for bishop on a long diagonal which can "see" both center squares
if (more_than_one(attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & Center))
Expand Down Expand Up @@ -438,7 +438,7 @@ namespace {
unsafeChecks |= b2 & attackedBy[Them][BISHOP];

// Enemy knights checks
knightChecks = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
knightChecks = attacks_bb<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
if (knightChecks & safe)
kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100
: KnightSafeCheck;
Expand Down Expand Up @@ -564,12 +564,12 @@ namespace {
Square s = pos.square<QUEEN>(Them);
safe = mobilityArea[Us] & ~stronglyProtected;

b = attackedBy[Us][KNIGHT] & pos.attacks_from<KNIGHT>(s);
b = attackedBy[Us][KNIGHT] & attacks_bb<KNIGHT>(s);

score += KnightOnQueen * popcount(b & safe);

b = (attackedBy[Us][BISHOP] & pos.attacks_from<BISHOP>(s))
| (attackedBy[Us][ROOK ] & pos.attacks_from<ROOK >(s));
b = (attackedBy[Us][BISHOP] & attacks_bb<BISHOP>(s, pos.pieces()))
| (attackedBy[Us][ROOK ] & attacks_bb<ROOK >(s, pos.pieces()));

score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]);
}
Expand Down
20 changes: 10 additions & 10 deletions src/movegen.cpp
Expand Up @@ -40,7 +40,7 @@ namespace {

// Knight promotion is the only promotion that can give a direct check
// that's not already included in the queen promotion.
if (Type == QUIET_CHECKS && (PseudoAttacks[KNIGHT][to] & ksq))
if (Type == QUIET_CHECKS && (attacks_bb<KNIGHT>(to) & ksq))
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
else
(void)ksq; // Silence a warning under MSVC
Expand Down Expand Up @@ -84,8 +84,8 @@ namespace {

if (Type == QUIET_CHECKS)
{
b1 &= pos.attacks_from<PAWN>(ksq, Them);
b2 &= pos.attacks_from<PAWN>(ksq, Them);
b1 &= pawn_attacks_bb(Them, ksq);
b2 &= pawn_attacks_bb(Them, ksq);

// Add pawn pushes which give discovered check. This is possible only
// if the pawn is not on the same file as the enemy king, because we
Expand Down Expand Up @@ -166,7 +166,7 @@ namespace {
if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
return moveList;

b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them);
b1 = pawnsNotOn7 & pawn_attacks_bb(Them, pos.ep_square());

assert(b1);

Expand All @@ -192,14 +192,14 @@ namespace {
if (Checks)
{
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
&& !(PseudoAttacks[Pt][from] & target & pos.check_squares(Pt)))
&& !(attacks_bb<Pt>(from) & target & pos.check_squares(Pt)))
continue;

if (pos.blockers_for_king(~us) & from)
continue;
}

Bitboard b = pos.attacks_from<Pt>(from) & target;
Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;

if (Checks)
b &= pos.check_squares(Pt);
Expand Down Expand Up @@ -248,7 +248,7 @@ namespace {
if (Type != QUIET_CHECKS && Type != EVASIONS)
{
Square ksq = pos.square<KING>(Us);
Bitboard b = pos.attacks_from<KING>(ksq) & target;
Bitboard b = attacks_bb<KING>(ksq) & target;
while (b)
*moveList++ = make_move(ksq, pop_lsb(&b));

Expand Down Expand Up @@ -303,10 +303,10 @@ ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
Square from = pop_lsb(&dc);
PieceType pt = type_of(pos.piece_on(from));

Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces();
Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces();

if (pt == KING)
b &= ~PseudoAttacks[QUEEN][pos.square<KING>(~us)];
b &= ~attacks_bb<QUEEN>(pos.square<KING>(~us));

while (b)
*moveList++ = make_move(from, pop_lsb(&b));
Expand Down Expand Up @@ -336,7 +336,7 @@ ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers();

// Generate evasions for king, capture and non capture moves
Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
Bitboard b = attacks_bb<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
while (b)
*moveList++ = make_move(ksq, pop_lsb(&b));

Expand Down
6 changes: 3 additions & 3 deletions src/pawns.cpp
Expand Up @@ -100,8 +100,8 @@ namespace {
opposed = theirPawns & forward_file_bb(Us, s);
blocked = theirPawns & (s + Up);
stoppers = theirPawns & passed_pawn_span(Us, s);
lever = theirPawns & PawnAttacks[Us][s];
leverPush = theirPawns & PawnAttacks[Us][s + Up];
lever = theirPawns & pawn_attacks_bb(Us, s);
leverPush = theirPawns & pawn_attacks_bb(Us, s + Up);
doubled = ourPawns & (s - Up);
neighbours = ourPawns & adjacent_files_bb(s);
phalanx = neighbours & rank_bb(s);
Expand Down Expand Up @@ -253,7 +253,7 @@ Score Entry::do_king_safety(const Position& pos) {
Bitboard pawns = pos.pieces(Us, PAWN);
int minPawnDist = 6;

if (pawns & PseudoAttacks[KING][ksq])
if (pawns & attacks_bb<KING>(ksq))
minPawnDist = 1;
else while (pawns)
minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns)));
Expand Down
30 changes: 15 additions & 15 deletions src/position.cpp
Expand Up @@ -139,7 +139,7 @@ void Position::init() {
for (Piece pc : Pieces)
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
if (PseudoAttacks[type_of(pc)][s1] & s2)
if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2))
{
Move move = make_move(s1, s2);
Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
Expand Down Expand Up @@ -319,10 +319,10 @@ void Position::set_check_info(StateInfo* si) const {

Square ksq = square<KING>(~sideToMove);

si->checkSquares[PAWN] = attacks_from<PAWN>(ksq, ~sideToMove);
si->checkSquares[KNIGHT] = attacks_from<KNIGHT>(ksq);
si->checkSquares[BISHOP] = attacks_from<BISHOP>(ksq);
si->checkSquares[ROOK] = attacks_from<ROOK>(ksq);
si->checkSquares[PAWN] = pawn_attacks_bb(~sideToMove, ksq);
si->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
si->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
si->checkSquares[ROOK] = attacks_bb<ROOK>(ksq, pieces());
si->checkSquares[QUEEN] = si->checkSquares[BISHOP] | si->checkSquares[ROOK];
si->checkSquares[KING] = 0;
}
Expand Down Expand Up @@ -455,8 +455,8 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners
pinners = 0;

// Snipers are sliders that attack 's' when a piece and other snipers are removed
Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK))
| (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
Bitboard snipers = ( (attacks_bb< ROOK>(s) & pieces(QUEEN, ROOK))
| (attacks_bb<BISHOP>(s) & pieces(QUEEN, BISHOP))) & sliders;
Bitboard occupancy = pieces() ^ snipers;

while (snipers)
Expand All @@ -480,12 +480,12 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners

Bitboard Position::attackers_to(Square s, Bitboard occupied) const {

return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
| (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
| (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
return (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN))
| (pawn_attacks_bb(WHITE, s) & pieces(BLACK, PAWN))
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT))
| (attacks_bb< ROOK>(s, occupied) & pieces( ROOK, QUEEN))
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
| (attacks_from<KING>(s) & pieces(KING));
| (attacks_bb<KING>(s) & pieces(KING));
}


Expand Down Expand Up @@ -588,15 +588,15 @@ bool Position::pseudo_legal(const Move m) const {
if ((Rank8BB | Rank1BB) & to)
return false;

if ( !(attacks_from<PAWN>(from, us) & pieces(~us) & to) // Not a capture
if ( !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture
&& !((from + pawn_push(us) == to) && empty(to)) // Not a single push
&& !( (from + 2 * pawn_push(us) == to) // Not a double push
&& (relative_rank(us, from) == RANK_2)
&& empty(to)
&& empty(to - pawn_push(us))))
return false;
}
else if (!(attacks_from(type_of(pc), from) & to))
else if (!(attacks_bb(type_of(pc), from, pieces()) & to))
return false;

// Evasions generator already takes care to avoid some kind of illegal moves
Expand Down Expand Up @@ -670,7 +670,7 @@ bool Position::gives_check(Move m) const {
Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1);
Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1);

return (PseudoAttacks[ROOK][rto] & square<KING>(~sideToMove))
return (attacks_bb<ROOK>(rto) & square<KING>(~sideToMove))
&& (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square<KING>(~sideToMove));
}
default:
Expand Down Expand Up @@ -794,7 +794,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
{
// Set en-passant square if the moved pawn can be captured
if ( (int(to) ^ int(from)) == 16
&& (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
&& (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)))
{
st->epSquare = to - pawn_push(us);
k ^= Zobrist::enpassant[file_of(st->epSquare)];
Expand Down

0 comments on commit a5e3b4e

Please sign in to comment.