dangi12012 wrote: ↑Mon Jun 27, 2022 10:45 am
petero2 wrote: ↑Fri Jun 24, 2022 12:44 am
Code: Select all
n(a,0) = 1
n(47,b) = 1
n(a,b) = n(a+1,b) + n(a+1,b-1)
...
Given these equations the int n[48][9] array can be computed.
The toIdx function clearly transforms the 8 bit binary representation into another base number but what is that number system called? (for googling this stuff)
I just made this up to solve this particular problem, so I don't know if it has a name. It would not surprise me though if someone else has already derived the same formula and given it a name.
First consider a slightly different function n0(a,b) = number of ways to place between 0 and "b" pawns on "a" squares. Like before, we have:
Code: Select all
n0(a,0) = 1 (one way to place 0 pawns)
n0(0,b) = 1 (one way to place pawns on 0 squares)
n0(a,b) = n0(a-1,b) + n0(a-1,b-1) (either you leave the first square empty or you put a pawn on it)
This function has the following values for a<=4, b<=2:
Code: Select all
b\a | 0 1 2 3 4
----+------------------
0 | 1 1 1 1 1
1 | 1 2 3 4 5
2 | 1 2 4 7 11
Now suppose you want to compute an index for the bit patterns when placing between 0 and 2 pawns on 4 squares. From the table we can see that there are 11 ways to do that. We can systematically list those patterns by counting in binary but skipping all patterns having more than two "1" bits, like this:
Code: Select all
s0 s1 s2 s3
0 : 0 0 0 0
1 : 0 0 0 1
2 : 0 0 1 0
3 : 0 0 1 1
4 : 0 1 0 0
5 : 0 1 0 1
6 : 0 1 1 0
7 : 1 0 0 0
8 : 1 0 0 1
9 : 1 0 1 0
10 : 1 1 0 0
Lets first consider bit pattern 1000. We can see that all patterns before this pattern have s0=0, so the number of such patterns are the number of ways to place 0-2 pawns on 3 squares (s1, s2, s3), which by definition is n0(3, 2) = 7, so the index of pattern 1000 is 7. Similarly consider pattern 0100, which has index n0(2, 2). In general the pattern with a one bit on only square s_i has index n0(3-i, 2).
Next, consider the pattern 1100. We know that this pattern comes after pattern 1000 (which has index n0(3,2)), and we can see that all patterns from 1000 to the pattern before 1100 are characterized by having s0=1, s1=0. The number of such patterns are n0(2,1), because there are two remaining squares (s2,s3) and one remaining 1 bit. Therefore the index of pattern 1100 is n0(3,2) + n0(2,1).
The same reasoning can be used for a=48, b=8 to derive the formula:
Code: Select all
int idx = 0;
for (int i = 8; m != 0; i--)
idx += n0[47-std::countr_zero(m)][i];
return idx;
To get rid of the "47-" in that formula I defined n(a,b)=n0(47-a,b), which leads to the formula in my program.
dangi12012 wrote: ↑Mon Jun 27, 2022 10:45 am
The code you posted can store one pawn bitboard in log2(465174935) = 29bits. And pack/unpack with the cost of toIdx.
My current code uses a big lookup table for the "unpack" case, which I think is the fastest way to do that, but the size of that table is around 4GB, which might be a problem, depending on the application.