Currently perft at depth 7 of initial position is ~3.8s (intel i7 8700, on current CPUs this would be lower but that's in my upcoming shopping basket

The two main bottlenecks of my engine currently are king moves, specifically verify whether the king can castle, and whether the squares it can go to are legal. If I ignore these 2 steps, my perft time drops to ~3.2 so huge improvement.
I feel like there's a genius idea waiting to be found to improve this...
I was curious if you guys have some tips & tricks to make these 2 scenarios as fast as possible, and how you usually implement this in your engine(s).
If you're curious, this is what my functions look like, I think it's mostly understandable without too much context:
This function clears bits of the king attacks if they are attacked by opposing pieces
Code: Select all
void filterKingAttacks(bool side, U64 occupancy, int kingSquare, U64& kingAttacks) {
if (!kingAttacks) {
return;
}
//kingAttacks &= pawnAttackZones[!side][kingSquare][_pext_u64(pieces[!side][p], pawnZones[!side][kingSquare])];
kingAttacks &= getPawnKingAttacks(!side, kingSquare, pieces[!side][p]);
kingAttacks &= ~getKingAttacks(king[!side]);
//remove king to avoid collisions, as it should not be considered when checking for threats
PopBit(occupancy, kingSquare);
U64 bitboard;
bitboard = pieces[!side][n] & knightAttackZones[kingSquare];
Bitloop(bitboard) {
kingAttacks &= ~getKnightAttacks(SquareOf(bitboard));
}
bitboard = (pieces[!side][b] | pieces[!side][q]) & bishopAttackZones[kingSquare];
Bitloop(bitboard) {
kingAttacks &= ~getBishopAttacks(SquareOf(bitboard), occupancy);
}
bitboard = (pieces[!side][r] | pieces[!side][q]) & rookAttackZones[kingSquare];
Bitloop(bitboard) {
kingAttacks &= ~getRookAttacks(SquareOf(bitboard), occupancy);
}
}
Code: Select all
bool castle(bool side, int castlingSide) {
if (!(castlingPermissions[moveCount] & CASTLING[castlingSide])) {
return false;
}
if (CASTLING_OCCUPIED_SQUARES[castlingSide] & occupancies[moveCount][both]) {
return false;
}
if (occupancies[moveCount][!side] & CASTLING_FORBIDDEN_SQUARES[castlingSide]) {
return false;
}
if ((occupancies[moveCount][!side] ^ pieces[!side][n]) & CASTLING_FORBIDDEN_SQUARE_EXCEPT_KNIGHT[castlingSide]) {
return false;
}
if ((occupancies[moveCount][!side] ^ pieces[!side][r]) & CASTLING_FORBIDDEN_SQUARE_EXCEPT_ROOK[castlingSide]) {
return false;
}
if (pieces[!side][n] & CASTLING_FORBIDDEN_KNIGHT_SQUARES[castlingSide]) {
return false;
}
U64 bishopAttacks = getBishopCastleAttacks(castlingSide, occupancies[moveCount][both]) & (pieces[!side][b] | pieces[!side][q]);
U64 rookAttacks = getRookCastleAttacks(castlingSide, occupancies[moveCount][both]) & (pieces[!side][r] | pieces[!side][q]);
return !(bishopAttacks | rookAttacks);
}