Rewriting RomiChess from scratch for SMP

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

mar
Posts: 2554
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Rewriting RomiChess from scratch for SMP

Post by mar »

Ras wrote: Thu Apr 09, 2020 11:31 am Are you sure that Demolito really calls QS on every move right after generation?
why would anybody want do this? (except for Bob in Crafty at root for move ordering - and I think even this is a bad idea)
Martin Sedlak
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Rewriting RomiChess from scratch for SMP

Post by Ras »

mar wrote: Thu Apr 09, 2020 12:31 pmwhy would anybody want do this?
See the first posting of this thread with regard to move generation. That was what I was replying and referring to.
(except for Bob in Crafty at root for move ordering - and I think even this is a bad idea)
At root, I'm doing that also, but apart from the question whether it helps, at least it doesn't take noticeable time.
Rasmus Althoff
https://www.ct800.net
mar
Posts: 2554
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Rewriting RomiChess from scratch for SMP

Post by mar »

Ras wrote: Thu Apr 09, 2020 12:39 pm
(except for Bob in Crafty at root for move ordering - and I think even this is a bad idea)
At root, I'm doing that also, but apart from the question whether it helps, at least it doesn't take noticeable time.
the problem I have with this is that when you're searching a position with qs explosion
(such as artifical positions with lots of queens that can capture each other),
it'll take very long to even finish depth 1
Martin Sedlak
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Rewriting RomiChess from scratch for SMP

Post by Ras »

mar wrote: Thu Apr 09, 2020 1:04 pmthe problem I have with this is that when you're searching a position with qs explosion
(such as artifical positions with lots of queens that can capture each other), it'll take very long to even finish depth 1
That's easy to solve by only considering recaptures after QS depth X. It also prevents going through pointless queen plunder raids in normal game positions. I even generate non-capture evasions in QS if a capture gives check, but limit that to one ply less than the recapture-only mode, and don't do it at all in pre-search.

Also, you can check for "mate in 1" right when cleaning the root move list from illegal moves, that catches even more of these artificial queen positions and, together with mate distance pruning, makes sure that the engine will never struggle with a mate in 1.
Rasmus Althoff
https://www.ct800.net
mar
Posts: 2554
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Rewriting RomiChess from scratch for SMP

Post by mar »

Ras wrote: Thu Apr 09, 2020 1:17 pm That's easy to solve by only considering recaptures after QS depth X. It also prevents going through pointless queen plunder raids in normal game positions. I even generate non-capture evasions in QS if a capture gives check, but limit that to one ply less than the recapture-only mode, and don't do it at all in pre-search.

Also, you can check for "mate in 1" right when cleaning the root move list from illegal moves, that catches even more of these artificial queen positions and, together with mate distance pruning, makes sure that the engine will never struggle with a mate in 1.
Well, I solved this problem completely by limiting qs depth based on root depth: I use -3*root_depth as minimum qs depth and never actually had to bother to adujsting anything.
works well for me, dead simple.
Martin Sedlak
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Rewriting RomiChess from scratch for SMP

Post by Ras »

mar wrote: Thu Apr 09, 2020 2:05 pmWell, I solved this problem completely by limiting qs depth based on root depth
Yeah, I read that. That's pretty equivalent because it means that initially, main search will turn into a mate-only detector, given that QS won't yield anything useful.
Rasmus Althoff
https://www.ct800.net
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Rewriting RomiChess from scratch for SMP

Post by Michael Sherwin »

I think that the GenAllMovesQ function is in its final form. It has been completely rewritten. I know some think it is not so great but I've wanted to try it for a long time. Actually a long time ago I modified TSCP1.81 to do something very similar. TSCP searched on average 2 ply deeper using that idea. Then it was incorporated into RomiChess. In my opinion this is superior. So one does not have to read back it works like so. Gen all moves one at a time, make a move, do a Qsearch to get a score, unmake the move and record the move if it is legal or if depth == 0 and the score is greater than alpha ... Dang, I just realized that I did not include, if score >= beta return FAILHIGH. Oh well that will be fixed tomorrow. I'll just put in a kludge for now and rework it tomorrow.

Code: Select all

bool GenAllMovesQ(s32 t, s32 alpha, s32 beta, s32 depth) {
  s32 pce, typ, target, adjtyp, score, i, j, *brd;
  u64 bb, pieces, wPieces, bPieces, aPieces, empty, notme;
  u32 fs, ts, sq;

  brd = board[t];

  i = first[t][ply[t]];

  pieces = piece[t][wtm[t]];
  wPieces = piece[t][WHITE];
  bPieces = piece[t][BLACK];
  aPieces = wPieces | bPieces;
  empty = 0xffffffffffffffff ^ aPieces;
  notme = 0xffffffffffffffff ^ pieces;

  do {
    _BitScanForward64(&fs, pieces);
    pieces ^= (one << fs);
    pce = brd[fs];
    switch (pce) {
      case OO: break;
      case WP:
        typ = fs >> 3;
        switch (typ) {
          case RANK1: break;
          case RANK2:
            _BitScanForward64(&sq, wPawnMoves[fs] & aPieces);
            bb = (wPawnMoves[fs] & below[sq]) | (wPawnCapts[fs] & bPieces);
            typ = WDOU;
            break;
          case RANK3:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bPieces);
            typ = WSGL;
            break;
          case RANK4:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bPieces);
            typ = WSGL;
            break;
          case RANK5:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & (bPieces | epbit[t][ply[t]]));
            typ = WCEP;
            break;
          case RANK6:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bPieces);
            typ = WSGL;
            break;
          case RANK7:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bPieces);
            while (bb) {
              _BitScanForward64(&ts, bb);
              bb ^= one << ts;
              for (j = 3; j >= 0; j--) {
                pce = WN + j;
                target = OneMM(t, fs, ts, WPRO, WP);
                score = Qsearch(t, alpha, beta);
                OneUM(t, fs, ts, WPRO, WP, target);

                if (score >= beta && depth == 0) return FAILHIGH;

                if (score != -INFINITY && (score > alpha || depth > 0)) {
                  frsq[t][i] = fs;
                  tosq[t][i] = ts;
                  trgt[t][i] = target;
                  type[t][i] = WPRO;
                  scor[t][i] = score;
                  i++;
                }
              }
            }
            break;
        }
        break;
      case WN:
        bb = knightMoves[fs] & notme;
        typ = WNMV;
        break;
      case WB:
        bb = qss[fs][(aPieces >> (fs & 56)) & 127][0]
           & qss[fs][(aPieces >> 8) & 255][1]
           & qss[fs][(aPieces >> 16) & 255][2]
           & qss[fs][(aPieces >> 24) & 255][3]
           & qss[fs][(aPieces >> 32) & 255][4]
           & qss[fs][(aPieces >> 40) & 255][5]
           & qss[fs][(aPieces >> 48) & 255][6]
           & bob[fs]
           & notme;
        typ = WBMV;
        break;
      case WR:
        bb = qss[fs][(aPieces >> (fs & 56)) & 127][0]
           & qss[fs][(aPieces >> 8) & 255][1]
           & qss[fs][(aPieces >> 16) & 255][2]
           & qss[fs][(aPieces >> 24) & 255][3]
           & qss[fs][(aPieces >> 32) & 255][4]
           & qss[fs][(aPieces >> 40) & 255][5]
           & qss[fs][(aPieces >> 48) & 255][6]
           & rob[fs]
           & notme;
        typ = WRMV;
        break;
      case WQ:
        bb = qss[fs][(aPieces >> (fs & 56)) & 127][0]
           & qss[fs][(aPieces >> 8) & 255][1]
           & qss[fs][(aPieces >> 16) & 255][2]
           & qss[fs][(aPieces >> 24) & 255][3]
           & qss[fs][(aPieces >> 32) & 255][4]
           & qss[fs][(aPieces >> 40) & 255][5]
           & qss[fs][(aPieces >> 48) & 255][6]
           & notme;
        typ = WQMV;
        break;
      case WK:
        bb = kingMoves[fs] & notme;
        typ = WKMV;
        if (wcancas[t] > ply[t]) {
          wcancas[t] = INFINITY;
          if (board[t][E1] == WK) {
            if (wcancask[t] > ply[t]) {
              wcancask[t] = INFINITY;
              if (board[t][H1] == WR) {
                if (!board[t][F1] && !board[t][G1]
                  && !Attacked(t, E1, BLACK) && !Attacked(t, F1, BLACK) && !Attacked(t, G1, BLACK)) {
                  OneMM(t, E1, G1, WSHT, WK);
                  score = Qsearch(t, alpha, beta);
                  OneUM(t, E1, G1, WSHT, WK, OO);

                  if (score >= beta && depth == 0) return FAILHIGH;

                  if (score > alpha || depth > 0) {
                    frsq[t][i] = E1;
                    tosq[t][i] = G1;
                    trgt[t][i] = OO;
                    type[t][i] = WSHT;
                    scor[t][i] = score;
                    i++;
                  }
                }
              }
              else {
                if (board[t][H1] == OO) {
                  wcancask[t] = ply[t] - 2;
                }
                else {
                  wcancask[t]--;
                }
              }
            }
          }
          else {
            wcancas[t] = ply[t] - 2;
          }
          if (wcancasq[t] > ply[t]) {
            wcancasq[t] = INFINITY;
            if (board[t][A1] == WR) {
              if (!board[t][D1] && !board[t][C1] && !board[t][B1]
                && !Attacked(t, E1, BLACK) && !Attacked(t, D1, BLACK) && !Attacked(t, C1, BLACK)) {
                OneMM(t, E1, C1, WLNG, WK);
                score = Qsearch(t, alpha, beta);
                OneUM(t, E1, C1, WLNG, WK, OO);

                if (score >= beta && depth == 0) return FAILHIGH;

                if (score > alpha || depth > 0) {
                  frsq[t][i] = E1;
                  tosq[t][i] = C1;
                  trgt[t][i] = OO;
                  type[t][i] = WLNG;
                  scor[t][i] = score;
                  i++;
                }
              }
            }
            else {
              if (board[t][A1] == OO) {
                wcancasq[t] = ply[t] - 2;
              }
              else {
                wcancasq[t]--;
              }
            }
          }
        }
        break;
      case BP:
        typ = fs >> 3;
        switch (typ) {
          case RANK1: break;
          case RANK2:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wPieces);
            while (bb) {
              _BitScanForward64(&ts, bb);
              bb ^= one << ts;
              for (j = 3; j >= 0; j--) {
                pce = BN + j;
                target = OneMM(t, fs, ts, BPRO, BP);
                score = Qsearch(t, alpha, beta);
                OneUM(t, fs, ts, BPRO, BP, target);

                if (score >= beta && depth == 0) return FAILHIGH;

                if (score != -INFINITY && (score > alpha || depth > 0)) {
                  frsq[t][i] = fs;
                  tosq[t][i] = ts;
                  trgt[t][i] = target;
                  type[t][i] = BPRO;
                  scor[t][i] = score;
                  i++;
                }
              }
            } 
            break;
          case RANK3:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wPieces);
            typ = BSGL;
            break;
          case RANK4:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & (wPieces | epbit[t][ply[t]]));
            typ = BCEP;
            break;
          case RANK5:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wPieces);
            typ = BSGL;
            break;
          case RANK6:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wPieces);
            typ = BSGL;
            break;
          case RANK7:
            _BitScanReverse64(&sq, bPawnMoves[fs] & aPieces);
            bb = (bPawnMoves[fs] & above[sq]) | (bPawnCapts[fs] & wPieces);
            typ = BDOU;
            break;
        }
        break;
      case BN:
        bb = knightMoves[fs] & notme;
        typ = BNMV;
        break;
      case BB:
        bb = qss[fs][(aPieces >> (fs & 56)) & 127][0]
           & qss[fs][(aPieces >> 8) & 255][1]
           & qss[fs][(aPieces >> 16) & 255][2]
           & qss[fs][(aPieces >> 24) & 255][3]
           & qss[fs][(aPieces >> 32) & 255][4]
           & qss[fs][(aPieces >> 40) & 255][5]
           & qss[fs][(aPieces >> 48) & 255][6]
           & bob[fs]
           & notme;
        typ = BBMV;
        break;
      case BR:
        bb = qss[fs][(aPieces >> (fs & 56)) & 127][0]
           & qss[fs][(aPieces >> 8) & 255][1]
           & qss[fs][(aPieces >> 16) & 255][2]
           & qss[fs][(aPieces >> 24) & 255][3]
           & qss[fs][(aPieces >> 32) & 255][4]
           & qss[fs][(aPieces >> 40) & 255][5]
           & qss[fs][(aPieces >> 48) & 255][6]
           & rob[fs]
           & notme;
        typ = BRMV;
        break;
      case BQ:
        bb = qss[fs][(aPieces >> (fs & 56)) & 127][0]
           & qss[fs][(aPieces >> 8) & 255][1]
           & qss[fs][(aPieces >> 16) & 255][2]
           & qss[fs][(aPieces >> 24) & 255][3]
           & qss[fs][(aPieces >> 32) & 255][4]
           & qss[fs][(aPieces >> 40) & 255][5]
           & qss[fs][(aPieces >> 48) & 255][6]
           & notme;
        typ = BQMV;
        break;
      case BK:
        bb = kingMoves[fs] & notme;
        typ = BKMV;
        if (bcancas[t] > ply[t]) {
          bcancas[t] = INFINITY;
          if (board[t][E8] == BK) {
            if (bcancask[t] > ply[t]) {
              bcancask[t] = INFINITY;
              if (board[t][H8] == BR) {
                if (!board[t][F8] && !board[t][G8]
                  && !Attacked(t, E8, WHITE) && !Attacked(t, F8, WHITE) && !Attacked(t, G8, WHITE)) {
                  OneMM(t, E8, G8, BSHT, pce);
                  score = Qsearch(t, alpha, beta);
                  OneUM(t, E8, G8, BSHT, pce, OO);

                  if (score >= beta && depth == 0) return FAILHIGH;

                  if (score > alpha || depth > 0) {
                    frsq[t][i] = E8;
                    tosq[t][i] = G8;
                    trgt[t][i] = OO;
                    type[t][i] = BSHT;
                    scor[t][i] = score;
                    i++;
                  }
                }
              }
              else {
                if (board[t][H8] == OO) {
                  bcancask[t] = ply[t] - 2;
                }
                else {
                  bcancask[t]--;
                }
              }
            }
          }
          else {
            bcancas[t] = ply[t] - 2;
          }
          if (bcancasq[t] > ply[t]) {
            bcancasq[t] = INFINITY;
            if (board[t][A8] == BR) {
              if (!board[t][D8] && !board[t][C8] && !board[t][B8]
                && !Attacked(t, E8, WHITE) && !Attacked(t, D8, WHITE) && !Attacked(t, C1, WHITE)) {
                OneMM(t, E8, C8, BLNG, pce);
                score = Qsearch(t, alpha, beta);
                OneUM(t, E8, C8, BLNG, pce, OO);

                if (score >= beta && depth == 0) return FAILHIGH;

                if (score > alpha || depth > 0) {
                  frsq[t][i] = E8;
                  tosq[t][i] = C8;
                  trgt[t][i] = OO;
                  type[t][i] = BLNG;
                  scor[t][i] = score;
                  i++;
                }
              }
            }
            else {
              if (board[t][A8] == OO) {
                bcancasq[t] = ply[t] - 2;
              }
              else {
                bcancasq[t]--;
              }
            }
          }
        }
        break;
    }

    while (bb) {
      _BitScanForward64(&ts, bb);
      bb ^= one << ts;

      target = OneMM(t, fs, ts, adjtyp, pce);

      score = Qsearch(t, alpha, beta);

      OneUM(t, fs, ts, adjtyp, pce, target);
    }

    if (score >= beta && depth == 0) return FAILHIGH;

    if (score != -INFINITY && (score > alpha || depth > 0)) {
      frsq[t][i] = fs;
      tosq[t][i] = ts;
      trgt[t][i] = target;
      type[t][i] = typ;
      scor[t][i] = score;
      i++;
    }

  } while (pieces);

  last[t][ply[t]] = i - 1;

  return OKAY;
}
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Rewriting RomiChess from scratch for SMP

Post by Michael Sherwin »

Two weeks to write one 'complicated' function is like a new record for me. Everything has been reimagined and reworked several times. I even renamed the new engine. And I'm very happy with the result. This is all the code so far.

Code: Select all

// Paradigm.cpp

#define data 1
#define defines 1

#include <intrin.h>

#if defined defines

typedef signed char s08;
typedef unsigned char u08;
typedef signed int s32;
typedef unsigned long u32;
typedef unsigned long long u64;

struct s_thread {
  s32 wtm;
  s32 ply;
  s32 wcancast;
  s32 wcancask;
  s32 wcancasq;
  s32 bcancast;
  s32 bcancask;
  s32 bcancasq;
  s32 board[64];
  s32 first[400];
  s32 last[400];
  s32 epbit[400];
  s32 fsqr[8000];
  s32 tsqr[8000];
  s32 scor[8000];
  u64 side[2];
};

#define side t->side
#define wtm t->wtm
#define ply t->ply
#define board t->board
#define first t->first
#define last t->last
#define epbit t->epbit
#define fsqr t->fsqr
#define tsqr t->tsqr
#define type t->type
#define trgt t->trgt
#define scor t->scor
#define stat t->stat
#define wcancast t->wcancast
#define wcancask t->wcancask
#define wcancasq t->wcancasq
#define bcancast t->bcancast
#define bcancask t->bcancask
#define bcancasq t->bcancasq

#define one 1ull

#define INFINITY 32767

#define B1bit 0b0000000000000000000000000000000000000000000000000000000000000010
#define C1bit 0b0000000000000000000000000000000000000000000000000000000000000100
#define D1bit 0b0000000000000000000000000000000000000000000000000000000000001000
#define F1bit 0b0000000000000000000000000000000000000000000000000000000000100000
#define G1bit 0b0000000000000000000000000000000000000000000000000000000001000000
#define B8bit 0b0000001000000000000000000000000000000000000000000000000000000000
#define C8bit 0b0000010000000000000000000000000000000000000000000000000000000000
#define D8bit 0b0000100000000000000000000000000000000000000000000000000000000000
#define F8bit 0b0010000000000000000000000000000000000000000000000000000000000000
#define G8bit 0b0100000000000000000000000000000000000000000000000000000000000000

enum {
  A1, B1, C1, D1, E1, F1, G1, H1,
  A2, B2, C2, D2, E2, F2, G2, H2,
  A3, B3, C3, D3, E3, F3, G3, H3,
  A4, B4, C4, D4, E4, F4, G4, H4,
  A5, B5, C5, D5, EF, F5, G5, H5,
  A6, B6, C6, D6, E6, F6, G6, H6,
  A7, B7, C7, D7, E7, F7, G7, H7,
  A8, B8, C8, D8, E8, F8, G8, H8
};

enum { OKAY, FAILHIGH };

enum { BLACK, WHITE };

enum { OO, WP, WN, WB, WR, WQ, WC, WK, BP, BN, BB, BR, BQ, BC, BK };

enum { RANK1, RANK2, RANK3, RANK4, RANK5, RANK6, RANK7, RANK8 };

#endif

#if defined data

  u64 qss[64][256][8];
  u64 bob[64];
  u64 rob[64];

  u64 above[64];
  u64 below[64];

  u64 wPawnMoves[64];
  u64 wPawnCapts[64];
  u64 bPawnMoves[64];
  u64 bPawnCapts[64];
  u64 knightMoves[64];
  u64 kingMoves[64];

#endif

s32 Qsearch(s_thread* t, s32 alpha, s32 beta) {


}

__forceinline void LegalMM(s_thread *t, s32 fs, s32 ts, s32 piece) {

}

__forceinline void LegalTB(s_thread* t, s32 fs, s32 ts, s32 piece) {

}

bool GenLegalMovesQ(s_thread* t, s32 alpha, s32 beta, s32 depth) {
  u64 pieces, wpieces, bpieces, apieces, empty, notme, bb;
  u32 fs, ts, sq, i;
  s32 piece, typ, target, score;

  i = first[ply];

  pieces = side[wtm];
  wpieces = side[WHITE];
  bpieces = side[BLACK];
  apieces = wpieces | bpieces;
  empty = 0xffffffffffffffff ^ apieces;
  notme = 0xffffffffffffffff ^ pieces;

  do {
    _BitScanForward64(&fs, pieces);
    pieces ^= one << fs;
    u32 fs = static_cast<s32>(fs);
    piece = board[fs];
    switch (piece) {
      case OO: break;
      case WP:
        typ = fs >> 3;
        switch (typ) {
          case RANK1: break;
          case RANK2:
            _BitScanForward64(&sq, wPawnMoves[fs] & apieces);
            bb = (wPawnMoves[fs] & below[sq]) | (wPawnCapts[fs] & bpieces);
           break;
          case RANK3:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bpieces);
            break;
          case RANK4:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bpieces);
            break;
          case RANK5:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & (bpieces | epbit[ply]));
            break;
          case RANK6:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bpieces);
            break;
          case RANK7:
            bb = (wPawnMoves[fs] & empty) | (wPawnCapts[fs] & bpieces);
            break;
        }
        break;
      case WN:
        bb = knightMoves[fs] & notme;
        break;
      case WB:
        bb = qss[fs][(apieces >> (fs & 56)) & 127][0]
           & qss[fs][(apieces >>  8) & 255][1]
           & qss[fs][(apieces >> 16) & 255][2]
           & qss[fs][(apieces >> 24) & 255][3]
           & qss[fs][(apieces >> 32) & 255][4]
           & qss[fs][(apieces >> 40) & 255][5]
           & qss[fs][(apieces >> 48) & 255][6]
           & bob[fs]
           & notme;
        break;
      case WR:
        bb = qss[fs][(apieces >> (fs & 56)) & 127][0]
           & qss[fs][(apieces >>  8) & 255][1]
           & qss[fs][(apieces >> 16) & 255][2]
           & qss[fs][(apieces >> 24) & 255][3]
           & qss[fs][(apieces >> 32) & 255][4]
           & qss[fs][(apieces >> 40) & 255][5]
           & qss[fs][(apieces >> 48) & 255][6]
           & rob[fs]
           & notme;
        break;
      case WQ:
        bb = qss[fs][(apieces >> (fs & 56)) & 127][0]
           & qss[fs][(apieces >>  8) & 255][1]
           & qss[fs][(apieces >> 16) & 255][2]
           & qss[fs][(apieces >> 24) & 255][3]
           & qss[fs][(apieces >> 32) & 255][4]
           & qss[fs][(apieces >> 40) & 255][5]
           & qss[fs][(apieces >> 48) & 255][6]
           & notme;
        break;
      case WC:
        bb = kingMoves[fs] & notme;
        if (wcancast >= ply) {
          if (board[E1] == WC) {
            wcancast = INFINITY;
            if (wcancask >= ply) {
              if (board[H1] == WR) {
                wcancask = INFINITY;
                if (!(apieces & (F1bit | G1bit))) {
                  bb |= G1bit;
                }
              }
              else {
                wcancask = ply;
              }
            }
          }
          if (wcancasq >= ply) {
            if (board[A1] == WR) {
              wcancasq = INFINITY;
              if (!(apieces & (D1bit | C1bit | B1bit))) {
                bb |= C1bit;
              }
            }
            else {
              wcancasq = ply;
             }
          }
        }
        else {
          wcancast = ply;
        }
        break;
      case WK:
        bb = kingMoves[fs] & notme;
        break;
      case BP:
        typ = fs >> 3;
        switch (typ) {
          case RANK1: break;
          case RANK2:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wpieces);
            break;
          case RANK3:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wpieces);
            break;
          case RANK4:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & (wpieces | epbit[ply]));
            break;
          case RANK5:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wpieces);
            break;
          case RANK6:
            bb = (bPawnMoves[fs] & empty) | (bPawnCapts[fs] & wpieces);
            break;
          case RANK7:
            _BitScanReverse64(&sq, bPawnMoves[fs] & apieces);
            bb = (bPawnMoves[fs] & above[sq]) | (bPawnCapts[fs] & wpieces);
            break;
        }
        break;
      case BN:
        bb = knightMoves[fs] & notme;
        break;
      case BB:
        bb = qss[fs][(apieces >> (fs & 56)) & 127][0]
           & qss[fs][(apieces >>  8) & 255][1]
           & qss[fs][(apieces >> 16) & 255][2]
           & qss[fs][(apieces >> 24) & 255][3]
           & qss[fs][(apieces >> 32) & 255][4]
           & qss[fs][(apieces >> 40) & 255][5]
           & qss[fs][(apieces >> 48) & 255][6]
           & bob[fs]
           & notme;
        break;
      case BR:
        bb = qss[fs][(apieces >> (fs & 56)) & 127][0]
           & qss[fs][(apieces >> 8)  & 255][1]
           & qss[fs][(apieces >> 16) & 255][2]
           & qss[fs][(apieces >> 24) & 255][3]
           & qss[fs][(apieces >> 32) & 255][4]
           & qss[fs][(apieces >> 40) & 255][5]
           & qss[fs][(apieces >> 48) & 255][6]
           & rob[fs]
           & notme;
        break;
      case BQ:
        bb = qss[fs][(apieces >> (fs & 56)) & 127][0]
           & qss[fs][(apieces >>  8) & 255][1]
           & qss[fs][(apieces >> 16) & 255][2]
           & qss[fs][(apieces >> 24) & 255][3]
           & qss[fs][(apieces >> 32) & 255][4]
           & qss[fs][(apieces >> 40) & 255][5]
           & qss[fs][(apieces >> 48) & 255][6]
           & notme;
        break;
      case BC:
        bb = kingMoves[fs] & notme;
        if (bcancast >= ply) {
          if (board[E8] == BC) {
            bcancast = INFINITY;
            if (bcancask >= ply) {
              if (board[H8] == BR) {
                bcancask = INFINITY;
                if (!(apieces & (F8bit | G8bit))) {
                  bb |= G8bit;
                }
              }
              else {
                bcancask = ply;
              }
            }
          }
          if (bcancasq >= ply) {
            if (board[A8] == BR) {
              bcancasq = INFINITY;
              if (!(apieces & (D8bit | C8bit | B8bit))) {
                bb |= C8bit;
              }
            }
            else {
              bcancasq = ply;
            }
          }
        }
        else {
          bcancast = ply;
        }
        break;
    }

    while (bb) {
      _BitScanForward64(&ts, bb);
      bb ^= one << ts;
      u32 ts = static_cast<s32>(ts);
      LegalMM(t, fs, ts, piece);
      score = Qsearch(t, alpha, beta);
      LegalTB(t, fs, ts, piece);
      if (depth == 0) {
        if (score >= beta) return FAILHIGH;
        if (score != -INFINITY && score > alpha) {
          fsqr[i] = fs;
          tsqr[i] = ts;
          scor[i] = score;
          i++;
        }
      }
      else {
        if (score != -INFINITY) {
          fsqr[i] = fs;
          tsqr[i] = ts;
          scor[i] = score;
          i++;
        }
      }
    }

  } while (pieces);

  last[ply] = i--;

  return OKAY;
}

void InitializeQSS() {
  u08 sq, sqr, k, l;
  u08 x, y, dx, dy;
  s32 i;
  u64 b, bb;

  for (sq = 0; sq < 64; sq++) {
    y = sq >> 3;
    x = sq & 7;
    bob[sq] = 0;
    rob[sq] = 0;
    for (i = 0; i < 256; i++) {
      for (k = 0, l = 0; k <= 56; k += 8, l++) {
        bb = 0;
        b = (u64)i << k;
        for (dx = +1, dy = +1; x + dx < +8 && y + dy < +8; dx++, dy++) {
          sqr = (((y + dy) << 3) + x + dx);
          bb |= one << sqr;
          bob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        for (dx = -1, dy = +1; x + dx > -1 && y + dy < +8; dx--, dy++) {
          sqr = (((y + dy) << 3) + x + dx);
          bb |= one << sqr;
          bob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        for (dx = +1, dy = -1; x + dx < +8 && y + dy > -1; dx++, dy--) {
          sqr = (((y + dy) << 3) + x + dx);
          bb |= one << sqr;
          bob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        for (dx = -1, dy = -1; x + dx > -1 && y + dy > -1; dx--, dy--) {
          sqr = (((y + dy) << 3) + x + dx);
          bb |= one << sqr;
          bob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        for (dx = -1; x + dx > -1; dx--) {
          sqr = (y << 3) + x + dx;
          bb |= one << sqr;
          rob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        for (dx = +1; x + dx < +8; dx++) {
          sqr = (y << 3) + x + dx;
          bb |= one << sqr;
          rob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        for (dy = +1; y + dy < +8; dy++) {
          sqr = ((y + dy) << 3) + x;
          bb |= one << sqr;
          rob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        for (dy = -1; y + dy > -1; dy--) {
          sqr = ((y + dy) << 3) + x;
          bb |= one << sqr;
          rob[sq] |= one << sqr;
          if ((one << sqr) & b) break;
        }
        qss[sq][i][l] = bb;
      }
    }
  }
}

void InitializeRNK() {
  u08 sq, sqr, i;
  u08 x, y, dx, dy;
  u64 bb, b;

  for (sq = 0; sq < 64; sq++) {
    y = sq >> 3;
    x = sq & 7;
    for (i = 0; i < 128; i++) {
      bb = 0;
      b = (u64)i << (sq & 56);
      for (dx = +1, dy = +1; x + dx < +8 && y + dy < +8; dx++, dy++) {
        sqr = (((y + dy) << 3) + x + dx);
        bb |= one << sqr;
        bob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      for (dx = -1, dy = +1; x + dx > -1 && y + dy < +8; dx--, dy++) {
        sqr = (((y + dy) << 3) + x + dx);
        bb |= one << sqr;
        bob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      for (dx = +1, dy = -1; x + dx < +8 && y + dy > -1; dx++, dy--) {
        sqr = (((y + dy) << 3) + x + dx);
        bb |= one << sqr;
        bob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      for (dx = -1, dy = -1; x + dx > -1 && y + dy > -1; dx--, dy--) {
        sqr = (((y + dy) << 3) + x + dx);
        bb |= one << sqr;
        bob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      for (dx = -1; x + dx > -1; dx--) {
        sqr = (y << 3) + x + dx;
        bb |= one << sqr;
        rob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      for (dx = +1; x + dx < +8; dx++) {
        sqr = (y << 3) + x + dx;
        bb |= one << sqr;
        rob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      for (dy = +1; y + dy < +8; dy++) {
        sqr = ((y + dy) << 3) + x;
        bb |= one << sqr;
        rob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      for (dy = -1; y + dy > -1; dy--) {
        sqr = ((y + dy) << 3) + x;
        bb |= one << sqr;
        rob[sq] |= one << sqr;
        if ((one << sqr) & b) break;
      }
      qss[sq][i][0] = bb;
    }
  }
}

void Initialize() {
  InitializeQSS();
  InitializeRNK();
}

s32 main() {

  Initialize();

  return 0;
}
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through