Magic Knight- and King-Move Generation
Posted: 11 Jan 2007, 12:36
The idea is to mul/shift/lookup a move(capture)-target bitboards, to do a almost branchless move-generation with precalculated moves inside movelists:
A king in a corner may have up to three moves.
Thus there are 2**3 == 8 possible movelists, eg. for a king on a1 (number of moves: vector of moves):
Kings on edges have 5 potential target squares, thus there are 32 possible movelists. All other kings have 8 all the 8 neightboars with up to 256 movelists. Similar movelist enumeration is possible with knights and ...
I was rather surprised that all possible move-target subsets of kings and knights for all 64 from-squares are perfectly hashable with a magic factor of only four one-bits set - 10016 possible king-movelists and 5520 knight-movelists:
The small test framework if you may try to search magics by yourself:
Cheers,
Gerd
- Code: Select all
moveTarget = KingAttacks[sq] & ~(ownPieces | attackedSquares);
idx = (moveTarget * kingMagic[sq]) >> kingShift[sq]);
movelists = kingMoveLists[sq];
movelist = movelists[idx];
moveCpy(target, movelist, movelist->n);
A king in a corner may have up to three moves.
Thus there are 2**3 == 8 possible movelists, eg. for a king on a1 (number of moves: vector of moves):
- Code: Select all
0:{empty}
1:{a1-b1}
1:{a1-a2}
1:{a1-b2}
2:{a1-b1,a1-a2}
2:{a1-b1,a1-b2}
2:{a1-a2,a1-b2}
3:{a1-b1,a1-a2,a1-b2}
Kings on edges have 5 potential target squares, thus there are 32 possible movelists. All other kings have 8 all the 8 neightboars with up to 256 movelists. Similar movelist enumeration is possible with knights and ...
I was rather surprised that all possible move-target subsets of kings and knights for all 64 from-squares are perfectly hashable with a magic factor of only four one-bits set - 10016 possible king-movelists and 5520 knight-movelists:
- Code: Select all
find Magics with 4 one bits for King-Moves, bits 3
magic/shift[ 0] 8 movelists: 0x1040000000000003 61
magic/shift[ 7] 8 movelists: 0x0081000000000003 61
magic/shift[56] 8 movelists: 0x0000000000002043 61
magic/shift[63] 8 movelists: 0x000000000000008e 61
4 magics found so far with 32 entries
find Magics with 4 one bits for King-Moves, bits 5
magic/shift[ 1] 32 movelists: 0x0c20000000000001 59
magic/shift[ 2] 32 movelists: 0x0610000000000001 59
magic/shift[ 3] 32 movelists: 0x0308000000000001 59
magic/shift[ 4] 32 movelists: 0x0184000000000001 59
magic/shift[ 5] 32 movelists: 0x00c2000000000001 59
magic/shift[ 6] 32 movelists: 0x0061000000000001 59
magic/shift[ 8] 32 movelists: 0x0810400000000001 59
magic/shift[15] 32 movelists: 0x0020810000000001 59
magic/shift[16] 32 movelists: 0x0008104000000001 59
magic/shift[23] 32 movelists: 0x0000208100000001 59
magic/shift[24] 32 movelists: 0x0000081040000001 59
magic/shift[31] 32 movelists: 0x0000002081000001 59
magic/shift[32] 32 movelists: 0x0000000810400001 59
magic/shift[39] 32 movelists: 0x0000000020810001 59
magic/shift[40] 32 movelists: 0x0000000008104001 59
magic/shift[47] 32 movelists: 0x0000000000208101 59
magic/shift[48] 32 movelists: 0x0000000000081041 59
magic/shift[55] 32 movelists: 0x0000000000002083 59
magic/shift[57] 32 movelists: 0x0000000000002013 59
magic/shift[58] 32 movelists: 0x000000000000100b 59
magic/shift[59] 32 movelists: 0x0000000000000807 59
magic/shift[60] 32 movelists: 0x000000000000088c 59
magic/shift[61] 32 movelists: 0x0000000000000446 59
magic/shift[62] 32 movelists: 0x0000000000000223 59
28 magics found so far with 800 entries
find Magics with 4 one bits for King-Moves, bits 8
magic/shift[ 9] 256 movelists: 0x0402600000000000 56
magic/shift[10] 256 movelists: 0x0201300000000000 56
magic/shift[11] 256 movelists: 0x0100980000000000 56
magic/shift[12] 256 movelists: 0x00804c0000000000 56
magic/shift[13] 256 movelists: 0x0040260000000000 56
magic/shift[14] 256 movelists: 0x0020130000000000 56
magic/shift[17] 256 movelists: 0x0004026000000000 56
magic/shift[18] 256 movelists: 0x0002013000000000 56
magic/shift[19] 256 movelists: 0x0001009800000000 56
magic/shift[20] 256 movelists: 0x0000804c00000000 56
magic/shift[21] 256 movelists: 0x0000402600000000 56
magic/shift[22] 256 movelists: 0x0000201300000000 56
magic/shift[25] 256 movelists: 0x0000040260000000 56
magic/shift[26] 256 movelists: 0x0000020130000000 56
magic/shift[27] 256 movelists: 0x0000010098000000 56
magic/shift[28] 256 movelists: 0x000000804c000000 56
magic/shift[29] 256 movelists: 0x0000004026000000 56
magic/shift[30] 256 movelists: 0x0000002013000000 56
magic/shift[33] 256 movelists: 0x0000000402600000 56
magic/shift[34] 256 movelists: 0x0000000201300000 56
magic/shift[35] 256 movelists: 0x0000000100980000 56
magic/shift[36] 256 movelists: 0x00000000804c0000 56
magic/shift[37] 256 movelists: 0x0000000040260000 56
magic/shift[38] 256 movelists: 0x0000000020130000 56
magic/shift[41] 256 movelists: 0x0000000004026000 56
magic/shift[42] 256 movelists: 0x0000000002013000 56
magic/shift[43] 256 movelists: 0x0000000001009800 56
magic/shift[44] 256 movelists: 0x0000000000804c00 56
magic/shift[45] 256 movelists: 0x0000000000402600 56
magic/shift[46] 256 movelists: 0x0000000000201300 56
magic/shift[49] 256 movelists: 0x0000000000040260 56
magic/shift[50] 256 movelists: 0x0000000000020130 56
magic/shift[51] 256 movelists: 0x0000000000010098 56
magic/shift[52] 256 movelists: 0x000000000000804c 56
magic/shift[53] 256 movelists: 0x0000000000004026 56
magic/shift[54] 256 movelists: 0x0000000000002013 56
64 magics found so far with 10016 entries
find Magics with 4 one bits for Knight-Moves, bits 2
magic/shift[ 0] 4 movelists: 0x0010400000000003 62
magic/shift[ 7] 4 movelists: 0x0002020000000003 62
magic/shift[56] 4 movelists: 0x0000000000202003 62
magic/shift[63] 4 movelists: 0x0000000000010403 62
4 magics found so far with 16 entries
find Magics with 4 one bits for Knight-Moves, bits 3
magic/shift[ 1] 8 movelists: 0x0004900000000001 61
magic/shift[ 6] 8 movelists: 0x0002048000000001 61
magic/shift[ 8] 8 movelists: 0x0800104000000001 61
magic/shift[15] 8 movelists: 0x0100020200000001 61
magic/shift[48] 8 movelists: 0x0000000010100021 61
magic/shift[55] 8 movelists: 0x000000000082000c 61
magic/shift[57] 8 movelists: 0x0000000000200803 61
magic/shift[62] 8 movelists: 0x0000000000010403 61
12 magics found so far with 80 entries
find Magics with 4 one bits for Knight-Moves, bits 4
magic/shift[ 2] 16 movelists: 0x0014100000000001 60
magic/shift[ 3] 16 movelists: 0x000a080000000001 60
magic/shift[ 4] 16 movelists: 0x0005040000000001 60
magic/shift[ 5] 16 movelists: 0x0002820000000001 60
magic/shift[ 9] 16 movelists: 0x0200082000000001 60
magic/shift[14] 16 movelists: 0x0100040100000001 60
magic/shift[16] 16 movelists: 0x0808001040000000 60
magic/shift[23] 16 movelists: 0x0041000202000000 60
magic/shift[24] 16 movelists: 0x0008080010400000 60
magic/shift[31] 16 movelists: 0x0000410002020000 60
magic/shift[32] 16 movelists: 0x0000080800104000 60
magic/shift[39] 16 movelists: 0x0000004100020200 60
magic/shift[40] 16 movelists: 0x0000000808001040 60
magic/shift[47] 16 movelists: 0x0000000041000202 60
magic/shift[49] 16 movelists: 0x0000000010040011 60
magic/shift[54] 16 movelists: 0x0000000000820018 60
magic/shift[58] 16 movelists: 0x0000000000082801 60
magic/shift[59] 16 movelists: 0x0000000000041401 60
magic/shift[60] 16 movelists: 0x0000000000020a01 60
magic/shift[61] 16 movelists: 0x0000000000010501 60
32 magics found so far with 400 entries
find Magics with 4 one bits for Knight-Moves, bits 6
magic/shift[10] 64 movelists: 0x0400091000000000 58
magic/shift[11] 64 movelists: 0x0200048800000000 58
magic/shift[12] 64 movelists: 0x0100024400000000 58
magic/shift[13] 64 movelists: 0x0080012200000000 58
magic/shift[17] 64 movelists: 0x0401000820000000 58
magic/shift[22] 64 movelists: 0x0020800401000000 58
magic/shift[25] 64 movelists: 0x0004010008200000 58
magic/shift[30] 64 movelists: 0x0000208004010000 58
magic/shift[33] 64 movelists: 0x0000040100082000 58
magic/shift[38] 64 movelists: 0x0000002080040100 58
magic/shift[41] 64 movelists: 0x0000000401000820 58
magic/shift[46] 64 movelists: 0x0000000020800401 58
magic/shift[50] 64 movelists: 0x0000000002080042 58
magic/shift[51] 64 movelists: 0x0000000001040021 58
magic/shift[52] 64 movelists: 0x0000000002018002 58
magic/shift[53] 64 movelists: 0x000000000100c001 58
48 magics found so far with 1424 entries
find Magics with 4 one bits for Knight-Moves, bits 8
magic/shift[18] 256 movelists: 0x0082000808000000 56
magic/shift[19] 256 movelists: 0x0041000404000000 56
magic/shift[20] 256 movelists: 0x0020800202000000 56
magic/shift[21] 256 movelists: 0x0010400101000000 56
magic/shift[26] 256 movelists: 0x0000820008080000 56
magic/shift[27] 256 movelists: 0x0000410004040000 56
magic/shift[28] 256 movelists: 0x0000208002020000 56
magic/shift[29] 256 movelists: 0x0000104001010000 56
magic/shift[34] 256 movelists: 0x0000008200080800 56
magic/shift[35] 256 movelists: 0x0000004100040400 56
magic/shift[36] 256 movelists: 0x0000002080020200 56
magic/shift[37] 256 movelists: 0x0000001040010100 56
magic/shift[42] 256 movelists: 0x0000000082000808 56
magic/shift[43] 256 movelists: 0x0000000041000404 56
magic/shift[44] 256 movelists: 0x0000000020800202 56
magic/shift[45] 256 movelists: 0x0000000010400101 56
64 magics found so far with 5520 entries
The small test framework if you may try to search magics by yourself:
- Code: Select all
#include <stdio.h>
typedef __int64 i64;
typedef unsigned __int64 u64;
typedef unsigned int u32;
#define MAXBITS 16
#define LOCKSIZE (1<<(MAXBITS-5))
u32 gLockArray[LOCKSIZE];
__forceinline
void clearLock()
{
for (int i = 0; i < LOCKSIZE; i++)
gLockArray[i] = 0;
}
__forceinline
bool testAndSet(u32 idx)
{
u32 bit = 1 << (idx & 31);
idx >>= 5; // 32 bits per u32
bool res = (gLockArray[idx] & bit) != 0;
gLockArray[idx] |= bit;
return res;
}
int tryMagic4knightMoves(u64 magic, u32 shift, u32 square)
{
u64 a0, a1, b, a = 1;
u32 idx, count = 0;
clearLock();
a <<= square;
a0 = (a << 1) & 0xFEFEFEFEFEFEFEFE;
a1 = (a >> 1) & 0x7F7F7F7F7F7F7F7F;
a = (a0|a1) >> 16;
a |= (a0|a1) << 16;
a0 = (a0 << 1) & 0xFEFEFEFEFEFEFEFE;
a1 = (a1 >> 1) & 0x7F7F7F7F7F7F7F7F;
a |= (a0|a1) >> 8;
a |= (a0|a1) << 8;
b = 0; // first subset
do { // traverse all subsets
idx = (u32)((b*magic)>>shift);
if ( testAndSet(idx))
return 0; // collision
count++;
b = (b - a) & a;
} while (b);
return count;
}
int tryMagic4kingMoves(u64 magic, u32 shift, u32 square)
{
u64 a0, a1, b, a = 1;
u32 idx, count = 0;
clearLock();
a <<= square;
a0 = (a << 1) & 0xFEFEFEFEFEFEFEFE;
a1 = (a >> 1) & 0x7F7F7F7F7F7F7F7F;
a0|= a1;
a0|= (a0 >> 8) | (a0 << 8);
a = (a >> 8) | (a << 8) | a0;
b = 0; // first subset
do { // traverse all subsets
idx = (u32)((b*magic)>>shift);
if ( testAndSet(idx))
return 0; // collision
count++;
b = (b - a) & a;
} while (b);
return count;
}
// search next higher word with same number of one bits
u64 snoob (u64 x) {
static const unsigned int deBruijnLookup[64] =
{
0, 1, 48, 2, 57, 49, 28, 3,
61, 58, 50, 42, 38, 29, 17, 4,
62, 55, 59, 36, 53, 51, 43, 22,
45, 39, 33, 30, 24, 18, 12, 5,
63, 47, 56, 27, 60, 41, 37, 16,
54, 35, 52, 21, 44, 32, 23, 11,
46, 26, 40, 15, 34, 20, 31, 10,
25, 14, 19, 9, 13, 8, 7, 6,
};
static const u64 deBruijn = 0x03f79d71b4cb0a89;
u64 smallest, ripple, ones;
smallest = x & -(i64)x;
ripple = x + smallest;
ones = x ^ ripple;
ones = (ones >> 2) >> deBruijnLookup[(smallest*deBruijn) >> 58];
return ripple | ones;
}
int findMagic(u32 sq, int nOneBits4Magic, int bits, int (*pTryFunc)(u64, u32, u32))
{
u64 x, y, first = 1;
u32 count;
first = (first << nOneBits4Magic)-1;
for (x = first; (y = snoob(x)) > x; x = y) {
count = pTryFunc(y, 64-bits, sq);
if ( count > 0 ) {
printf("magic/shift[%2d] %3d movelists: 0x%08x%08x %2d\n",
sq, count, (u32)(y>>32), (u32)y, 64-bits);
return 1; // found
}
}
return 0;
}
void findMagics(int n1Bits4Magic, int width, int (*pTryFunc)(u64, u32, u32), const char* str)
{
u64 sqbb, set = 0;
u32 sq, bits;
int count = 0, total = 0;
for (bits = width; bits <= MAXBITS; bits++) {
printf("find Magics with %d one bits for %s, bits %d\n", n1Bits4Magic, str, bits);
for (sq=0, sqbb=1; sq < 64; sq++, sqbb+=sqbb) {
if ( (set & sqbb) == 0 && findMagic(sq, n1Bits4Magic, bits, pTryFunc) ) {
set |= sqbb;
count++;
total += (1<<bits);
}
printf("%d magics found so far with %d entries\n", count, total);
if ( count == 64 )
return;
}
}
}
int main(int argc, char* argv[])
{
findMagics(4, 2, tryMagic4knightMoves, "Knight-Moves");
findMagics(4, 3, tryMagic4kingMoves, "King-Moves");
return 0;
}
Cheers,
Gerd