Yet another bitboard attack generator
Posted: Wed Oct 28, 2009 6:50 am
Gaviota uses the following functions to find the squares attacked by a given slider in a given board with blocking pieces (occ). I dropped my own implementation of rotated bitboards because the code was akward and carrying extra bitboards all over the place was a nuisance. This implementation is not faster or better, but at least it is not slower in my engine. It is certainly more compact, readable and clearer. It only needs a little supporting table. Most importantly (at least for me), It allows me to do something different than everybody else. It is more fun.
I checked CPW to see whether there is anything similar. Apparently, this would be a modification of the Dumb7fill method. The difference is that I do attacks in all directions in parallel, including the queen (with a little trick).
The method assume that we have a table
uint64_t reach [MAXPIECES] [MAXSQUARES];
where each bitboard there represents the attacks of a given slider from a given square in an empty board. I generate the table at start up with a 0x88 procedure , but it is small enough to hardwire it into the program.
You can replace this with
uint64_t reach_bishop [64];
uint64_t reach_queen [64];
uint64_t reach_rook [64];
That is about ~1.5 k
The code below is optimized for (my) readability, so I am sure that it could be improved. At least in my engine, unrolling the loops slow things down.
Miguel
PS: I hope that the code is self-explanatory.
I checked CPW to see whether there is anything similar. Apparently, this would be a modification of the Dumb7fill method. The difference is that I do attacks in all directions in parallel, including the queen (with a little trick).
The method assume that we have a table
uint64_t reach [MAXPIECES] [MAXSQUARES];
where each bitboard there represents the attacks of a given slider from a given square in an empty board. I generate the table at start up with a 0x88 procedure , but it is small enough to hardwire it into the program.
You can replace this with
uint64_t reach_bishop [64];
uint64_t reach_queen [64];
uint64_t reach_rook [64];
That is about ~1.5 k
The code below is optimized for (my) readability, so I am sure that it could be improved. At least in my engine, unrolling the loops slow things down.
Miguel
PS: I hope that the code is self-explanatory.
Code: Select all
/* not_A is a bitboard with all bits turned on except on column A */
/* not_H is a bitboard with all bits turned on except on column H */
/* grow in all directions */
static uint64_t
grow (uint64_t x)
{
x |= (x << 1) & not_A;
x |= (x >> 1) & not_H;
x |= x >> 8;
x |= x << 8;
return x;
}
/* grow laterally like a rook */
static uint64_t
growlat (uint64_t x)
{
uint64_t y = x;
x |= (x << 1) & not_A;
x |= (x >> 1) & not_H;
y |= y >> 8;
y |= y << 8;
return x | y;
}
extern uint64_t
B_attacks (SQUARE from, uint64_t occ)
{
uint64_t g, corral, prev, r, ini;
r = reach[BISHOP][from];
corral = r & ~occ;
ini = U64(1) << from;
g = ini;
do {
prev = g;
g = grow (prev) & corral;
} while (prev != g);
g |= ini;
return (grow(g) & r) & ~ini;
}
extern uint64_t
R_attacks (SQUARE from, uint64_t occ)
{
uint64_t g, corral, prev, r, ini;
r = reach[ROOK][from];
corral = r & ~occ;
ini = U64(1) << from;
g = ini;
do {
prev = g;
g = grow (prev) & corral;
} while (prev != g);
g |= ini;
return (grow(g) & r) & ~ini;
}
extern uint64_t
Q_attacks (SQUARE from, uint64_t occ)
{
uint64_t g, corral, prev, r, ini, h;
r = reach[QUEEN][from];
ini = U64(1) << from;
g = grow (ini) & ~ini;
h = growlat (g & occ);
h &= ~g;
corral = r & ~occ;
corral &= ~h;
g &= ~occ;
do {
prev = g;
g = grow (prev) & corral;
} while (prev != g);
g |= ini;
return (grow(g) & r) & ~ini & ~h ;
}