Add Pseudo Move Generator #12

Merged
Josh merged 17 commits from 7-add-pseudo-move-generator into main 2025-08-18 00:28:00 +00:00
Showing only changes of commit c37c85d99e - Show all commits

View File

@@ -61,14 +61,14 @@ void create_king_attack_cache(void) {
} }
} }
static int first_set_index(uint64_t bb) { int first_set_index(uint64_t bb) {
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
if ((bb >> i) & 1ULL) return i; if ((bb >> i) & 1ULL) return i;
} }
return -1; return -1;
} }
static int pop_lsb_index(uint64_t *bb) { int pop_lsb_index(uint64_t *bb) {
if (*bb == 0) return -1; if (*bb == 0) return -1;
int idx = first_set_index(*bb); int idx = first_set_index(*bb);
// Clears bit. // Clears bit.
@@ -76,7 +76,7 @@ static int pop_lsb_index(uint64_t *bb) {
return idx; return idx;
} }
static uint64_t ray_attacks(int start_square, int delta_file, int delta_rank, uint64_t occupied) uint64_t ray_attacks(int start_square, int delta_file, int delta_rank, uint64_t occupied)
{ {
uint64_t attacks = 0; uint64_t attacks = 0;
@@ -104,28 +104,28 @@ static uint64_t ray_attacks(int start_square, int delta_file, int delta_rank, ui
return attacks; return attacks;
} }
static uint64_t rook_attacks(int square, uint64_t occupied) { uint64_t rook_attacks(int square, uint64_t occupied) {
return ray_attacks(square, +1, 0, occupied) // east return ray_attacks(square, +1, 0, occupied) // east
| ray_attacks(square, -1, 0, occupied) // west | ray_attacks(square, -1, 0, occupied) // west
| ray_attacks(square, 0, +1, occupied) // north | ray_attacks(square, 0, +1, occupied) // north
| ray_attacks(square, 0, -1, occupied); // south | ray_attacks(square, 0, -1, occupied); // south
} }
static uint64_t bishop_attacks(int square, uint64_t occupied) { uint64_t bishop_attacks(int square, uint64_t occupied) {
return ray_attacks(square, +1, +1, occupied) // NE return ray_attacks(square, +1, +1, occupied) // NE
| ray_attacks(square, -1, +1, occupied) // NW | ray_attacks(square, -1, +1, occupied) // NW
| ray_attacks(square, +1, -1, occupied) // SE | ray_attacks(square, +1, -1, occupied) // SE
| ray_attacks(square, -1, -1, occupied); // SW | ray_attacks(square, -1, -1, occupied); // SW
} }
static uint64_t queen_attacks(int square, uint64_t occupied) { uint64_t queen_attacks(int square, uint64_t occupied) {
// Simply combine both types of attacks // Simply combine both types of attacks
return rook_attacks(square, occupied) | bishop_attacks(square, occupied); 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) void push_move(struct Move *out, int *count, int from, int to, uint8_t piece, uint8_t promo, uint8_t flags)
{ {
out[*count] = (Move){ out[*count] = (struct Move){
.from = (uint16_t)from, .from = (uint16_t)from,
.to = (uint16_t)to, .to = (uint16_t)to,
.piece = piece, .piece = piece,
@@ -146,7 +146,7 @@ static void push_move(struct Move *out, int *count, int from, int to, uint8_t pi
most complicated movement patterns and behaviors in the game. Separating out the logic should most complicated movement patterns and behaviors in the game. Separating out the logic should
hopefully make debugging easier. hopefully make debugging easier.
*/ */
static void gen_white_pawn_quiet_pushes(const struct Board *b, struct Move *out, int *n) { void gen_white_pawn_quiet_pushes(const struct Board *b, struct Move *out, int *count) {
const uint64_t occ = b->occ[BOTH]; const uint64_t occ = b->occ[BOTH];
const uint64_t empty = ~occ; const uint64_t empty = ~occ;
@@ -166,18 +166,18 @@ static void gen_white_pawn_quiet_pushes(const struct Board *b, struct Move *out,
while (bb) { while (bb) {
int to = pop_lsb_index(&bb); int to = pop_lsb_index(&bb);
int from = to - 8; int from = to - 8;
push_move(out, n, from, to, P, 0, MF_NONE); push_move(out, count, from, to, P, 0, MF_NONE);
} }
bb = two_step; bb = two_step;
while (bb) { while (bb) {
int to = pop_lsb_index(&bb); int to = pop_lsb_index(&bb);
int from = to - 16; int from = to - 16;
push_move(out, n, from, to, P, 0, MF_DOUBLE_PUSH); push_move(out, count, from, to, P, 0, MF_DOUBLE_PUSH);
} }
} }
static void gen_black_pawn_quiet_pushes(const struct Board *b, struct Move *out, int *n) { void gen_black_pawn_quiet_pushes(const struct Board *b, struct Move *out, int *count) {
const uint64_t occ = b->occ[BOTH]; const uint64_t occ = b->occ[BOTH];
const uint64_t empty = ~occ; const uint64_t empty = ~occ;
@@ -195,20 +195,20 @@ static void gen_black_pawn_quiet_pushes(const struct Board *b, struct Move *out,
while (bb) { while (bb) {
int to = pop_lsb_index(&bb); int to = pop_lsb_index(&bb);
int from = to + 8; int from = to + 8;
push_move(out, n, from, to, p, 0, MF_NONE); push_move(out, count,from, to, p, 0, MF_NONE);
} }
bb = two_step; bb = two_step;
while (bb) { while (bb) {
int to = pop_lsb_index(&bb); int to = pop_lsb_index(&bb);
int from = to + 16; int from = to + 16;
push_move(out, n, from, to, p, 0, MF_DOUBLE_PUSH); push_move(out, count,from, to, p, 0, MF_DOUBLE_PUSH);
} }
} }
// We will only allow pawns to promote to queen. Technically, they should be allowed // 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. // 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) { void gen_white_pawn_push_promotions(const struct Board *b, struct Move *out, int *count) {
const uint64_t occ = b->occ[BOTH]; const uint64_t occ = b->occ[BOTH];
const uint64_t empty = ~occ; const uint64_t empty = ~occ;
const uint64_t pawns = b->pieces[P]; const uint64_t pawns = b->pieces[P];
@@ -219,11 +219,11 @@ static void gen_white_pawn_push_promotions(const struct Board *b, struct Move *o
while (promos) { while (promos) {
int to = pop_lsb_index(&promos); int to = pop_lsb_index(&promos);
int from = to - 8; int from = to - 8;
push_move(out, n, from, to, P, Q, MF_PROMO); push_move(out, count, from, to, P, Q, MF_PROMO);
} }
} }
static void gen_black_pawn_push_promotions(const struct Board *b, struct Move *out, int *n) { void gen_black_pawn_push_promotions(const struct Board *b, struct Move *out, int *count) {
const uint64_t occ = b->occ[BOTH]; const uint64_t occ = b->occ[BOTH];
const uint64_t empty = ~occ; const uint64_t empty = ~occ;
const uint64_t pawns = b->pieces[p]; const uint64_t pawns = b->pieces[p];
@@ -234,47 +234,47 @@ static void gen_black_pawn_push_promotions(const struct Board *b, struct Move *o
while (promos) { while (promos) {
int to = pop_lsb_index(&promos); int to = pop_lsb_index(&promos);
int from = to + 8; int from = to + 8;
push_move(out, n, from, to, p, q, MF_PROMO); push_move(out, count, from, to, p, q, MF_PROMO);
} }
} }
static void gen_white_pawn_capture_promotions(const struct Board *b, struct Move *out, int *n) { void gen_white_pawn_capture_promotions(const struct Board *b, struct Move *out, int *count) {
const uint64_t opp = b->occ[BLACK]; const uint64_t opp = b->occ[BLACK];
// left capture (from white view): +7, mask off file A // left capture (from white view): +7, mask off file A
uint64_t left = ((b->pieces[P] & ~FILE_A) << 7) & opp & RANK_8; uint64_t left = ((b->pieces[P] & ~FILE_A) << 7) & opp & RANK_8;
while (left) { while (left) {
int to = pop_lsb_index(&left); int to = pop_lsb_index(&left);
int from = to - 7; int from = to - 7;
push_move(out, n, from, to, P, Q, MF_CAPTURE | MF_PROMO); push_move(out, count,from, to, P, Q, MF_CAPTURE | MF_PROMO);
} }
// right capture: +9, mask off file H // right capture: +9, mask off file H
uint64_t right = ((b->pieces[P] & ~FILE_H) << 9) & opp & RANK_8; uint64_t right = ((b->pieces[P] & ~FILE_H) << 9) & opp & RANK_8;
while (right) { while (right) {
int to = pop_lsb_index(&right); int to = pop_lsb_index(&right);
int from = to - 9; int from = to - 9;
push_move(out, n, from, to, P, Q, MF_CAPTURE | MF_PROMO); push_move(out, count,from, to, P, Q, MF_CAPTURE | MF_PROMO);
} }
} }
static void gen_black_pawn_capture_promotions(const struct Board *b, struct Move *out, int *n) { void gen_black_pawn_capture_promotions(const struct Board *b, struct Move *out, int *count) {
const uint64_t opp = b->occ[WHITE]; const uint64_t opp = b->occ[WHITE];
// from black view, “left” is -7 (mask off file H before shifting) // from black view, “left” is -7 (mask off file H before shifting)
uint64_t left = ((b->pieces[p] & ~FILE_H) >> 7) & opp & RANK_1; uint64_t left = ((b->pieces[p] & ~FILE_H) >> 7) & opp & RANK_1;
while (left) { while (left) {
int to = pop_lsb_index(&left); int to = pop_lsb_index(&left);
int from = to + 7; int from = to + 7;
push_move(out, n, from, to, p, q, MF_CAPTURE | MF_PROMO); push_move(out, count,from, to, p, q, MF_CAPTURE | MF_PROMO);
} }
// “right” is -9 (mask off file A) // “right” is -9 (mask off file A)
uint64_t right = ((b->pieces[p] & ~FILE_A) >> 9) & opp & RANK_1; uint64_t right = ((b->pieces[p] & ~FILE_A) >> 9) & opp & RANK_1;
while (right) { while (right) {
int to = pop_lsb_index(&right); int to = pop_lsb_index(&right);
int from = to + 9; int from = to + 9;
push_move(out, n, from, to, p, q, MF_CAPTURE | MF_PROMO); push_move(out, count,from, to, p, q, MF_CAPTURE | MF_PROMO);
} }
} }
static void gen_white_pawn_captures(const struct Board *b, struct Move *out, int *n) { void gen_white_pawn_captures(const struct Board *b, struct Move *out, int *count) {
const uint64_t pawns = b->pieces[P]; const uint64_t pawns = b->pieces[P];
const uint64_t opp = b->occ[BLACK]; const uint64_t opp = b->occ[BLACK];
@@ -286,12 +286,12 @@ static void gen_white_pawn_captures(const struct Board *b, struct Move *out, int
while (left_caps) { while (left_caps) {
int to = pop_lsb_index(&left_caps); int to = pop_lsb_index(&left_caps);
int from = to - 7; int from = to - 7;
push_move(out, n, from, to, P, 0, MF_CAPTURE); push_move(out, count,from, to, P, 0, MF_CAPTURE);
} }
while (right_caps) { while (right_caps) {
int to = pop_lsb_index(&right_caps); int to = pop_lsb_index(&right_caps);
int from = to - 9; int from = to - 9;
push_move(out, n, from, to, P, 0, MF_CAPTURE); push_move(out, count,from, to, P, 0, MF_CAPTURE);
} }
// En passant (destination is ep_square) // En passant (destination is ep_square)
@@ -305,12 +305,12 @@ static void gen_white_pawn_captures(const struct Board *b, struct Move *out, int
int from = pop_lsb_index(&ep_from); int from = pop_lsb_index(&ep_from);
int to = b->ep_square; int to = b->ep_square;
// EP never promotes, so no promo piece; still a capture // EP never promotes, so no promo piece; still a capture
push_move(out, n, from, to, P, 0, MF_CAPTURE | MF_ENPASSANT); push_move(out, count,from, to, P, 0, MF_CAPTURE | MF_ENPASSANT);
} }
} }
} }
static void gen_black_pawn_captures(const struct Board *b, struct Move *out, int *n) { void gen_black_pawn_captures(const struct Board *b, struct Move *out, int *count) {
const uint64_t pawns = b->pieces[p]; const uint64_t pawns = b->pieces[p];
const uint64_t opp = b->occ[WHITE]; const uint64_t opp = b->occ[WHITE];
@@ -321,12 +321,12 @@ static void gen_black_pawn_captures(const struct Board *b, struct Move *out, int
while (left_caps) { while (left_caps) {
int to = pop_lsb_index(&left_caps); int to = pop_lsb_index(&left_caps);
int from = to + 7; int from = to + 7;
push_move(out, n, from, to, p, 0, MF_CAPTURE); push_move(out, count,from, to, p, 0, MF_CAPTURE);
} }
while (right_caps) { while (right_caps) {
int to = pop_lsb_index(&right_caps); int to = pop_lsb_index(&right_caps);
int from = to + 9; int from = to + 9;
push_move(out, n, from, to, p, 0, MF_CAPTURE); push_move(out, count,from, to, p, 0, MF_CAPTURE);
} }
// En passant // En passant
@@ -339,7 +339,7 @@ static void gen_black_pawn_captures(const struct Board *b, struct Move *out, int
while (ep_from) { while (ep_from) {
int from = pop_lsb_index(&ep_from); int from = pop_lsb_index(&ep_from);
int to = b->ep_square; int to = b->ep_square;
push_move(out, n, from, to, p, 0, MF_CAPTURE | MF_ENPASSANT); push_move(out, count,from, to, p, 0, MF_CAPTURE | MF_ENPASSANT);
} }
} }
} }
@@ -351,7 +351,7 @@ static void gen_black_pawn_captures(const struct Board *b, struct Move *out, int
*/ */
static void gen_knight_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) { void gen_knight_moves(const struct Board *b, struct Move *out, int *count, bool captures_only) {
enum Color side = b->side_to_move; enum Color side = b->side_to_move;
uint64_t own = b->occ[side]; uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1]; uint64_t opp = b->occ[side ^ 1];
@@ -367,23 +367,23 @@ static void gen_knight_moves(const struct Board *b, struct Move *out, int *n, bo
uint64_t quiet = mask & ~opp; uint64_t quiet = mask & ~opp;
while (quiet) { while (quiet) {
int to = pop_lsb_index(&quiet); int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE); push_move(out, count, from, to, pid, 0, MF_NONE);
} }
} }
while (caps) { while (caps) {
int to = pop_lsb_index(&caps); int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE); push_move(out, count, from, to, pid, 0, MF_CAPTURE);
} }
} }
} }
static void gen_bishop_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) { void gen_bishop_moves(const struct Board *board, struct Move *out, int *count, bool captures_only) {
enum Color side = b->side_to_move; enum Color side = board->side_to_move;
uint64_t own = b->occ[side]; uint64_t own = board->occ[side];
uint64_t opp = b->occ[side ^ 1]; uint64_t opp = board->occ[side ^ 1];
uint64_t occ = b->occ[BOTH]; uint64_t occ = board->occ[BOTH];
uint8_t pid = (side == WHITE) ? B : b; uint8_t pid = (side == WHITE) ? B : b;
uint64_t bb = (side == WHITE) ? b->pieces[B] : b->pieces[b]; uint64_t bb = (side == WHITE) ? board->pieces[B] : board->pieces[b];
while (bb) { while (bb) {
int from = pop_lsb_index(&bb); int from = pop_lsb_index(&bb);
@@ -394,17 +394,17 @@ static void gen_bishop_moves(const struct Board *b, struct Move *out, int *n, bo
uint64_t quiet = mask & ~opp; uint64_t quiet = mask & ~opp;
while (quiet) { while (quiet) {
int to = pop_lsb_index(&quiet); int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE); push_move(out, count, from, to, pid, 0, MF_NONE);
} }
} }
while (caps) { while (caps) {
int to = pop_lsb_index(&caps); int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE); push_move(out, count, from, to, pid, 0, MF_CAPTURE);
} }
} }
} }
static void gen_rook_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) { void gen_rook_moves(const struct Board *b, struct Move *out, int *count, bool captures_only) {
enum Color side = b->side_to_move; enum Color side = b->side_to_move;
uint64_t own = b->occ[side]; uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1]; uint64_t opp = b->occ[side ^ 1];
@@ -421,17 +421,17 @@ static void gen_rook_moves(const struct Board *b, struct Move *out, int *n, bool
uint64_t quiet = mask & ~opp; uint64_t quiet = mask & ~opp;
while (quiet) { while (quiet) {
int to = pop_lsb_index(&quiet); int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE); push_move(out, count,from, to, pid, 0, MF_NONE);
} }
} }
while (caps) { while (caps) {
int to = pop_lsb_index(&caps); int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE); push_move(out, count,from, to, pid, 0, MF_CAPTURE);
} }
} }
} }
static void gen_queen_moves(const struct Board *b, struct Move *out, int *n, bool captures_only) { void gen_queen_moves(const struct Board *b, struct Move *out, int *count, bool captures_only) {
enum Color side = b->side_to_move; enum Color side = b->side_to_move;
uint64_t own = b->occ[side]; uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1]; uint64_t opp = b->occ[side ^ 1];
@@ -448,17 +448,17 @@ static void gen_queen_moves(const struct Board *b, struct Move *out, int *n, boo
uint64_t quiet = mask & ~opp; uint64_t quiet = mask & ~opp;
while (quiet) { while (quiet) {
int to = pop_lsb_index(&quiet); int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE); push_move(out, count,from, to, pid, 0, MF_NONE);
} }
} }
while (caps) { while (caps) {
int to = pop_lsb_index(&caps); int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE); push_move(out, count,from, to, pid, 0, MF_CAPTURE);
} }
} }
} }
static void gen_king_moves(struct Board *b, struct Move *out, int *n, bool captures_only) { void gen_king_moves(struct Board *b, struct Move *out, int *count, bool captures_only) {
enum Color side = b->side_to_move; enum Color side = b->side_to_move;
uint64_t own = b->occ[side]; uint64_t own = b->occ[side];
uint64_t opp = b->occ[side ^ 1]; uint64_t opp = b->occ[side ^ 1];
@@ -474,36 +474,36 @@ static void gen_king_moves(struct Board *b, struct Move *out, int *n, bool captu
uint64_t quiet = mask & ~opp; uint64_t quiet = mask & ~opp;
while (quiet) { while (quiet) {
int to = pop_lsb_index(&quiet); int to = pop_lsb_index(&quiet);
push_move(out, n, from, to, pid, 0, MF_NONE); push_move(out, count,from, to, pid, 0, MF_NONE);
} }
} }
while (caps) { while (caps) {
int to = pop_lsb_index(&caps); int to = pop_lsb_index(&caps);
push_move(out, n, from, to, pid, 0, MF_CAPTURE); push_move(out, count,from, to, pid, 0, MF_CAPTURE);
} }
if (!captures_only) { if (!captures_only) {
uint64_t occ = b->occ[BOTH]; uint64_t occ = b->occ[BOTH];
if (side == WHITE) { if (side == WHITE) {
if ((b->castling_rights & CASTLE_WK) && !(occ & WK_EMPTY_MASK)) { if ((b->castling_rights & CASTLE_WK) && !(occ & WK_EMPTY_MASK)) {
push_move(out, n, E1, WK_TO, K, 0, MF_CASTLE); push_move(out, count,E1, WK_TO, K, 0, MF_CASTLE);
} }
if ((b->castling_rights & CASTLE_WQ) && !(occ & WQ_EMPTY_MASK)) { if ((b->castling_rights & CASTLE_WQ) && !(occ & WQ_EMPTY_MASK)) {
push_move(out, n, E1, WQ_TO, K, 0, MF_CASTLE); push_move(out, count,E1, WQ_TO, K, 0, MF_CASTLE);
} }
} else { } else {
if ((b->castling_rights & CASTLE_BK) && !(occ & BK_EMPTY_MASK)) { if ((b->castling_rights & CASTLE_BK) && !(occ & BK_EMPTY_MASK)) {
push_move(out, n, E8, BK_TO, k, 0, MF_CASTLE); push_move(out, count,E8, BK_TO, k, 0, MF_CASTLE);
} }
if ((b->castling_rights & CASTLE_BQ) && !(occ & BQ_EMPTY_MASK)) { if ((b->castling_rights & CASTLE_BQ) && !(occ & BQ_EMPTY_MASK)) {
push_move(out, n, E8, BQ_TO, k, 0, MF_CASTLE); push_move(out, count,E8, BQ_TO, k, 0, MF_CASTLE);
} }
} }
} }
} }
void print_board(const struct Board *b) { void print_board(const struct Board *b) {
static const char PIECE_CH[12] = { const char PIECE_CH[12] = {
'P','N','B','R','Q','K', 'P','N','B','R','Q','K',
'p','n','b','r','q','k' 'p','n','b','r','q','k'
}; };