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
&& 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
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)]
: 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.
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)
{
&& 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;
// 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);
}
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;
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;
// 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];
* (!(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))
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;
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]);
}
// 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
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
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);
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);
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));
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));
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));
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);
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)));
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;
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;
}
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)
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));
}
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 - 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
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:
{
// 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)];
// Attacks to/from a given square
Bitboard attackers_to(Square s) const;
Bitboard attackers_to(Square s, Bitboard occupied) const;
- Bitboard attacks_from(PieceType pt, Square s) const;
- template<PieceType> Bitboard attacks_from(Square s) const;
- template<PieceType> Bitboard attacks_from(Square s, Color c) const;
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
// Properties of moves
return castlingRookSquare[cr];
}
-template<PieceType Pt>
-inline Bitboard Position::attacks_from(Square s) const {
- static_assert(Pt != PAWN, "Pawn attacks need color");
-
- return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, pieces())
- : Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s)
- : PseudoAttacks[Pt][s];
-}
-
-template<>
-inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
- return PawnAttacks[c][s];
-}
-
-inline Bitboard Position::attacks_from(PieceType pt, Square s) const {
- return attacks_bb(pt, s, pieces());
-}
-
inline Bitboard Position::attackers_to(Square s) const {
return attackers_to(s, pieces());
}