!! Development Log, My Last Try

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

!! Development Log, My Last Try

Post by Mike Sherwin »

I know that I have started many of these only to forget about them. It is not that I abandon them. It really is because they leave my memory. And when I stumble upon one of them I don't remember having started them. But I'm going to keep better notes this time to keep myself reminded what I am trying to do. And I will finish this time or die trying. Also I have run out of names so for now I'm just naming this engine !! :D

I have a little bit done so far that is similar to what I have done already but hopefully the code is a little cleaner. And maybe a bit faster. As always I use C++ as a better C. I do not use classes. It is not that I don't like classes. It is because I can't keep them in my memory long enough to be able to program with them. I have to operate within my limitations.

Some definitions

Code: Select all

// !!
// A Chess Engine
// By Michael Sherwin

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

#define defines
#ifdef defines  
typedef int8_t s08;
typedef int32_t s32;
typedef uint64_t u64;

constexpr s32 maxThreads = 4;
constexpr u64 one = 1ull;

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 occ_w_s = 0x0000000000000060;
constexpr u64 occ_w_l = 0x000000000000000e;
constexpr u64 occ_b_s = 0x6000000000000000;
constexpr u64 occ_b_l = 0x0e00000000000000;
constexpr u64 atk_w_s = 0x0000000000000070;
constexpr u64 atk_w_l = 0x000000000000001c;
constexpr u64 atk_b_s = 0x7000000000000000;
constexpr u64 atk_b_l = 0x1c00000000000000;

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

enum { BLACK, WHITE };

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

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

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

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

struct sMove {
	s08 fs;
	s08 ts;
	s08 ft;
	s08 tt;
	s32 sc;
};

union uMove {
	sMove s;
	u64 u;
};

struct Thread {
	u64 occupied[2];
	u64 pawns[2];
	u64 knights[2];
	u64 bishops[2];
	u64 rooks[2];
	u64 queens[2];
	u64 kings[2];
	u64 epsq;
	u64* occType[27];
	s32 board[64];
	s32 stm;
	s32 otm;
	s32 sly;
	s32 gly;
	s32 mat[2];
	s32 pos[2];
};

#define occupied t->occupied
#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 epsq t->epsq
#define occType t->occType
#define board t->board
#define stm t->stm
#define otm t->otm
#define sly t->sly
#define gly t->gly
#define mat t->mat
#define pos t->pos

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

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

Some Globals

Code: Select all

#define globals
#ifdef globals

s32 mode;
s32 numThreads;
uMove gameMove;
Thread** thread;

u64 wPawnAtks[64];
u64 bPawnAtks[64];
u64 knightMvs[64];
u64 kingMvs[64];

u64 aMask[64];
u64 dMask[64];
u64 aSubset[64][64];
u64 dSubset[64][64];
u64 vSubset[64][64];
u64 hSubset[64][64];

s32 hShift[64];

s32 iBoard[] = {
	WRC,  WN,  WB,  WQ, WKC,  WB,  WN, WRC,
	WP2, WP2, WP2, WP2, WP2, WP2, WP2, WP2,
	 ES,  ES,  ES,  ES,  ES,  ES,  ES,  ES,
	 ES,  ES,  ES,  ES,  ES,  ES,  ES,  ES,
	 ES,  ES,  ES,  ES,  ES,  ES,  ES,  ES,
	 ES,  ES,  ES,  ES,  ES,  ES,  ES,  ES,
	BP7, BP7, BP7, BP7, BP7, BP7, BP7, BP7,
	BRC,  BN,  BB,  BQ, BKC,  BB,  BN, BRC
};

s32 value[] = {
	valp, valp, valp, valp, valp, valp, valn, valb, valr, valr, valq, na, na,
	na,
	valp, valp, valp, valp, valp, valp, valn, valb, valr, valr, valq, na, na
};

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

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

Some Initializations

Code: Select all

static void InitThreads() {
	numThreads = 4;
	thread = new Thread * [numThreads];
	for (int i = 0; i < numThreads; i++) thread[i] = new Thread;
}

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

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

		// knights
		knightMvs[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
		kingMvs[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 (u64 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 (u64 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 (u64 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 (u64 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;
	}
}

static void NewGame() {
	Thread* t = thread[0];
	mode = GETCMD;
	occupied[WHITE] = 0x000000000000ffff;
	occupied[BLACK] = 0xffff000000000000;
	pawns[WHITE] = 0x000000000000ff00;
	pawns[BLACK] = 0x00ff000000000000;
	knights[WHITE] = 0x0000000000000042;
	knights[BLACK] = 0x4200000000000000;
	bishops[WHITE] = 0x0000000000000024;
	bishops[BLACK] = 0x2400000000000000;
	rooks[WHITE] = 0x0000000000000081;
	rooks[BLACK] = 0x8100000000000000;
	queens[WHITE] = 0x0000000000000008;
	queens[BLACK] = 0x0800000000000000;
	kings[WHITE] = 0x0000000000000010;
	kings[BLACK] = 0x1000000000000000;
	stm = WHITE;
	otm = BLACK;
	sly = 0;
	gly = 0;
	for (s32 i = a1; i <= h8; i++) board[i] = iBoard[i];
}

static void Initialize() {
	InitThreads();
	InitBitboards();
	NewGame();
}

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

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

A couple of utilities

Code: Select all

static bool AtkByWhite(Thread* t, u64 bb) {
	u64 atk = 0;
	u64 occ = occupied[WHITE] | occupied[BLACK];
	while (bb) {
		s32 sq = std::countr_zero(bb);
		bb ^= 1ull << sq;
		atk |= (bPawnAtks[sq] & pawns[WHITE]);
		atk |= (knightMvs[sq] & knights[WHITE]);
		atk |= (kingMvs[sq] & kings[WHITE]);
		atk |= (dSubset[sq][(((occ & dMask[sq]) * file_b2_b7) >> 58)] & (bishops[WHITE] | queens[WHITE]));
		atk |= (aSubset[sq][(((occ & aMask[sq]) * file_b2_b7) >> 58)] & (bishops[WHITE] | queens[WHITE]));
		atk |= (hSubset[sq][(occ >> hShift[sq]) & 63] & (rooks[WHITE] | queens[WHITE]));
		atk |= (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 bb) {
	u64 atk = 0;
	u64 occ = occupied[WHITE] | occupied[BLACK];
	while (bb) {
		s32 sq = std::countr_zero(bb);
		bb ^= 1ull << sq;
		atk |= (wPawnAtks[sq] & pawns[BLACK]);
		atk |= (knightMvs[sq] & knights[BLACK]);
		atk |= (kingMvs[sq] & kings[BLACK]);
		atk |= (dSubset[sq][(((occ & dMask[sq]) * file_b2_b7) >> 58)] & (bishops[BLACK] | queens[BLACK]));
		atk |= (aSubset[sq][(((occ & aMask[sq]) * file_b2_b7) >> 58)] & (bishops[BLACK] | queens[BLACK]));
		atk |= (hSubset[sq][(occ >> hShift[sq]) & 63] & (rooks[BLACK] | queens[BLACK]));
		atk |= (vSubset[sq][((((occ >> (sq & 7)) & file_a2_a7) * diag_c2_h7) >> 58)] & (rooks[BLACK] | queens[BLACK]));
	}
	return (atk != 0);
}
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

Generate all moves

Code: Select all

static s32 GenAllMoves(Thread* t, uMove* m) {
	uMove* n = m;
	u64 atk = 0;
	u64 bb = 0;
	u64 friends = occupied[stm];
	u64 enemies = occupied[otm];
	u64 occ = friends | enemies;
	u64 empty = ~occ;
	u64 notme = ~friends;

	do {
		s08 fs = std::countr_zero(friends);
		friends ^= one << fs;
		s32 ft = board[fs];
		switch (ft) {
		case WP2:
			atk |= bb = wPawnAtks[fs] & enemies;
			bb |= (one << (fs + 8)) & empty;
			bb |= (bb << 8) & (one << (fs + 16)) & empty;
			break;
		case WP3: case WP4: case WP6:
			atk |= bb = wPawnAtks[fs] & enemies;
			bb |= (one << (fs + 8)) & empty;
			break;
		case WP5:
			atk |= bb = wPawnAtks[fs] & (enemies | epsq);
			bb |= (one << (fs + 8)) & empty;
			break;
		case WP7:
			atk |= bb = wPawnAtks[fs] & enemies;
			bb |= (one << (fs + 8)) & empty;
			while (bb) {
				s08 ts = std::countr_zero(bb);
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPQ;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPN;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPR;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPB;
				m++;
			}
			continue;
		case WN: case BN:
			atk |= bb = knightMvs[fs] & notme;
			break;
		case WB: case BB:
			atk |= bb = (
				dSubset[fs][(((occ & dMask[fs]) * file_b2_b7) >> 58)] |
				aSubset[fs][(((occ & aMask[fs]) * file_b2_b7) >> 58)]
				) & notme;
			break;
		case WRC: case WR: case BRC: case BR:
			atk |= bb = (
				hSubset[fs][(occ >> hShift[fs]) & 63] |
				vSubset[fs][((((occ >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
				) & notme;
			break;
		case WQ:
			atk |= 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)]
				) & notme;
			break;
		case WKC:
			m->s.ft = ((u64)((board[h1] == WRC) && !(occ & occ_w_s) && !AtkByBlack(t, atk_w_s))) * WCS;
			m += (m->s.ft == WCS);
			m->s.ft = ((u64)((board[a1] == WRC) && !(occ & occ_w_l) && !AtkByBlack(t, atk_w_l))) * WCL;
			m += (m->s.ft == WCL);
			[[fallthrough]];
		case WK: 
			atk |= bb = kingMvs[fs] & notme;
			break;
		case BP7:
			atk |= bb = bPawnAtks[fs] & enemies;
			bb |= (one << (fs - 8)) & empty;
			bb |= (bb >> 8) & (one << (fs - 16)) & empty;
			break;
		case BP6: case BP5: case BP3:
			atk |= bb = bPawnAtks[fs] & enemies;
			bb |= (one << (fs - 8)) & empty;
			break;
		case BP4:
			atk |= bb = bPawnAtks[fs] & (enemies | epsq);
			bb |= (one << (fs - 8)) & empty;
			break;
		case BP2:
			atk |= bb = bPawnAtks[fs] & enemies;
			bb |= (one << (fs - 8)) & empty;
			while (bb) {
				s08 ts = std::countr_zero(bb);
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPQ;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPN;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPR;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPB;
				m++;
			}
			continue;
		case BKC:
			m->s.ft = ((u64)((board[h8] == BRC) && !(occ & occ_b_s) && !AtkByWhite(t, atk_b_s))) * BCS;
			m += (m->s.ft == BCS);
			m->s.ft = ((u64)((board[a8] == BRC) && !(occ & occ_b_l) && !AtkByWhite(t, atk_b_l))) * BCL;
			m += (m->s.ft == BCL);
			[[fallthrough]];
		case BK:
			atk |= bb = kingMvs[fs] & notme;
			break;
		}

		while (bb) {
			s08 ts = std::countr_zero(bb);
			bb ^= one << ts;
			m->s.fs = fs;
			m->s.ts = ts;
			m->s.ft = ft;
			m++;
		}

	} while (friends);

	epsq = 0;

	return (m - n) * (1 - (atk & kings[otm]));
}
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

And last for today generate captures

Code: Select all

static s32 GenCaptures(Thread* t, uMove* m) {
	u64 atk = 0;
	u64 bb = 0;
	u64 friends = occupied[stm];
	u64 enemies = occupied[otm];
	u64 occ = friends | enemies;
	u64 empty = ~occ;

	do {
		s08 fs = std::countr_zero(friends);
		friends ^= one << fs;
		s32 ft = board[fs];
		switch (ft) {
		case WP2:
			atk |= bb = wPawnAtks[fs] & enemies;
			break;
		case WP3: case WP4: case WP6:
			atk |= bb = wPawnAtks[fs] & enemies;
			break;
		case WP5:
			atk |= bb = wPawnAtks[fs] & (enemies | epsq);
			break;
		case WP7:
			atk |= bb = wPawnAtks[fs] & enemies;
			bb |= (one << (fs + 8)) & empty;
			while (bb) {
				s08 ts = std::countr_zero(bb);
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPQ;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPN;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPR;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = WPB;
				m++;
			}
			continue;
		case WN: case BN:
			atk |= bb = knightMvs[fs] & enemies;
			break;
		case WB: case BB:
			atk |= bb = (
				dSubset[fs][(((occ & dMask[fs]) * file_b2_b7) >> 58)] |
				aSubset[fs][(((occ & aMask[fs]) * file_b2_b7) >> 58)]
				) & enemies;
			break;
		case WRC: case WR: case BRC: case BR:
			atk |= bb = (
				hSubset[fs][(occ >> hShift[fs]) & 63] |
				vSubset[fs][((((occ >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
				) & enemies;
			break;
		case WQ:
			atk |= 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)]
				) & enemies;
			break;
		case WKC:
			[[fallthrough]];
		case WK:
			atk |= bb = kingMvs[fs] & enemies;
			break;
		case BP7:
			atk |= bb = bPawnAtks[fs] & enemies;
			break;
		case BP6: case BP5: case BP3:
			atk |= bb = bPawnAtks[fs] & enemies;
			break;
		case BP4:
			atk |= bb = bPawnAtks[fs] & (enemies | epsq);
			break;
		case BP2:
			atk |= bb = bPawnAtks[fs] & enemies;
			bb |= (one << (fs - 8)) & empty;
			while (bb) {
				s08 ts = std::countr_zero(bb);
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPQ;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPN;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPR;
				m++;
				m->s.fs = fs;
				m->s.ts = ts;
				m->s.ft = BPB;
				m++;
			}
			continue;
		case BKC:
			[[fallthrough]];
		case BK:
			atk |= bb = kingMvs[fs] & enemies;
			break;
		}

		while (bb) {
			s08 ts = std::countr_zero(bb);
			bb ^= one << ts;
			m->s.fs = fs;
			m->s.ts = ts;
			m->s.ft = ft;
			m++;
		}

	} while (friends);

	epsq = 0;

	return 1 - (atk & kings[otm]);
}
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

None of this has been debugged yet. The MakeMove() is almost done. I'll try to post that tomorrow some time. TakeBack() should be soon after. Then hopefully I'll be able to write a Perft() for the original position.

My philosophy is no unnecessary if statements and to optimize Qsearch() as much as possible. So in the functions GenMoves(), GenCaptures(), AtkByWhite(), AtkByBlack(), MakeMove() and TakeBack() there is not a single if statement in any of them. And in MakeMove() and TakeBack() all moves are treated as though they are captures as 85% or greater of all moves will be moves that capture. For example if a move is not a capture

*occType[m->s.tt] ^= (u64)(m->s.tt != ES) << m->s.ts; // (0 or 1), zero changes nothing
mat[otm] -= value[m->s.tt]; // if to-type is ES zero is subtracted

For now one would have to trust me when I say this is all very fast.
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: !! Development Log, My Last Try

Post by Henk »

How do you handle fifty moves rule?
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

Henk wrote: Tue Oct 15, 2024 1:20 pm How do you handle fifty moves rule?
fifty[sly + 1] = (m->s.tt == ES) * (fifty[sly] + 1); // sly is search ply
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: !! Development Log, My Last Try

Post by Mike Sherwin »

I'm still working on MakeMove(). I'm going to try to get it done before tonight is over. If not it will probably be tomorrow.

Here is just a sample to show my philosophy. Good or bad I'm sticking with it because I really like branchless designs and it's working for me. Comments welcome.

Code: Select all

	case WN: case BN:
		m->s.tt = board[m->s.ts];
		occupied[otm] ^= (u64)(m->s.tt != ES) << m->s.ts;
		*occType[m->s.tt] ^= (u64)(m->s.tt != ES) << m->s.ts;
		mat[otm] -= value[m->s.tt];
		occupied[stm] ^= (one << m->s.fs | one << m->s.ts);
		knights[stm] ^= (one << m->s.fs | one << m->s.ts);
		board[m->s.fs] = ES;
		board[m->s.ts] = m->s.ft;
		fifty[sly + 1] = (u64)(m->s.tt == ES) * (fifty[sly] + 1);
		break;