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
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: Fastest perft

Post by lucasart »

I don't understand all these posts on perft. The only point of having a perft function is to validate that a chess engine move generator is bugfree. But perft is not a goal in itself. It is totally useless, so I just can't understand all this fascination about fast perft computation...
Michel
Posts: 2272
Joined: Mon Sep 29, 2008 1:50 am

Re: Fastest perft

Post by Michel »

I don't understand all these posts on perft. The only point of having a perft function is to validate that a chess engine move generator is bugfree. But perft is not a goal in itself. It is totally useless, so I just can't understand all this fascination about fast perft computation...
To each his own. A strong chess program is just as useless as a fast perft.
User avatar
marcelk
Posts: 348
Joined: Sat Feb 27, 2010 12:21 am

Re: Fastest perft

Post by marcelk »

Michel wrote:
I don't understand all these posts on perft. The only point of having a perft function is to validate that a chess engine move generator is bugfree. But perft is not a goal in itself. It is totally useless, so I just can't understand all this fascination about fast perft computation...
To each his own. A strong chess program is just as useless as a fast perft.
I was just thinking of commercializing Cluster Perft in some kind of rental scheme.
Daniel Shawul
Posts: 4185
Joined: Tue Mar 14, 2006 11:34 am
Location: Ethiopia

Re: Fastest perft

Post by Daniel Shawul »

marcelk wrote:
Michel wrote:
I don't understand all these posts on perft. The only point of having a perft function is to validate that a chess engine move generator is bugfree. But perft is not a goal in itself. It is totally useless, so I just can't understand all this fascination about fast perft computation...
To each his own. A strong chess program is just as useless as a fast perft.
I was just thinking of commercializing Cluster Perft in some kind of rental scheme.
Fail. It is as useless regarding its _scientific merit_. And yes I have a cluster perft and a cluster search both useless to me interms of monetary values. OP also misunderstood the current perft discussion when he classifies perft as a mere debugging tool! Well to each his own. I for one hate regurgitating chewed up stuff again and again to get a discussion going. The perft discussions were a breath of fresh air. Why bother commenting about it if yout think it is useless anyway?
F. Bluemers
Posts: 868
Joined: Thu Mar 09, 2006 11:21 pm
Location: Nederland

Re: Fastest perft

Post by F. Bluemers »

Daniel Shawul wrote:
marcelk wrote:
Michel wrote:
I don't understand all these posts on perft. The only point of having a perft function is to validate that a chess engine move generator is bugfree. But perft is not a goal in itself. It is totally useless, so I just can't understand all this fascination about fast perft computation...
To each his own. A strong chess program is just as useless as a fast perft.
I was just thinking of commercializing Cluster Perft in some kind of rental scheme.
Fail. It is as useless regarding its _scientific merit_. And yes I have a cluster perft and a cluster search both useless to me interms of monetary values. OP also misunderstood the current perft discussion when he classifies perft as a mere debugging tool! Well to each his own. I for one hate regurgitating chewed up stuff again and again to get a discussion going. The perft discussions were a breath of fresh air. Why bother commenting about it if yout think it is useless anyway?
uPerft sounds like a seller to me :lol:
User avatar
stegemma
Posts: 859
Joined: Mon Aug 10, 2009 10:05 pm
Location: Italy
Full name: Stefano Gemma

Re: Fastest perft

Post by stegemma »

The discussion about useless of perft raise up periodically. I still think that everything that was so difficult or just so interesting to somebody to make hes/her brain getting hot is a good thing, despite for its usefullness or... uselessness.
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: Fastest perft

Post by Rein Halbersma »

F. Bluemers wrote:
Daniel Shawul wrote:
marcelk wrote:
Michel wrote:
I don't understand all these posts on perft. The only point of having a perft function is to validate that a chess engine move generator is bugfree. But perft is not a goal in itself. It is totally useless, so I just can't understand all this fascination about fast perft computation...
To each his own. A strong chess program is just as useless as a fast perft.
I was just thinking of commercializing Cluster Perft in some kind of rental scheme.
Fail. It is as useless regarding its _scientific merit_. And yes I have a cluster perft and a cluster search both useless to me interms of monetary values. OP also misunderstood the current perft discussion when he classifies perft as a mere debugging tool! Well to each his own. I for one hate regurgitating chewed up stuff again and again to get a discussion going. The perft discussions were a breath of fresh air. Why bother commenting about it if yout think it is useless anyway?
uPerft sounds like a seller to me :lol:
Viperfish also seems a nice name. And check out a potential logo :-)
http://en.wikipedia.org/wiki/Viperfish
User avatar
Ajedrecista
Posts: 1968
Joined: Wed Jul 13, 2011 9:04 pm
Location: Madrid, Spain.

Re: Fastest perft

Post by Ajedrecista »

Hello:

There is a perft counter much faster (for the initial position) than qperft, i-perft and oliperft. Here is JetChess 1.0.0.0 by Thomas Zipproth (it has some years, but it is quite good):

http://www.zipproth.de/jetchess/

I tried to run qperft, i-perft and oliperft and they always closed when I opened them. I do not know if my firewall or antivirus closed them, but I was unable to run them. I thought that I could not run a perft counter when I found JetChess. It is pity that it has not got multi-core support. I have an old CPU (5 years) and here are the results I got:

Code: Select all

Benchmark = 13.818 sec &#40;when Hash = 256 MB&#41;.

n		Perft&#40;n&#41;	     Hash size &#40;MB&#41;		t &#40;hr&#58;min&#58;sec.ms&#41;

1		20		        64		     	    0&#58;00&#58;00.000
2		400		       64			         0&#58;00&#58;00.000
3		8902		      64			         0&#58;00&#58;00.000
4		197281		    64			         0&#58;00&#58;00.003
5		4865609		   64			         0&#58;00&#58;00.048
6		119060324       64			         0&#58;00&#58;00.695
7		3195901860	   128			        0&#58;00&#58;08.449
8		84998978956	  1024			       0&#58;01&#58;59.147
9		2439530234167	1024			       0&#58;45&#58;20.810
I run several times Benchmark and Perft(4) to Perft(7) changing hash size, and I picked the shortest time of each case. I also run Perft(8) four or five times, and Perft(9) only once. As everybody can see, Perft(7) could be counted in less than eight seconds (I am over eight seconds because my CPU is slow), so no need of forty seconds. Please try it.

Regards from Spain.

Ajedrecista.
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Fastest perft

Post by hgm »

Did you run qperft with the proper arguments? If you run it without arguments, it just prints how you should use it, and exits immediately. It is not an interactive application, its houldbe run from a terminal / command prompt.