Add Pseudo Move Generator #12
@@ -135,6 +135,214 @@ static void push_move(struct Move *out, int *count, int from, int to, uint8_t pi
|
|||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
PAWN struct Movement Psuedo Moves
|
||||||
|
|
||||||
|
|
||||||
|
Separate the white and black pawn logic. Although the logic is similar,
|
||||||
|
by separating the logic, we can isolate the different cases and have clearer parent functions.
|
||||||
|
These pieces are also the only ones that move in opposite ways, meaning we only need
|
||||||
|
to separate out seemingly related code for this case. Additionally, pawns have the
|
||||||
|
most complicated movement patterns and behaviors in the game. Separating out the logic should
|
||||||
|
hopefully make debugging easier.
|
||||||
|
*/
|
||||||
|
static void gen_white_pawn_quiet_pushes(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t occ = b->occ[BOTH];
|
||||||
|
const uint64_t empty = ~occ;
|
||||||
|
|
||||||
|
const uint64_t pawns = b->pieces[P];
|
||||||
|
|
||||||
|
// One-step pushes: shift pawns up by 8 onto empty squares
|
||||||
|
uint64_t one_step = (pawns << 8) & empty;
|
||||||
|
|
||||||
|
// Exclude promotions here (dest on rank 8) — handled by a separate promo-push function
|
||||||
|
uint64_t one_step_no_promo = one_step & ~RANK_8;
|
||||||
|
|
||||||
|
// Two-step pushes: those one-step pawns that landed on rank 3 can go one more if still empty
|
||||||
|
// (means they originally stood on rank 2)
|
||||||
|
uint64_t two_step = ((one_step & RANK_3) << 8) & empty;
|
||||||
|
|
||||||
|
uint64_t bb = one_step_no_promo;
|
||||||
|
while (bb) {
|
||||||
|
int to = pop_lsb_index(&bb);
|
||||||
|
int from = to - 8;
|
||||||
|
push_move(out, n, from, to, P, 0, MF_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bb = two_step;
|
||||||
|
while (bb) {
|
||||||
|
int to = pop_lsb_index(&bb);
|
||||||
|
int from = to - 16;
|
||||||
|
push_move(out, n, from, to, P, 0, MF_DOUBLE_PUSH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_black_pawn_quiet_pushes(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t occ = b->occ[BOTH];
|
||||||
|
const uint64_t empty = ~occ;
|
||||||
|
|
||||||
|
const uint64_t pawns = b->pieces[p];
|
||||||
|
|
||||||
|
// One-step pushes: shift pawns down by 8 onto empty squares
|
||||||
|
uint64_t one_step = (pawns >> 8) & empty;
|
||||||
|
|
||||||
|
// Exclude promotions here (dest on rank 1) — handle in a promo-push function
|
||||||
|
uint64_t one_step_no_promo = one_step & ~RANK_1;
|
||||||
|
|
||||||
|
uint64_t two_step = ((one_step & RANK_6) >> 8) & empty;
|
||||||
|
|
||||||
|
uint64_t bb = one_step_no_promo;
|
||||||
|
while (bb) {
|
||||||
|
int to = pop_lsb_index(&bb);
|
||||||
|
int from = to + 8;
|
||||||
|
push_move(out, n, from, to, p, 0, MF_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bb = two_step;
|
||||||
|
while (bb) {
|
||||||
|
int to = pop_lsb_index(&bb);
|
||||||
|
int from = to + 16;
|
||||||
|
push_move(out, n, from, to, p, 0, MF_DOUBLE_PUSH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will only allow pawns to promote to queen. Technically, they should be allowed
|
||||||
|
// to promote to any of the following: Rook, Bishop, Knight, Queen.
|
||||||
|
static void gen_white_pawn_push_promotions(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t occ = b->occ[BOTH];
|
||||||
|
const uint64_t empty = ~occ;
|
||||||
|
const uint64_t pawns = b->pieces[P];
|
||||||
|
|
||||||
|
// destinations on rank 8 reachable by a single push
|
||||||
|
uint64_t promos = ((pawns << 8) & empty) & RANK_8;
|
||||||
|
|
||||||
|
while (promos) {
|
||||||
|
int to = pop_lsb_index(&promos);
|
||||||
|
int from = to - 8;
|
||||||
|
push_move(out, n, from, to, P, Q, MF_PROMO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_black_pawn_push_promotions(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t occ = b->occ[BOTH];
|
||||||
|
const uint64_t empty = ~occ;
|
||||||
|
const uint64_t pawns = b->pieces[p];
|
||||||
|
|
||||||
|
// destinations on rank 1 reachable by a single push
|
||||||
|
uint64_t promos = ((pawns >> 8) & empty) & RANK_1;
|
||||||
|
|
||||||
|
while (promos) {
|
||||||
|
int to = pop_lsb_index(&promos);
|
||||||
|
int from = to + 8;
|
||||||
|
push_move(out, n, from, to, p, q, MF_PROMO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_white_pawn_capture_promotions(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t opp = b->occ[BLACK];
|
||||||
|
// left capture (from white view): +7, mask off file A
|
||||||
|
uint64_t left = ((b->pieces[P] & ~FILE_A) << 7) & opp & RANK_8;
|
||||||
|
while (left) {
|
||||||
|
int to = pop_lsb_index(&left);
|
||||||
|
int from = to - 7;
|
||||||
|
push_move(out, n, from, to, P, Q, MF_CAPTURE | MF_PROMO);
|
||||||
|
}
|
||||||
|
// right capture: +9, mask off file H
|
||||||
|
uint64_t right = ((b->pieces[P] & ~FILE_H) << 9) & opp & RANK_8;
|
||||||
|
while (right) {
|
||||||
|
int to = pop_lsb_index(&right);
|
||||||
|
int from = to - 9;
|
||||||
|
push_move(out, n, from, to, P, Q, MF_CAPTURE | MF_PROMO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_black_pawn_capture_promotions(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t opp = b->occ[WHITE];
|
||||||
|
// from black view, “left” is -7 (mask off file H before shifting)
|
||||||
|
uint64_t left = ((b->pieces[p] & ~FILE_H) >> 7) & opp & RANK_1;
|
||||||
|
while (left) {
|
||||||
|
int to = pop_lsb_index(&left);
|
||||||
|
int from = to + 7;
|
||||||
|
push_move(out, n, from, to, p, q, MF_CAPTURE | MF_PROMO);
|
||||||
|
}
|
||||||
|
// “right” is -9 (mask off file A)
|
||||||
|
uint64_t right = ((b->pieces[p] & ~FILE_A) >> 9) & opp & RANK_1;
|
||||||
|
while (right) {
|
||||||
|
int to = pop_lsb_index(&right);
|
||||||
|
int from = to + 9;
|
||||||
|
push_move(out, n, from, to, p, q, MF_CAPTURE | MF_PROMO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_white_pawn_captures(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t pawns = b->pieces[P];
|
||||||
|
const uint64_t opp = b->occ[BLACK];
|
||||||
|
|
||||||
|
// Normal captures (exclude promotion rank)
|
||||||
|
uint64_t left_caps = ((pawns & ~FILE_A) << 7) & opp & ~RANK_8;
|
||||||
|
uint64_t right_caps = ((pawns & ~FILE_H) << 9) & opp & ~RANK_8;
|
||||||
|
|
||||||
|
// Emit normal captures
|
||||||
|
while (left_caps) {
|
||||||
|
int to = pop_lsb_index(&left_caps);
|
||||||
|
int from = to - 7;
|
||||||
|
push_move(out, n, from, to, P, 0, MF_CAPTURE);
|
||||||
|
}
|
||||||
|
while (right_caps) {
|
||||||
|
int to = pop_lsb_index(&right_caps);
|
||||||
|
int from = to - 9;
|
||||||
|
push_move(out, n, from, to, P, 0, MF_CAPTURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// En passant (destination is ep_square)
|
||||||
|
if (b->ep_square >= 0) {
|
||||||
|
uint64_t ep = 1ULL << b->ep_square;
|
||||||
|
|
||||||
|
// From-squares that can capture onto ep (reverse of +7/+9)
|
||||||
|
uint64_t ep_from = (((ep & ~FILE_H) >> 7) | ((ep & ~FILE_A) >> 9)) & pawns;
|
||||||
|
|
||||||
|
while (ep_from) {
|
||||||
|
int from = pop_lsb_index(&ep_from);
|
||||||
|
int to = b->ep_square;
|
||||||
|
// EP never promotes, so no promo piece; still a capture
|
||||||
|
push_move(out, n, from, to, P, 0, MF_CAPTURE | MF_ENPASSANT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_black_pawn_captures(const struct Board *b, struct Move *out, int *n) {
|
||||||
|
const uint64_t pawns = b->pieces[p];
|
||||||
|
const uint64_t opp = b->occ[WHITE];
|
||||||
|
|
||||||
|
// Normal captures (exclude promotion rank)
|
||||||
|
uint64_t left_caps = ((pawns & ~FILE_H) >> 7) & opp & ~RANK_1; // from black POV, "left" is -7
|
||||||
|
uint64_t right_caps = ((pawns & ~FILE_A) >> 9) & opp & ~RANK_1; // "right" is -9
|
||||||
|
|
||||||
|
while (left_caps) {
|
||||||
|
int to = pop_lsb_index(&left_caps);
|
||||||
|
int from = to + 7;
|
||||||
|
push_move(out, n, from, to, p, 0, MF_CAPTURE);
|
||||||
|
}
|
||||||
|
while (right_caps) {
|
||||||
|
int to = pop_lsb_index(&right_caps);
|
||||||
|
int from = to + 9;
|
||||||
|
push_move(out, n, from, to, p, 0, MF_CAPTURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// En passant
|
||||||
|
if (b->ep_square >= 0) {
|
||||||
|
uint64_t ep = 1ULL << b->ep_square;
|
||||||
|
|
||||||
|
// From-squares that can capture onto ep (reverse of -7/-9)
|
||||||
|
uint64_t ep_from = (((ep & ~FILE_A) << 7) | ((ep & ~FILE_H) << 9)) & pawns;
|
||||||
|
|
||||||
|
while (ep_from) {
|
||||||
|
int from = pop_lsb_index(&ep_from);
|
||||||
|
int to = b->ep_square;
|
||||||
|
push_move(out, n, from, to, p, 0, MF_CAPTURE | MF_ENPASSANT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user