Add non pawn movement generators

This commit is contained in:
2025-08-16 15:07:13 -04:00
parent e9d64a35db
commit 9c9dedc7bf

View File

@@ -76,7 +76,7 @@ static int pop_lsb_index(uint64_t *bb) {
return idx;
}
static inline uint64_t ray_attacks(int start_square, int delta_file, int delta_rank, uint64_t occupied)
static uint64_t ray_attacks(int start_square, int delta_file, int delta_rank, uint64_t occupied)
{
uint64_t attacks = 0;
@@ -104,25 +104,196 @@ static inline uint64_t ray_attacks(int start_square, int delta_file, int delta_r
return attacks;
}
static inline uint64_t rook_attacks(int square, uint64_t occupied) {
static 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) {
static 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) {
static uint64_t queen_attacks(int square, uint64_t occupied) {
// Simply combine both types of attacks
return rook_attacks(square, occupied) | bishop_attacks(square, occupied);
}
static void push_move(struct Move *out, int *count, int from, int to, uint8_t piece, uint8_t promo, uint8_t flags)
{
out[*count] = (Move){
.from = (uint16_t)from,
.to = (uint16_t)to,
.piece = piece,
.promo = promo, // 0 for non-promo;
.flags = flags
};
(*count)++;
}
/**
Pieces that are not PAWNs
*/
static void gen_knight_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) {
enum Color side = b->side_to_move;
uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1];
uint8_t pid = (side == WHITE) ? N : n;
uint64_t bb = (side == WHITE) ? b->pieces[N] : b->pieces[n];
while (bb) {
int from = pop_lsb_index(&bb);
uint64_t mask = KNIGHT_ATTACKS[from] & ~own;
uint64_t caps = mask & opp;
if (!captures_only) {
uint64_t quiet = mask & ~opp;
while (quiet) {
int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE);
}
}
while (caps) {
int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE);
}
}
}
static void gen_bishop_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) {
enum Color side = b->side_to_move;
uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1];
uint64_t occ = b->occ[BOTH];
uint8_t pid = (side == WHITE) ? B : b;
uint64_t bb = (side == WHITE) ? b->pieces[B] : b->pieces[b];
while (bb) {
int from = pop_lsb_index(&bb);
uint64_t mask = bishop_attacks(from, occ) & ~own;
uint64_t caps = mask & opp;
if (!captures_only) {
uint64_t quiet = mask & ~opp;
while (quiet) {
int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE);
}
}
while (caps) {
int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE);
}
}
}
static void gen_rook_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) {
enum Color side = b->side_to_move;
uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1];
uint64_t occ = b->occ[BOTH];
uint8_t pid = (side == WHITE) ? R : r;
uint64_t bb = (side == WHITE) ? b->pieces[R] : b->pieces[r];
while (bb) {
int from = pop_lsb_index(&bb);
uint64_t mask = rook_attacks(from, occ) & ~own;
uint64_t caps = mask & opp;
if (!captures_only) {
uint64_t quiet = mask & ~opp;
while (quiet) {
int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE);
}
}
while (caps) {
int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE);
}
}
}
static void gen_queen_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) {
enum Color side = b->side_to_move;
uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1];
uint64_t occ = b->occ[BOTH];
uint8_t pid = (side == WHITE) ? Q : q;
uint64_t bb = (side == WHITE) ? b->pieces[Q] : b->pieces[q];
while (bb) {
int from = pop_lsb_index(&bb);
uint64_t mask = (rook_attacks(from, occ) | bishop_attacks(from, occ)) & ~own;
uint64_t caps = mask & opp;
if (!captures_only) {
uint64_t quiet = mask & ~opp;
while (quiet) {
int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE);
}
}
while (caps) {
int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE);
}
}
}
static void gen_king_moves(struct Board *b, struct Move *out, int *n, bool captures_only) {
enum Color side = b->side_to_move;
uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1];
uint8_t pid = (side == WHITE) ? K : k;
uint64_t kk = (side == WHITE) ? b->pieces[K] : b->pieces[k];
if (!kk) return;
int from = first_set_index(kk);
uint64_t mask = KING_ATTACKS[from] & ~own;
uint64_t caps = mask & opp;
if (!captures_only) {
uint64_t quiet = mask & ~opp;
while (quiet) {
int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE);
}
}
while (caps) {
int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE);
}
if (!captures_only) {
uint64_t occ = b->occ[BOTH];
if (side == WHITE) {
if ((b->castling_rights & CASTLE_WK) && !(occ & WK_EMPTY_MASK)) {
push_move(out, n, E1, WK_TO, K, 0, MF_CASTLE);
}
if ((b->castling_rights & CASTLE_WQ) && !(occ & WQ_EMPTY_MASK)) {
push_move(out, n, E1, WQ_TO, K, 0, MF_CASTLE);
}
} else {
if ((b->castling_rights & CASTLE_BK) && !(occ & BK_EMPTY_MASK)) {
push_move(out, n, E8, BK_TO, k, 0, MF_CASTLE);
}
if ((b->castling_rights & CASTLE_BQ) && !(occ & BQ_EMPTY_MASK)) {
push_move(out, n, E8, BQ_TO, k, 0, MF_CASTLE);
}
}
}
}
void print_board(const struct Board *b) {
static const char PIECE_CH[12] = {
'P','N','B','R','Q','K',