Fastest perft

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

ethanara
Posts: 134
Joined: Mon May 16, 2011 6:58 pm
Location: Denmark

Fastest perft

Post by ethanara »

Hi
As far as i know, i-perft is the fastest perft so far.
After editing oliperft by editing to this:

Code: Select all

for &#40;i = 0; i < 0x10000; i++) &#123;
	    LSB&#91;i&#93; = _slow_lsb&#40;i&#41;;
	    hashxor&#91;i&#93; = _rand_64&#40;);
	    BITC&#91;i&#93; = _bitcount&#40;i&#41;;
	&#125;
from this:

Code: Select all

for &#40;i = 0; i < 0x10000; i++) LSB&#91;i&#93; = _slow_lsb&#40;i&#41;;
for &#40;i = 0; i < 0x10000; i++) hashxor&#91;i&#93; = _rand_64&#40;);
for &#40;i = 0; i < 0x10000; i++) BITC&#91;i&#93; = _bitcount&#40;i&#41;;
and a couple of other "unoptimized loops"
now, recompiling it , it calculates starting position perft 7 (correct result) in 39.98 seconds.


here is the code (warning, 1000 lines):

Code: Select all

/* OliPerft 1.0.1 - Bitboard Magic Move &#40;c&#41; Oliver Brausch 01.Jan.2008, ob112@web.de */
/* oliperft 6 "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1"
Nodes&#58; 8229523927 ms&#58; 40610 knps&#58; 202647 &#40;VS2005 64bit AMD64 4600+)
Nodes&#58; 8229523927 ms&#58; 64860 knps&#58; 126881 &#40;VS2005 32bit AMD64 4600+)
Nodes&#58; 8229523927 ms&#58; 97251 knps&#58; 84621 &#40;gcc4 32bit AMD Opteron 1210HE&#41;
*/
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#ifdef _WIN32
#include <sys/timeb.h>
struct _timeb tv;
#else
#include <sys/time.h>
struct timeval tv;
struct timezone tz;
#endif

#define PAWN 1
#define KNIGHT 2
#define KING 3
#define ENP 4
#define BISHOP 5
#define ROOK 6
#define QUEEN 7

#define FROM&#40;x&#41; (&#40;x&#41; & 0x3F&#41;
#define TO&#40;x&#41; ((&#40;x&#41; >> 6&#41; & 0x3F&#41;
#define ONMV&#40;x&#41; ((&#40;x&#41; >> 12&#41; & 1&#41;
#define PIECE&#40;x&#41; ((&#40;x&#41; >> 13&#41; & 7&#41;
#define PROM&#40;x&#41; ((&#40;x&#41; >> 16&#41; & 7&#41;
#define CAP&#40;x&#41; ((&#40;x&#41; >> 19&#41; & 7&#41;

#define _TO&#40;x&#41; (&#40;x&#41; << 6&#41;
#define _ONMV&#40;x&#41; (&#40;x&#41; << 12&#41;
#define _PIECE&#40;x&#41; (&#40;x&#41; << 13&#41;
#define _PROM&#40;x&#41; (&#40;x&#41; << 16&#41;
#define _CAP&#40;x&#41; (&#40;x&#41; << 19&#41;
#define PREMOVE&#40;f, p&#41; (&#40;f&#41; | _ONMV&#40;c&#41; | _PIECE&#40;p&#41;)

#define RATT1&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key000&#40;board, f&#41;&#93;
#define RATT2&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key090&#40;board, f&#41; | 0x2000&#93;
#define BATT3&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key045&#40;board, f&#41; | 0x4000&#93;
#define BATT4&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key135&#40;board, f&#41; | 0x6000&#93;
#define RXRAY1&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key000&#40;board, f&#41; | 0x8000&#93;
#define RXRAY2&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key090&#40;board, f&#41; | 0xA000&#93;
#define BXRAY3&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key045&#40;board, f&#41; | 0xC000&#93;
#define BXRAY4&#40;f&#41; rays&#91;(&#40;f&#41; << 7&#41; | key135&#40;board, f&#41; | 0xE000&#93;

#define ROCC1&#40;f&#41; &#40;RATT1&#40;f&#41; & board&#41;
#define ROCC2&#40;f&#41; &#40;RATT2&#40;f&#41; & board&#41;
#define BOCC3&#40;f&#41; &#40;BATT3&#40;f&#41; & board&#41;
#define BOCC4&#40;f&#41; &#40;BATT4&#40;f&#41; & board&#41;
#define RMOVE1&#40;f&#41; &#40;RATT1&#40;f&#41; & (~board&#41;)
#define RMOVE2&#40;f&#41; &#40;RATT2&#40;f&#41; & (~board&#41;)
#define BMOVE3&#40;f&#41; &#40;BATT3&#40;f&#41; & (~board&#41;)
#define BMOVE4&#40;f&#41; &#40;BATT4&#40;f&#41; & (~board&#41;)
#define RCAP1&#40;f, c&#41; &#40;RATT1&#40;f&#41; & colorb&#91;&#40;c&#41;^1&#93;)
#define RCAP2&#40;f, c&#41; &#40;RATT2&#40;f&#41; & colorb&#91;&#40;c&#41;^1&#93;)
#define BCAP3&#40;f, c&#41; &#40;BATT3&#40;f&#41; & colorb&#91;&#40;c&#41;^1&#93;)
#define BCAP4&#40;f, c&#41; &#40;BATT4&#40;f&#41; & colorb&#91;&#40;c&#41;^1&#93;)
#define ROCC&#40;f&#41; &#40;ROCC1&#40;f&#41; | ROCC2&#40;f&#41;)
#define BOCC&#40;f&#41; &#40;BOCC3&#40;f&#41; | BOCC4&#40;f&#41;)
#define RMOVE&#40;f&#41; &#40;RMOVE1&#40;f&#41; | RMOVE2&#40;f&#41;)
#define BMOVE&#40;f&#41; &#40;BMOVE3&#40;f&#41; | BMOVE4&#40;f&#41;)
#define RCAP&#40;f, c&#41; &#40;ROCC&#40;f&#41; & colorb&#91;&#40;c&#41;^1&#93;)
#define BCAP&#40;f, c&#41; &#40;BOCC&#40;f&#41; & colorb&#91;&#40;c&#41;^1&#93;)

#define SHORTMOVE&#40;x&#41; (&#40;x&#41; & (&#40;x&#41;^board&#41;)
#define SHORTOCC&#40;x&#41; (&#40;x&#41; & board&#41;)
#define SHORTCAP&#40;x, c&#41; (&#40;x&#41; & colorb&#91;&#40;c&#41;^1&#93;)

#define NMOVE&#40;x&#41; &#40;SHORTMOVE&#40;nmoves&#91;x&#93;))
#define KMOVE&#40;x&#41; &#40;SHORTMOVE&#40;kmoves&#91;x&#93;))
#define PMOVE&#40;x, c&#41; &#40;pmoves&#91;&#40;x&#41; | (&#40;c&#41;<<6&#41;&#93; & (~board&#41;)
#define NOCC&#40;x&#41; &#40;SHORTOCC&#40;nmoves&#91;x&#93;))
#define KOCC&#40;x&#41; &#40;SHORTOCC&#40;kmoves&#91;x&#93;))
#define POCC&#40;x, c&#41; &#40;pcaps&#91;&#40;x&#41; | (&#40;c&#41;<<6&#41;&#93; & board&#41;
#define NCAP&#40;x, c&#41; &#40;SHORTCAP&#40;nmoves&#91;x&#93;, &#40;c&#41;))
#define KCAP&#40;x, c&#41; &#40;SHORTCAP&#40;kmoves&#91;x&#93;, &#40;c&#41;))
#define PCAP&#40;x, c&#41; &#40;pcaps&#91;&#40;x&#41; | (&#40;c&#41;<<6&#41;&#93; & colorb&#91;&#40;c&#41;^1&#93;)
#define PCA3&#40;x, c&#41; &#40;pcaps&#91;&#40;x&#41; | (&#40;c&#41;<<6&#41; | 128&#93; & &#40;colorb&#91;&#40;c&#41;^1&#93; | (&#40;BIT&#91;ENPASS&#93;) & &#40;c ? 0xFF0000LL &#58; 0xFF0000000000LL&#41;)))
#define PCA4&#40;x, c&#41; &#40;pcaps&#91;&#40;x&#41; | (&#40;c&#41;<<6&#41; | 256&#93; & &#40;colorb&#91;&#40;c&#41;^1&#93; | (&#40;BIT&#91;ENPASS&#93;) & &#40;c ? 0xFF0000LL &#58; 0xFF0000000000LL&#41;)))

#define RANK&#40;x, y&#41; ((&#40;x&#41; & 0x38&#41; == &#40;y&#41;)
#define TEST&#40;f, b&#41; &#40;BIT&#91;f&#93; & &#40;b&#41;)
#define ENPASS &#40;flags & 63&#41;
#define CASTLE &#40;flags & 960&#41;

typedef unsigned long long u64;
typedef unsigned long u32;
typedef int Move;

static u64 rays&#91;0x10000&#93;;
u64 nmoves&#91;64&#93;;
u64 kmoves&#91;64&#93;;
u64 pmoves&#91;128&#93;;
u64 pcaps&#91;384&#93;;
int _knight&#91;8&#93; = &#123;-17,-10,6,15,17,10,-6,-15&#125;;
int _king&#91;8&#93; = &#123;-9,-1,7,8,9,1,-7,-8&#125;;
u64 pieceb&#91;8&#93;;
u64 colorb&#91;2&#93;;
u64 board;
u64 hashb;
static u64 BIT&#91;64&#93;;
static u64 hashxor&#91;0x10000&#93;;
static char LSB&#91;0x10000&#93;;
static char BITC&#91;0x10000&#93; ;
int flags;
int crevoke&#91;64&#93;;
int onmove;
Move movelist&#91;128*256&#93;;
int movenum&#91;128&#93;;
int kingpos&#91;2&#93;;

const char pieceChar&#91;&#93; = "*PNK.BRQ";

void setBit&#40;int f, u64 *board&#41; &#123;
	*board |= BIT&#91;f&#93;;
&#125;

void xorBit&#40;int f, u64 *board&#41; &#123;
	*board ^= BIT&#91;f&#93;;
&#125;

u64 getLowestBit&#40;u64 bb&#41; &#123;
	return bb & (-&#40;long long&#41;bb&#41;;
&#125;

void _parse_fen&#40;char *fen&#41; &#123;
	char c, mv, pos&#91;128&#93;, cas&#91;4&#93;, enps&#91;2&#93;;
	int i, j = 0, halfm = 0, fullm = 1, col = 0, row = 7;
	for &#40;i = 0; i < 8; i++) &#123;
		pieceb&#91;i&#93; = 0LL;
	&#125;
	colorb&#91;0&#93; = colorb&#91;1&#93; = hashb = 0LL;
	sscanf&#40;fen, "%s %c %s %s %d %d", pos, &mv, cas, enps, &halfm, &fullm&#41;;
	while (&#40;c = pos&#91;j++&#93;)) &#123;
		if &#40;c == '/') &#123;
			row--;
			col = 0;
		&#125; else if &#40;c >= '1' && c <= '8') &#123;
			col += c - '0';
		&#125; else for &#40;i = 1; i < 8; i++) &#123;
			if &#40;pieceChar&#91;i&#93; == c&#41; &#123;
				if &#40;i == KING&#41; kingpos&#91;0&#93; = row*8 + col;
				hashb ^= hashxor&#91;0 | &#40;row << 1&#41; | &#40;i << 4&#41; | &#40;col << 7&#41;&#93;;
				setBit&#40;row*8 + col, pieceb+i&#41;;
				setBit&#40;row*8 + &#40;col++), colorb&#41;;
				break;
			&#125; else if &#40;pieceChar&#91;i&#93; == c - 32&#41; &#123;
				if &#40;i == KING&#41; kingpos&#91;1&#93; = row*8 + col;
				hashb ^= hashxor&#91;1 | &#40;row << 1&#41; | &#40;i << 4&#41; | &#40;col << 7&#41;&#93;;
				setBit&#40;row*8 + col, pieceb+i&#41;;
				setBit&#40;row*8 + &#40;col++), colorb+1&#41;;
				break;
			&#125;
		&#125;
	&#125;
	onmove = mv == 'b' ? 1 &#58; 0;
	flags = j = 0;
	while (&#40;c = cas&#91;j++&#93;)) &#123;
		if &#40;c == 'K') flags |= BIT&#91;6&#93;;
		if &#40;c == 'k') flags |= BIT&#91;7&#93;;
		if &#40;c == 'Q') flags |= BIT&#91;8&#93;;
		if &#40;c == 'q') flags |= BIT&#91;9&#93;;
	&#125;
	if &#40;enps&#91;0&#93; != '-') &#123;
		flags |= 8*&#40;enps&#91;1&#93; - '1') + enps&#91;0&#93; - 'a';
	&#125;
	board = colorb&#91;0&#93; | colorb&#91;1&#93;;
&#125;

static u32 r_x = 30903, r_y = 30903, r_z = 30903, r_w = 30903, r_carry = 0;
u32 _rand_32&#40;) &#123;
	u32 t;
	r_x = r_x * 69069 + 1;
	r_y ^= r_y << 13;
	r_y ^= r_y >> 17;
	r_y ^= r_y << 5;
	t = &#40;r_w << 1&#41; + r_z + r_carry;
	r_carry = (&#40;r_z >> 2&#41; + &#40;r_w >> 3&#41; + &#40;r_carry >> 2&#41;) >> 30;
	r_z = r_w;
	r_w = t;
	return r_x + r_y + r_w;
&#125;

u64 _rand_64&#40;) &#123; u64 c = _rand_32&#40;); return _rand_32&#40;) | &#40;c << 32&#41;; &#125;

u64 getTime&#40;)
&#123;
#ifdef _WIN32
	_ftime&#40;&tv&#41;;
	return&#40;tv.time * 1000LL + tv.millitm&#41;;
#else
	gettimeofday (&tv, &tz&#41;;
	return&#40;tv.tv_sec * 1000LL + &#40;tv.tv_usec / 1000&#41;);
#endif
&#125;

char getLsb&#40;u64 bm&#41; &#123;
	u32 n = &#40;u32&#41; &#40;bm & 0xFFFFFFFF&#41;;
	if &#40;n&#41; &#123;
		if &#40;n & 0xFFFF&#41; return LSB&#91;n & 0xFFFF&#93;;
		else return 16 | LSB&#91;&#40;n >> 16&#41; & 0xFFFF&#93;;
	&#125; else &#123;
		n = &#40;u32&#41;&#40;bm >> 32&#41;;
		if &#40;n & 0xFFFF&#41; return 32 | LSB&#91;n & 0xFFFF&#93;;
		else return 48 | LSB&#91;&#40;n >> 16&#41; & 0xFFFF&#93;;
	&#125;
&#125;

char _slow_lsb&#40;u64 bm&#41; &#123;
	int k = -1;
	while &#40;bm&#41; &#123; k++; if &#40;bm & 1&#41; break; bm >>= 1; &#125;
	return &#40;char&#41;k;
&#125;

int pullLsb&#40;u64* bit&#41; &#123;
	int f = getLsb&#40;*bit&#41;;
	*bit ^= BIT&#91;f&#93;;
	return f;
&#125;

int _bitcount&#40;u64 bit&#41; &#123;
	int count=0;
	while &#40;bit&#41; &#123; bit &= &#40;bit-1&#41;; count++; &#125;
	return count;
&#125;

int bitcount &#40;u64 n&#41;
&#123;
     return BITC&#91;n         & 0xFFFF&#93;
         +  BITC&#91;&#40;n >> 16&#41; & 0xFFFF&#93;
         +  BITC&#91;&#40;n >> 32&#41; & 0xFFFF&#93;
         +  BITC&#91;&#40;n >> 48&#41; & 0xFFFF&#93;;
&#125;

int identPiece&#40;int f&#41; &#123;
	if &#40;TEST&#40;f, pieceb&#91;PAWN&#93;)) return PAWN;
	if &#40;TEST&#40;f, pieceb&#91;KNIGHT&#93;)) return KNIGHT;
	if &#40;TEST&#40;f, pieceb&#91;BISHOP&#93;)) return BISHOP;
	if &#40;TEST&#40;f, pieceb&#91;ROOK&#93;)) return ROOK;
	if &#40;TEST&#40;f, pieceb&#91;QUEEN&#93;)) return QUEEN;
	if &#40;TEST&#40;f, pieceb&#91;KING&#93;)) return KING;
	return ENP;
&#125;

int identColor&#40;int f&#41; &#123;
	if &#40;TEST&#40;f, colorb&#91;1&#93;)) return 1;
	return 0;
&#125;

u64 bmask45&#91;64&#93;;
u64 bmask135&#91;64&#93;;

int key000&#40;u64 b, int f&#41; &#123;
	return &#40;int&#41; (&#40;b >> &#40;f & 56&#41;) & 0x7E&#41;;
&#125;

#if defined&#40;_WIN64&#41; || defined&#40;_LP64&#41;
int key090&#40;u64 b, int f&#41; &#123;
	u64 _b = &#40;b >> &#40;f&7&#41;) & 0x0101010101010101LL;
	_b = _b * 0x0080402010080400LL;
	return &#40;int&#41;(_b >> 57&#41;;
&#125;

int keyDiag&#40;u64 _b&#41; &#123;
	_b = _b * 0x0202020202020202LL;
	return &#40;int&#41;(_b >> 57&#41;;
&#125;
#else
int key090&#40;u64 b, int f&#41; &#123;
	int h;
	b = b >> &#40;f&7&#41;;
	h = &#40;int&#41;(&#40;b & 0x1010101&#41; | (&#40;b >> 31&#41; & 0x2020202&#41;);
	h = &#40;h & 0x303&#41; | (&#40;h >> 14&#41; & 0xC0C&#41;;
	return &#40;h & 0xE&#41; | (&#40;h >> 4&#41; & 0x70&#41;;
&#125;

int keyDiag&#40;u64 _b&#41; &#123;
   int h = &#40;int&#41;(_b | _b >> 32&#41;;
   h |= h >> 16;
   h |= h >>  8;
   return h & 0x7E;
&#125;
#endif

int key045&#40;u64 b, int f&#41; &#123;
   return keyDiag&#40;b & bmask45&#91;f&#93;);
&#125;

int key135&#40;u64 b, int f&#41; &#123;
   return keyDiag&#40;b & bmask135&#91;f&#93;);
&#125;

#define DUALATT&#40;x, y, c&#41; &#40;battacked&#40;x, c&#41; || battacked&#40;y, c&#41;)
#define RQU &#40;pieceb&#91;ROOK&#93; | pieceb&#91;QUEEN&#93;)
#define BQU &#40;pieceb&#91;BISHOP&#93; | pieceb&#91;QUEEN&#93;)

int battacked&#40;int f, int c&#41; &#123;
	if &#40;PCAP&#40;f, c&#41; & pieceb&#91;PAWN&#93;) return 1;
	if &#40;NCAP&#40;f, c&#41; & pieceb&#91;KNIGHT&#93;) return 1;
	if &#40;KCAP&#40;f, c&#41; & pieceb&#91;KING&#93;) return 1;
	if &#40;RCAP1&#40;f, c&#41; & RQU&#41; return 1;
	if &#40;RCAP2&#40;f, c&#41; & RQU&#41; return 1;
	if &#40;BCAP3&#40;f, c&#41; & BQU&#41; return 1;
	if &#40;BCAP4&#40;f, c&#41; & BQU&#41; return 1;
	return 0;
&#125;

u64 reach&#40;int f, int c&#41; &#123;
	return &#40;NCAP&#40;f, c&#41; & pieceb&#91;KNIGHT&#93;)
		| &#40;RCAP1&#40;f, c&#41; & RQU&#41;
		| &#40;RCAP2&#40;f, c&#41; & RQU&#41;
		| &#40;BCAP3&#40;f, c&#41; & BQU&#41;
		| &#40;BCAP4&#40;f, c&#41; & BQU&#41;;
&#125;

u64 attacked&#40;int f, int c&#41; &#123;
	return &#40;PCAP&#40;f, c&#41; & pieceb&#91;PAWN&#93;) | reach&#40;f, c&#41;;
&#125;

void _init_pawns&#40;u64* moves, u64* caps, int c&#41; &#123;
	int i;
	for &#40;i = 0; i < 64; i++) &#123;
		int m = i + &#40;c ? -8 &#58; 8&#41;;
		if &#40;m < 0 || m > 63&#41; continue;
		setBit&#40;m, moves + i&#41;;
		if (&#40;i&7&#41; > 0&#41; &#123;
			m = i + &#40;c ? -9 &#58; 7&#41;;
			if &#40;m < 0 || m > 63&#41; continue;
			setBit&#40;m, caps + i&#41;;
			setBit&#40;m, caps + i + 128*&#40;2 - c&#41;);
		&#125;
		if (&#40;i&7&#41; < 7&#41; &#123;
			m = i + &#40;c ? -7 &#58; 9&#41;;
			if &#40;m < 0 || m > 63&#41; continue;
			setBit&#40;m, caps + i&#41;;
			setBit&#40;m, caps + i + 128*&#40;c + 1&#41;);
		&#125;
	&#125;
&#125;

void _init_shorts&#40;u64* moves, int* m&#41; &#123;
	int i, j, n;
	for &#40;i = 0; i < 64; i++) &#123;
		for &#40;j = 0; j < 8; j++) &#123;
			n = i + m&#91;j&#93;;
			if &#40;n < 64 && n >= 0 && (&#40;n & 7&#41;-&#40;i & 7&#41;)*(&#40;n & 7&#41;-&#40;i & 7&#41;) <= 4&#41; &#123;
				setBit&#40;n, moves+i&#41;;
			&#125;
		&#125;
	&#125;
&#125;

u64 _occ_free_board&#40;int bc, int del, u64 free&#41; &#123;
	u64 low, perm = free;
	int i;
	for &#40;i = 0; i < bc; i++) &#123;
		low = getLowestBit&#40;free&#41;;
		free &= (~low&#41;;
		if (!TEST&#40;i, del&#41;) perm &= (~low&#41;;
	&#125;
	return perm;
&#125;

void _init_rays&#40;u64* rays, u64 (*rayFunc&#41; &#40;int, u64, int&#41;, int (*key&#41;&#40;u64, int&#41;) &#123;
	int i, f, iperm, bc, index;
	u64 board, mmask, occ, move, xray;
	for &#40;f = 0; f < 64; f++) &#123;
		mmask = (*rayFunc&#41;&#40;f, 0LL, 0&#41; | BIT&#91;f&#93;;
		iperm = 1 << &#40;bc = bitcount&#40;mmask&#41;);
		for &#40;i = 0; i < iperm; i++) &#123;
			board = _occ_free_board&#40;bc, i, mmask&#41;;
			move = (*rayFunc&#41;&#40;f, board, 1&#41;;
			occ = (*rayFunc&#41;&#40;f, board, 2&#41;;
			xray = (*rayFunc&#41;&#40;f, board, 3&#41;;
			index = (*key&#41;&#40;board, f&#41;;
			rays&#91;&#40;f << 7&#41; + index&#93; = occ | move;
			rays&#91;&#40;f << 7&#41; + index + 0x8000&#93; = xray;
		&#125;
	&#125;
&#125;

#define RAYMACRO &#123;if &#40;TEST&#40;i, board&#41;) &#123; if &#40;b&#41; &#123; setBit&#40;i, &xray&#41;; break; &#125; else &#123; setBit&#40;i, &occ&#41;; b = 1; &#125; &#125; if (!b&#41; setBit&#40;i, &free&#41;;&#125;
u64 _rook0&#40;int f, u64 board, int t&#41; &#123;
	u64 free = 0LL, occ = 0LL, xray = 0LL;
	int i, b;
	for &#40;b = 0, i = f+1; i < 64 && i%8 != 0; i++) RAYMACRO
	for &#40;b = 0, i = f-1; i >= 0 && i%8 != 7; i--) RAYMACRO
	return &#40;t < 2&#41; ? free &#58; &#40;t == 2 ? occ &#58; xray&#41;;
&#125;

u64 _rook90&#40;int f, u64 board, int t&#41; &#123;
	u64 free = 0LL, occ = 0LL, xray = 0LL;
	int i, b;
	for &#40;b = 0, i = f-8; i >= 0; i-=8&#41; RAYMACRO
	for &#40;b = 0, i = f+8; i < 64; i+=8&#41; RAYMACRO
	return &#40;t < 2&#41; ? free &#58; &#40;t == 2 ? occ &#58; xray&#41;;
&#125;

u64 _bishop45&#40;int f, u64 board, int t&#41; &#123;
	u64 free = 0LL, occ = 0LL, xray = 0LL;
	int i, b;
	for &#40;b = 0, i = f+9; i < 64 && &#40;i%8 != 0&#41;; i+=9&#41; RAYMACRO
		for &#40;b = 0, i = f-9; i >= 0 && &#40;i%8 != 7&#41;; i-=9&#41; RAYMACRO
			return &#40;t < 2&#41; ? free &#58; &#40;t == 2 ? occ &#58; xray&#41;;
&#125;

u64 _bishop135&#40;int f, u64 board, int t&#41; &#123;
	u64 free = 0LL, occ = 0LL, xray = 0LL;
	int i, b;
	for &#40;b = 0, i = f-7; i >= 0 && &#40;i%8 != 0&#41;; i-=7&#41; RAYMACRO
		for &#40;b = 0, i = f+7; i < 64 && &#40;i%8 != 7&#41;; i+=7&#41; RAYMACRO
			return &#40;t < 2&#41; ? free &#58; &#40;t == 2 ? occ &#58; xray&#41;;
&#125;

void display64&#40;u64 bb&#41; &#123;
	int i, j;
	for &#40;i = 0; i < 8; i++) &#123;
		for &#40;j = 0; j < 8; j++) &#123;
			printf&#40;" %d", TEST&#40;j + &#40;7-i&#41;*8, bb&#41; ? 1 &#58; 0&#41;;
		&#125;
		printf&#40;"\n");
	&#125;
	printf&#40;"\n");
&#125;

void displayb&#40;) &#123;
	int i, j;
	for &#40;i = 0; i < 8; i++) &#123;
		for &#40;j = 0; j < 8; j++) &#123;
			int f = j + &#40;7-i&#41;*8;
			printf&#40;" %c", pieceChar&#91;identPiece&#40;f&#41;&#93; + identColor&#40;f&#41;*32&#41;;
		&#125;
		printf&#40;"\n");
	&#125;
	printf&#40;"\n");
&#125;

void displaym&#40;Move m&#41; &#123;
	printf&#40;"%c%c%c%c%c%c", pieceChar&#91;PIECE&#40;m&#41;&#93;, 'a' + FROM&#40;m&#41; % 8, '1' + FROM&#40;m&#41; / 8,
		CAP&#40;m&#41; == 0 ? '-' &#58; 'x', 'a' + TO&#40;m&#41; % 8, '1' + TO&#40;m&#41; / 8&#41;;
	if &#40;PROM&#40;m&#41;) printf&#40;"%c", pieceChar&#91;PROM&#40;m&#41;&#93;+32&#41;;
&#125;

Move movestack&#91;128&#93;;
void displaypv&#40;int ply&#41; &#123;
	int i;
	for &#40;i = 0; i < ply; i++) &#123;
		displaym&#40;movestack&#91;i&#93;); printf&#40;" ");
	&#125;
	printf&#40;"\n");
&#125;

void doMove&#40;Move m, int c&#41; &#123;
	int f = FROM&#40;m&#41;;
	int t = TO&#40;m&#41;;
	int p = PIECE&#40;m&#41;;
	int a = CAP&#40;m&#41;;

	xorBit&#40;f, colorb+c&#41;;
	xorBit&#40;f, pieceb+p&#41;;

	xorBit&#40;t, colorb+c&#41;;
	xorBit&#40;t, pieceb+p&#41;;
	flags &= 960;
	if &#40;a&#41; &#123;
		if &#40;a == ENP&#41; &#123; // Enpassant Capture
			t = &#40;t&7&#41; | &#40;f&56&#41;;
			a = PAWN;
		&#125; else if &#40;a == ROOK && CASTLE&#41; &#123; //Revoke castling rights.
			flags &= crevoke&#91;t&#93;;
		&#125;
		xorBit&#40;t, pieceb+a&#41;;
		xorBit&#40;t, colorb+&#40;c^1&#41;);
	&#125;
	if &#40;p == PAWN&#41; &#123;
		if ((&#40;f^t&#41;&8&#41; == 0&#41; flags |= f^24; //Enpassant
		else if (&#40;t&56&#41; == 0 || &#40;t&56&#41; == 56&#41; &#123;
			xorBit&#40;t, pieceb+PAWN&#41;;
			xorBit&#40;t, pieceb+PROM&#40;m&#41;);
		&#125;
	&#125; else if &#40;p == KING&#41; &#123;
		if &#40;kingpos&#91;c&#93; == f&#41; kingpos&#91;c&#93; = t; else kingpos&#91;c&#93; = f;
		flags &= ~&#40;320 << c&#41;; // Lose castling rights
		if ((&#40;f^t&#41;&3&#41; == 2&#41; &#123; // Castle
			if &#40;t == 6&#41; &#123; f = 7; t = 5; &#125;
			else if &#40;t == 2&#41; &#123; f = 0; t = 3; &#125;
			else if &#40;t == 62&#41; &#123; f = 63; t = 61; &#125;
			else &#123; f = 56; t = 59; &#125;
			xorBit&#40;f, colorb+c&#41;;
			xorBit&#40;f, pieceb+ROOK&#41;;
			xorBit&#40;t, colorb+c&#41;;
			xorBit&#40;t, pieceb+ROOK&#41;;
			hashb ^= hashxor&#91;f | c << 12 | ROOK << 13&#93;;
			hashb ^= hashxor&#91;t | c << 12 | ROOK << 13&#93;;
		&#125;
	&#125; else if &#40;p == ROOK && CASTLE&#41; &#123;
		flags &= crevoke&#91;f&#93;;
	&#125;
	board = colorb&#91;0&#93; | colorb&#91;1&#93;;
	hashb ^= hashxor&#91;f | (&#40;m >> 6&#41; & 0x3C0&#41;&#93;;
	hashb ^= hashxor&#91;m >> 6&#93;;
&#125;

void registerCaps&#40;Move m, u64 bc, int* mlist, int* mn&#41; &#123;
	while &#40;bc&#41; &#123;
		int t = pullLsb&#40;&bc&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _TO&#40;t&#41; | _CAP&#40;identPiece&#40;t&#41;);
	&#125;
&#125;

void registerMoves&#40;Move m, u64 bc, u64 bm, int* mlist, int* mn&#41; &#123;
	while &#40;bc&#41; &#123;
		int t = pullLsb&#40;&bc&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _TO&#40;t&#41; | _CAP&#40;identPiece&#40;t&#41;);
	&#125;
	while &#40;bm&#41; &#123;
		mlist&#91;(*mn&#41;++&#93; = m | _TO&#40;pullLsb&#40;&bm&#41;);
	&#125;
&#125;

void registerProms&#40;int f, int c, u64 bc, u64 bm, int* mlist, int* mn&#41; &#123;
	while &#40;bc&#41; &#123;
		int t = pullLsb&#40;&bc&#41;;
		Move m = f | _ONMV&#40;c&#41; | _PIECE&#40;PAWN&#41; | _TO&#40;t&#41; | _CAP&#40;identPiece&#40;t&#41;);
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;QUEEN&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;KNIGHT&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;ROOK&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;BISHOP&#41;;
	&#125;
	while &#40;bm&#41; &#123;
		Move m = f | _ONMV&#40;c&#41; | _PIECE&#40;PAWN&#41; | _TO&#40;pullLsb&#40;&bm&#41;);
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;QUEEN&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;KNIGHT&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;ROOK&#41;;
		mlist&#91;(*mn&#41;++&#93; = m | _PROM&#40;BISHOP&#41;;
	&#125;
&#125;

void registerKing&#40;Move m, u64 bc, u64 bm, int* mlist, int* mn, int c&#41; &#123;
	while &#40;bc&#41; &#123;
		int t = pullLsb&#40;&bc&#41;;
		if &#40;battacked&#40;t, c&#41;) continue;
		mlist&#91;(*mn&#41;++&#93; = m | _TO&#40;t&#41; | _CAP&#40;identPiece&#40;t&#41;);
	&#125;
	while &#40;bm&#41; &#123;
		int t = pullLsb&#40;&bm&#41;;
		if &#40;battacked&#40;t, c&#41;) continue;
		mlist&#91;(*mn&#41;++&#93; = m | _TO&#40;t&#41;;
	&#125;
&#125;

char getDir&#40;int f, int t&#41; &#123;
	if (!(&#40;f ^ t&#41; & 56&#41;) return 8;
	if (!(&#40;f ^ t&#41; & 7&#41;) return 16;
	return (&#40;f - t&#41; % 7&#41; ? 32 &#58; 64;
&#125;

int generateCheckEsc&#40;u64 ch, u64 apin, int c, int k, int *ml, int *mn&#41; &#123;
	u64 cc, fl;
	int d, bf = _bitcount&#40;ch&#41;;
	board ^= BIT&#91;k&#93;;
	registerKing&#40;PREMOVE&#40;k, KING&#41;, KCAP&#40;k, c&#41;, KMOVE&#40;k&#41;, ml, mn, c&#41;;
	board ^= BIT&#91;k&#93;;
	if &#40;bf > 1&#41; return bf; //Multicheck
	bf = getLsb&#40;ch&#41;;

	cc = attacked&#40;bf, c^1&#41; & apin;  //Can we capture the checker?
	while &#40;cc&#41; &#123;
		int cf = pullLsb&#40;&cc&#41;;
		int p = identPiece&#40;cf&#41;;
		if &#40;p == PAWN && RANK&#40;cf, c ? 0x08 &#58; 0x30&#41;) &#123;
			registerProms&#40;cf, c, ch, 0LL, ml, mn&#41;;
		&#125; else &#123;
			registerMoves&#40;PREMOVE&#40;cf, p&#41;, ch, 0LL, ml, mn&#41;;
		&#125;
	&#125;
	if &#40;ENPASS && &#40;ch & pieceb&#91;PAWN&#93;)) &#123; //Enpassant capture of attacking Pawn
		cc = PCAP&#40;ENPASS, c^1&#41; & pieceb&#91;PAWN&#93; & apin;
		while &#40;cc&#41; &#123;
			int cf = pullLsb&#40;&cc&#41;;
			registerMoves&#40;PREMOVE&#40;cf, PAWN&#41;, BIT&#91;ENPASS&#93;, 0LL, ml, mn&#41;;
		&#125;
	&#125;
	if &#40;ch & &#40;nmoves&#91;k&#93; | kmoves&#91;k&#93;)) return 1; // We can't move anything between!

	d = getDir&#40;bf, k&#41;;
	if &#40;d & 8&#41; fl = RMOVE1&#40;bf&#41; & RMOVE1&#40;k&#41;;
	else if &#40;d & 16&#41; fl = RMOVE2&#40;bf&#41; & RMOVE2&#40;k&#41;;
	else if &#40;d & 32&#41; fl = BMOVE3&#40;bf&#41; & BMOVE3&#40;k&#41;;
	else fl = BMOVE4&#40;bf&#41; & BMOVE4&#40;k&#41;;

	while &#40;fl&#41; &#123;
		int f = pullLsb&#40;&fl&#41;;
		cc = reach&#40;f, c^1&#41; & apin;
		while &#40;cc&#41; &#123;
			int cf = pullLsb&#40;&cc&#41;;
			int p = identPiece&#40;cf&#41;;
			registerMoves&#40;PREMOVE&#40;cf, p&#41;, 0LL, BIT&#91;f&#93;, ml, mn&#41;;
		&#125;
		bf = c ? f+8 &#58; f-8;
		if &#40;bf < 0 || bf > 63&#41; continue;
		if &#40;BIT&#91;bf&#93; & pieceb&#91;PAWN&#93; & colorb&#91;c&#93; & apin&#41; &#123;
			if &#40;RANK&#40;bf, c ? 0x08 &#58; 0x30&#41;)
				registerProms&#40;bf, c, 0LL, BIT&#91;f&#93;, ml, mn&#41;;
			else
				registerMoves&#40;PREMOVE&#40;bf, PAWN&#41;, 0LL, BIT&#91;f&#93;, ml, mn&#41;;
		&#125;
		if &#40;RANK&#40;f, c ? 0x20 &#58; 0x18&#41; && &#40;board & BIT&#91;bf&#93;) == 0 && &#40;BIT&#91;c ? f+16 &#58; f-16&#93; & pieceb&#91;PAWN&#93; & colorb&#91;c&#93; & apin&#41;)
			registerMoves&#40;PREMOVE&#40;c ? f+16 &#58; f-16, PAWN&#41;, 0LL, BIT&#91;f&#93;, ml, mn&#41;;
	&#125;
	return 1;
&#125;

u64 pinnedPieces&#40;int f, int oc&#41; &#123;
	u64 pin = 0LL;
	u64 b = (&#40;RXRAY1&#40;f&#41; | RXRAY2&#40;f&#41;) & colorb&#91;oc&#93;) & RQU;
	while &#40;b&#41; &#123;
		int t = pullLsb&#40;&b&#41;;
		pin |= RCAP&#40;t, oc&#41; & ROCC&#40;f&#41;;
	&#125;
	b = (&#40;BXRAY3&#40;f&#41; | BXRAY4&#40;f&#41;) & colorb&#91;oc&#93;) & BQU;
	while &#40;b&#41; &#123;
		int t = pullLsb&#40;&b&#41;;
		pin |= BCAP&#40;t, oc&#41; & BOCC&#40;f&#41;;
	&#125;
	return pin;
&#125;

int generateMoves&#40;int c, int ply&#41; &#123;
	int t, f = kingpos&#91;c&#93;;
	int *mn = movenum + ply;
	int *ml = movelist + &#40;ply << 8&#41;;
	u64 m, b, a, cb = colorb&#91;c&#93;, ch = attacked&#40;f, c&#41;;
	u64 pin = pinnedPieces&#40;f, c^1&#41;;
	*mn = 0;

	if &#40;ch&#41; return generateCheckEsc&#40;ch, ~pin, c, f, ml, mn&#41;;
	registerKing&#40;PREMOVE&#40;f, KING&#41;, KCAP&#40;f, c&#41;, KMOVE&#40;f&#41;, ml, mn, c&#41;;

	cb = colorb&#91;c&#93; & (~pin&#41;;
	b = pieceb&#91;PAWN&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		m = PMOVE&#40;f, c&#41;;
		a = PCAP&#40;f, c&#41;;
		if &#40;m && RANK&#40;f, c ? 0x30 &#58; 0x08&#41;) m |= PMOVE&#40;c ? f-8 &#58; f+8, c&#41;;
		if &#40;RANK&#40;f, c ? 0x08 &#58; 0x30&#41;) &#123;
			registerProms&#40;f, c, a, m, ml, mn&#41;;
		&#125; else &#123;
			if &#40;ENPASS && &#40;BIT&#91;ENPASS&#93; & pcaps&#91;&#40;f&#41; | (&#40;c&#41;<<6&#41;&#93;)) &#123;
				u64 hh;
				int clbd = ENPASS^8;
				board ^= BIT&#91;clbd&#93;;
				hh = ROCC1&#40;f&#41;;
				if (!&#40;hh & BIT&#91;kingpos&#91;c&#93;&#93;) || !&#40;hh & colorb&#91;c^1&#93; & RQU&#41;) &#123;
					a = a | BIT&#91;ENPASS&#93;;
				&#125;
				board ^= BIT&#91;clbd&#93;;
			&#125;
			registerMoves&#40;PREMOVE&#40;f, PAWN&#41;, a, m, ml, mn&#41;;
		&#125;
	&#125;

	b = pin & pieceb&#91;PAWN&#93;;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		t = getDir&#40;f, kingpos&#91;c&#93;);
		if &#40;t & 8&#41; continue;
		m = a = 0LL;
		if &#40;t & 16&#41; &#123;
			m = PMOVE&#40;f, c&#41;;
			if &#40;m && RANK&#40;f, c ? 0x30 &#58; 0x08&#41;) m |= PMOVE&#40;c ? f-8 &#58; f+8, c&#41;;
		&#125; else if &#40;t & 32&#41; &#123;
			a = PCA3&#40;f, c&#41;;
		&#125; else &#123;
			a = PCA4&#40;f, c&#41;;
		&#125;
		if &#40;RANK&#40;f, c ? 0x08 &#58; 0x30&#41;) &#123;
			registerProms&#40;f, c, a, m, ml, mn&#41;;
		&#125; else &#123;
			registerMoves&#40;PREMOVE&#40;f, PAWN&#41;, a, m, ml, mn&#41;;
		&#125;
	&#125;

	b = pieceb&#91;KNIGHT&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		registerMoves&#40;PREMOVE&#40;f, KNIGHT&#41;, NCAP&#40;f, c&#41;, NMOVE&#40;f&#41;, ml, mn&#41;;
	&#125;

	b = pieceb&#91;ROOK&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		registerMoves&#40;PREMOVE&#40;f, ROOK&#41;, RCAP&#40;f, c&#41;, RMOVE&#40;f&#41;, ml, mn&#41;;
		if &#40;CASTLE && !ch&#41; &#123;
			if &#40;c&#41; &#123;
				if (&#40;flags & 128&#41; && &#40;f == 63&#41; && &#40;RMOVE1&#40;63&#41; & BIT&#91;61&#93;))
					if (!DUALATT&#40;61, 62, c&#41;) registerMoves&#40;PREMOVE&#40;60, KING&#41;, 0LL, BIT&#91;62&#93;, ml, mn&#41;;
				if (&#40;flags & 512&#41; && &#40;f == 56&#41; && &#40;RMOVE1&#40;56&#41; & BIT&#91;59&#93;))
					if (!DUALATT&#40;59, 58, c&#41;) registerMoves&#40;PREMOVE&#40;60, KING&#41;, 0LL, BIT&#91;58&#93;, ml, mn&#41;;
			&#125; else &#123;
				if (&#40;flags & 64&#41; && &#40;f == 7&#41; && &#40;RMOVE1&#40;7&#41; & BIT&#91;5&#93;))
					if (!DUALATT&#40;5, 6, c&#41;) registerMoves&#40;PREMOVE&#40;4, KING&#41;, 0LL, BIT&#91;6&#93;, ml, mn&#41;;
				if (&#40;flags & 256&#41; && &#40;f == 0&#41; && &#40;RMOVE1&#40;0&#41; & BIT&#91;3&#93;))
					if (!DUALATT&#40;3, 2, c&#41;) registerMoves&#40;PREMOVE&#40;4, KING&#41;, 0LL, BIT&#91;2&#93;, ml, mn&#41;;
			&#125;
		&#125;
	&#125;

	b = pieceb&#91;BISHOP&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		registerMoves&#40;PREMOVE&#40;f, BISHOP&#41;, BCAP&#40;f, c&#41;, BMOVE&#40;f&#41;, ml, mn&#41;;
	&#125;

	b = pieceb&#91;QUEEN&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		registerMoves&#40;PREMOVE&#40;f, QUEEN&#41;, RCAP&#40;f, c&#41; | BCAP&#40;f,c&#41;, RMOVE&#40;f&#41; | BMOVE&#40;f&#41;, ml, mn&#41;;
	&#125;

	b = pin & &#40;pieceb&#91;ROOK&#93; | pieceb&#91;BISHOP&#93; | pieceb&#91;QUEEN&#93;);
	while &#40;b&#41; &#123;
		int p;
		f = pullLsb&#40;&b&#41;;
		p = identPiece&#40;f&#41;;
		t = p | getDir&#40;f, kingpos&#91;c&#93;);
		if (&#40;t & 10&#41; == 10&#41; registerMoves&#40;PREMOVE&#40;f, p&#41;, RCAP1&#40;f, c&#41;, RMOVE1&#40;f&#41;, ml, mn&#41;;
		if (&#40;t & 18&#41; == 18&#41; registerMoves&#40;PREMOVE&#40;f, p&#41;, RCAP2&#40;f, c&#41;, RMOVE2&#40;f&#41;, ml, mn&#41;;
		if (&#40;t & 33&#41; == 33&#41; registerMoves&#40;PREMOVE&#40;f, p&#41;, BCAP3&#40;f, c&#41;, BMOVE3&#40;f&#41;, ml, mn&#41;;
		if (&#40;t & 65&#41; == 65&#41; registerMoves&#40;PREMOVE&#40;f, p&#41;, BCAP4&#40;f, c&#41;, BMOVE4&#40;f&#41;, ml, mn&#41;;
	&#125;
	return 0;
&#125;

void countKing&#40;u64 bm, int* mn, int c&#41; &#123;
	while &#40;bm&#41; &#123;
		if (!battacked&#40;pullLsb&#40;&bm&#41;, c&#41;) (*mn&#41;++;
	&#125;
&#125;

int countMoves&#40;int c, int ply&#41; &#123;
	int t, f = kingpos&#91;c&#93;;
	int* mn = movenum + ply;
	int* ml = movelist + &#40;ply << 8&#41;;
	u64 m, b, a, cb = colorb&#91;c&#93;, ch = attacked&#40;f, c&#41;;
	u64 pin = pinnedPieces&#40;f, c^1&#41;;
	*mn = 0;

	if &#40;ch&#41; return generateCheckEsc&#40;ch, ~pin, c, f, ml, mn&#41;;
	countKing&#40;KCAP&#40;f, c&#41; | KMOVE&#40;f&#41;, mn, c&#41;;

	cb = colorb&#91;c&#93; & (~pin&#41;;
	b = pieceb&#91;PAWN&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		m = PMOVE&#40;f, c&#41;;
		a = PCAP&#40;f, c&#41;;
		if &#40;m && RANK&#40;f, c ? 0x30 &#58; 0x08&#41;) m |= PMOVE&#40;c ? f-8 &#58; f+8, c&#41;;
		if &#40;RANK&#40;f, c ? 0x08 &#58; 0x30&#41;) &#123;
			*mn += _bitcount&#40;a | m&#41; << 2;
		&#125; else &#123;
			if &#40;ENPASS && &#40;BIT&#91;ENPASS&#93; & pcaps&#91;&#40;f&#41; | (&#40;c&#41;<<6&#41;&#93;)) &#123;
				u64 hh;
				int clbd = ENPASS^8;
				board ^= BIT&#91;clbd&#93;;
				hh = ROCC1&#40;f&#41;;
				if (!&#40;hh & BIT&#91;kingpos&#91;c&#93;&#93;) || !&#40;hh & colorb&#91;c^1&#93; & RQU&#41;) &#123;
					a = a | BIT&#91;ENPASS&#93;;
				&#125;
				board ^= BIT&#91;clbd&#93;;
			&#125;
			*mn += _bitcount&#40;a | m&#41;;
		&#125;
	&#125;

	b = pin & pieceb&#91;PAWN&#93;;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		t = getDir&#40;f, kingpos&#91;c&#93;);
		if &#40;t & 8&#41; continue;
		m = a = 0LL;
		if &#40;t & 16&#41; &#123;
			m = PMOVE&#40;f, c&#41;;
			if &#40;m && RANK&#40;f, c ? 0x30 &#58; 0x08&#41;) m |= PMOVE&#40;c ? f-8 &#58; f+8, c&#41;;
		&#125; else if &#40;t & 32&#41; &#123;
			a = PCA3&#40;f, c&#41;;
		&#125; else &#123;
			a = PCA4&#40;f, c&#41;;
		&#125;
		if &#40;RANK&#40;f, c ? 0x08 &#58; 0x30&#41;) &#123;
			*mn += _bitcount&#40;a | m&#41; << 2;
		&#125; else &#123;
			*mn += _bitcount&#40;a | m&#41;;
		&#125;
	&#125;

	b = pieceb&#91;KNIGHT&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		*mn += bitcount&#40;NCAP&#40;f, c&#41; | NMOVE&#40;f&#41;);
	&#125;

	b = pieceb&#91;BISHOP&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		*mn += bitcount&#40;BCAP&#40;f,c&#41; | BMOVE&#40;f&#41;);
	&#125;

	b = pieceb&#91;ROOK&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		*mn += bitcount&#40;RCAP&#40;f,c&#41; | RMOVE&#40;f&#41;);
		if &#40;CASTLE && !ch&#41; &#123;
			if &#40;c&#41; &#123;
				if (&#40;flags & 128&#41; && &#40;f == 63&#41; && &#40;RMOVE1&#40;63&#41; & BIT&#91;61&#93;) && (!DUALATT&#40;61, 62, c&#41;)) (*mn&#41;++;
				if (&#40;flags & 512&#41; && &#40;f == 56&#41; && &#40;RMOVE1&#40;56&#41; & BIT&#91;59&#93;) && (!DUALATT&#40;59, 58, c&#41;)) (*mn&#41;++;
			&#125; else &#123;
				if (&#40;flags & 64&#41; && &#40;f == 7&#41; && &#40;RMOVE1&#40;7&#41; & BIT&#91;5&#93;) && (!DUALATT&#40;5, 6, c&#41;)) (*mn&#41;++;
				if (&#40;flags & 256&#41; && &#40;f == 0&#41; && &#40;RMOVE1&#40;0&#41; & BIT&#91;3&#93;) && (!DUALATT&#40;3, 2, c&#41;)) (*mn&#41;++;
			&#125;
		&#125;
	&#125;

	b = pieceb&#91;QUEEN&#93; & cb;
	while &#40;b&#41; &#123;
		f = pullLsb&#40;&b&#41;;
		*mn += bitcount&#40;RCAP&#40;f, c&#41; | BCAP&#40;f, c&#41; | RMOVE&#40;f&#41; | BMOVE&#40;f&#41;);
	&#125;

	b = pin & &#40;pieceb&#91;ROOK&#93; | pieceb&#91;BISHOP&#93; | pieceb&#91;QUEEN&#93;);
	while &#40;b&#41; &#123;
		int p;
		f = pullLsb&#40;&b&#41;;
		p = identPiece&#40;f&#41;;
		t = p | getDir&#40;f, kingpos&#91;c&#93;);
		if (&#40;t & 10&#41; == 10&#41; *mn += _bitcount&#40;RCAP1&#40;f, c&#41; | RMOVE1&#40;f&#41;);
		if (&#40;t & 18&#41; == 18&#41; *mn += _bitcount&#40;RCAP2&#40;f, c&#41; | RMOVE2&#40;f&#41;);
		if (&#40;t & 33&#41; == 33&#41; *mn += _bitcount&#40;BCAP3&#40;f, c&#41; | BMOVE3&#40;f&#41;);
		if (&#40;t & 65&#41; == 65&#41; *mn += _bitcount&#40;BCAP4&#40;f, c&#41; | BMOVE4&#40;f&#41;);
	&#125;
	return 0;
&#125;

#define HASHB&#40;d&#41; &#40;hashb ^ hashxor&#91;flags | &#40;c&#41; << 10 | &#40;d&#41; << 11&#93;)
#define HSIZE 0x400000
#define HMASK 0x3FFFFF
#define HINV 0xFFFFFFFFFFC00000LL
u64 hashDB&#91;HSIZE&#93;;
u64 num&#91;128&#93;;

void perft&#40;int c, int d, int ply&#41; &#123;
	int i, poff;
	int flagstor = flags;

	u64 hb = HASHB&#40;d&#41;;
	u64 he = hashDB&#91;hb & HMASK&#93;;
	u64 n0, n1 = he & HMASK;

	if (!(&#40;he^hb&#41; & HINV&#41;) &#123;
		num&#91;ply+d&#93; += n1;
		return;
	&#125;

	if &#40;d<= 1&#41; &#123;
		countMoves&#40;c, ply&#41;;
		if &#40;movenum&#91;ply&#93; > n1&#41; hashDB&#91;hb & HMASK&#93; = &#40;hb & HINV&#41; | movenum&#91;ply&#93;;
		num&#91;ply+1&#93;+= movenum&#91;ply&#93;;
		return;
	&#125;
	n0 = num&#91;ply+d&#93;;

	generateMoves&#40;c, ply&#41;;
	poff = ply << 8;
	for &#40;i = 0; i < movenum&#91;ply&#93;; i++) &#123;
		Move m = movelist&#91;poff + i&#93;;
//		movestack&#91;ply&#93; = m;
		doMove&#40;m, c&#41;;

		num&#91;ply+1&#93;++;
		if &#40;d > 1&#41; perft&#40;c^1, d-1, ply+1&#41;;

		doMove&#40;m, c&#41;;
		flags = flagstor;
	&#125;
	n0 = num&#91;ply+d&#93; - n0;
	if &#40;n0 < 0x100000 && n0 > n1&#41; &#123;
		hashDB&#91;hb & HMASK&#93; = &#40;hb & HINV&#41; | n0;
	&#125;
&#125;

int main&#40;int argc, char **argv&#41;
&#123;
	int i, divide = 0, sd = 7;
	u64 t1, n = 0;
	char *sfen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
	if &#40;argc > 1&#41; sscanf&#40;argv&#91;1&#93;, "%d", &sd&#41;;
	if &#40;argc > 2&#41; sfen = argv&#91;2&#93;;
	if &#40;sd < 0&#41; &#123;
		sd = -sd;
		divide = 1;
	&#125;
	for &#40;i = 0; i < 0x10000; i++) &#123;
	    LSB&#91;i&#93; = _slow_lsb&#40;i&#41;;
	    hashxor&#91;i&#93; = _rand_64&#40;);
	    BITC&#91;i&#93; = _bitcount&#40;i&#41;;
	&#125;
	for &#40;i = 0; i < HSIZE; i++) hashDB&#91;i&#93; = 0LL;
	for &#40;i = 0; i < 64; i++) &#123;
     BIT&#91;i&#93; = 1LL << i;
	 crevoke&#91;i&#93; = 0x3FF;
	&#125;
	for &#40;i = 0; i < 128; i++) pmoves&#91;i&#93; = 0LL;
	for &#40;i = 0; i < 384; i++) pcaps&#91;i&#93; = 0LL;
	crevoke&#91;7&#93; ^= BIT&#91;6&#93;;
	crevoke&#91;63&#93; ^= BIT&#91;7&#93;;
	crevoke&#91;0&#93; ^= BIT&#91;8&#93;;
	crevoke&#91;56&#93; ^= BIT&#91;9&#93;;

	for &#40;i = 0; i < 64; i++) &#123;
     bmask45&#91;i&#93; = _bishop45&#40;i, 0LL, 0&#41; | BIT&#91;i&#93;;
	 bmask135&#91;i&#93; = _bishop135&#40;i, 0LL, 0&#41; | BIT&#91;i&#93;; &#125;

	_init_rays&#40;rays, _rook0, key000&#41;;
	_init_rays&#40;rays + 0x2000, _rook90, key090&#41;;
	_init_rays&#40;rays + 0x4000, _bishop45, key045&#41;;
	_init_rays&#40;rays + 0x6000, _bishop135, key135&#41;;
	_init_shorts&#40;nmoves, _knight&#41;;
	_init_shorts&#40;kmoves, _king&#41;;
	_init_pawns&#40;pmoves, pcaps, 0&#41;;
	_init_pawns&#40;pmoves + 64, pcaps + 64, 1&#41;;
	_parse_fen&#40;sfen&#41;;
	displayb&#40;);

	t1 = getTime&#40;);

	if &#40;divide&#41; &#123;
		int flagstor = flags;
		generateMoves&#40;onmove, 0&#41;;
		for &#40;i = 0; i < movenum&#91;0&#93;; i++) &#123;
			Move m = movelist&#91;i&#93;;
			doMove&#40;m, onmove&#41;;

			num&#91;1&#93;++;
			perft&#40;onmove^1, sd-1, 1&#41;;

			displaym&#40;m&#41;; printf&#40;"&#58; %llu\n", num&#91;sd&#93;);
			doMove&#40;m, onmove&#41;;
			flags = flagstor;
			n += num&#91;sd&#93;;
			num&#91;sd&#93; = 0;
		&#125;
	&#125; else &#123;
		for &#40;i = 1; i <= sd; i++) &#123;
			num&#91;i&#93; = 0;
			perft&#40;onmove, i, 0&#41;;
			printf&#40;"%2d %5d %6llu %11llu\n", i, 0, &#40;getTime&#40;) - t1&#41;/10, num&#91;i&#93;);
		&#125;
	&#125;
	t1 = getTime&#40;) - t1 + 1;
	printf&#40;"\nNodes&#58; %llu cs&#58; %llu knps&#58; %llu\n", n, t1/10, n/t1&#41;;
	return 0;
&#125;
please see if it is also faster than i-perft on your pc.
I think that in next week or so i will try to optimize it as much as possible (maybe getting down to 35?)
Regards
Ethan[/code]
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: Fastest perft

Post by lucasart »

ethanara wrote:Hi
As far as i know, i-perft is the fastest perft so far.
After editing oliperft by editing to this:

Code: Select all

for &#40;i = 0; i < 0x10000; i++) &#123;
	    LSB&#91;i&#93; = _slow_lsb&#40;i&#41;;
	    hashxor&#91;i&#93; = _rand_64&#40;);
	    BITC&#91;i&#93; = _bitcount&#40;i&#41;;
	&#125;
from this:

Code: Select all

for &#40;i = 0; i < 0x10000; i++) LSB&#91;i&#93; = _slow_lsb&#40;i&#41;;
for &#40;i = 0; i < 0x10000; i++) hashxor&#91;i&#93; = _rand_64&#40;);
for &#40;i = 0; i < 0x10000; i++) BITC&#91;i&#93; = _bitcount&#40;i&#41;;
and a couple of other "unoptimized loops"
Modern compiler will optimize the code, so I don't think your optimization is useful anyway
rbarreira
Posts: 900
Joined: Tue Apr 27, 2010 3:48 pm

Re: Fastest perft

Post by rbarreira »

lucasart wrote:
ethanara wrote:Hi
As far as i know, i-perft is the fastest perft so far.
After editing oliperft by editing to this:

Code: Select all

for &#40;i = 0; i < 0x10000; i++) &#123;
	    LSB&#91;i&#93; = _slow_lsb&#40;i&#41;;
	    hashxor&#91;i&#93; = _rand_64&#40;);
	    BITC&#91;i&#93; = _bitcount&#40;i&#41;;
	&#125;
from this:

Code: Select all

for &#40;i = 0; i < 0x10000; i++) LSB&#91;i&#93; = _slow_lsb&#40;i&#41;;
for &#40;i = 0; i < 0x10000; i++) hashxor&#91;i&#93; = _rand_64&#40;);
for &#40;i = 0; i < 0x10000; i++) BITC&#91;i&#93; = _bitcount&#40;i&#41;;
and a couple of other "unoptimized loops"
Modern compiler will optimize the code, so I don't think your optimization is useful anyway
Last I've checked, it's better to do it with three separate loops. It was surprising to me, but I guess it has something to do with cache coherence traffic or something...