Devlog of !

Discussion of chess software programming and technical issues.

Moderator: Ras

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

Devlog of !

Post by Mike Sherwin »

:!: is possibly my last attempt to write an engine that learns during real time. The Thread struct is set up to meet that goal with every thread having it's own game record for playing quick games. Another goal is for it to be somewhat fast so to play as many games as possible in the allotted time. The chess board is not a very good environment for CPU conditional branch instructions. And every time a branch prediction is wrong it cost performance. Some conditional branches are okay like loops that do not change drastically. Mostly I just wanted to get rid of as many "if" statements as possible. It's not that all eliminations are faster. Some might even be slower. It is just about following a philosophy so to speak. There are no "if" statements in GenAllMoves(), [GenQuiMoves()], AttackedByWhite(), AttackedByBlack(), MakeMove(), TakeBack() and FillMoveFields().

The first mile marker has been reached. The above mentioned functions have been debugged and seem to be working properly, no guarantees. I have entered every series of moves I can think of to test every possibility and had GenAllMoves() do the verification. Enter e2e4 to make a move, e7e8n to promote and e1g1 to castle, etc.

The code has been written as simple to understand as I can. But, if one is new to writing branchless code then it might not be easily understood. Some examples are.

In MakeMove() the following line of code is executed for every move.

Code: Select all

piece[BLACK] ^= (u64)(mtt != ES) << mts;
It does not matter if the move is a capture or not. (mtt != ES) equates to 0 or to 1.
(u64)0 << mts; (m->s.ts) does nothing.
(u64)1 << mts; removes the captured piece from that sides piece list. One might object that performing that operation when not necessary waste time. However, most moves are capture moves from Qsearch(). Something like 90% or more of the moves are captures!

Code: Select all

m.s.ft += ((ts == g1) * (WCS - WKC) + (ts == c1) * (WCL - WKC));

! uses pseudo piece types. WKC, WRC, BKC, BRC appear on the board. The other pseudo pieces exist only in switch statements. But some of them could also appear on the board. For example a pawn that moves to the 5th rank can change from a WP to a WPE. It would be a little faster because the second switch(fs >> 3) for the pawns would not be needed. I might optimize that later. In the code above WCS and WCL are pseudo pieces for castling that cannot be on the board. The from type starts off as a WKC (white king that can castle). That is (pseudo) piece 7. WCS and WCL is further along in the piece type list.

Code: Select all

enum {
  ES,
  WP, WN, WB, WRC, WR, WQ, WKC, WK,
  BP, BN, BB, BRC, BR, BQ, BKC, BK,
  WCS, WCL, WPD, WPE, WPQ, WPN, WPR, WPB,
  BCS, BCL, BPD, BPE, BPQ, BPN, BPR, BPB
};
WKC + (WCS - WKC), therefore ft WKC becomes WCS for the switch() in MakeMove(). Since only one side can be true both sides are computed at once.

Here is the complete MSVS 2022 standard 2020 code so far.

Code: Select all

// !
// !.cpp

#include <cstring>
#include <bit>
#include <cctype>
#include <iostream>

#include "Defines.cpp"
#include "Equates.cpp"
#include "Globals.cpp"
#include "Utilities.cpp"
#include "Move.cpp"
#include "GenMoves.cpp"
#include "Search.cpp"
#include "GetCommand.cpp"
#include "Initialize.cpp"
#include "Main.cpp"

Code: Select all

// !
// Main.cpp

s32 main() {

  Initialize();

  while (mode) {
	if (mode == GETCMD) GetCommand(thread[0]);
	if (mode == SEARCH) StartSearch(thread[0]);
  }

  return 0;
}

Code: Select all

// !
// Initialize.cpp

void InitThreads() {
  numThreads = 4;

  thread = new Thread * [numThreads];

  for (s32 i = 0; i < numThreads; i++) {
	thread[i] = new Thread;
  }
}

u64 mask_shift(u64 bb, s32 ranks) {
  if (ranks > 0) return bb >> (ranks << 3);
  else return bb << -(ranks << 3);
}

void InitRays() {
  // Classic style sliding piece bitboards.
  // Bob-Mike-Dan
  // Bob = Robert Hyatt - originator of basic approach
  // Mike = Michael Sherwin - Originally stop bits but later worked to modernize
  // Dan = Daniel Infuehr - Final optimizations and code example 
  for (s32 sq = a1; sq <= h8; sq++) {
	ray[sq].NW = dir_D2(sq) & GetUpper(sq);
	ray[sq].NN = dir_VE(sq) & GetUpper(sq);
	ray[sq].NE = dir_D1(sq) & GetUpper(sq);
	ray[sq].EE = dir_HO(sq) & GetUpper(sq);
	ray[sq].SE = dir_D1(sq) & GetLower(sq);
	ray[sq].SS = dir_VE(sq) & GetLower(sq);
	ray[sq].SW = dir_D2(sq) & GetLower(sq);
	ray[sq].WW = dir_HO(sq) & GetLower(sq);
  }
  ray[64] = ray[63];

  for (s32 sq = a1; sq <= h8; sq++) rev[sq] = ray[63 - sq];
  rev[64] = ray[0];
}

void InitBoardBB() {
  s32 file, rank;
  for (s32 sq = a1; sq <= h8; sq++) {
	file = sq & 7;
	rank = sq >> 3;

	wPawnCapts[sq] = 0;
	bPawnCapts[sq] = 0;
	knightMoves[sq] = 0;
	bishopMoves[sq] = 0;
	rookMoves[sq] = 0;
	queenMoves[sq] = 0;
	kingMoves[sq] = 0;

	// pawns
	if (sq >= a2 && sq <= h7) {
	  if (file != FILEa) {
		wPawnCapts[sq] |= 1ull << (sq + 7);
		bPawnCapts[sq] |= 1ull << (sq - 9);
	  }
	  if (file != FILEh) {
		wPawnCapts[sq] |= 1ull << (sq + 9);
		bPawnCapts[sq] |= 1ull << (sq - 7);
	  }
	}

	// knights
	if (rank <= RANK6 && file <= FILEg) knightMoves[sq] |= 1ull << (sq + 17);
	if (rank <= RANK7 && file <= FILEf) knightMoves[sq] |= 1ull << (sq + 10);
	if (rank >= RANK2 && file <= FILEf) knightMoves[sq] |= 1ull << (sq - +6);
	if (rank >= RANK3 && file <= FILEg) knightMoves[sq] |= 1ull << (sq - 15);
	if (rank >= RANK3 && file >= FILEb) knightMoves[sq] |= 1ull << (sq - 17);
	if (rank >= RANK2 && file >= FILEc) knightMoves[sq] |= 1ull << (sq - 10);
	if (rank <= RANK7 && file >= FILEc) knightMoves[sq] |= 1ull << (sq + +6);
	if (rank <= RANK6 && file >= FILEb) knightMoves[sq] |= 1ull << (sq + 15);

	// bishops
	bishopMoves[sq] = ray[sq].NW | ray[sq].NE | ray[sq].SE | ray[sq].SW;

	//rooks
	rookMoves[sq] = ray[sq].NN | ray[sq].EE | ray[sq].SS | ray[sq].WW;

	// queen
	queenMoves[sq] = bishopMoves[sq] | rookMoves[sq];

	// king
	if (rank <= RANK7) kingMoves[sq] |= 1ull << (sq + 8);
	if (rank >= RANK2) kingMoves[sq] |= 1ull << (sq - 8);
	if (file <= FILEg) kingMoves[sq] |= 1ull << (sq + 1);
	if (file >= FILEb) kingMoves[sq] |= 1ull << (sq - 1);
	if (rank <= RANK7 && file <= FILEg) kingMoves[sq] |= 1ull << (sq + 9);
	if (rank >= RANK2 && file <= FILEg) kingMoves[sq] |= 1ull << (sq - 7);
	if (rank >= RANK2 && file >= FILEb) kingMoves[sq] |= 1ull << (sq - 9);
	if (rank <= RANK7 && file >= FILEb) kingMoves[sq] |= 1ull << (sq + 7);
  }
}

void InitGame(Thread* t) {
  s32 ok;
  mode = GETCMD;
  computer = BLACK;
  ply = 0;
  gly = 0;
  ok = LoadFen(t, startFen);
  if (!ok) {
	std::cout << "Apparently a bad fen" << std::endl;
  }
}

void InitStruct(Thread* t) {

  piece[BLACK] = 0;
  piece[WHITE] = 0;
  king[BLACK] = 0;
  king[WHITE] = 0;

  for (s32 i = 0; i <= BK; i++) pctypbb[i] = 0;

  for (s32 sq = a1; sq <= h8; sq++) {
	s32 pce = board[sq];
	switch (pce) {
	case ES:
	  // no action
	  break;
	case WP:
	  piece[WHITE] |= 1ull << sq;
	  pctypbb[WP] |= 1ull << sq;
	  break;
	case WN:
	  piece[WHITE] |= 1ull << sq;
	  pctypbb[WN] |= 1ull << sq;
	  break;
	case WB:
	  piece[WHITE] |= 1ull << sq;
	  pctypbb[WB] |= 1ull << sq;
	  break;
	case WRC:
	case WR:
	  piece[WHITE] |= 1ull << sq;
	  pctypbb[WR] |= 1ull << sq;
	  break;
	case WQ:
	  piece[WHITE] |= 1ull << sq;
	  pctypbb[WQ] |= 1ull << sq;
	  break;
	case WKC:
	case WK:
	  piece[WHITE] |= 1ull << sq;
	  king[WHITE] |= 1ull << sq;
	  break;
	case BP:
	  piece[BLACK] |= 1ull << sq;
	  pctypbb[BP] |= 1ull << sq;
	  break;
	case BN:
	  piece[BLACK] |= 1ull << sq;
	  pctypbb[BN] |= 1ull << sq;
	  break;
	case BB:
	  piece[BLACK] |= 1ull << sq;
	  pctypbb[BB] |= 1ull << sq;
	  break;
	case BRC:
	case BR:
	  piece[BLACK] |= 1ull << sq;
	  pctypbb[BR] |= 1ull << sq;
	  break;
	case BQ:
	  piece[BLACK] |= 1ull << sq;
	  pctypbb[BQ] |= 1ull << sq;
	  break;
	case BKC:
	case BK:
	  piece[BLACK] |= 1ull << sq;
	  king[BLACK] |= 1ull << sq;
	  break;
	}
  }
  for (s32 i = 0; i < 100; i++) epbit[i] = 0;
}

void Initialize() {
  InitThreads();
  InitRays();
  InitBoardBB();
  InitGame(thread[0]);
  InitStruct(thread[0]);
}

Code: Select all

// !
// GetCommand.cpp

void GetCommand(Thread* t) {
  s08 line[256], cmd[256], a_move, fs, ts, fs2;
  uMove m;
  u64 pieces;
  s32 ok, not_ok;

  if (!fgets(line, 256, stdin)) return;
  ok = sscanf(line, "%s", cmd);
  cmd[255] = '\0';

  a_move = true;
  if (line[0] < 'a' || line[0] > 'h') a_move = false;
  if (line[1] < '1' || line[1] > '8') a_move = false;
  if (line[2] < 'a' || line[2] > 'h') a_move = false;
  if (line[3] < '1' || line[3] > '8') a_move = false;

  if (a_move) {
	ok = GenAllMoves(t);
	if (!ok) {
	  printf("Illegal Move/n");
	  return;
	}
	fs = (line[1] - '1') * 8 + (line[0] - 'a');
	ts = (line[3] - '1') * 8 + (line[2] - 'a');
	a_move = false;
	pieces = piece[stm];
	while (pieces) {
	  fs2 = std::countr_zero(pieces);
	  pieces ^= 1ull << fs2;
	  if (fs == fs2) {
		if (gbb[ply][fs] & (1ull << ts)) {
		  a_move = true;
		  break;
		}
	  }
	}
	if (a_move) {
	  m = FillMoveFields(t, fs, ts);
	  if (m.s.ft == WPQ) {
		if (line[4] == 'n') m.s.ft = WPN; else;
		if (line[4] == 'b') m.s.ft = WPB; else;
		if (line[4] == 'r') m.s.ft = WPR;
	  }
	  else;
	  if (m.s.ft == BPQ) {
		if (line[4] == 'n') m.s.ft = BPN; else;
		if (line[4] == 'b') m.s.ft = BPB; else;
		if (line[4] == 'r') m.s.ft = BPR;
	  }
	  MakeMove(t, &m);
	  g[gly] = m;
	  gly++;
	  not_ok = InCheckBy[stm](t, king[1 - stm]); 
	  if (not_ok) {
		gly--;
		m = g[gly];
		TakeBack(t, &m);
		return;
	  }
	}
	PrintBoard(t);
	return;
  }

  if (!strcmp(cmd, "undo") && gly > 0) {
	gly--;
	m = g[gly];
	TakeBack(t, &m);
	PrintBoard(t);
	return;
  }

}
 

Code: Select all

// !
// Search.cpp

void StartSearch(Thread* t) {

}

Code: Select all

// !
// GenMoves.cpp

bool GenAllMoves(Thread* t) {
  s08 fs, ft;
  u64 atk;
  
  u64 pieces = piece[stm];
  u64 notme = ~pieces;
  u64 occ = pieces | piece[1 - stm];
  u64 empty = ~occ;
  u64 enemy = notme ^ empty;

  abb[ply] = 0;

  do {
    fs = std::countr_zero(pieces);
    ft = board[fs];
    switch (ft) {
    case ES:
      // can't get here
      break;
    case WP:
      switch (fs >> 3) {
      case RANK1:
        // can't get here
        break;
      case RANK2:
        gbb[ply][fs] = ((0x0000000000000100ull << fs) & empty);
        gbb[ply][fs] |= ((gbb[ply][fs] << 8) & empty);
        atk = wPawnCapts[fs];
        gbb[ply][fs] |= atk & enemy;
        abb[ply] |= atk;
        break;
      case RANK3:
      case RANK4:
        gbb[ply][fs] = ((0x0000000000000100ull << fs) & empty);
        atk = wPawnCapts[fs];
        gbb[ply][fs] |= atk & enemy;
        abb[ply] |= atk;
        break;
      case RANK5:
        gbb[ply][fs] = ((0x0000000000000100ull << fs) & empty);
        atk = wPawnCapts[fs];
        gbb[ply][fs] |= (atk & (enemy | epbit[ply]));
        abb[ply] |= atk;
        break;
      case RANK6:
      case RANK7:
        gbb[ply][fs] = ((0x0000000000000100ull << fs) & empty);
        atk = wPawnCapts[fs];
        gbb[ply][fs] |= atk & enemy;
        abb[ply] |= atk;
        break;
      }
      break;
    case WN:
      gbb[ply][fs] = knightMoves[fs] & notme;
      abb[ply] |= knightMoves[fs];
      break;
    case WB:
      gbb[ply][fs]
        = (ray[std::countr_zero(ray[fs].NW & occ)].NW
         | ray[std::countr_zero(ray[fs].NE & occ)].NE
         | rev[std::countl_zero(ray[fs].SE & occ)].SE
         | rev[std::countl_zero(ray[fs].SW & occ)].SW)
         ^ bishopMoves[fs];
      abb[ply] |= gbb[ply][fs];
      gbb[ply][fs] &= notme;
      break;
    case WRC:
    case WR:
      gbb[ply][fs]
        = (ray[std::countr_zero(ray[fs].NN & occ)].NN
         | ray[std::countr_zero(ray[fs].EE & occ)].EE
         | rev[std::countl_zero(ray[fs].SS & occ)].SS
         | rev[std::countl_zero(ray[fs].WW & occ)].WW)
         ^ rookMoves[fs];
      abb[ply] |= gbb[ply][fs];
      gbb[ply][fs] &= notme;
      break;
    case WQ:
      gbb[ply][fs]
        = (ray[std::countr_zero(ray[fs].NW & occ)].NW
         | ray[std::countr_zero(ray[fs].NE & occ)].NE
         | rev[std::countl_zero(ray[fs].SE & occ)].SE
         | rev[std::countl_zero(ray[fs].SW & occ)].SW
         | ray[std::countr_zero(ray[fs].NN & occ)].NN
         | ray[std::countr_zero(ray[fs].EE & occ)].EE
         | rev[std::countl_zero(ray[fs].SS & occ)].SS
         | rev[std::countl_zero(ray[fs].WW & occ)].WW) 
         ^ queenMoves[fs];
      abb[ply] |= gbb[ply][fs];
      gbb[ply][fs] &= notme;
      break;
    case WKC:
      gbb[ply][fs] = kingMoves[fs] & notme;
      abb[ply] |= kingMoves[fs];
      gbb[ply][fs] |= (u64)((board[h1] == WRC) + ((occ & SWCS) == 0) + (AttackedByBlack(t, AWCS) == 0) == 3) << g1;
      gbb[ply][fs] |= (u64)((board[a1] == WRC) + ((occ & SWCL) == 0) + (AttackedByBlack(t, AWCL) == 0) == 3) << c1;
      break;
    case WK:
      gbb[ply][fs] = kingMoves[fs] & notme;
      abb[ply] |= kingMoves[fs];
      break;
    case BP:
      switch (fs >> 3) {
      case RANK1:
        // can't get here
        break;
      case RANK2:
      case RANK3:
        gbb[ply][fs] = (1ull << (fs - 8)) & empty;
        atk = bPawnCapts[fs];
        gbb[ply][fs] |= atk & enemy;
        abb[ply] |= atk;
        break;
      case RANK4:
        gbb[ply][fs] = (1ull << (fs - 8)) & empty;
        atk = bPawnCapts[fs];
        gbb[ply][fs] |= (atk & (enemy | epbit[ply]));
        abb[ply] |= atk;
        break;
      case RANK5:
      case RANK6:
        gbb[ply][fs] = (1ull << (fs - 8)) & empty;
        atk = bPawnCapts[fs];
        gbb[ply][fs] |= atk & enemy;
        abb[ply] |= atk;
        break;
      case RANK7:
        gbb[ply][fs] = (1ull << (fs - 8)) & empty;
        gbb[ply][fs] |= ((gbb[ply][fs] >> 8) & empty);
        atk = bPawnCapts[fs];
        gbb[ply][fs] |= atk & enemy;
        abb[ply] |= atk;
        break;
      }
      break;
    case BN:
      gbb[ply][fs] = knightMoves[fs] & notme;
      abb[ply] |= knightMoves[fs];
      break;
    case BB:
      gbb[ply][fs]
        = (ray[std::countr_zero(ray[fs].NW & occ)].NW
          | ray[std::countr_zero(ray[fs].NE & occ)].NE
          | rev[std::countl_zero(ray[fs].SE & occ)].SE
          | rev[std::countl_zero(ray[fs].SW & occ)].SW)
        ^ bishopMoves[fs];
      abb[ply] |= gbb[ply][fs];
      gbb[ply][fs] &= notme;
      break;
    case BRC:
    case BR:
      gbb[ply][fs]
        = (ray[std::countr_zero(ray[fs].NN & occ)].NN
         | ray[std::countr_zero(ray[fs].EE & occ)].EE
         | rev[std::countl_zero(ray[fs].SS & occ)].SS
         | rev[std::countl_zero(ray[fs].WW & occ)].WW)
         ^ rookMoves[fs];
      abb[ply] |= gbb[ply][fs];
      gbb[ply][fs] &= notme;
      break;
    case BQ:
      gbb[ply][fs]
        = (ray[std::countr_zero(ray[fs].NW & occ)].NW
         | ray[std::countr_zero(ray[fs].NE & occ)].NE
         | rev[std::countl_zero(ray[fs].SE & occ)].SE
         | rev[std::countl_zero(ray[fs].SW & occ)].SW
         | ray[std::countr_zero(ray[fs].NN & occ)].NN
         | ray[std::countr_zero(ray[fs].EE & occ)].EE
         | rev[std::countl_zero(ray[fs].SS & occ)].SS
         | rev[std::countl_zero(ray[fs].WW & occ)].WW)
         ^ queenMoves[fs];
      abb[ply] |= gbb[ply][fs];
      gbb[ply][fs] &= notme;
      break;
    case BKC:
      gbb[ply][fs] = kingMoves[fs] & notme;
      abb[ply] |= kingMoves[fs];
      gbb[ply][fs] |= (u64)((board[h8] == BRC) + ((occ & SBCS) == 0) + (AttackedByWhite(t, ABCS) == 0) == 3) << g8;
      gbb[ply][fs] |= (u64)((board[a8] == BRC) + ((occ & SBCL) == 0) + (AttackedByWhite(t, ABCL) == 0) == 3) << c8;
      break;
    case BK:
      gbb[ply][fs] = kingMoves[fs] & notme;
      abb[ply] |= kingMoves[fs];
      break;
    }
    pieces ^= 1ull << fs;
  } while (pieces);

  return 1 - (king[1 - stm] & abb[ply]);
}

Code: Select all

// !
// Move.cpp

void MakeMove(Thread* t, uMove* m) {

  switch (m->s.ft) {
  case ES:
	// can't get here
	break;
  case WP:
	board[mfs] = ES;
	board[mts] = WP;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WP][mts];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[WP] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WN:
	board[mfs] = ES;
	board[mts] = WN;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WN][mfs];
	wpos += pst[WN][mts];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WN] ^= 1ull << mfs;
	pctypbb[WN] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WB:
	board[mfs] = ES;
	board[mts] = WB;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WB][mfs];
	wpos += pst[WB][mts];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WB] ^= 1ull << mfs;
	pctypbb[WB] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WRC:
  case WR:
	board[mfs] = ES;
	board[mts] = WR;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WR][mfs];
	wpos += pst[WR][mts];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WR] ^= 1ull << mfs;
	pctypbb[WR] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WQ:
	board[mfs] = ES;
	board[mts] = WQ;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WQ][mfs];
	wpos += pst[WQ][mts];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WQ] ^= 1ull << mfs;
	pctypbb[WQ] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WKC:
  case WK:
	board[mfs] = ES;
	board[mts] = WK;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	king[WHITE] ^= 1ull << mfs;
	king[WHITE] ^= 1ull << mts;
	wpos -= pst[WK][mfs];
	wpos += pst[WK][mts];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BP:
	board[mfs] = ES;
	board[mts] = BP;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BP][mfs];
	bpos += pst[BP][mts];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[BP] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BN:
	board[mfs] = ES;
	board[mts] = BN;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BN][mfs];
	bpos += pst[BN][mts];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BN] ^= 1ull << mfs;
	pctypbb[BN] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BB:
	board[mfs] = ES;
	board[mts] = BB;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BB][mfs];
	bpos += pst[BB][mts];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BB] ^= 1ull << mfs;
	pctypbb[BB] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BRC:
  case BR:
	board[mfs] = ES;
	board[mts] = BR;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BR][mfs];
	bpos += pst[BR][mts];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BR] ^= 1ull << mfs;
	pctypbb[BR] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BQ:
	board[mfs] = ES;
	board[mts] = BQ;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BQ][mfs];
	bpos += pst[BQ][mts];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BQ] ^= 1ull << mfs;
	pctypbb[BQ] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BKC:
  case BK:
	board[mfs] = ES;
	board[mts] = BK;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	king[BLACK] ^= 1ull << mfs;
	king[BLACK] ^= 1ull << mts;
	bpos -= pst[BK][mfs];
	bpos += pst[BK][mts];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WCS:
	board[e1] = ES;
	board[g1] = WK;
	piece[WHITE] ^= 1ull << e1;
	piece[WHITE] ^= 1ull << g1;
	king[WHITE] ^= 1ull << e1;
	king[WHITE] ^= 1ull << g1;
	wpos -= pst[WK][e1];
	wpos += pst[WK][g1];
	board[h1] = ES;
	board[f1] = WR;
	piece[WHITE] ^= 1ull << h1;
	piece[WHITE] ^= 1ull << f1;
	wpos += 10;
	pctypbb[WR] ^= 1ull << h1;
	pctypbb[WR] ^= 1ull << f1;
	break;
  case WCL:
	board[e1] = ES;
	board[c1] = WK;
	piece[WHITE] ^= 1ull << e1;
	piece[WHITE] ^= 1ull << c1;
	king[WHITE] ^= 1ull << e1;
	king[WHITE] ^= 1ull << c1;
	wpos -= pst[WK][e1];
	wpos += pst[WK][c1];
	board[a1] = ES;
	board[d1] = WR;
	piece[WHITE] ^= 1ull << a1;
	piece[WHITE] ^= 1ull << d1;
	wpos += 8;
	pctypbb[WR] ^= 1ull << a1;
	pctypbb[WR] ^= 1ull << d1;
	break;
  case WPD:
	board[mfs] = ES;
	board[mts] = WP;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WP][mts];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[WP] ^= 1ull << mts;
	epbit[ply + 1] = 1ull << (mts - 8);
	break;
  case WPE:
	board[mfs] = ES;
	board[mts] = WP;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WP][mts];
	board[mts - 8] = ES;
	piece[BLACK] ^= 1ull << (mts - 8);
	bmat -= val[BP];
	bpos -= pst[BP][mts - 8];
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[WP] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << (mts - 8);
	break;
  case WPQ:
	board[mfs] = ES;
	board[mts] = WQ;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WQ][mts];
	wmat += 80;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[WQ] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WPN:
	board[mfs] = ES;
	board[mts] = WN;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WN][mts];
	wmat += 19;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[WN] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WPR:
	board[mfs] = ES;
	board[mts] = WR;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WR][mts];
	wmat += 40;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[WR] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WPB:
	board[mfs] = ES;
	board[mts] = WB;
	piece[WHITE] ^= 1ull << mfs;
	piece[WHITE] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WB][mts];
	wmat += 22;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat -= val[mtt];
	bpos -= pst[mtt][mts];
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[WB] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BCS:
	board[e8] = ES;
	board[g8] = BK;
	piece[BLACK] ^= 1ull << e8;
	piece[BLACK] ^= 1ull << g8;
	king[BLACK] ^= 1ull << e8;
	king[BLACK] ^= 1ull << g8;
	bpos -= pst[BK][e8];
	bpos += pst[BK][g8];
	board[h8] = ES;
	board[f8] = BR;
	piece[BLACK] ^= 1ull << h8;
	piece[BLACK] ^= 1ull << f8;
	bpos += 10;
	pctypbb[BR] ^= 1ull << h8;
	pctypbb[BR] ^= 1ull << f8;
	break;
  case BCL:
	board[e8] = ES;
	board[c8] = BK;
	piece[BLACK] ^= 1ull << e8;
	piece[BLACK] ^= 1ull << c8;
	king[BLACK] ^= 1ull << e8;
	king[BLACK] ^= 1ull << c8;
	bpos -= pst[BK][e8];
	bpos += pst[BK][c8];
	board[a8] = ES;
	board[d8] = BR;
	piece[BLACK] ^= 1ull << a8;
	piece[BLACK] ^= 1ull << d8;
	bpos += 8;
	pctypbb[BR] ^= 1ull << a8;
	pctypbb[BR] ^= 1ull << d8;
	break;
  case BPD:
	board[mfs] = ES;
	board[mts] = BP;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BP][mfs];
	bpos += pst[BP][mts];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[BP] ^= 1ull << mts;
	epbit[ply + 1] = 1ull << (mts + 8);
	break;
  case BPE:
	board[mfs] = ES;
	board[mts] = BP;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	wpos -= pst[WP][mfs];
	wpos += pst[WP][mts];
	board[mts + 8] = ES;
	piece[WHITE] ^= 1ull << (mts + 8);
	wmat -= val[WP];
	wpos -= pst[WP][mts + 8];
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[BP] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << (mts + 8);
	break;
  case BPQ:
	board[mfs] = ES;
	board[mts] = BQ;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BP][mfs];
	bpos += pst[BQ][mts];
	bmat += 80;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[BQ] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BPN:
	board[mfs] = ES;
	board[mts] = BN;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BP][mfs];
	bpos += pst[BN][mts];
	bmat += 19;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[BN] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BPR:
	board[mfs] = ES;
	board[mts] = BR;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BP][mfs];
	bpos += pst[BN][mts];
	bmat += 40;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[BR] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BPB:
	board[mfs] = ES;
	board[mts] = BB;
	piece[BLACK] ^= 1ull << mfs;
	piece[BLACK] ^= 1ull << mts;
	bpos -= pst[BP][mfs];
	bpos += pst[BB][mts];
	bmat += 22;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat -= val[mtt];
	wpos -= pst[mtt][mts];
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[BB] ^= 1ull << mts;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  }

  ply++;
  stm = 1 - stm;
}

void TakeBack(Thread* t, uMove* m) {
  s08 ft;

  ply--;
  stm = 1 - stm;

  ft = m->s.ft;
  switch (ft) {
  case ES:
	// can't get here
	break;
  case WP:
	board[mfs] = WP;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WP][mts];
	wpos += pst[WP][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WP] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WN:
	board[mfs] = WN;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WN][mts];
	wpos += pst[WN][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WN] ^= 1ull << mts;
	pctypbb[WN] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WB:
	board[mfs] = WB;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WB][mts];
	wpos += pst[WB][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WB] ^= 1ull << mts;
	pctypbb[WB] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WRC:
	board[mfs] = WRC;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WR][mts];
	wpos += pst[WR][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WR] ^= 1ull << mts;
	pctypbb[WR] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WR:
	board[mfs] = WR;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WR][mts];
	wpos += pst[WR][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WR] ^= 1ull << mts;
	pctypbb[WR] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WQ:
	board[mfs] = WQ;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WQ][mts];
	wpos += pst[WQ][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WQ] ^= 1ull << mts;
	pctypbb[WQ] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WKC:
	board[mfs] = WKC;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	king[WHITE] ^= 1ull << mts;
	king[WHITE] ^= 1ull << mfs;
	wpos -= pst[WK][mts];
	wpos += pst[WK][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WK:
	board[mfs] = WK;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	king[WHITE] ^= 1ull << mts;
	king[WHITE] ^= 1ull << mfs;
	wpos -= pst[WK][mts];
	wpos += pst[WK][mfs];
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BP:
	board[mfs] = BP;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BP][mts];
	bpos += pst[BP][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BP] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BN:
	board[mfs] = BN;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BN][mts];
	bpos += pst[BN][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BN] ^= 1ull << mts;
	pctypbb[BN] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BB:
	board[mfs] = BB;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BB][mts];
	bpos += pst[BB][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BB] ^= 1ull << mts;
	pctypbb[BB] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BRC:
	board[mfs] = BRC;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BR][mts];
	bpos += pst[BR][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BR] ^= 1ull << mts;
	pctypbb[BR] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BR:
	board[mfs] = BR;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BR][mts];
	bpos += pst[BR][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BR] ^= 1ull << mts;
	pctypbb[BR] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BQ:
	board[mfs] = BQ;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BR][mts];
	bpos += pst[BR][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BQ] ^= 1ull << mts;
	pctypbb[BQ] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BKC:
	board[mfs] = BKC;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	king[BLACK] ^= 1ull << mts;
	king[BLACK] ^= 1ull << mfs;
	bpos -= pst[BK][mts];
	bpos += pst[BK][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BK:
	board[mfs] = BK;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	king[BLACK] ^= 1ull << mts;
	king[BLACK] ^= 1ull << mfs;
	bpos -= pst[BK][mts];
	bpos -= pst[BK][mts];
	bpos += pst[BK][mfs];
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WCS:
	board[e1] = WKC;
	board[g1] = ES;
	piece[WHITE] ^= 1ull << g1;
	piece[WHITE] ^= 1ull << e1;
	king[WHITE] ^= 1ull << g1;
	king[WHITE] ^= 1ull << e1;
	bpos -= pst[BK][mts];
	wpos -= pst[WK][g1];
	wpos += pst[WK][e1];
	board[h1] = WRC;
	board[f1] = ES;
	piece[WHITE] ^= 1ull << f1;
	piece[WHITE] ^= 1ull << h1;
	wpos -= pst[WR][f1];
	wpos += pst[WR][h1];
	pctypbb[WR] ^= 1ull << f1;
	pctypbb[WR] ^= 1ull << h1;
	break;
  case WCL:
	board[e1] = WKC;
	board[c1] = ES;
	piece[WHITE] ^= 1ull << c1;
	piece[WHITE] ^= 1ull << e1;
	king[WHITE] ^= 1ull << c1;
	king[WHITE] ^= 1ull << e1;
	wpos -= pst[WK][c1];
	wpos += pst[WK][e1];
	board[a1] = WRC;
	board[d1] = ES;
	piece[WHITE] ^= 1ull << d1;
	piece[WHITE] ^= 1ull << a1;
	wpos -= pst[WR][d1];
	wpos += pst[WR][a1];
	pctypbb[WR] ^= 1ull << d1;
	pctypbb[WR] ^= 1ull << a1;
	break;
  case WPD:
	board[mfs] = WP;
	board[mts] = ES;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WP][mts];
	wpos += pst[WP][mfs];
	epbit[ply + 1] = 0;
	pctypbb[WP] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << mfs;
	break;
  case WPE:
	board[mfs] = WP;
	board[mts] = ES;
	board[mts - 8] = BP;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WP][mts];
	wpos += pst[WP][mfs];
	piece[BLACK] ^= 1ULL << (mts - 8);
	bmat += val[BP];
	bpos += pst[BP][mts];
	pctypbb[WP] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[BP] ^= 1ull << (mts - 8);
	break;
  case WPQ:
	board[mfs] = WP;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WQ][mts];
	wpos += pst[WP][mfs];
	wmat -= 80;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WQ] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WPN:
	board[mfs] = WP;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WN][mts];
	wpos += pst[WP][mfs];
	wmat -= 19;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WN] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WPR:
	board[mfs] = WP;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WR][mts];
	wpos += pst[WP][mfs];
	wmat -= 40;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WR] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case WPB:
	board[mfs] = WP;
	board[mts] = mtt;
	piece[WHITE] ^= 1ull << mts;
	piece[WHITE] ^= 1ull << mfs;
	wpos -= pst[WB][mts];
	wpos += pst[WP][mfs];
	wmat -= 22;
	piece[BLACK] ^= (u64)(mtt != ES) << mts;
	bmat += val[mtt];
	bpos += pst[mtt][mts];
	pctypbb[WB] ^= 1ull << mts;
	pctypbb[WP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BCS:
	board[e8] = BKC;
	board[g8] = ES;
	piece[BLACK] ^= 1ull << g8;
	piece[BLACK] ^= 1ull << e8;
	king[BLACK] ^= 1ull << g8;
	king[BLACK] ^= 1ull << e8;
	bpos -= pst[BK][g8];
	bpos += pst[BK][e8];
	board[h8] = BRC;
	board[f8] = ES;
	piece[BLACK] ^= 1ull << f8;
	piece[BLACK] ^= 1ull << h8;
	bpos -= pst[BR][f8];
	bpos += pst[BR][h8];
	pctypbb[BR] ^= 1ull << f8;
	pctypbb[BR] ^= 1ull << h8;
	break;
  case BCL:
	board[e8] = BKC;
	board[c8] = ES;
	piece[BLACK] ^= 1ull << c8;
	piece[BLACK] ^= 1ull << e8;
	king[BLACK] ^= 1ull << c8;
	king[BLACK] ^= 1ull << e8;
	bpos -= pst[BK][c8];
	bpos += pst[BK][e8];
	board[a8] = BRC;
	board[d8] = ES;
	piece[BLACK] ^= 1ull << c8;
	piece[BLACK] ^= 1ull << a8;
	bpos -= pst[BR][d8];
	bpos += pst[BR][a8];
	pctypbb[BR] ^= 1ull << c8;
	pctypbb[BR] ^= 1ull << a8;
	break;
  case BPD:
	board[mfs] = BP;
	board[mts] = ES;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BP][mts];
	bpos += pst[BP][mfs];
	pctypbb[BP] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << mfs;
	epbit[ply + 1] = 0;
	break;
  case BPE:
	board[mfs] = BP;
	board[mts] = ES;
	board[mts + 8] = WP;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BP][mts];
	bpos += pst[BP][mfs];
	piece[WHITE] ^= 1ULL << (mts + 8);
	bmat += val[WP];
	bpos += pst[WP][mts];
	pctypbb[BP] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[WP] ^= 1ull << (mts + 8);
	break;
  case BPQ:
	board[mfs] = BP;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BQ][mts];
	bpos += pst[BP][mfs];
	bmat -= 80;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BQ] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BPN:
	board[mfs] = BP;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BN][mts];
	bpos += pst[BP][mfs];
	bmat -= 19;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BN] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BPR:
	board[mfs] = BP;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BR][mts];
	bpos += pst[BP][mfs];
	bmat -= 40;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BR] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  case BPB:
	board[mfs] = BP;
	board[mts] = mtt;
	piece[BLACK] ^= 1ull << mts;
	piece[BLACK] ^= 1ull << mfs;
	bpos -= pst[BB][mts];
	bpos += pst[BP][mfs];
	bmat -= 22;
	piece[WHITE] ^= (u64)(mtt != ES) << mts;
	wmat += val[mtt];
	wpos += pst[mtt][mts];
	pctypbb[BB] ^= 1ull << mts;
	pctypbb[BP] ^= 1ull << mfs;
	pctypbb[mtt] ^= 1ull << mts;
	break;
  }
}

Code: Select all

// !
// Utilities.cpp

void PrintBoard(Thread* t) {
  s32 x, y, sq, pce;
  s08 fig[] = { ".PNBRRQKKpnbrrqkk" };

  for (y = 7; y >= 0; y--) {
	for (x = 0; x < 8; x++) {
	  sq = ((y << 3) + x);
	  pce = board[sq];
	  std::cout << "  " << fig[pce];
	}
	std::cout << std::endl;
  }
  std::cout << std::endl;
}


bool LoadFen(Thread* t, s08* f) {
  s32 rank, file, sq, fs, pce;

  for (sq = a1; sq <= h8; sq++) board[sq] = ES;
  
  ply = 0;
  file = FILEa;
  rank = RANK8;
  fs = 56;

  for (;; f++) {
	if (*f == ' ') break;
	switch (*f) {
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	  file += *f - '0';
	  fs = (rank * 8 + file) & 63;
	  continue;
	case '/':
	  file = FILEa;
	  rank--;
	  fs = (rank * 8 + file) & 63;
	  continue;
	case 'P':
	  pce = WP;
	  break;
	case 'N':
	  pce = WN;
	  break;
	case 'B':
	  pce = WB;
	  break;
	case 'R':
	  pce = WR;
	  break;
	case 'Q':
	  pce = WQ;
	  break;
	case 'K':
	  pce = WK;
	  break;
	case 'p':
	  pce = BP;
		break;
	case 'n':
	  pce = BN;
	  break;
	case 'b':
	  pce = BB;
	  break;
	case 'r':
	  pce = BR;
	  break;
	case 'q':
	  pce = BQ;
	  break;
	case 'k':
	  pce = BK;
	  break;
	}
	board[fs] = pce;
	file++;
	fs = (rank * 8 + file) & 63;
  }
  f++;
  switch (*f++) {
  case 'w':
	stm = WHITE;
	break;
  case 'b':
	stm = BLACK;
	break;
  default:
	return false;
  }
  if (*f++ != ' ') return false;
  if (*f == '-') {
	f++;
	if (*f++ != ' ') return false;
  }
  else {
	for (;;) {
	  if (*f == ' ') {
		f++;
		break;
	  }
	  switch (*f++) {
	  case 'K':
		board[e1] = WKC;
		board[h1] = WRC;
		break;
	  case 'Q':
		board[e1] = WKC;
		board[a1] = WRC;
		break;
	  case 'k':
		board[e8] = BKC;
		board[h8] = BRC;
		break;
	  case 'q':
		board[e8] = BKC;
		board[a8] = BRC;
		break;
	  default:
		return false;
	  }
	}
  }
  epbit[0] = 0;
  if (*f == '-') f++;
  else {
	if (*f < 'a' || *f > 'h') return false;
	if (*(f + 1) < '0' || *(f + 1) > '7') return false;
	rank = *(f + 1) - '1';
	file = *f - 'a';
	f += 2;
  }
  if (*f++ != ' ') return false;
  fifty[0] = 0;
  for (;;) {
	if (!isdigit(*f)) break;
	fifty[0] = *f++ * 10;
	fifty[0] += *f++ - '0';
  }
  if (*f++ != ' ') return false;
  start = 0;
  for (;;) {
	if (!isdigit(*f)) break;
	start = *f++ * 10;
	start += *f++ - '0';
  }
  if (start < 1) return false;
  while (*f == ' ') f++;
  if (*f != '\0') return false;

  return true;
}

s32 AttackedByWhite(Thread* t, u64 bb) {
  s32 n = 0;
  u64 bbn;
  u64 occ = piece[BLACK] | piece[WHITE];

  do {
	s32 sq = std::countr_zero(bb);
	bbn = (knightMoves[sq] & pctypbb[WN])
	  | (bPawnCapts[sq] & pctypbb[WP])
	  | (kingMoves[sq] & pctypbb[WK])
	  | (((ray[std::countr_zero(ray[sq].NW & occ)].NW
		 | ray[std::countr_zero(ray[sq].NE & occ)].NE
		 | rev[std::countl_zero(ray[sq].SE & occ)].SE
		 | rev[std::countl_zero(ray[sq].SW & occ)].SW)
		 ^ bishopMoves[sq])
		 & (pctypbb[WB] | pctypbb[WQ]))
	  | (((ray[std::countr_zero(ray[sq].NN & occ)].NN
		 | ray[std::countr_zero(ray[sq].EE & occ)].EE
		 | rev[std::countl_zero(ray[sq].SS & occ)].SS
		 | rev[std::countl_zero(ray[sq].WW & occ)].WW)
		 ^ rookMoves[sq])
		 & (pctypbb[WR] | pctypbb[WQ]));
	n += std::popcount(bbn);
	bb ^= 1ull << sq;
  } while (bb);

  return n;

}

s32 AttackedByBlack(Thread* t, u64 bb) {
  s32 n = 0;
  u64 bbn;
  u64 occ = piece[BLACK] | piece[WHITE];

  do {
	s32 sq = std::countr_zero(bb);
	bbn = (knightMoves[sq] & pctypbb[BN])
	    | (wPawnCapts[sq] & pctypbb[BP])
	    | (kingMoves[sq] & pctypbb[BK])
	    | (((ray[std::countr_zero(ray[sq].NW & occ)].NW
		   | ray[std::countr_zero(ray[sq].NE & occ)].NE
		   | rev[std::countl_zero(ray[sq].SE & occ)].SE
		   | rev[std::countl_zero(ray[sq].SW & occ)].SW)
		   ^ bishopMoves[sq])
		   & (pctypbb[BB] | pctypbb[BQ]))
	    | (((ray[std::countr_zero(ray[sq].NN & occ)].NN
		   | ray[std::countr_zero(ray[sq].EE & occ)].EE
		   | rev[std::countl_zero(ray[sq].SS & occ)].SS
		   | rev[std::countl_zero(ray[sq].WW & occ)].WW)
		   ^ rookMoves[sq])
		   & (pctypbb[BR] | pctypbb[BQ]));
	n += std::popcount(bbn);
	bb ^= 1ull << sq;
  } while (bb);

  return n;
}

s32(*InCheckBy[2])(Thread*, u64) = { AttackedByBlack, AttackedByWhite };

uMove FillMoveFields(Thread* t, s08 fs, s08 ts) {
  uMove m;

  m.s.fs = fs;
  m.s.ts = ts;
  m.s.tt = board[ts];

  m.s.ft = board[fs];
  switch (m.s.ft) {
  case ES:
	// can't get here
	break;
  case WP:
	switch (fs >> 3) {
	case RANK1:
	  // can't get here
	  break;
	case RANK2:
	  m.s.ft += ((fs + 16 == ts) * (WPD - WP));
	  break;
	case RANK3:
	case RANK4:
	  // no action
	  break;
	case RANK5:
	  m.s.ft += ((ts != fs + 8 && !m.s.tt) * (WPE - WP));
	  break;
	case RANK6:
	  // no action
	  break;
	case RANK7:
	  m.s.ft = WPQ;
	  break;
	}
	break;
  case WN:
  case WB:
  case WRC:
  case WR:
  case WQ:
	// no action
	break;
  case WKC:
	m.s.ft += ((ts == g1) * (WCS - WKC) + (ts == c1) * (WCL - WKC));
	break;
  case WK:
	// no action
	break;
  case BP:
	switch (fs >> 3) {
	case RANK1:
	  // can't get here
	  break;
	case RANK2:
	  m.s.ft = BPQ;
	  break;
	case RANK3:
	  // no action
	  break;
	case RANK4:
	  m.s.ft += ((ts != fs - 8 && !m.s.tt) * (BPE - BP));
	  break;
	case RANK5:
	case RANK6:
	  // no action
	  break;
	case RANK7:
	  m.s.ft += ((fs - 16 == ts) * (BPD - BP));
	  break;
	}
	break;
  case BN:
  case BB:
  case BRC:
  case BR:
  case BQ:
	// no action
	break;
  case BKC:
	m.s.ft += ((ts == g8) * (BCS - BKC) + (ts == c8) * (BCL - BKC));
	break;
  }

  return m;
}

Code: Select all

// !
// Globals.cpp

s32 mode;
s32 computer;

s32 numThreads;

Thread** thread;

Ray ray[65];
Ray rev[65];

u64 wPawnCapts[64];
u64 bPawnCapts[64];
u64 knightMoves[64];
u64 bishopMoves[64];
u64 rookMoves[64];
u64 queenMoves[64];
u64 kingMoves[64];

s32 val[] = { 0, 10, 29, 32, 50, 50, 90, 0, 0, 10, 29, 32, 50, 50, 90, 0, 0 };

s32 pst[17][64];

s08 startFen[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
s08 fen[100];

Code: Select all

// !
// Equates.cpp

constexpr auto AWCS = 0b0000000000000000000000000000000000000000000000000000000001110000;
constexpr auto AWCL = 0b0000000000000000000000000000000000000000000000000000000000011100;
constexpr auto ABCS = 0b0111000000000000000000000000000000000000000000000000000000000000;
constexpr auto ABCL = 0b0001110000000000000000000000000000000000000000000000000000000000;

constexpr auto SWCS = 0b0000000000000000000000000000000000000000000000000000000001100000;
constexpr auto SWCL = 0b0000000000000000000000000000000000000000000000000000000000001110;
constexpr auto SBCS = 0b0110000000000000000000000000000000000000000000000000000000000000;
constexpr auto SBCL = 0b0000111000000000000000000000000000000000000000000000000000000000;

enum { EXIT, GETCMD, SEARCH };

enum { BLACK, WHITE };

enum { ILLEGAL, LEGAL };

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, e5, 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 { FILEa, FILEb, FILEc, FILEd, FILEe, FILEf, FILEg, FILEh };

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

enum {
  ES,
  WP, WN, WB, WRC, WR, WQ, WKC, WK,
  BP, BN, BB, BRC, BR, BQ, BKC, BK,
  WCS, WCL, WPD, WPE, WPQ, WPN, WPR, WPB,
  BCS, BCL, BPD, BPE, BPQ, BPN, BPR, BPB
};

Code: Select all

// !
// Defines.cpp

typedef char s08;
typedef int s32;
typedef unsigned long long u64;
typedef long long s64;

#define dir_HO(X) (0xFFull << (X & 56))
#define dir_VE(X) (0x0101010101010101ull << (X & 7))
#define dir_D1(X) (mask_shift(0x8040201008040201ull, (X & 7) - (X >> 3)))
#define dir_D2(X) (mask_shift(0x0102040810204080ull, 7 - (X & 7) - (X >> 3)))
#define GetLower(X) ((1ull << X) - 1)
#define GetUpper(X) (0xFFFFFFFFFFFFFFFE << (X))

struct Ray {
  u64 NW;
  u64 NN;
  u64 NE;
  u64 EE;
  u64 SE;
  u64 SS;
  u64 SW;
  u64 WW;
};

struct sMove {
  s08 fs; // from square
  s08 ts; // to square
  s08 ft; // from type
  s08 tt; // to type
  s32 sc; // score
};

union uMove {
  sMove s;
  u64 u;
};

// instead of typing m->s.fs just type mfs
#define mfs m->s.fs
#define mts m->s.ts
#define mft m->s.ft
#define mtt m->s.tt

struct Thread {
  uMove g[500];
  u64 piece[2];
  u64 king[2];
  u64 pctypbb[17];
  u64 epbit[100];
  u64 abb[100];
  u64 gbb[100][64];
  s32 board[64];
  s32 fifty[100];
  s32 ply;
  s32 gly;
  s32 stm;
  s32 wmat;
  s32 bmat;
  s32 wpos;
  s32 bpos;
  s32 start;
};

// to avoid having to type t->whatever just type whatever
#define g       t->g
#define piece   t->piece
#define king    t->king
#define pctypbb t->pctypbb
#define epbit   t->epbit
#define abb     t->abb
#define gbb     t->gbb
#define board   t->board
#define fifty   t->fifty
#define ply     t->ply
#define gly     t->gly
#define stm     t->stm
#define matsc   t->matsc
#define wmat    t->wmat
#define bmat    t->bmat
#define wpos    t->wpos
#define bpos    t->bpos
#define start   t->start
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Devlog of !

Post by Mike Sherwin »

I have not made any reports lately because I've just been bug hunting. And I've not been very successful. Still perft() does return mostly correct results. Enough so that I can compare the performance of ! with Bricabrac when results are identical. And the results are very good for !.

Before the results are compared there are some caveats. ! uses Bob-Mike-Daniel classic bitboards and Bric uses the faster SISSY bitboards. The results extended to searching are not directly comparable. ! generates and stores only the bitboards. If there is an early cutoff not many bits get spun into moves saving a lot of time. Bric generates a move list. ! is basically a rewrite of Bric to increase performance.

There is something I just can't get a handle on. And that is the speed of various engines and their perft function. There is no standardization for comparison. Authors are usually vague and/or incomplete about the tricks they employ or the hardware it runs on often claiming unbelievable nodes per second. So I'm left wondering if my code is fast or maybe not. However, my node rate while searching is usually superior. Bric searches over 10 million nodes per second and up to 15 million nodes per second in the endgame. ! does not have a search yet but I have started writing one.

The results are for perft 6 in this position.
[fen]rnbqk2r/ppppppbp/5np1/8/2PP4/2N2N2/PP2PPPP/R1BQKB1R b KQkq - 3 4 [/fen]
Bricabrac - 895,702,085 nodes in 39320 milliseconds = 39.32 seconds, 22,779,827 nodes per second.
! - 895,702,085 nodes in 28590 milliseconds = 28.59 seconds, 31,329,208 nodes per second.

It is just hopeful speculation at this point but I'm guesstimating that ! will search very close to 20 million nodes per second in the original position.

These results can be compared to Halfwit which is just a move generator example I wrote that is not a proper perft because it does not have an InCheck function. It's move generator is the same classic style that RomiChess uses. In the above position it registers 38,841,592 nodes per second. Although calling InCheck() for every move would cut that down to about 20 million nodes per second.

RomiChess op 7,293k nps
Bricabrac op 10,025k
! op ?k - we shall soon see.

If anyone has any insight into these results please let me know.
dangi12012
Posts: 1062
Joined: Tue Apr 28, 2020 10:03 pm
Full name: Daniel Infuehr

Re: Devlog of !

Post by dangi12012 »

I want to share an idea in the spirit of branchlessness.

A square can be represented by a config number.
A config is a unique ID that encodes for all squares that are reachable from it - as well as the piece + color that is moving + if the moves are taking or not.

I calculated this to be around a few million unique ids.
Now your movegenerator does not return the target square BB - but the unique config number!

This is effectively condensing a movelist of 0..14 moves into a single number! (So 32 bits for any and all moves, and not a list of 16bits ever!)
This ID is just the index into a preprepared array of structs which can contain the BBs to apply the move, as well as the zobrist and other information. (queens need two ids)

I already implemented this making my apply move look like that:

Code: Select all

static constexpr Position apply_move(Position& pos, const BinaryMove& move)
{
	const uint64_t* source = (uint64_t*)(&pos);
	return
	{
		(source[0] & move.clear[0]) | move.set[0],
		(source[1] & move.clear[1]) | move.set[1],
		(source[2] & move.clear[2]) | move.set[2],
		(source[3] & move.clear[3]) | move.set[3],
	};
}
Boiling down to a precalculated array of two AVX2 instructions for any and all moves in chess.
Branchless. Efficient. Keeping a single Register for the whole position.

I wish I had more time - leading me to skip CPU and continue my developments of a pure gpu engine that does not need to transfer anything to the cpu ever! the PV + tree can just be printed out on demand via memory mapped IO - other than that the gpu works on its own.
Worlds-fastest-Bitboard-Chess-Movegenerator
Daniel Inführ - Software Developer
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Devlog of !

Post by Mike Sherwin »

I don't really understand any of that. Wouldn't it deserve it's own thread? Besides I don't have any spare time to devote to anything other than what I'm trying to do. And no one wants to help with that. So why do I continue to bother? You know what the definition of insanity is? Doing the same thing over and over expecting a different result.
dangi12012
Posts: 1062
Joined: Tue Apr 28, 2020 10:03 pm
Full name: Daniel Infuehr

Re: Devlog of !

Post by dangi12012 »

Mike Sherwin wrote: Wed Sep 14, 2022 8:06 pm So why do I continue to bother? You know what the definition of insanity is? Doing the same thing over and over expecting a different result.
I think if you put what you have so far in a public git repository then co-working with most people here can be done easily.

Also from your initial statement you are expanding the horizon of the known in chessprogramming - which is awesome 👍
No one implemented dynamic learning so far so I don't see how that can be repetition.
Worlds-fastest-Bitboard-Chess-Movegenerator
Daniel Inführ - Software Developer
User avatar
lithander
Posts: 915
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: Devlog of !

Post by lithander »

Mike Sherwin wrote: Wed Sep 14, 2022 8:06 pm I don't really understand any of that. Wouldn't it deserve it's own thread? Besides I don't have any spare time to devote to anything other than what I'm trying to do. And no one wants to help with that. So why do I continue to bother? You know what the definition of insanity is? Doing the same thing over and over expecting a different result.
I would guess that most chessprogrammers here are either working on their own set of problems or they have taken a break from chess-programming and are mostly just reading. It's very hard to get involved in someone else's ideas and codebase in a way that it's truely "helping". And as Daniel said, a Github repo would go a long way in making your ideas, code and binaries more accessible and thus more likely to find a more involved audience.

I've read your posts with interest but I didn't really understand why you abandoned Bricabrac and started again from scratch with an even faster move generator idea. If it's really about dynamic learning a few nps more or less wouldn't really matter, right? Why bother with threading so early? To me that seems like distractions from what you're really interested in. But you can see how that does not make a very great first reply to a new project's devlog so I chose to just wait and see how the project unfolds before chiming in with unwanted opinions.

I think expecting people to want to co-develop your new engine after reading just one or two (very complex) forum posts about your plans is too optimistic but drawing the conclusion from that that nobody cares about the project and it's doomed to fail is way too negative.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Devlog of !

Post by Mike Sherwin »

lithander wrote: Thu Sep 15, 2022 5:36 am
Mike Sherwin wrote: Wed Sep 14, 2022 8:06 pm I don't really understand any of that. Wouldn't it deserve it's own thread? Besides I don't have any spare time to devote to anything other than what I'm trying to do. And no one wants to help with that. So why do I continue to bother? You know what the definition of insanity is? Doing the same thing over and over expecting a different result.
I would guess that most chessprogrammers here are either working on their own set of problems or they have taken a break from chess-programming and are mostly just reading. It's very hard to get involved in someone else's ideas and codebase in a way that it's truely "helping". And as Daniel said, a Github repo would go a long way in making your ideas, code and binaries more accessible and thus more likely to find a more involved audience.

I've read your posts with interest but I didn't really understand why you abandoned Bricabrac and started again from scratch with an even faster move generator idea. If it's really about dynamic learning a few nps more or less wouldn't really matter, right? Why bother with threading so early? To me that seems like distractions from what you're really interested in. But you can see how that does not make a very great first reply to a new project's devlog so I chose to just wait and see how the project unfolds before chiming in with unwanted opinions.

I think expecting people to want to co-develop your new engine after reading just one or two (very complex) forum posts about your plans is too optimistic but drawing the conclusion from that that nobody cares about the project and it's doomed to fail is way too negative.
From minute to minute, hour to hour, day to day, week to week my life disappears. I was born with a very weak memory. I was also born with an inoperable hole in my heart. I wasn't supposed to live. Then I was never supposed to make it passed 40. Despite all that I scored 145 on a Mensa IQ test. I wonder what I might have scored if I had even only an average memory. The point being at times I don't even remember that I have an engine named Bricabrac. And at times I remember. I rely on copious notes to keep me on task. But that doesn't always work. What takes someone an hour or two to write takes me a day or two or even a week or two or longer. I just can't remember what it is that I'm trying to do while I'm doing it. And every day I have to start over from scratch. It took me 22 years to write RomiChess. I started over because I remembered how I did move generation in RomiChess and with what I "learned" writing Bricabrac I realized in search I could search at twice the node rate. I'm trying to prove that now but it is not going well because I have to lean how alpha-beta negamax works all over again. I do things like I have always had to do things; 100 steps forward and 99 back. Maybe you can give me a pass for my pessimism? I have had to explain this way to many times! Never again.
smatovic
Posts: 3230
Joined: Wed Mar 10, 2010 10:18 pm
Location: Hamburg, Germany
Full name: Srdja Matovic

Re: Devlog of !

Post by smatovic »

Mike Sherwin wrote: Thu Sep 15, 2022 7:54 am [...]
From minute to minute, hour to hour, day to day, week to week my life disappears. I was born with a very weak memory. I was also born with an inoperable hole in my heart. I wasn't supposed to live. Then I was never supposed to make it passed 40. Despite all that I scored 145 on a Mensa IQ test. I wonder what I might have scored if I had even only an average memory. The point being at times I don't even remember that I have an engine named Bricabrac. And at times I remember. I rely on copious notes to keep me on task. But that doesn't always work. What takes someone an hour or two to write takes me a day or two or even a week or two or longer. I just can't remember what it is that I'm trying to do while I'm doing it. And every day I have to start over from scratch. It took me 22 years to write RomiChess. I started over because I remembered how I did move generation in RomiChess and with what I "learned" writing Bricabrac I realized in search I could search at twice the node rate. I'm trying to prove that now but it is not going well because I have to lean how alpha-beta negamax works all over again. I do things like I have always had to do things; 100 steps forward and 99 back. Maybe you can give me a pass for my pessimism? I have had to explain this way to many times! Never again.
Dear Mike,

the universe gives and it takes, you might have a weak memory, but I am sure the universe gave you the opportunity to view the world in your own special, unique way, a kind of gift. I've read recently that meanwhile science concluded that dyslexia and dyscalculia for example are considered as an evolutionary tradeoff, you loose in one domain, but gain in another. Be assured that there are other programmers in here who have their own kind of shortcomings, and gains, I guess they just don't like to talk about this in the public. As I mentioned already in another CTF thread, discover the mystery of yourself, and enjoy it. Harley Quinn might say, "own this shit, own it!" ;)

--
Srdja