Page 1 of 1

Protozoa Dev Log

Posted: Wed Mar 27, 2024 2:04 am
by Michael Sherwin
Starting from zero.

I'm using MSVS 2022 Community Edition, C++ as a better C.

***Protozoa.cpp*** // Just the files off the top of my head that I know will be needed.

Code: Select all

// Protozoa
// A Chess Engine
// By Michael Sherwin

// Protozoa.cpp

#include <stdint.h>
#include <bit>

#include "Defines.cpp"
#include "Globals.cpp"
#include "Utilities.cpp"
#include "Initialize.cpp"
#include "Evaluate.cpp"
#include "Move.cpp"
#include "GenerateMoves.cpp"
#include "GetCommand.cpp"
#include "Search.cpp"
#include "Main.cpp"
Some defines that I know will be needed.

Code: Select all

// Protozoa
// A Chess Engine
// By Michael Sherwin

// Defines.cpp

typedef int8_t s08;
typedef uint8_t u08;
typedef int32_t s32;
typedef uint64_t u64;

constexpr auto ILLEGAL = 10000;

constexpr s32 valp = 100;
constexpr s32 valn = 290;
constexpr s32 valb = 320;
constexpr s32 valr = 500;
constexpr s32 valq = 960;
constexpr s32 na = 0;

constexpr u64 file_b2_b7 = 0x0002020202020200;
constexpr u64 file_a2_a7 = 0x0001010101010100;
constexpr u64 diag_c2_h7 = 0x0080402010080400;

constexpr u64 owcs = 0x0000000000000060; // Occupied as concerning White Castling Short
constexpr u64 owcl = 0x000000000000000e;
constexpr u64 obcs = 0x6000000000000000;
constexpr u64 obcl = 0x0e00000000000000;
constexpr u64 awcs = 0x0000000000000070; // Attacked as concerning White Castling Short
constexpr u64 awcl = 0x000000000000001c;
constexpr u64 abcs = 0x7000000000000000;
constexpr u64 abcl = 0x1c00000000000000;

enum { EXIT, GETCMD, SEARCH, MOVE , ANALYZE };

enum { BLACK, WHITE };

enum { FILEa, FILEb, FILEc, FILEd, FILEe, FILEf, FILEg, FILEh };

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

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
};

// These are piece types and pseudo piece types
// WP2 - white pawn on rank 2
// WRC - white rook that can castle
// WKC - white king that can castle
// WPQ - white pawn that promotes to queen
// WCS - white castles short
enum {
    WP2, WP3, WP4, WP5, WP6, WP7, WN, WB, WRC, WR, WQ, WKC, WK,
    ES,
    BP7, BP6, BP5, BP4, BP3, BP2, BN, BB, BRC, BR, BQ, BKC, BK,
    WPQ, WPN, WPR, WPB, WCS, WCL,
    BPQ, BPN, BPR, BPB, BCS, BCL
};

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

// So I don't have to type "->" all the time
#define mfs m->fs
#define mts m->ts
#define mft m->ft
#define mtt m->tt
#define msc m->sc

union uMove {
    sMove s;
    u64 u;
};

struct Thread {
    u64 sides[2];		// bitboards for white and black pieces
    u64 pawns[2];	// specific piece type bitboards
    u64 knights[2];
    u64 bishops[2];
    u64 rooks[2];
    u64 queens[2];
    u64 kings[2];
    u64* types[27]; 	// another way of accessing the piece types by pointer
    u64 epbit[100];
    s32 mat[2];		// material score
    s32 pos[2];		// positional
    u08 board[64];	// the chess board
    u08 wptbl[64];  	// WP piece Table
    u08 bptbl[64];
    u08 wntbl[64];
    u08 bntbl[64];
    u08 wbtbl[64];
    u08 bbtbl[64];
    u08 wrtbl[64];
    u08 brtbl[64];
    u08 wqtbl[64];
    u08 bqtbl[64];
    u08 wktbl[64];
    u08 bktbl[64];
    u08 estbl[64];    	// empty square table all zero
    u08* tbls[27];	// to access the tables by pointer
    u08 stm;		// side to move
    u08 otm;		// other side to move (maybe)
    u08 ply;
};

#define sides t->sides
#define pawns t->pawns
#define knights t->knights
#define bishops t->bishops
#define rooks t->rooks
#define queens t->queens
#define kings t->kings
#define types t->types
#define epbit t->epbit
#define mat t->mat
#define pos t->pos
#define board t->board
#define wptbl t->wptbl
#define bptbl t->bptbl
#define wntbl t->wntbl
#define bntbl t->bntbl
#define wbtbl t->wbtbl
#define bbtbl t->bbtbl
#define wrtbl t->wrtbl
#define brtbl t->brtbl
#define wqtbl t->wqtbl
#define bqtbl t->bqtbl
#define wktbl t->wktbl
#define bktbl t->bktbl
#define estbl t->estbl
#define tbls t->tbls
#define stm t->stm
#define otm t->otm
#define ply t->ply
And a simple Main.cpp to get started.

Code: Select all

// Protozoa
// A Chess Engine
// By Michael Sherwin

// Main.cpp

s32 main() {
	Initialize();
	while (mode != EXIT) {
		if (mode == GETCMD) GetCommand();
		if (mode == SEARCH) StartSearch();
		if (mode == MOVE) GameMove();
		if (mode == ANALYZE) Analyze();
	}
}

Re: Protozoa Dev Log

Posted: Wed Mar 27, 2024 2:30 am
by Michael Sherwin
When I start writing a chess engine I always write the move generators first. It just seems to me to be a solid center to build a chess engine around. But first the move generator initialization code needs to be written. Luckily for this project the initialization code already exist from when I developed my latest sliding piece algorithm. So all that was needed was mostly some copy & paste. It will still need debugged of course when something is up and running

Code: Select all

// Protozoa
// A Chess Engine
// By Michael Sherwin

// Initialize.cpp

void InitBySquare() {
	u08 sq, ts, x, y, dx, dy;
	u64 occ, index;
	for (sq = a1; sq <= h8; sq++) {
		x = sq & 7;
		y = sq >> 3;

		// pawns
		if (sq >= a2 && sq <= h7) {
			wPawnCaptures[sq] = ((u64)(x > FILEa) << (sq + 7)) | ((u64)(x < FILEh) << (sq + 9));
			bPawnCaptures[sq] = ((u64)(x > FILEa) << (sq - 9)) | ((u64)(x < FILEh) << (sq - 7));
		}

		// knights
		knightMoves[sq] =
			((u64)(x > FILEb && y < RANK8) << (sq + 06)) |
			((u64)(x > FILEa && y < RANK7) << (sq + 15)) |
			((u64)(x < FILEh && y < RANK7) << (sq + 17)) |
			((u64)(x < FILEg && y < RANK8) << (sq + 10)) |
			((u64)(x < FILEg && y > RANK1) << (sq - 06)) |
			((u64)(x < FILEh && y > RANK2) << (sq - 15)) |
			((u64)(x > FILEa && y > RANK2) << (sq - 17)) |
			((u64)(x > FILEb && y > RANK1) << (sq - 10));

		// kings
		kingMoves[sq] = 
			((u64)(x > FILEa) << (sq - 1)) |
			((u64)(x < FILEh) << (sq + 1)) |
			((u64)(y < RANK8) << (sq + 8)) |
			((u64)(y > RANK1) << (sq - 8)) |
			((u64)(x > FILEa && y < RANK8) << (sq + 7)) |
			((u64)(x < FILEh && y < RANK8) << (sq + 9)) |
			((u64)(x < FILEh && y > RANK1) << (sq - 7)) |
			((u64)(x > FILEa && y > RANK1) << (sq - 9));

		// diagonals
		for (ts = sq + 9, dx = x + 1, dy = y + 1; dx < FILEh && dy < RANK8; dMask[sq] |= 1ull << ts, ts += 9, dx++, dy++);
		for (ts = sq - 9, dx = x - 1, dy = y - 1; dx > FILEa && dy > RANK1; dMask[sq] |= 1ull << ts, ts -= 9, dx--, dy--);

		// anti diagonals
		for (ts = sq + 7, dx = x - 1, dy = y + 1; dx > FILEa && dy < RANK8; aMask[sq] |= 1ull << ts, ts += 7, dx--, dy++);
		for (ts = sq - 7, dx = x + 1, dy = y - 1; dx < FILEh && dy > RANK1; aMask[sq] |= 1ull << ts, ts -= 7, dx++, dy--);

		// diagonal indexes
		for (index = 0; index < 64; index++) {
			dSubset[sq][index] = 0;
			occ = index << 1;
			if ((sq & 7) != FILEh && (sq >> 3) != RANK8) {
				for (ts = sq + 9; ; ts += 9) {
					dSubset[sq][index] |= (1ull << ts);
					if (occ & (1ull << (ts & 7))) break;
					if ((ts & 7) == FILEh || (ts >> 3) == RANK8) break;
				}
			}
			if ((sq & 7) != FILEa && (sq >> 3) != RANK1) {
				for (ts = sq - 9; ; ts -= 9) {
					dSubset[sq][index] |= (1ull << ts);
					if (occ & (1ull << (ts & 7))) break;
					if ((ts & 7) == FILEa || (ts >> 3) == RANK1) break;
				}
			}
		}

		// anti diagonal indexes
		for (index = 0; index < 64; index++) {
			aSubset[sq][index] = 0;
			occ = index << 1;
			if ((sq & 7) != FILEa && (sq >> 3) != RANK8) {
				for (ts = sq + 7; ; ts += 7) {
					aSubset[sq][index] |= (1ull << ts);
					if (occ & (1ull << (ts & 7))) break;
					if ((ts & 7) == FILEa || (ts >> 3) == RANK8) break;
				}
			}
			if ((sq & 7) != FILEh && (sq >> 3) != RANK1) {
				for (ts = sq - 7; ; ts -= 7) {
					aSubset[sq][index] |= (1ull << ts);
					if (occ & (1ull << (ts & 7))) break;
					if ((ts & 7) == FILEh || (ts >> 3) == RANK1) break;
				}
			}
		}

		// vertical indexes
		for (index = 0; index < 64; index++) {
			vSubset[sq][index] = 0;
			uint64_t blockers = 0;
			for (int i = 0; i <= 5; i++) {
				if (index & (1ull << i)) {
					blockers |= (1ull << (((5 - i) << 3) + 8));
				}
			}
			if ((sq >> 3) != RANK8) {
				for (ts = sq + 8; ; ts += 8) {
					vSubset[sq][index] |= (1ull << ts);
					if (blockers & (1ull << (ts - (ts & 7)))) break;
					if ((ts >> 3) == RANK8) break;
				}
			}
			if ((sq >> 3) != RANK1) {
				for (ts = sq - 8; ; ts -= 8) {
					vSubset[sq][index] |= (1ull << ts);
					if (blockers & (1ull << (ts - (ts & 7)))) break;
					if ((ts >> 3) == RANK1) break;
				}
			}
		}

		// horizontal indexes
		for (index = 0; index < 64; index++) {
			hSubset[sq][index] = 0;
			occ = index << 1;
			if ((sq & 7) != FILEh) {
				for (ts = sq + 1; ; ts += 1) {
					hSubset[sq][index] |= (1ull << ts);
					if (occ & (1ull << (ts & 7))) break;
					if ((ts & 7) == FILEh) break;
				}
			}
			if ((sq & 7) != FILEa) {
				for (ts = sq - 1; ; ts -= 1) {
					hSubset[sq][index] |= (1ull << ts);
					if (occ & (1ull << (ts & 7))) break;
					if ((ts & 7) == FILEa) break;
				}
			}
		}

		// horizontal shift
		hShift[sq] = (sq & 56) + 1;
	}
}

Re: Protozoa Dev Log

Posted: Wed Mar 27, 2024 9:14 pm
by Michael Sherwin
I get criticized for the way I do things. But I do things the way I do things for personal reasons.

I'm thinking I want 3 move generators -- a move only generator, a captures only generator and an all moves generator just until I figure out what combination is best.

Branchless code is extensively used except for an initial switch statement. I'm told it is almost an automatic misprediction but if it is it is the only one as there are absolutely zero 'if' statements in the whole function. I hope it will be fast overall.

Code: Select all

// Protozoa
// A Chess Engine
// By Michael Sherwin

// GenerateMoves.cpp

static sMove* GenNonCaptures(Thread* t, sMove* m) {
	u08 fs, ts, type;
	u64 bb, b;

	u64 side = sides[stm];
	u64 enemy = sides[otm];
	u64 occ = side | enemy;
	u64 empty = ~occ;

	do {
		fs = std::countr_zero(side);
		side ^= 1ull << fs;
		type = board[fs];
		switch (type) {
		case ES:
			// unreachable
			break;
		case WP2:
			b = (1ull << 8 << fs) & empty;
			bb = (b << 8 & empty);
			break;
		case WP3: case WP4: case WP5: case WP6:
			bb = (1ull << 8 << fs) & empty;
			break;
		case WP7:
			bb = (1ull << 8 << fs) & empty;
			while (bb) {
				ts = std::countr_zero(bb);
				mfs = fs;
				mts = ts;
				mft = WPQ;
				m++;
				mfs = fs;
				mts = ts;
				mft = WPN;
				m++;
				mfs = fs;
				mts = ts;
				mft = WPR;
				m++;
				mfs = fs;
				mts = ts;
				mft = WPB;
				m++;
			}
			continue;
		case BP7:
			b = (1ull << fs >> 8) & empty;
			bb = (b >> 8 & empty);
			break;
		case BP6: case BP5: case BP4: case BP3:
			bb = (1ull << fs >> 8) & empty;
			break;
		case BP2:
			bb = (1ull << fs >> 8) & empty;
			while (bb) {
				ts = std::countr_zero(bb);
				mfs = fs;
				mts = ts;
				mft = BPQ;
				m++;
				mfs = fs;
				mts = ts;
				mft = BPN;
				m++;
				mfs = fs;
				mts = ts;
				mft = BPR;
				m++;
				mfs = fs;
				mts = ts;
				mft = BPB;
				m++;
			}
		    continue;
		case WN: case BN:
			bb = knightMoves[fs] & empty;
			break;
		case WB: case BB:
			bb = (
				dSubset[fs][(((occ & dMask[fs]) * file_b2_b7) >> 58)] |
				aSubset[fs][(((occ & aMask[fs]) * file_b2_b7) >> 58)]
				) & empty;
			break;
		case WRC: case WR: case BRC: case BR:
			bb = (
				hSubset[fs][(occ >> hShift[fs]) & 63] |
				vSubset[fs][((((occ >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
				) & empty;
			break;
		case WQ: case BQ:
			bb = (
				dSubset[fs][(((occ & dMask[fs]) * file_b2_b7) >> 58)] |
				aSubset[fs][(((occ & aMask[fs]) * file_b2_b7) >> 58)] |
				hSubset[fs][(occ >> hShift[fs]) & 63] |
				vSubset[fs][((((occ >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
				) & empty;
			break;
		case WKC:
			mft = ((u64)((board[h1] == WRC) && !(occ & owcs) && !AtkByBlack(t, awcs))) * WCS;
			m += (mft == WCS);
			mft = ((u64)((board[a1] == WRC) && !(occ & owcl) && !AtkByBlack(t, awcl))) * WCL;
			m += (mft == WCL);
		case WK: 
			bb = kingMoves[fs] & empty;
			break;
		case BKC:
			mft = ((u64)((board[h8] == BRC) && !(occ & obcs) && !AtkByWhite(t, abcs))) * BCS;
			m += (mft == BCS);
			mft = ((u64)((board[a8] == BRC) && !(occ & obcl) && !AtkByWhite(t, abcl))) * BCL;
			m += (mft == BCL);
		case BK:
			bb = kingMoves[fs] & empty;
			break;
		}

		while (bb) {
			mfs = fs;
			mts = std::countr_zero(bb);
			mft = type;
			bb ^= 1ull << mts;
			m++;
		}

	} while (side);

	return m;
}

// Protozoa
// A Chess Engine
// By Michael Sherwin

// Utilities.cpp

static bool AtkByWhite(Thread* t, u64 b) {
	u64 atk = 0;
	u64 occ = sides[WHITE] | sides[BLACK];
	while (b) {
		s32 sq = std::countr_zero(b);
		b ^= 1ull << sq;
		atk |=
			(bPawnCaptures[sq] & pawns[WHITE]) |
			(knightMoves[sq] & knights[WHITE]) |
			(kingMoves[sq] & kings[WHITE]) |
			(dSubset[sq][(((occ & dMask[sq]) * file_b2_b7) >> 58)] & (bishops[WHITE] | queens[WHITE])) |
			(aSubset[sq][(((occ & aMask[sq]) * file_b2_b7) >> 58)] & (bishops[WHITE] | queens[WHITE])) |
			(hSubset[sq][(occ >> hShift[sq]) & 63] & (rooks[WHITE] | queens[WHITE])) |
			(vSubset[sq][((((occ >> (sq & 7)) & file_a2_a7) * diag_c2_h7) >> 58)] & (rooks[WHITE] | queens[WHITE]));
	}
	return (atk != 0);
}

static bool AtkByBlack(Thread* t, u64 b) {
	u64 atk = 0;
	u64 occ = sides[WHITE] | sides[BLACK];
	while (b) {
		s32 sq = std::countr_zero(b);
		b ^= 1ull << sq;
		atk |=
			(wPawnCaptures[sq] & pawns[BLACK]) |
			(knightMoves[sq] & knights[BLACK]) |
			(kingMoves[sq] & kings[BLACK]) |
			(dSubset[sq][(((occ & dMask[sq]) * file_b2_b7) >> 58)] & (bishops[BLACK] | queens[BLACK])) |
			(aSubset[sq][(((occ & aMask[sq]) * file_b2_b7) >> 58)] & (bishops[BLACK] | queens[BLACK])) |
			(hSubset[sq][(occ >> hShift[sq]) & 63] & (rooks[BLACK] | queens[BLACK])) |
			(vSubset[sq][((((occ >> (sq & 7)) & file_a2_a7) * diag_c2_h7) >> 58)] & (rooks[BLACK] | queens[BLACK]));
	}
	return (atk != 0);
}

Re: Protozoa Dev Log

Posted: Sat Mar 30, 2024 9:57 pm
by Michael Sherwin
I was not feeling well the last couple days. So I id not make any updates. I did get a little bit more done though.
The capture only generator. And added mft = ES; move from type = empty square to mark the end of the move list. Forgot to put it in before.

Code: Select all

static bool GenCaptures(Thread* t, sMove* m) {
	u08 fs, ts, type;
	u64 bb, b, atk = 0;

	u64 side = sides[stm];
	u64 enemy = sides[otm];
	u64 occ = side | enemy;
	u64 empty = ~occ;
	u64 notme = ~side;

	do {
		fs = std::countr_zero(side);
		side ^= 1ull << fs;
		type = board[fs];
		switch (type) {
		case ES:
			// unreachable
			break;
		case WP2: case WP3: case WP4: case WP6:
			atk |= bb = wPawnCaptures[fs] & enemy;
			break;
		case WP5:
			atk |= bb = wPawnCaptures[fs] & (enemy | epbit[ply]);
			break;
		case WP7:
			atk |= bb = wPawnCaptures[fs] & enemy;
			bb |= (1ull << 8 << fs) & empty;
			while (bb) {
				ts = std::countr_zero(bb);
				mfs = fs;
				mts = ts;
				mft = WPQ;
				m++;
				mfs = fs;
				mts = ts;
				mft = WPN;
				m++;
				mfs = fs;
				mts = ts;
				mft = WPR;
				m++;
				mfs = fs;
				mts = ts;
				mft = WPB;
				m++;
			}
			continue;
		case BP7: case BP6: case BP5: case BP3: 
			atk |= bb = bPawnCaptures[fs] & enemy;
			break;
		case BP4:
			atk |= bb = bPawnCaptures[fs] & (enemy | epbit[ply]);
			break;
		case BP2:
			atk |= bb = bPawnCaptures[fs] & enemy;
			bb |= (1ull << fs >> 8) & empty;
			while (bb) {
				ts = std::countr_zero(bb);
				mfs = fs;
				mts = ts;
				mft = BPQ;
				m++;
				mfs = fs;
				mts = ts;
				mft = BPN;
				m++;
				mfs = fs;
				mts = ts;
				mft = BPR;
				m++;
				mfs = fs;
				mts = ts;
				mft = BPB;
				m++;
			}
			continue;
		case WN: case BN:
			bb = knightMoves[fs] & enemy;
			break;
		case WB: case BB:
			bb = (
				dSubset[fs][(((occ & dMask[fs]) * file_b2_b7) >> 58)] |
				aSubset[fs][(((occ & aMask[fs]) * file_b2_b7) >> 58)]
				) & enemy;
			break;
		case WRC: case WR: case BRC: case BR:
			bb = (
				hSubset[fs][(occ >> hShift[fs]) & 63] |
				vSubset[fs][((((occ >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
				) & enemy;
			break;
		case WQ: case BQ:
			bb = (
				dSubset[fs][(((occ & dMask[fs]) * file_b2_b7) >> 58)] |
				aSubset[fs][(((occ & aMask[fs]) * file_b2_b7) >> 58)] |
				hSubset[fs][(occ >> hShift[fs]) & 63] |
				vSubset[fs][((((occ >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
				) & enemy;
			break;
		case WKC: case WK: case BKC: case BK:
			bb = kingMoves[fs] & enemy;
			break;
		}

		while (bb) {
			mfs = fs;
			mts = std::countr_zero(bb);
			mft = type;
			bb ^= 1ull << mts;
			m++;
		}

	} while (side);

	mft = ES;

	return ((atk & kings[otm]) != false);
}

Re: Protozoa Dev Log

Posted: Sat Mar 30, 2024 10:16 pm
by Michael Sherwin
Also got the make move and take back done. There is method to my madness or maybe madness to my method. I'm not sure which. Once again all if statements have been eliminated. If the switch statement is mostly mispredicted at most there is only one misprediction per move. Since, because, 85% or more of the moves are captures due to quiescence search every move is assumed to be a capture. It just that capturing an empty square does not do anything. For an extreme example of branchless programming check out, case WP5:. It is a pawn that handles capture en-passant without using any 'if' statements. It is like a riddle that gets ones brain all twisted, lol.

Code: Select all

// Protozoa
// A Chess Engine
// By Michael Sherwin

// GameMove.cpp

void GameMove() {

}

void MakeMove(Thread* t, sMove* m) {
    s32 p16;
    u08 sq;
    switch (mft) {
    case WP2:
        mtt = board[mts];
        p16 = (u64)(mts - mfs == 16) << (mfs + 8);
        epbit[ply + 1] = p16;
        board[mfs] = ES;
        board[mts] = WP3 + (p16 != 0);
        pawns[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (wptbl[mts] - wptbl[mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WP3: case WP4: case WP6:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = mft + 1;
        pawns[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (wptbl[mts] - wptbl[mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WP5:
        sq = mts - ((epbit[ply] == (1ull << mts)) << 3);
        mtt = board[sq];
        board[mfs] = ES;
        board[mts] = WP6;
        pawns[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << sq;
        sides[BLACK] ^= (u64)(mtt != ES) << sq;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (wptbl[mts] - wptbl[mfs]);
        pos[BLACK] -= tbls[mtt][sq];
        break;
    case WP7:
        // unreachable
        break;
    case WN: case WB: case WR: case WQ: case WK:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = mft;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (tbls[mft][mts] - tbls[mft][mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WRC:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = WR;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (tbls[mft][mts] - tbls[mft][mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WKC:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = WK;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (tbls[mft][mts] - tbls[mft][mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case ES:
        // unreachable
        break;
    case BP7:
        mtt = board[mts];
        p16 = (u64)(mfs - mts == 16) << (mfs - 8);
        epbit[ply + 1] = p16;
        board[mfs] = ES;
        board[mts] = BP6 + (p16 != 0);
        pawns[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (bptbl[mts] - bptbl[mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BP6: case BP5: case BP3:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = mft + 1;
        pawns[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (bptbl[mts] - bptbl[mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BP4:
        sq = mts + ((epbit[ply] == (1ull << mts)) << 3);
        mtt = board[sq];
        board[mfs] = ES;
        board[mts] = BP3;
        pawns[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << sq;
        sides[WHITE] ^= (u64)(mtt != ES) << sq;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (bptbl[mts] - bptbl[mfs]);
        pos[WHITE] -= tbls[mtt][sq];
        break;
    case BP2:
        // unreachable
        break;
    case BN: case BB: case BR: case BQ: case BK:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = mft;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (tbls[mft][mts] - tbls[mft][mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BRC:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = BR;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (tbls[mft][mts] - tbls[mft][mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BKC:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = BK;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (tbls[mft][mts] - tbls[mft][mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case WPQ:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = WQ;
        pawns[WHITE] ^= 1ull << mfs;
        queens[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += valq - valp;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WPN:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = WN;
        pawns[WHITE] ^= 1ull << mfs;
        knights[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += valn - valp;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WPR:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = WR;
        pawns[WHITE] ^= 1ull << mfs;
        rooks[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += valr - valp;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WPB:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = WB;
        pawns[WHITE] ^= 1ull << mfs;
        bishops[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += valb - valp;
        mat[BLACK] -= value[mtt];
        pos[WHITE] += (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] -= tbls[mtt][mts];
        break;
    case WCS:
        board[e1] = ES;
        board[g1] = WK;
        board[h1] = ES;
        board[f1] = WR;
        sides[WHITE] ^= 0x00000000000000f0;
        kings[WHITE] ^= 0x0000000000000050;
        rooks[WHITE] ^= 0x00000000000000a0;
        pos[WHITE] += 60;
        break;
    case WCL:
        board[e1] = ES;
        board[c1] = WK;
        board[a1] = ES;
        board[d1] = WR;
        sides[WHITE] ^= 0x000000000000001d;
        kings[WHITE] ^= 0x000000000000014;
        rooks[WHITE] ^= 0x000000000000009;
        pos[WHITE] += 50;
        break;
    case BPQ:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = BQ;
        pawns[BLACK] ^= 1ull << mfs;
        queens[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += valq - valp;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (bqtbl[mts] - bptbl[mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BPN:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = BN;
        pawns[BLACK] ^= 1ull << mfs;
        knights[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += valn - valp;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (bntbl[mts] - bptbl[mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BPR:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = BR;
        pawns[BLACK] ^= 1ull << mfs;
        rooks[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += valr - valp;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (brtbl[mts] - bptbl[mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BPB:
        mtt = board[mts];
        board[mfs] = ES;
        board[mts] = BB;
        pawns[BLACK] ^= 1ull << mfs;
        bishops[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += valb - valp;
        mat[WHITE] -= value[mtt];
        pos[BLACK] += (bbtbl[mts] - bptbl[mfs]);
        pos[WHITE] -= tbls[mtt][mts];
        break;
    case BCS:
        board[e8] = ES;
        board[g8] = BK;
        board[h8] = ES;
        board[f8] = BR;
        sides[BLACK] ^= 0xf000000000000000;
        kings[BLACK] ^= 0x5000000000000000;
        rooks[BLACK] ^= 0xa000000000000000;
        pos[BLACK] += 60;
        break;
    case BCL:
        board[e8] = ES;
        board[c8] = BK;
        board[a8] = ES;
        board[d8] = BR;
        sides[BLACK] ^= 0x1d00000000000000;
        kings[BLACK] ^= 0x1400000000000000;
        rooks[BLACK] ^= 0x0900000000000000;
        pos[BLACK] += 50;
        break;
    }

    ply++;
    stm = 1 - stm;
}

void TakeBack(Thread* t, sMove* m) {
    u08 sq;

    ply--;
    stm = 1 - stm;

    switch (mft) {
    case WP2:
        epbit[ply + 1] = 0;
    case WP3: case WP4: case WP6:
        board[mts] = mtt;
        board[mfs] = mft;
        pawns[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (wptbl[mts] - wptbl[mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case WP5:
        sq = mts - ((epbit[ply] == (1ull << mts)) << 3);
        board[mts] = ES;
        board[sq] = mtt;
        board[mfs] = WP5;
        pawns[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << sq;
        sides[BLACK] ^= (u64)(mtt != ES) << sq;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (wptbl[mts] - wptbl[mfs]);
        pos[BLACK] += tbls[mtt][sq];
        break;
    case WP7:
        // unreachable
        break;
    case WN: case WB: case WR: case WQ: case WK:
        board[mts] = mtt;
        board[mfs] = mft;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (tbls[mft][mts] - tbls[mft][mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case WRC:
        board[mts] = mtt;
        board[mfs] = WRC;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (tbls[mft][mts] - tbls[mft][mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case WKC:
        board[mts] = mtt;
        board[mfs] = WKC;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (tbls[mft][mts] - tbls[mft][mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case ES:
        // unreachable
        break;
    case BP7:
        epbit[ply + 1] = 0;
        break;
    case BP6: case BP5: case BP3:
        board[mts] = mtt;
        board[mfs] = mtt;
        pawns[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (bptbl[mts] - bptbl[mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BP4:
        sq = mts + ((epbit[ply] == (1ull << mts)) << 3);
        mtt = board[sq];
        board[mfs] = BP3;
        board[mts] = mtt;
        pawns[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[WHITE] ^= (u64)(mtt != ES) << sq;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (bptbl[mts] - bptbl[mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BP2:
        // unreachable
        break;
    case BN: case BB: case BR: case BQ: case BK:
        board[mts] = mtt;
        board[mfs] = mft;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (tbls[mft][mts] - tbls[mft][mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BRC:
        board[mts] = mtt;
        board[mfs] = BRC;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (tbls[mft][mts] - tbls[mft][mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BKC:
        board[mts] = mtt;
        board[mfs] =  BKC;
        *types[mft] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (tbls[mft][mts] - tbls[mft][mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case WPQ:
        board[mts] = mtt;
        board[mfs] = WP7;
        pawns[WHITE] ^= 1ull << mfs;
        queens[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= valq - valp;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case WPN:
        board[mts] = mtt;
        board[mfs] = WP7;
        pawns[WHITE] ^= 1ull << mfs;
        knights[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= valn - valp;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case WPR:
        board[mts] = mtt;
        board[mfs] = WP7;
        pawns[WHITE] ^= 1ull << mfs;
        rooks[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= valr - valp;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case WPB:
        board[mts] = mtt;
        board[mfs] = WP7;
        pawns[WHITE] ^= 1ull << mfs;
        bishops[WHITE] ^= 1ull << mts;
        sides[WHITE] ^= (1ull << mfs | 1ull << mts);
        sides[BLACK] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[WHITE] -= valb - valp;
        mat[BLACK] += value[mtt];
        pos[WHITE] -= (wqtbl[mts] - wptbl[mfs]);
        pos[BLACK] += tbls[mtt][mts];
        break;
    case WCS:
        board[e1] = WKC;
        board[g1] = ES;
        board[h1] = WRC;
        board[f1] = ES;
        sides[WHITE] ^= 0x00000000000000f0;
        kings[WHITE] ^= 0x0000000000000050;
        rooks[WHITE] ^= 0x00000000000000a0;
        pos[WHITE] -= 60;
        break;
    case WCL:
        board[e1] = WKC;
        board[c1] = ES;
        board[a1] = WRC;
        board[d1] = ES;
        sides[WHITE] ^= 0x000000000000001d;
        kings[WHITE] ^= 0x000000000000014;
        rooks[WHITE] ^= 0x000000000000009;
        pos[WHITE] -= 50;
        break;
    case BPQ:
        board[mts] = mtt;
        board[mfs] = BP7;
        pawns[BLACK] ^= 1ull << mfs;
        queens[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= valq - valp;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (bqtbl[mts] - bptbl[mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BPN:
        board[mts] = mtt;
        board[mfs] = BP7;
        pawns[BLACK] ^= 1ull << mfs;
        knights[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= valn - valp;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (bntbl[mts] - bptbl[mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BPR:
        board[mts] = mtt;
        board[mfs] = BP7;
        pawns[BLACK] ^= 1ull << mfs;
        rooks[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= valr - valp;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (brtbl[mts] - bptbl[mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BPB:
        board[mts] = mtt;
        board[mfs] = BP7;
        pawns[BLACK] ^= 1ull << mfs;
        bishops[BLACK] ^= 1ull << mts;
        sides[BLACK] ^= (1ull << mfs | 1ull << mts);
        sides[WHITE] ^= (u64)(mtt != ES) << mts;
        *types[mtt] ^= (u64)(mtt != ES) << mts;
        mat[BLACK] -= valb - valp;
        mat[WHITE] += value[mtt];
        pos[BLACK] -= (bbtbl[mts] - bptbl[mfs]);
        pos[WHITE] += tbls[mtt][mts];
        break;
    case BCS:
        board[e8] = BKC;
        board[g8] = ES;
        board[h8] = BRC;
        board[f8] = ES;
        sides[BLACK] ^= 0xf000000000000000;
        kings[BLACK] ^= 0x5000000000000000;
        rooks[BLACK] ^= 0xa000000000000000;
        pos[BLACK] += 60;
        break;
    case BCL:
        board[e8] = BKC;
        board[c8] = ES;
        board[a8] = BRC;
        board[d8] = ES;
        sides[BLACK] ^= 0x1d00000000000000;
        kings[BLACK] ^= 0x1400000000000000;
        rooks[BLACK] ^= 0x0900000000000000;
        pos[BLACK] += 50;
        break;
    }
}