The bitboard trials OR just say no to magic

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Mike Sherwin
Posts: 860
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

The bitboard trials OR just say no to magic

Post by Mike Sherwin »

Obviously this blog is inspired by HGM's, The mailbox trials. It basically has the same goal however with a bitboard flavor. The idea is to create a quiescent search in MVV-LVA order. Except that the extra work to play p x r before q x q is not going to be done. I figure it will work out rather quickly anyway. Besides it is just an experiment. If it turns out to be slow then I'll have to resort to making a list of moves and then sorting them. Either way the move generator is built right into the Qsearch. And may even be less work to just make the move list.

After each move the from square and to square is processed to incrementally update the u64 to[wtm][ts][ply] array so that to find if a square is attacked is as easy as, if ( to[wtm][square][ply] & 1ull << square) SquareIsAttacked(); So if I have not botched anything this is what the Qsearch looks like.

Code: Select all

s32 Qsearch(Thread* t, s32 alpha, s32 beta) {
  unsigned long index, attacker;
  s32 ts, sort[12], i, j, k, low, score;
  u32 indexes;
  u64 attackers;

  score = Eval(t);
  
  if (score >= beta) return beta;

  indexes = pieces[1 - wtm];

  while (_BitScanReverse(&index, indexes)) {
    indexes ^= 1 << index;
    ts = piece[1 - wtm][index].square;
    attackers = to[wtm][ts][ply];
    i = 0;
    while (_BitScanForward64(&attacker, attackers)) {
      attackers ^= 1ull << attacker;
      sort[i] = board[attacker];
      i++;
    }
    while (i) {
      low = 64;
      for (j = 0; j < i; j++) {
        if (sort[j] < low) {
          low = sort[j];
          k = j;
        }
      }
      sort[k] = INF;
      MakeMove(t, k, ts);
      score = -Qsearch(t, -beta, -alpha);
      TakeBack(t, k, ts);
      if (score > alpha) {
        if (score >= beta) return beta;
        alpha = score;
      }
    }
  }
  return alpha;
}
At first it might look expensive but considering that it also includes the move generator, move sorting and requires a modest amount of memory it does not look bad at all.

We will see shortly... sometime in 2021 ... or maybe 2022 :lol:
Mike Sherwin
Posts: 860
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: The bitboard trials OR just say no to magic

Post by Mike Sherwin »

The above code speculation just captures the MVV first without regard to the value of the attacker. I figured it would quickly work itself out at the next ply. I also thought it good enough for a first try. The idea was the most gain for the least amount of work. However, for very little additional work it could be far more refined.

First the order of what to look for is defined.

Code: Select all

enum {
  KXQU, QXQU, RXQU, BXQU, NXQU, PXQU, PXQP, NXQP, BXQP, KXRU, QXRU, RXRU, BXRU, NXRU, PXRU,
  PXRP, RXQP, KXBU, QXBU, RXBU, BXBU, NXBU, PXBU, KXNU, QXNU, RXNU, BXNU, NXNU, PXNU, PXBP,
  NXRP, PXNP, BXRP, KXPU, QXPU, RXPU, BXPU, NXPU, PXPU
};
Each value is a bit in.

Code: Select all

u64 state[2][100];
This has to be initialized for piece[WHITE][0] and piece[BLACK][0] at the beginning of the game.

Code: Select all

void InitState(Thread* t) {
  s32 sq, piece;
  piece[WHITE][0] = 0;
  piece[BLACK][0] = 0;
  for (sq = a1; sq <= h8; sq++) {
    piece = board[sq];
    if (piece) {
      if (piece <= WK) {
        piece[WHITE][0] ^= one << sq;
      }
      else {
        piece[BLACK][0] ^= one << sq;
      }
      InitStatePC[piece](t, sq);
    }
  }
}
InitStatePC[piece](t, sq); This line is a jump table into each of the initializing functions for the various piece types. This engine's name is Sneaky. Anyway, in sneaky there are more than the standard piece types on the board.
WKC - white king that is on e1 and that has never moved
WK - white king that has moved
Same for rooks, WRC and WR as well as pawns by rank WP2, WP3, ... WP7.

Code: Select all

enum {
  OO,
  WP2, WP3, WP4, WP5, WP6, WP7, WN, WB, WRC, WR, WQ, WKC, WK,
  BP7, BP6, BP5, BP4, BP3, BP2, BN, BB, BRC, BR, BQ, BKC, BK,
  WCS, WCL, BCS, BCL
};
Here is the jumptable definition.

Code: Select all

void (*InitStatePC[])(Thread*, s32) = {
  nullptr,
  InitStateWP, InitStateWP, InitStateWP, InitStateWP, InitStateWP, InitStateWP,
  InitStateWN, InitStateWB, InitStateWR, InitStateWR, InitStateWQ, InitStateWK, InitStateWK,
  InitStateBP, InitStateBP, InitStateBP, InitStateBP, InitStateBP, InitStateBP,
  InitStateBN, InitStateBB, InitStateBR, InitStateBR, InitStateBQ, InitStateBK, InitStateBK,
};
With all this in place it is possible to call the state initialization for each piece type. Here is the initialization for a white queen.

Code: Select all

void InitStateWQ(Thread* t, s32 fs) {
  u32 ts;
  Occ occ.o = piece[WHITE][ply] | piece[BLACK][ply];
  u64 bb = qss[fs][occ.r1][RANK1]
         & qss[fs][occ.r2][RANK2]
         & qss[fs][occ.r3][RANK3]
         & qss[fs][occ.r4][RANK4]
         & qss[fs][occ.r5][RANK5]
         & qss[fs][occ.r6][RANK6]
         & qss[fs][occ.r7][RANK7]
         & qss[fs][occ.r8][RANK8]
         & piece[BLACK][ply];
  while (bb) {
    _BitScanForward64(&ts, bb);
    bb ^= one << ts;
    if (!AttackedByBlack(t, one << ts) {
      state[WHITE][0] |= one << qStateIDU[board[ts];
    }
  }
}
For now I only care about unprotected captures for the queen as equal captures that are protected may or may not be better than just any non capture move. qStateIDU is the lookup table for queen captures.

Code: Select all

s32 wqStateIDU[] = { 
  0,
  WP2, WP3, WP4, WP5, WP6, WP7, WN, WB, WR, WR, WQ, WK, WK,
   34,  34,  34,  34,  34,  34, 24, 18, 10, 10,  1, BK, BK,
};
The piece types are just for visual reference. The numbers are the ID of the state that may or may not be present on the board.
34 - capturing an unprotected black pawn has the lowest priority
24 - capturing an unprotected black knight
18 - capturing an unprotected black bishop
10 - capturing a BRC or BR
01 - capturing a black queen
Mike Sherwin
Posts: 860
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: The bitboard trials OR just say no to magic

Post by Mike Sherwin »

Here are all the state IDU and IDP tables. U means unprotected and P means protected. The king, queen and rook do not have IDP tables. The king and queen because they are not applicable. And the rook because it can ONLY capture a protected queen in this phase;

Code: Select all

s32 wkStateIDU[] = {
  0,
   WP2,  WP3,  WP4,  WP5,  WP6,  WP7,   WN,   WB,  WRC,   WR,   WQ, WKC, WK,
  KXPU, KXPU, KXPU, KXPU, KXPU, KXPU, KXNU, KXBU, KXRU, KXRU, KXQU, BKC, BK,
};

s32 bkStateIDU[] = {
  0,
  KXPU, KXPU, KXPU, KXPU, KXPU, KXPU, KXNU, KXBU, KXRU, KXRU, KXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};


s32 wqStateIDU[] = { 
  0,
   WP2,  WP3,  WP4,  WP5,  WP6,  WP7,   WN,   WB,  WRC,   WR,   WQ, WKC, WK,
  QXPU, QXPU, QXPU, QXPU, QXPU, QXPU, QXNU, QXBU, QXRU, QXRU, QXQU, BKC, BK,
};

s32 bqStateIDU[] = {
  0,
  QXPU, QXPU, QXPU, QXPU, QXPU, QXPU, QXNU, QXBU, QXRU, QXRU, QXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

S32 wrStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  RXPU, RXPU, RXPU, RXPU, RXPU, RXPU, RXNU, RXBU, RXRU, RXRU, RXQU, BKC, BK,
};

S32 brStateIDU[] = {
  0,
  RXPU, RXPU, RXPU, RXPU, RXPU, RXPU, RXNU, RXBU, RXRU, RXRU, RXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

S32 wbStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BXPU, BXPU, BXPU, BXPU, BXPU, BXPU, BXNU, BXBU, BXRU, BXRU, BXQU, BKC, BK,
};

S32 wbStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB, BXRP, BXRP, BXQP, BKC, BK,
};

S32 bbStateIDU[] = {
  0,
  BXPU, BXPU, BXPU, BXPU, BXPU, BXPU, BXNU, BXBU, BXRU, BXRU, BXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

S32 bbStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB, BXRP, BXRP, BXQP,  WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ,  BKC, BK,
};

S32 wnStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  NXPU, NXPU, NXPU, NXPU, NXPU, NXPU, NXNU, NXBU, NXRU, NXRU, NXQU, BKC, BK,
};

S32 wnStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN, NXBP, NXRP, NXRP, NXQP, BKC, BK,
};

S32 bnStateIDU[] = {
  0,
  NXPU, NXPU, NXPU, NXPU, NXPU, NXPU, NXNU, NXBU, NXRU, NXRU, NXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

S32 bnStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN, NXBP, NXRP, NXRP, NXQP,  WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ,  BKC, BK,
};

S32 wpStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  PXPU, PXPU, PXPU, PXPU, PXPU, PXPU, PXNU, PXBU, PXRU, PXRU, PXQU, BKC, BK,
};

S32 wpStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2, PXNP, PXBP, PXRP, PXRP, PXQP, BKC, BK,
};

S32 bpStateIDU[] = {
  0,
  PXPU, PXPU, PXPU, PXPU, PXPU, PXPU, PXNU, PXBU, PXRU, PXRU, PXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

S32 bpStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2, PXNP, PXBP, PXRP, PXRP, PXQP,  WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ,  BKC, BK,
};
Mike Sherwin
Posts: 860
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: The bitboard trials OR just say no to magic

Post by Mike Sherwin »

Also I forgot to put in the count of each state type which is now in the code block below. Next I will finish writing all the state ID functions.

Code: Select all

void InitStateWQ(Thread* t, s32 fs) {
  u32 ts;
  Occ occ.o = piece[WHITE][0] | piece[BLACK][0];
  u64 bb = qss[fs][occ.r1][RANK1]
         & qss[fs][occ.r2][RANK2]
         & qss[fs][occ.r3][RANK3]
         & qss[fs][occ.r4][RANK4]
         & qss[fs][occ.r5][RANK5]
         & qss[fs][occ.r6][RANK6]
         & qss[fs][occ.r7][RANK7]
         & qss[fs][occ.r8][RANK8]
         & piece[BLACK][0];
  while (bb) {
    _BitScanForward64(&ts, bb);
    bb ^= one << ts;
    if (!AttackedByBlack(t, one << ts) {
      state[WHITE][0] |= one << qStateID[board[ts];
      nStates[WHITE][qStateID[board[ts]][0]++;
    }
  }
}
Mike Sherwin
Posts: 860
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: The bitboard trials OR just say no to magic

Post by Mike Sherwin »

Decided to write bitboard capture functions as they will be useful elsewhere.

Code: Select all

u64 GenCaptsWQ(Thread* t) {
  Occ occ.o = piece[WHITE][ply] | piece[BLACK][ply];
  u64 bb = qss[fs][occ.r1][RANK1]
         & qss[fs][occ.r2][RANK2]
         & qss[fs][occ.r3][RANK3]
         & qss[fs][occ.r4][RANK4]
         & qss[fs][occ.r5][RANK5]
         & qss[fs][occ.r6][RANK6]
         & qss[fs][occ.r7][RANK7]
         & qss[fs][occ.r8][RANK8]
         & piece[BLACK][ply];
  return bb;
}

void InitStateWQ(Thread* t, s32 fs) {
  u32 ts;
  u64 bb = GenCaptsWQ(t);
  while (bb) {
    _BitScanForward64(&ts, bb);
    bb ^= one << ts;
    if (!AttackedByBlack(t, one << ts) {
      state[WHITE][0] |= one << qStateID[board[ts];
      nStates[WHITE][qStateID[board[ts]][0]++;
    }
  }
}
Mike Sherwin
Posts: 860
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: The bitboard trials OR just say no to magic

Post by Mike Sherwin »

Has anyone noticed that programming chess is hard and confusing?

Code: Select all

u64 GenCaptsWQ(Thread* t, s32 fs, Occ occ) {
  u64 bb = qss[fs][occ.r1][RANK1]
         & qss[fs][occ.r2][RANK2]
         & qss[fs][occ.r3][RANK3]
         & qss[fs][occ.r4][RANK4]
         & qss[fs][occ.r5][RANK5]
         & qss[fs][occ.r6][RANK6]
         & qss[fs][occ.r7][RANK7]
         & qss[fs][occ.r8][RANK8]
         & piece[BLACK][ply];
  return bb;
}

void InitStateWQ(Thread* t, s32 fs, u64 occ) {
  u32 ts;
  u64 bb = GenCaptsWQ(t, fs, occ);
  while (bb) {
    _BitScanForward64(&ts, bb);
    bb ^= one << ts;
    if (!AttackedByBlack(t, one << ts) {
      state[WHITE][0] |= one << qStateID[board[ts];
      nStates[WHITE][qStateID[board[ts]][0]++;
    }
  }
}

void InitState(Thread* t) {
  Occ occ.o = piece[WHITE][0] | piece[BLACK][0];
  s32 sq, pce;
  for (sq = a1; sq <= h8; sq++) {
    pce = board[sq];
    if (pce) {
      InitStatePC[pce](t, sq, occ);
    }
  }
}
Mike Sherwin
Posts: 860
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: The bitboard trials OR just say no to magic

Post by Mike Sherwin »

I was able to generalize all the various initializations down to one function! :D
Edit: Oh fooey, there are a couple of small errors. I forgot I needed some ... Just my bad memory at work but it will be fixed.

Code: Select all

void InitState(Thread* t) {
  s32 fs, pce;
  u32 ts;
  Occ occ;
  occ.bb = piece[WHITE][0] | piece[BLACK][0];
  for (fs = a1; fs <= h8; fs++) {
    pce = board[fs];
    if (pce) {
      u64 bb = GenMoves[pce <= WK](t, fs, occ) & piece[pce < WK][0];
      while (bb) {
        _BitScanForward64(&ts, bb);
        bb ^= one << ts;
        if (!AttackedBy[pce > WK](t, one << ts)) {
          state[pce <= WK][0] |= one << stateIDU[pce][board[ts]];
          nStates[pce <= WK][stateIDU[pce][board[ts]]][ply]++;
        }
        else if (value[board[ts]] > value[board[fs]]) {
          state[pce <= WK][0] |= one << stateIDP[pce][board[ts]];
          nStates[pce <= WK][stateIDP[pce][board[ts]]][ply]++;
        }
      }
    }
  }
}

Code: Select all

enum {
  KXQU, QXQU, RXQU, BXQU, NXQU, PXQU, PXQP, NXQP, BXQP, KXRU, QXRU, RXRU, BXRU, NXRU, PXRU,
  PXRP, RXQP, KXBU, QXBU, RXBU, BXBU, NXBU, PXBU, KXNU, QXNU, RXNU, BXNU, NXNU, PXNU, PXBP,
  NXRP, PXNP, BXRP, KXPU, QXPU, RXPU, BXPU, NXPU, PXPU, NXBP
};

s32 wkStateIDU[] = {
  0,
   WP2,  WP3,  WP4,  WP5,  WP6,  WP7,   WN,   WB,  WRC,   WR,   WQ, WKC, WK,
  KXPU, KXPU, KXPU, KXPU, KXPU, KXPU, KXNU, KXBU, KXRU, KXRU, KXQU, BKC, BK,
};

s32 bkStateIDU[] = {
  0,
  KXPU, KXPU, KXPU, KXPU, KXPU, KXPU, KXNU, KXBU, KXRU, KXRU, KXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};


s32 wqStateIDU[] = { 
  0,
   WP2,  WP3,  WP4,  WP5,  WP6,  WP7,   WN,   WB,  WRC,   WR,   WQ, WKC, WK,
  QXPU, QXPU, QXPU, QXPU, QXPU, QXPU, QXNU, QXBU, QXRU, QXRU, QXQU, BKC, BK,
};

s32 bqStateIDU[] = {
  0,
  QXPU, QXPU, QXPU, QXPU, QXPU, QXPU, QXNU, QXBU, QXRU, QXRU, QXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

s32 wrStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  RXPU, RXPU, RXPU, RXPU, RXPU, RXPU, RXNU, RXBU, RXRU, RXRU, RXQU, BKC, BK,
};

s32 wrStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR, RXQP, BKC, BK,
};

s32 brStateIDU[] = {
  0,
  RXPU, RXPU, RXPU, RXPU, RXPU, RXPU, RXNU, RXBU, RXRU, RXRU, RXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

s32 brStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR, RXQP,  WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ,  BKC, BK,
};

s32 wbStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BXPU, BXPU, BXPU, BXPU, BXPU, BXPU, BXNU, BXBU, BXRU, BXRU, BXQU, BKC, BK,
};

s32 wbStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB, BXRP, BXRP, BXQP, BKC, BK,
};

s32 bbStateIDU[] = {
  0,
  BXPU, BXPU, BXPU, BXPU, BXPU, BXPU, BXNU, BXBU, BXRU, BXRU, BXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

s32 bbStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB, BXRP, BXRP, BXQP,  WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ,  BKC, BK,
};

s32 wnStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  NXPU, NXPU, NXPU, NXPU, NXPU, NXPU, NXNU, NXBU, NXRU, NXRU, NXQU, BKC, BK,
};

s32 wnStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN, NXBP, NXRP, NXRP, NXQP, BKC, BK,
};

s32 bnStateIDU[] = {
  0,
  NXPU, NXPU, NXPU, NXPU, NXPU, NXPU, NXNU, NXBU, NXRU, NXRU, NXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

s32 bnStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN, NXBP, NXRP, NXRP, NXQP,  WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ,  BKC, BK,
};

s32 wpStateIDU[] = {
  0,
   WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  PXPU, PXPU, PXPU, PXPU, PXPU, PXPU, PXNU, PXBU, PXRU, PXRU, PXQU, BKC, BK,
};

s32 wpStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2,   WN,   WB,  WRC,   WR,   WQ, WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2, PXNP, PXBP, PXRP, PXRP, PXQP, BKC, BK,
};

s32 bpStateIDU[] = {
  0,
  PXPU, PXPU, PXPU, PXPU, PXPU, PXPU, PXNU, PXBU, PXRU, PXRU, PXQU, WKC, WK,
   BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ, BKC, BK,
};

s32 bpStateIDP[] = {
  0,
  WP7,  WP6,  WP5,  WP4,  WP3,  WP2, PXNP, PXBP, PXRP, PXRP, PXQP,  WKC, BK,
  BP7,  BP6,  BP5,  BP4,  BP3,  BP2,   BN,   BB,  BRC,   BR,   BQ,  BKC, BK,
};

s32* stateIDU[] = {
  nullptr,
  wpStateIDU, wpStateIDU, wpStateIDU, wpStateIDU, wpStateIDU, wpStateIDU,
  wnStateIDU, wbStateIDU, wrStateIDU, wrStateIDU, wqStateIDU, wkStateIDU, wkStateIDU,
  bpStateIDU, bpStateIDU, bpStateIDU, bpStateIDU, bpStateIDU, bpStateIDU,
  bnStateIDU, bbStateIDU, brStateIDU, brStateIDU, bqStateIDU, bkStateIDU, bkStateIDU,
};

s32* stateIDP[] = {
  nullptr,
  wpStateIDP, wpStateIDP, wpStateIDP, wpStateIDP, wpStateIDP, wpStateIDP,
  wnStateIDP, wbStateIDP, wrStateIDP, wrStateIDP, nullptr, nullptr, nullptr,
  bpStateIDP, bpStateIDP, bpStateIDP, bpStateIDP, bpStateIDP, bpStateIDP,
  bnStateIDP, bbStateIDP, brStateIDP, brStateIDP, nullptr, nullptr, nullptr,
};

Code: Select all

u64 GenMovesB(Thread* t, s32 fs, Occ occ) {
  return qss[fs][occ.r2][RANK2]
       & qss[fs][occ.r3][RANK3]
       & qss[fs][occ.r4][RANK4]
       & qss[fs][occ.r5][RANK5]
       & qss[fs][occ.r6][RANK6]
       & qss[fs][occ.r6][RANK7]
       & bob[fs];
}

u64 GenMovesR(Thread* t, s32 fs, Occ occ) {
  return qss[fs][occ.r1][RANK1]
       & qss[fs][occ.r2][RANK2]
       & qss[fs][occ.r3][RANK3]
       & qss[fs][occ.r4][RANK4]
       & qss[fs][occ.r5][RANK5]
       & qss[fs][occ.r6][RANK6]
       & qss[fs][occ.r7][RANK7]
       & qss[fs][occ.r8][RANK8]
       & rob[fs];
}

u64 GenMovesQ(Thread* t, s32 fs, Occ occ) {
  return qss[fs][occ.r1][RANK1]
       & qss[fs][occ.r2][RANK2]
       & qss[fs][occ.r3][RANK3]
       & qss[fs][occ.r4][RANK4]
       & qss[fs][occ.r5][RANK5]
       & qss[fs][occ.r6][RANK6]
       & qss[fs][occ.r7][RANK7]
       & qss[fs][occ.r8][RANK8];
}

u64 GenMovesK(Thread* t, s32 fs, Occ occ) {
  return kingMoves[fs];
}

u64 GenMovesN(Thread* t, s32 fs, Occ occ) {
  return knightMoves[fs];
}

u64 GenMovesWP(Thread* t, s32 fs, Occ occ) {
  return wPawnCapts[fs];
}

u64 GenMovesWe(Thread* t, s32 fs, Occ occ) {
  return wPawnCapts[fs] & (one << epsq[ply]);
}

u64 GenMovesBP(Thread* t, s32 fs, Occ occ) {
  return bPawnCapts[fs];
}

u64 GenMovesBe(Thread* t, s32 fs, Occ occ) {
  return bPawnCapts[fs] & (one << epsq[ply]);
}

u64(*GenMoves[])(Thread*, s32, Occ) = {
  nullptr,
  GenMovesWP, GenMovesWP, GenMovesWP, GenMovesWe, GenMovesWP, GenMovesWP,
  GenMovesN, GenMovesB, GenMovesR, GenMovesR, GenMovesQ, GenMovesK, GenMovesK,
  GenMovesBP, GenMovesBP, GenMovesBP, GenMovesBe, GenMovesBP, GenMovesBP,
  GenMovesN, GenMovesB, GenMovesR, GenMovesR, GenMovesQ, GenMovesK, GenMovesK,
};