For computing masks for square f we use something like:
Code: Select all
#define FILE_A 0x0101010101010101
#define FILE_B 0x0202020202020202
#define D_C2H7 0x0080402010080400
#define MaskV(f) int(((Occupied>>(f&7))&FILE_A) * D_C2H7 >> 58) // mask for vertical moves
#define MaskH(f) int((Occupied&Mask_H[f]) * FILE_B >> 58) // mask for horizontal moves
#define MaskD(f) int((Occupied&Mask_D[f]) * FILE_B >> 58) // mask for diagonal moves
#define MaskA(f) int((Occupied&Mask_A[f]) * FILE_B >> 58) // mask for antidiagonal moves
Code: Select all
#define AttacksV(f) MovesF[f>>3][MaskV(f)]<<(f&7)
#define AttacksH(f) MovesR[f&7 ][MaskH(f)]&Mask_H[f]
#define AttacksD(f) MovesR[f&7 ][MaskD(f)]&Mask_D[f]
#define AttacksA(f) MovesR[f&7 ][MaskA(f)]&Mask_A[f]
#define RookAttacks(f) (AttacksV(f)|AttacksH(f))
#define BishopAttacks(f) (AttacksD(f)|AttacksA(f))
#define QueenAttacks(f) (RookAttacks(f)|BishopAttacks(f))
In 32-bit environment computing masks by 64-bit multiplying is rather slow, but we can replace multiplying with some 32-bit shift and bit or operations.
First, we can define functions PackV and PackH, which pack 64-bit bitboard into 8-bit bitboard, where Nth bit is set if Nth file (or rank) of original bitboard has any square set. From this 8-bit mask we get inner 6 bits.
Code: Select all
inline int PackV(U64 b)
{
int m=int(b>>32);
m=(m<<4)|int(b);
m|=m>>14;
m|=m>>7;
return (m&126)>>1;
}
inline int PackH(U64 b)
{
int m=int(b>>32)|int(b);
m|=m>>16;
m|=m>>8;
return (m&126)>>1;
}
Now we can modify computing masks into:
Code: Select all
#define MaskV(f) PackV((Occupied>>(f&7))&FILE_A)
#define MaskH(f) PackH(Occupied&Mask_H[f]))
#define MaskD(f) PackH(Occupied&Mask_D[f]))
#define MaskA(f) PackH(Occupied&Mask_A[f]))
There is yet small further optimisation.
If we remove >>1 from functions PackV and PackH, we get the index multiplied by 2. By interleaving tables with even indexes for ranks and odd for files we can use then this index directly as index+1 for files and index for ranks. Note, that compiler should optimise "tab[index+1]" into "(tab+1)[index]" and (tab+1) is constant at compilation time.
So finally masks and attacks are computed in following way:
Code: Select all
inline int PackV(U64 b)
{
int m=int(b>>32);
m=(m<<4)|int(b);
m|=m>>14;
m|=m>>7;
return m&126;
}
inline int PackH(U64 b)
{
int m=int(b>>32)|int(b);
m|=m>>16;
m|=m>>8;
return m&126;
}
#define MaskV(f) PackV((Occupied>>(f&7))&FILE_A)+1
#define MaskH(f) PackH(Occupied&Mask_H[f]))
#define MaskD(f) PackH(Occupied&Mask_D[f]))
#define MaskA(f) PackH(Occupied&Mask_A[f]))
#define AttacksV(f) MovesFR[f>>3][MaskV(f)]<<(f&7)
#define AttacksH(f) MovesFR[f&7 ][MaskH(f)]&Mask_H[f]
#define AttacksD(f) MovesFR[f&7 ][MaskD(f)]&Mask_D[f]
#define AttacksA(f) MovesFR[f&7 ][MaskA(f)]&Mask_A[f]
#define RookAttacks(f) (AttacksV(f)|AttacksH(f))
#define BishopAttacks(f) (AttacksD(f)|AttacksA(f))
#define QueenAttacks(f) (RookAttacks(f)|BishopAttacks(f))