//
// bits.h
// fornax3
//
// Created by Anders on 16/12/2020.
//
#ifndef bits_h
#define bits_h
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
typedef uint8_t square;
#define SQUARE_IS_VALID(sq) (sq < 64)
#define SQUARE_FLATTEN(x, y) ((square) (x + (y << 3)))
#define SQUARE_X(sq) (sq & 7)
#define SQUARE_Y(sq) (sq / 8)
#define SQUARE_MIRROR(sq) (sq ^ 56)
#define SQUARE_NONE 64
#define SQUARE_AXIS_NONE 8
typedef uint64_t bits64;
#define BITS_FROM_SQUARE(sq) (((bits64)1U) << sq)
#define BITS_SET(bits, sq) ((bits) |= ((bits64)1U) << (sq))
#define BITS_CLEAR(bits, sq) ((bits) &= ~(((bits64)1U) << (sq)))
#define BITS_REMOVE(bits, sq) ((bits) -= (((bits64)1U) << (sq)))
#define BITS_TEST(bits, sq) (((bits) >> (sq)) & 1U)
#define BITS_COUNT(bits) ((uint8_t) (__builtin_popcountll(bits)))
#define BITS_HAS_MULTIPLE(bits) (bits & (bits - 1))
#define BITS_VERT_MIRROR(bits) __builtin_bswap64(bits)
enum direction : uint8_t {
N = 0,
E,
S,
W,
NE,
SE,
SW,
NW,
};
constexpr bits64 BB_RANK8 = 0xff00000000000000;
constexpr bits64 BB_RANK7 = 0x00ff000000000000;
constexpr bits64 BB_RANK6 = 0x0000ff0000000000;
constexpr bits64 BB_RANK5 = 0x000000ff00000000;
constexpr bits64 BB_RANK4 = 0x00000000ff000000;
constexpr bits64 BB_RANK3 = 0x0000000000ff0000;
constexpr bits64 BB_RANK2 = 0x000000000000ff00;
constexpr bits64 BB_RANK1 = 0x00000000000000ff;
constexpr bits64 BB_RANKS[8] = {
BB_RANK1, BB_RANK2, BB_RANK3, BB_RANK4,
BB_RANK5, BB_RANK6, BB_RANK7, BB_RANK8
};
constexpr bits64 BB_FILE_H = 0x8080808080808080;
constexpr bits64 BB_FILE_G = 0x4040404040404040;
constexpr bits64 BB_FILE_F = 0x2020202020202020;
constexpr bits64 BB_FILE_E = 0x1010101010101010;
constexpr bits64 BB_FILE_D = 0x0808080808080808;
constexpr bits64 BB_FILE_C = 0x0404040404040404;
constexpr bits64 BB_FILE_B = 0x0202020202020202;
constexpr bits64 BB_FILE_A = 0x0101010101010101;
constexpr bits64 BB_FILES[8] = {
BB_FILE_A, BB_FILE_B, BB_FILE_C, BB_FILE_D,
BB_FILE_E, BB_FILE_F, BB_FILE_G, BB_FILE_H
};
constexpr bits64 BB_MAX = (bits64) -1;
constexpr bits64 BB_LSB = 1;
constexpr bits64 BB_MSB = (BB_LSB << 63);
constexpr bits64 BB_RIGHTS_WCQ = 0x0000000000000001;
constexpr bits64 BB_RIGHTS_WCK = 0x0000000000000080;
constexpr bits64 BB_RIGHTS_BCQ = 0x0100000000000000;
constexpr bits64 BB_RIGHTS_BCK = 0x8000000000000000;
constexpr bits64 BB_REQUIRED_EMPTY_WCK = 0x0000000000000060;
constexpr bits64 BB_REQUIRED_EMPTY_WCQ = 0x000000000000000e;
constexpr bits64 BB_REQUIRED_EMPTY_BCK = 0x6000000000000000;
constexpr bits64 BB_REQUIRED_EMPTY_BCQ = 0x0e00000000000000;
constexpr bits64 BB_CENTERMASK4 = 0x1818000000;
constexpr bits64 BB_CENTERMASK16 = 0x3c3c3c3c0000;
constexpr bits64 BB_CORNERS = 0x8100000000000081;
static constexpr bits64 bits_remove_trailing(bits64 bits) {
assert(bits > 0);
return bits & (bits - 1);
}
static constexpr bits64 bits_remove_leading(bits64 bits) {
assert(bits > 0);
return bits - BITS_FROM_SQUARE((63 - __builtin_clzll(bits)));
}
static constexpr square bits_get_trailing(bits64 bits) {
assert(bits > 0);
square sq = (square)__builtin_ctzll(bits);
return sq;
}
static constexpr square bits_get_leading(bits64 bits) {
assert(bits > 0);
square sq = 63 - (square)__builtin_clzll(bits);
return sq;
}
static constexpr square bits_pop_trailing(bits64 *bits) {
assert(*bits > 0);
square sq = (square)__builtin_ctzll(*bits);
*bits &= *bits - 1;
return sq;
}
static constexpr square bits_pop_leading(bits64 *bits) {
assert(*bits > 0);
square sq = 63 - (square)__builtin_clzll(*bits);
*bits -= BITS_FROM_SQUARE(sq);
return sq;
}
template<direction direction>
static constexpr square bits_pop_directional(bits64 *b) {
switch (direction) {
case N: case E: case NW: case NE:
return bits_pop_trailing(b);
case S: case W: case SE: case SW:
return bits_pop_leading(b);
}
}
static inline bool bits_is_multi_bit(bits64 bits) {
return (bits & (bits - 1));
}
static constexpr bits64 bits_from_array(const bool array[64]) {
bits64 bits = 0;
for (int i = 0; i < 64; ++i) if (array[i]) BITS_SET(bits, i);
return BITS_VERT_MIRROR(bits);
}
template<direction direction>
static constexpr uint8_t bits_shift_distance() {
switch (direction) {
case N:
case S:
return 8;
case E:
case W:
return 1;
case NW:
case SE:
return 7;
case NE:
case SW:
return 9;
}
}
template<direction direction, uint8_t n = 1>
static constexpr bits64 bits_shift(bits64 bits) {
switch (direction) {
case N:
case E:
case NW:
case NE:
return bits << bits_shift_distance<direction>() * n;
case S:
case W:
case SE:
case SW:
return bits >> bits_shift_distance<direction>() * n;
}
}
template<direction direction>
static constexpr bits64 bits_add_shift_guards(bits64 bits) {
switch (direction) {
case NE: case E: case SE:
return bits & ~BB_FILE_A;
case SW: case W: case NW:
return bits & ~BB_FILE_H;
default:
return bits;
}
}
template<direction direction, uint8_t n = 1>
static constexpr bits64 bits_shift_guarded(bits64 bits) {
return bits_add_shift_guards<direction>(bits_shift<direction, n>(bits));
}
template<direction direction>
static constexpr bits64 bits_koggestone_occluded_fill(bits64 sliders, bits64 empty) {
empty = bits_add_shift_guards<direction>(empty);
sliders |= empty & bits_shift<direction,1>(sliders);
empty &= bits_shift<direction,1>(empty);
sliders |= empty & bits_shift<direction,2>(sliders);
empty &= bits_shift<direction,2>(empty);
sliders |= empty & bits_shift<direction,4>(sliders);
return sliders;
}
template<direction direction>
static constexpr bits64 bits_koggestone_attacks(bits64 sliders, bits64 empty) {
bits64 fill = bits_koggestone_occluded_fill<direction>(sliders, empty);
return bits_shift_guarded<direction>(fill);
}
static constexpr bits64 bits_koggestone_bishop_attacks(bits64 sliders, bits64 empty) {
return bits_koggestone_attacks<NE>(sliders, empty)
| bits_koggestone_attacks<SE>(sliders, empty)
| bits_koggestone_attacks<SW>(sliders, empty)
| bits_koggestone_attacks<NW>(sliders, empty);
}
static constexpr bits64 bits_koggestone_rook_attacks(bits64 sliders, bits64 empty) {
return bits_koggestone_attacks<N>(sliders, empty)
| bits_koggestone_attacks<E>(sliders, empty)
| bits_koggestone_attacks<S>(sliders, empty)
| bits_koggestone_attacks<W>(sliders, empty);
}
template<direction direction>
static constexpr bits64 bits_fill(bits64 bits) {
static_assert(direction == S || direction == N, "wrong dir");
bits |= bits_shift<direction>(bits);
bits |= bits_shift<direction, 2>(bits);
bits |= bits_shift<direction, 4>(bits);
return bits;
}
#endif /* bits_h */