Hi
Try this
http://wbforum.vpittlik.org/viewtopic.php?t=5997
Grant
Magic bitboards, Java
Moderators: hgm, Rebel, chrisw
-
- Posts: 67
- Joined: Mon Aug 06, 2007 4:42 pm
- Location: London, England
-
- Posts: 2250
- Joined: Wed Mar 08, 2006 8:47 pm
- Location: Hattingen, Germany
Re: Magic bitboards, Java
"Kindergarten" was more intended to the easyness of the carryless multiplication - which is simply copy/topcut of "vertical file-strings" to each distinct "one" per file - which I suppose is even understandable by 3 year old kids with some colored paper stripesGuetti wrote: "Kindergarten" in the sense of easyness to implement. It takes some time to understand, but Pradu's magic, well
If you already have a normal bitboard move generator (not rotated), you probably only have to add and correctly initialize these four arrays for the "Kindergarten" method:
Code: Select all
h . . . . . . . 1 . . . . . . . a b c d e f g h
g . . . . . . . . 1 . . . . . . . a b c d e f g
f . . . . . . . . . 1 . . . . . . . a b c d e f
e . . . . . . . . . . 1 . . . . . . . a b c d e
d . . . . . . . * . . . . 1 . . . = . . . . a b c d
c . . . . . . . . . . . . 1 . . . . . . . a b c
b . . . . . . . . . . . . . 1 . . . . . . . a b
a . . . . . . . . . . . . . . 1 . . . . . . . a
1 . . . . . . . a . . . . . . . a b c d e f g h
1 . . . . . . . . b . . . . . . . b c d e f g h
1 . . . . . . . . . c . . . . . . . c d e f g h
1 . . . . . . . . . . d . . . . . . . d e f g h
1 . . . . . . . * . . . . e . . . = . . . . e f g h
1 . . . . . . . . . . . . f . . . . . . . f g h
1 . . . . . . . . . . . . . g . . . . . . . g h
1 . . . . . . . . . . . . . . h . . . . . . . h
Multiplying masked rank/diagonal by A-(B)file (2*)0x0101..01 - or
multiplying masked file by main-diagonal (0x8040201008040201) seems somehow more intuitional, than trying to multiply by some "random" magic numbers found by brute force until all occupied recombinations leave unique indices. But the way to recognize the simple "nature" of the Kindergarten-multiplication was full of meanders and traps for me. De Bruijn- and random-numbers where my and Tony Werten's first trials even for directionwise attack-getters with quite small tables. Lasse Hanssen had the idea to map the occupancy of both rook/bishop directions to one index-range - while Pradu Kannan improved Lasse's idea with Java-like arrays for a much denser lookup-range over all squares - the real magic bitboards.
To Sargon:
In Java - what about a pure fill based approach using Steffan Westcott's Kogge-Stone routines and no lookups at all?
Safes the boundscheckings and you may process multiple sliders in one run - real fun to implement.
Here some C-code where you can replace u64 by Java long and >> by >>>:
Code: Select all
const u64 notA = 0xfefefefefefefefe;
const u64 notH = 0x7f7f7f7f7f7f7f7f;
u64 eastOne (u64 b) {return (b<<1) & notA;}
u64 noEaOne (u64 b) {return (b<<9) & notA;}
u64 soEaOne (u64 b) {return (b>>7) & notA;}
u64 westOne (u64 b) {return (b>>1) & notH;}
u64 noWeOne (u64 b) {return (b<<7) & notH;}
u64 soWeOne (u64 b) {return (b>>9) & notH;}
u64 nortOne (u64 b) {return b<<8;}
u64 soutOne (u64 b) {return b>>8;}
// Kogge Stones occluded fills
// by Steffan Westcott
u64 eastOccl(u64 gen, u64 pro) {
pro = pro & notA;
gen |= pro & (gen << 1);
pro = pro & (pro << 1);
gen |= pro & (gen << 2);
pro = pro & (pro << 2);
gen |= pro & (gen << 4);
return gen;
}
u64 noEaOccl(u64 gen, u64 pro) {
pro = pro & notA;
gen |= pro & (gen << 9);
pro = pro & (pro << 9);
gen |= pro & (gen << 18);
pro = pro & (pro << 18);
gen |= pro & (gen << 36);
return gen;
}
u64 soEaOccl(u64 gen, u64 pro) {
pro = pro & notA;
gen |= pro & (gen >> 7);
pro = pro & (pro >> 7);
gen |= pro & (gen >> 14);
pro = pro & (pro >> 14);
gen |= pro & (gen >> 28);
return gen;
}
u64 westOccl(u64 gen, u64 pro) {
pro = pro & notH;
gen |= pro & (gen >> 1);
pro = pro & (pro >> 1);
gen |= pro & (gen >> 2);
pro = pro & (pro >> 2);
gen |= pro & (gen >> 4);
return gen;
}
u64 noWeOccl(u64 gen, u64 pro) {
pro = pro & notH;
gen |= pro & (gen << 7);
pro = pro & (pro << 7);
gen |= pro & (gen << 14);
pro = pro & (pro << 14);
gen |= pro & (gen << 28);
return gen;
}
u64 soWeOccl(u64 gen, u64 pro) {
pro = pro & notH;
gen |= pro & (gen >> 9);
pro = pro & (pro >> 9);
gen |= pro & (gen >> 18);
pro = pro & (pro >> 18);
gen |= pro & (gen >> 36);
return gen;
}
u64 nortOccl(u64 gen, u64 pro) {
gen |= pro & (gen << 8);
pro = pro & (pro << 8);
gen |= pro & (gen << 16);
pro = pro & (pro << 16);
gen |= pro & (gen << 32);
return gen;
}
u64 soutOccl(u64 gen, u64 pro) {
gen |= pro & (gen >> 8);
pro = pro & (pro >> 8);
gen |= pro & (gen >> 16);
pro = pro & (pro >> 16);
gen |= pro & (gen >> 32);
return gen;
}
// sliding attacks
u64 eastSld (u64 rooks, u64 empty) {return eastOne(eastOccl(rooks, empty));}
u64 soutSld (u64 rooks, u64 empty) {return soutOne(soutOccl(rooks, empty));}
u64 westSld (u64 rooks, u64 empty) {return westOne(westOccl(rooks, empty));}
u64 nortSld (u64 rooks, u64 empty) {return nortOne(nortOccl(rooks, empty));}
u64 noEaSld (u64 rooks, u64 empty) {return noEaOne(noEaOccl(rooks, empty));}
u64 soEaSld (u64 rooks, u64 empty) {return soEaOne(soEaOccl(rooks, empty));}
u64 soWeSld (u64 rooks, u64 empty) {return soWeOne(soWeOccl(rooks, empty));}
u64 noWeSld (u64 rooks, u64 empty) {return noWeOne(noWeOccl(rooks, empty));}
Gerd
Re: Magic bitboards, Java
Hi Gerd
I've not yet decided about the programming language, but your fill-based approach looks interesting.
At the moment I'm trying to understand magic bitboards though - really a cool idea! Wrote a program which should calculate all possible magic numbers but that's most likely never gonna finish. :) Are the total numbers known? For input keys with 8, 16 and 32 bits I came up with 4, 32 and 4096 solutions. Can anyone confirm those numbers?
Sargon
PS. And your "kindergarten" algorithm will probably make me feel very stupid if I don't understand it within minutes. ;)
I've not yet decided about the programming language, but your fill-based approach looks interesting.
At the moment I'm trying to understand magic bitboards though - really a cool idea! Wrote a program which should calculate all possible magic numbers but that's most likely never gonna finish. :) Are the total numbers known? For input keys with 8, 16 and 32 bits I came up with 4, 32 and 4096 solutions. Can anyone confirm those numbers?
Sargon
PS. And your "kindergarten" algorithm will probably make me feel very stupid if I don't understand it within minutes. ;)
-
- Posts: 287
- Joined: Sat Mar 11, 2006 3:19 am
- Location: Atlanta, GA
Re: Magic bitboards, Java
Are you talking about bitscan magics? It think your number of magic numbers are double of what they should be. Here are my values:Sargon wrote:Hi Gerd
I've not yet decided about the programming language, but your fill-based approach looks interesting.
At the moment I'm trying to understand magic bitboards though - really a cool idea! Wrote a program which should calculate all possible magic numbers but that's most likely never gonna finish. Are the total numbers known? For input keys with 8, 16 and 32 bits I came up with 4, 32 and 4096 solutions. Can anyone confirm those numbers?
Here's 8 (2 solutions)
Here's 16 (16 solutions)
Here's 32 (2048 solutions)
Interesting enough, there is power of 2 number of solutions for every power of two bits.
Sargon
PS. And your "kindergarten" algorithm will probably make me feel very stupid if I don't understand it within minutes.
Re: Magic bitboards, Java
Yes, I meant bitscan magics. Sorry, should have been clearer.
I'm a bit confused though.. my 4 solutions for 8 bit are:
Code: Select all
0x3a (0011'1010)
0x2e (0010'1110)
0x1d (0001'1101)
0x17 (0001'0111)
Sargon
-
- Posts: 2250
- Joined: Wed Mar 08, 2006 8:47 pm
- Location: Hattingen, Germany
Re: Magic bitboards, Java
Cyclic bit rotation does not really distinguish De Bruijn rings. I consider the odd ones original De Bruijn rings. They have log2(N) ( eg. 3 of 8) number of leading binary zeros - and therefor the property to map at least the first two keys to itself.Sargon wrote: Yes, I meant bitscan magics. Sorry, should have been clearer.
I'm a bit confused though.. my 4 solutions for 8 bit are:
Did I miss something?Code: Select all
0x3a (0011'1010) 0x2e (0010'1110) 0x1d (0001'1101) 0x17 (0001'0111)
Sargon
Code: Select all
eg. 0x17 =
00010111(00)
000 ^^ 0->0
001 1->1
010 2->2
101 3->5
011 4->3
111 5->7
110 6->6
100 7->4
^^ ^^
||______|| wrapped hidden zeros
The even "pseudo" De Bruijns just fulfill that condition and may be used in bitscans as well, implying a cyclic transformation of a bitscan mapping.
Code: Select all
2*0x17 = 0x2E
00101110(00)
001 ^^ 0->1
010 1->2
101 2->5
011 3->3
111 4->7
110 5->6
100 6->4
000 7->0
^^ ^^
||______|| wrapped hidden zeros
-
- Posts: 287
- Joined: Sat Mar 11, 2006 3:19 am
- Location: Atlanta, GA
Re: Magic bitboards, Java
Indeed I was mistaken. I have a bug in my code. Lousy me! Arrg, I have the same bug in my optimal magic generator too.... I have to do all the proofs over again... Anyways thanks for the verificationSargon wrote:Yes, I meant bitscan magics. Sorry, should have been clearer.
I'm a bit confused though.. my 4 solutions for 8 bit are:
Did I miss something?Code: Select all
0x3a (0011'1010) 0x2e (0010'1110) 0x1d (0001'1101) 0x17 (0001'0111)
Sargon
-
- Posts: 287
- Joined: Sat Mar 11, 2006 3:19 am
- Location: Atlanta, GA
Re: Magic bitboards, Java
Here are the corrections:
8 bits
16 bits
32 bits
There are way too many 64-bit magics to print out; however, there should be 2^27 magics for 64-bits:
8 bits
16 bits
32 bits
There are way too many 64-bit magics to print out; however, there should be 2^27 magics for 64-bits:
Code: Select all
#include <stdio.h>
//START - BUILD CONFIGURATION
//#define SHOW_TRACE /*define this to show trace output for this program*/
//Number of bits to hash to (make this the minimal bits)
#define BITS 6
//The type of the number we are trying to bitscan
typedef unsigned int TYPE;
//END - BUILD CONFIGURATION
TYPE indecies[1<<BITS];
unsigned int count = 0;
#define FAIL 1
#define SUCCESS 0
//START - FUNCTION PROTOTYPES
int main();
int try0(TYPE depth);
int try1(TYPE depth);
int unique(TYPE index, TYPE depth);
int main()
{
TYPE magic;
TYPE i;
//generate indecies
try0(0);
try1(0);
printf("%d magics\n", count);
system("Pause");
return SUCCESS;
}
int compile()
{
count++;
/*#ifdef SHOW_TRACE
printf("\nIndecies\n");
for(i=(1<<BITS)-1;i;i--)
printf("%X ",(unsigned long)indecies[i]);
printf("%X",(unsigned long)(*indecies));
printf("\n");
#endif
magic=0;
//compile indecies
for(i=(1<<BITS)-1;i;i--)
{
magic|=indecies[i]>>(BITS-1);
magic<<=1;
}
magic|=(*indecies)>>(BITS-1);
printf("Magic %u: ",count);
for(i=2*sizeof(TYPE);i;i--)
printf("%X",(magic>>(4*(i-1)))&0xF);
printf("\n");*/
}
int try0(TYPE depth)
{
#ifdef SHOW_TRACE
printf("%d) Trying 0\n",depth);
#endif
if(!depth) *indecies=0;
else indecies[depth]=indecies[depth-1]>>1;
if(unique(indecies[depth],depth)) return FAIL;
if(depth==((1<<BITS)-1)) {compile(); return FAIL;}
if(try0(depth+1)) return try1(depth+1);
return SUCCESS;
}
int try1(TYPE depth)
{
#ifdef SHOW_TRACE
printf("%d) Trying 1\n", depth);
#endif
if(!depth) *indecies=((TYPE)1)<<(BITS-1);
else indecies[depth]=(indecies[depth-1]>>1) | (1<<(BITS-1));
if(unique(indecies[depth],depth)) return FAIL;
if(depth==((1<<BITS)-1)) {compile(); return FAIL;}
if(try0(depth+1)) return try1(depth+1);
return SUCCESS;
}
int unique(TYPE index, TYPE depth)
{
TYPE i;
for(i=0;i!=depth;i++)
if(indecies[i]==index)
{
#ifdef SHOW_TRACE
printf("Fail\n");
#endif
return FAIL;
}
return SUCCESS;
}
-
- Posts: 287
- Joined: Sat Mar 11, 2006 3:19 am
- Location: Atlanta, GA
Re: Magic bitboards, Java
Code corrections again...
I wish this forum had a much longer time limit for editing posts so that we wouldn't have to double post like this to correct mistakes.
I wish this forum had a much longer time limit for editing posts so that we wouldn't have to double post like this to correct mistakes.
Code: Select all
#include <stdio.h>
//START - BUILD CONFIGURATION
//#define SHOW_TRACE /*define this to show trace output for this program*/
//Number of bits to hash to (make this the minimal bits)
#define BITS 6
//The type of the number we are trying to bitscan
typedef unsigned long long TYPE;
//END - BUILD CONFIGURATION
TYPE indecies[1<<BITS];
unsigned int count = 0;
#define FAIL 1
#define SUCCESS 0
//START - FUNCTION PROTOTYPES
int main();
int try0(TYPE depth);
int try1(TYPE depth);
int unique(TYPE index, TYPE depth);
int main()
{
TYPE magic;
TYPE i;
//generate indecies
try0(0);
try1(0);
printf("%d magics\n", count);
system("Pause");
return SUCCESS;
}
int compile()
{
count++;
/*#ifdef SHOW_TRACE
printf("\nIndecies\n");
for(i=(1<<BITS)-1;i;i--)
printf("%X ",(unsigned long)indecies[i]);
printf("%X",(unsigned long)(*indecies));
printf("\n");
#endif
magic=0;
//compile indecies
for(i=(1<<BITS)-1;i;i--)
{
magic|=indecies[i]>>(BITS-1);
magic<<=1;
}
magic|=(*indecies)>>(BITS-1);
printf("Magic %u: ",count);
for(i=2*sizeof(TYPE);i;i--)
printf("%X",(magic>>(4*(i-1)))&0xF);
printf("\n");*/
}
int try0(TYPE depth)
{
#ifdef SHOW_TRACE
printf("%d) Trying 0\n",depth);
#endif
if(!depth) *indecies=0;
else indecies[depth]=indecies[depth-1]>>1;
if(unique(indecies[depth],depth)) return FAIL;
if(depth==((1<<BITS)-1)) {compile(); return FAIL;}
if(try0(depth+1)) return try1(depth+1);
return SUCCESS;
}
int try1(TYPE depth)
{
#ifdef SHOW_TRACE
printf("%d) Trying 1\n", depth);
#endif
if(!depth) *indecies=((TYPE)1)<<(BITS-1);
else indecies[depth]=(indecies[depth-1]>>1) | (1<<(BITS-1));
if(unique(indecies[depth],depth)) return FAIL;
if(depth==((1<<BITS)-1)) {compile(); return FAIL;}
if(try0(depth+1)) return try1(depth+1);
return SUCCESS;
}
int unique(TYPE index, TYPE depth)
{
TYPE i;
for(i=0;i!=depth;i++)
if(indecies[i]==index)
{
#ifdef SHOW_TRACE
printf("Fail\n");
#endif
return FAIL;
}
return SUCCESS;
}
-
- Posts: 892
- Joined: Sun Nov 19, 2006 9:16 pm
- Location: Russia
Re: Magic bitboards, Java
Please, show here the smallest one.There are way too many 64-bit magics to print out; however, there should be 2^27 magics for 64-bits