#ifndef BITBOARD_H_INCLUDED
#define BITBOARD_H_INCLUDED

#include <stdint.h>
#include <stdio.h>
#include "ramjet.h"

// the bitboard data type
typedef uint64_t BITBOARD;

// square selection
#define BB_CONST(val) (UINT64_C(val))
#define BB_NULL (BB_CONST(0x0000000000000000))
#define BB_ALL(x) ((BITBOARD) (-((int64_t) (x))))
#define BB_SQ(sq) (BB_CONST(0x0000000000000001) << (sq))

// rays on an empty board (including origin square)
extern BITBOARD bb_diag[64];
extern BITBOARD bb_anti[64];
#define BB_RANK(sq) (BB_CONST(0x00000000000000FF) << ((sq) & ~7))
#define BB_FILE(sq) (BB_CONST(0x0101010101010101) << SQ_FILE(sq))

// leapers on an empty board (no origin square)
extern BITBOARD bb_k_leap[64];
extern BITBOARD bb_n_leap[64];

// en-passant attackers
extern BITBOARD bb_ep_atk[65];

// castle occupancy mask[from][to] on both rank 1 and 8
extern BITBOARD bb_castle_occ[8][8];
#define BB_CASTLE_CHECK(from, to) ((((BB_SQ(from) - 1) ^ (BB_SQ(to) - 1)) & ~BB_SQ(to)) | BB_SQ(from))

// generalised left shift operator
BITBOARD bb_shift(BITBOARD bb, int i);

// initialise the constants
void bb_init();

// return the index of the least significant bit
int bb_lsb_sq(BITBOARD bb);
int bb_lsb_next(BITBOARD* bb); // (read and reset)

// return the number of bits that are on
int bb_pop_count(BITBOARD bb);

// true for single populated bitboards
int is_bb_single(BITBOARD bb);

// sliding attacks along the four rays (no origin square)
BITBOARD bb_diag_atk(BITBOARD occ, SQUARE sq);
BITBOARD bb_anti_atk(BITBOARD occ, SQUARE sq);
BITBOARD bb_rank_atk(BITBOARD occ, SQUARE sq);
BITBOARD bb_file_atk(BITBOARD occ, SQUARE sq);

// rook and bishop combo attacks
BITBOARD bb_b_slide(BITBOARD occ, SQUARE sq);
BITBOARD bb_r_slide(BITBOARD occ, SQUARE sq);

// colour-dependent shifts
BITBOARD bb_front(BITBOARD bb, PLAYER pl);
BITBOARD bb_front_45(BITBOARD bb, PLAYER pl);
BITBOARD bb_dia_w(BITBOARD bb, PLAYER pl);
BITBOARD bb_dia_e(BITBOARD bb, PLAYER pl);

// pawn combo attacks and pushes
BITBOARD bb_p_atk(SQUARE sq, PLAYER pl);
BITBOARD bb_p_push(BITBOARD occ, SQUARE sq, PLAYER pl);

// print the bitboard in 0-1 format
void bb_print_01(FILE* fp, BITBOARD bb);

// test the functions above
int bb_test();

#endif // BITBOARD_H_INCLUDED
