#include "bitboard.h" #include uint64_t PAWN_ATTACKS[2][64]; uint64_t KNIGHT_ATTACKS[64]; uint64_t KING_ATTACKS[64]; void create_knight_attack_cache(void) { for (int sq = 0; sq < 64; sq++) { uint64_t b = 1ULL << sq; uint64_t mask = 0ULL; mask |= (b & ~FILE_A) << 15; mask |= (b & ~FILE_H) << 17; mask |= (b & ~(FILE_A | FILE_B)) << 6; mask |= (b & ~(FILE_G | FILE_H)) << 10; mask |= (b & ~FILE_A) >> 17; mask |= (b & ~FILE_H) >> 15; mask |= (b & ~(FILE_A | FILE_B)) >> 10; mask |= (b & ~(FILE_G | FILE_H)) >> 6; KNIGHT_ATTACKS[sq] = mask; } } void create_pawn_attack_cache(void) { for (int sq = 0; sq < 64; sq++) { uint64_t b = 1ULL << sq; // White: NE (+9), NW (+7), but never from rank 8 uint64_t w = ((b & ~FILE_H & ~RANK_8) << 9) | ((b & ~FILE_A & ~RANK_8) << 7); // Black: SE (-7), SW (-9), but never from rank 1 uint64_t bl = ((b & ~FILE_H & ~RANK_1) >> 7) | ((b & ~FILE_A & ~RANK_1) >> 9); PAWN_ATTACKS[WHITE][sq] = w; PAWN_ATTACKS[BLACK][sq] = bl; } } void create_king_attack_cache(void) { for (int sq = 0; sq < 64; sq++) { uint64_t b = 1ULL << sq; uint64_t mask = 0ULL; // North / South mask |= (b & ~RANK_8) << 8; mask |= (b & ~RANK_1) >> 8; // East / West mask |= (b & ~FILE_H) << 1; mask |= (b & ~FILE_A) >> 1; // Diagonals mask |= (b & ~FILE_A & ~RANK_8) << 7; mask |= (b & ~FILE_H & ~RANK_8) << 9; mask |= (b & ~FILE_A & ~RANK_1) >> 9; mask |= (b & ~FILE_H & ~RANK_1) >> 7; KING_ATTACKS[sq] = mask; } } static int first_set_index(uint64_t bb) { for (int i = 0; i < 64; ++i) { if ((bb >> i) & 1ULL) return i; } return -1; } static int pop_lsb_index(uint64_t *bb) { if (*bb == 0) return -1; int idx = first_set_index(*bb); // Clears bit. *bb &= ~(1ULL << idx); return idx; } static inline uint64_t ray_attacks(int start_square, int delta_file, int delta_rank, uint64_t occupied) { uint64_t attacks = 0; int start_file = start_square % 8; int start_rank = start_square / 8; int next_file = start_file + delta_file; int next_rank = start_rank + delta_rank; while (next_file >= 0 && next_file < 8 && next_rank >= 0 && next_rank < 8) { int next_square = next_rank * 8 + next_file; uint64_t next_bit = 1ULL << next_square; // can attack this square attacks |= next_bit; // blocker: include it, then stop if (occupied & next_bit) break; next_file += delta_file; next_rank += delta_rank; } return attacks; } static inline uint64_t rook_attacks(int square, uint64_t occupied) { return ray_attacks(square, +1, 0, occupied) // east | ray_attacks(square, -1, 0, occupied) // west | ray_attacks(square, 0, +1, occupied) // north | ray_attacks(square, 0, -1, occupied); // south } static inline uint64_t bishop_attacks(int square, uint64_t occupied) { return ray_attacks(square, +1, +1, occupied) // NE | ray_attacks(square, -1, +1, occupied) // NW | ray_attacks(square, +1, -1, occupied) // SE | ray_attacks(square, -1, -1, occupied); // SW } static inline uint64_t queen_attacks(int square, uint64_t occupied) { // Simply combine both types of attacks return rook_attacks(square, occupied) | bishop_attacks(square, occupied); } void print_board(const struct Board *b) { static const char PIECE_CH[12] = { 'P','N','B','R','Q','K', 'p','n','b','r','q','k' }; char grid[64]; for (int i = 0; i < 64; ++i) grid[i] = '.'; for (int p = 0; p < 12; ++p) { uint64_t bb = b->pieces[p]; while (bb) { int sq = pop_lsb_index(&bb); grid[sq] = PIECE_CH[p]; } } for (int r = 7; r >= 0; --r) { for (int f = 0; f < 8; ++f) { putchar(grid[r * 8 + f]); if (f < 7) putchar(' '); } putchar('\n'); } }