#include "../moves.h" #define add_promote_moves(other_flags) \ add_move(moves, from, to, .flags = other_flags | MOVE_PROMOTE_Q); \ add_move(moves, from, to, .flags = other_flags | MOVE_PROMOTE_R); \ add_move(moves, from, to, .flags = other_flags | MOVE_PROMOTE_B); \ add_move(moves, from, to, .flags = other_flags | MOVE_PROMOTE_N) bitboard_t get_white_pawn_forwardmoves(moves_t* moves, position_t position) { bitboard_t enemy_bitboard = blacks(position); bitboard_t friendly_pieces = whites(position); bitboard_t friendly_pawns = position.bitboards[WHITE_PAWN]; bitboard_t y = friendly_pieces | enemy_bitboard; bitboard_t x = ~((friendly_pawns << 8) & y) & (friendly_pawns << 8); bitboard_t first_move_x = x & BITMASK_RANK_3; first_move_x |= (first_move_x << 8) & (~y); x |= first_move_x; return x; } bitboard_t get_black_pawn_forwardmoves(moves_t* moves, position_t position) { bitboard_t enemy_bitboard = whites(position); bitboard_t friendly_pieces = blacks(position); bitboard_t friendly_pawns = position.bitboards[BLACK_PAWN]; bitboard_t y = friendly_pieces | enemy_bitboard; bitboard_t x = ~((friendly_pawns >> 8) & y) & (friendly_pawns >> 8); bitboard_t first_move_x = x & BITMASK_RANK_6; first_move_x |= (first_move_x >> 8) & (~y); x |= first_move_x; return x; } void get_pawn_moves(moves_t* moves, position_t position) { assert_valid_position(position); bitboard_t forward_moves; bitboard_t friendly_pawns; bitboard_t enemy_bitboard; if (position.turn == WHITE_TURN) { forward_moves = get_white_pawn_forwardmoves(moves, position); friendly_pawns = position.bitboards[WHITE_PAWN]; enemy_bitboard = blacks(position); } else { forward_moves = get_black_pawn_forwardmoves(moves, position); friendly_pawns = position.bitboards[BLACK_PAWN]; enemy_bitboard = whites(position); } bitboard_t file_masks[8] = { BITMASK_FILE_A, BITMASK_FILE_B, BITMASK_FILE_C, BITMASK_FILE_D, BITMASK_FILE_E, BITMASK_FILE_F, BITMASK_FILE_G, BITMASK_FILE_H, }; for (int i = 0; i < 8; i++) { bitboard_t item = file_masks[i] & forward_moves; bitboard_t pawns = file_masks[i] & friendly_pawns; int from = __builtin_ctzll(pawns); pawns &= (pawns - 1); int next_from = __builtin_ctzll(pawns); if (pawns == 0) next_from = 64; // to work around UB while (item) { int to = __builtin_ctzll(item); if (to > next_from) { from = next_from; pawns &= (pawns - 1); next_from = __builtin_ctzll(pawns); if (pawns == 0) next_from = 64; } item &= (item - 1); if (to >= 56 || to <= 7) { add_promote_moves(0); } else add_move(moves, from, to); } } if (position.passantable_file != 0) { bitboard_t PASSANT_RANK; int rank_shift; int from_shift; if (position.turn == WHITE_TURN) { PASSANT_RANK = BITMASK_RANK_5; rank_shift = 40; from_shift = -9; } else { PASSANT_RANK = BITMASK_RANK_4; from_shift = 7; rank_shift = 16; } int left = 0, right = 0; if (position.passantable_file > 1) left = position.passantable_file - 1; if (position.passantable_file < 8) right = position.passantable_file + 1; if (left != 0) { bitboard_t MASK = file_masks[left - 1] & friendly_pawns & PASSANT_RANK; if (MASK != 0) { int from = left + rank_shift + from_shift; int to = position.passantable_file + rank_shift - 1; if (to >= 56 || to <= 7) { add_promote_moves(MOVE_EN_PASSANT | MOVE_CAPTURE); } else add_move( moves, from, to, .flags = MOVE_EN_PASSANT | MOVE_CAPTURE ); } } if (right != 0) { bitboard_t MASK = file_masks[right - 1] & friendly_pawns & PASSANT_RANK; if (MASK != 0) { int from = right + rank_shift + from_shift; int to = position.passantable_file + rank_shift - 1; if (to >= 56 || to <= 7) { add_promote_moves(MOVE_EN_PASSANT | MOVE_CAPTURE); } else add_move( moves, from, to, .flags = MOVE_EN_PASSANT | MOVE_CAPTURE ); } } } bitboard_t ATTACK_MASK; int shift; if (position.turn == WHITE_TURN) { shift = 0; } else { shift = -16; } for (int i = 0; i < 8; i++) { if (i == 0) ATTACK_MASK = 512; else if (i == 7) ATTACK_MASK = 128; else { ATTACK_MASK = 640; } bitboard_t pawns = file_masks[i] & friendly_pawns; while (pawns) { int from = __builtin_ctzll(pawns); pawns &= pawns - 1; bitboard_t MASK; if (from + shift > 0) { MASK = ATTACK_MASK << (from + shift); } else { MASK = ATTACK_MASK >> -(from + shift); } MASK &= enemy_bitboard; while (MASK) { int to = __builtin_ctzll(MASK); MASK &= MASK - 1; if (to >= 56 || to <= 7) { add_promote_moves(MOVE_CAPTURE); } else add_move(moves, from, to, .flags = MOVE_CAPTURE); } } } }