home / fornax / fornax-v4-0 / src / bits.h

bits.h



//
//  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 */