//
// 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(square) (square < 64)
#define SQUARE_FLATTEN(x, y) ((square) (x + (y << 3)))
#define SQUARE_X(square) (square & 7)
#define SQUARE_Y(square) (square / 8)
#define SQUARE_MIRROR(position) (square ^ 56)
#define SQUARE_NONE 64
typedef uint64_t bits64;
#define BITS_FROM_SQUARE(position) (((bits64)1U) << position)
#define BITS_SET(bits, position) ((bits) |= ((bits64)1U) << (position))
#define BITS_CLEAR(bits, position) ((bits) &= ~(((bits64)1U) << (position)))
#define BITS_REMOVE(bits, position) ((bits) -= (((bits64)1U) << (position)))
#define BITS_TEST(bits, position) (((bits) >> (position)) & 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)
typedef enum {
N = 0,
E,
S,
W,
NE,
SE,
SW,
NW,
} direction;
#define BB_RANK8 0xff00000000000000
#define BB_RANK7 0x00ff000000000000
#define BB_RANK6 0x0000ff0000000000
#define BB_RANK5 0x000000ff00000000
#define BB_RANK4 0x00000000ff000000
#define BB_RANK3 0x0000000000ff0000
#define BB_RANK2 0x000000000000ff00
#define BB_RANK1 0x00000000000000ff
static constexpr bits64 BB_RANKS[8] = {
BB_RANK1, BB_RANK2, BB_RANK3, BB_RANK4,
BB_RANK5, BB_RANK6, BB_RANK7, BB_RANK8
};
#define BB_FILE_H ((bits64) 0x8080808080808080)
#define BB_FILE_G ((bits64) 0x4040404040404040)
#define BB_FILE_F ((bits64) 0x2020202020202020)
#define BB_FILE_E ((bits64) 0x1010101010101010)
#define BB_FILE_D ((bits64) 0x0808080808080808)
#define BB_FILE_C ((bits64) 0x0404040404040404)
#define BB_FILE_B ((bits64) 0x0202020202020202)
#define BB_FILE_A ((bits64) 0x0101010101010101)
static 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
};
#define BB_MAX ((bits64) -1)
#define BB_LSB ((bits64) 1U)
#define BB_MSB (BB_LSB << 63)
#define BB_RIGHTS_WCQ 0x0000000000000001
#define BB_RIGHTS_WCK 0x0000000000000080
#define BB_RIGHTS_BCQ 0x0100000000000000
#define BB_RIGHTS_BCK 0x8000000000000000
#define BB_REQUIRED_EMPTY_WCK 0x0000000000000060
#define BB_REQUIRED_EMPTY_WCQ 0x000000000000000e
#define BB_REQUIRED_EMPTY_BCK 0x6000000000000000
#define BB_REQUIRED_EMPTY_BCQ 0x0e00000000000000
#define BB_CENTERMASK4 0x1818000000
#define BB_CENTERMASK16 0x3c3c3c3c0000
#define 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 position = (square)__builtin_ctzll(bits);
return position;
}
static constexpr square bits_get_leading(bits64 bits) {
assert(bits > 0);
square position = 63 - (square)__builtin_clzll(bits);
return position;
}
static constexpr square bits_pop_trailing(bits64 *bits) {
assert(*bits > 0);
square position = (square)__builtin_ctzll(*bits);
*bits &= *bits - 1;
return position;
}
static constexpr square bits_pop_leading(bits64 *bits) {
assert(*bits > 0);
square position = 63 - (square)__builtin_clzll(*bits);
*bits -= BITS_FROM_SQUARE(position);
return position;
}
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 */