algerbrex wrote: ↑Tue Jan 04, 2022 4:38 pm
What method are you using to generate slider moves? Magics? Or something like Hyperbola Quintessence or rotated bitboards? Or the ray look-up method?

With so many options to chose from on the wiki I thought I should first start with something original as a challenge to myself. And what I found was pleasently concise and fast and so I stuck with it.

Code: Select all

```
//returns the index of the least significant bit of the bitboard, bb can't be 0
public static int LSB(ulong bb) => BitOperations.TrailingZeroCount(bb);
//resets the least significant bit of the bitboard
public static ulong ClearLSB(ulong bb) => Bmi1.X64.ResetLowestSetBit(bb);
//public static ulong ClearLSB(ulong bb) => bb & (bb - 1);
const ulong HORIZONTAL = 0x00000000000000FFUL;
const ulong VERTICAL = 0x0101010101010101UL;
public static ulong GetDiagonalTargets(ulong occupation, int square)
{
ulong bbPiece = 1UL << square;
ulong bbBlocker = occupation & ~bbPiece;
//mask the bits below bbPiece
ulong bbBelow = bbPiece - 1;
return GenLines(Diagonals[square], Diagonals[square+64], bbBlocker, bbBelow);
}
public static ulong GetOrthogonalTargets(ulong occupation, int square)
{
ulong bbPiece = 1UL << square;
ulong bbBlocker = occupation & ~bbPiece;
//mask the bits below bbPiece
ulong bbBelow = bbPiece - 1;
//horizontal line through square
ulong bbHorizontal = HORIZONTAL << (square & 56);
//vertical line through square
ulong bbVertical = VERTICAL << (square & 7);
return GenLines(bbHorizontal, bbVertical, bbBlocker, bbBelow);
}
private static ulong GenLines(ulong bbLineA, ulong bbLineB, ulong bbBlocker, ulong bbBelow) =>
GenLine(bbLineA, bbBlocker & bbLineA, bbBelow) |
GenLine(bbLineB, bbBlocker & bbLineB, bbBelow);
private static ulong GenLine(ulong bbLine, ulong bbBlocker, ulong bbBelow)
{
//MaskLow sets all low bits up to and including the lowest blocker above orgin, the rest are zeroed out.
//MaskHigh sets all low bits up to and including the highest blocker below origin, the rest are zerored out.
//The bits of the line that are different between the two masks are the valid targets (including the first blockers on each side)
return (MaskLow(bbBlocker & ~bbBelow) ^ MaskHigh(bbBlocker & bbBelow)) & bbLine;
}
//identify the highest set bit and shift a mask so the bits below are set and the rest are zeroed
private static ulong MaskHigh(ulong bb) => 0x7FFFFFFFFFFFFFFFUL >> BitOperations.LeadingZeroCount(bb | 1);
//identify the lowest set bit and set all bits below while zeroing the rest
private static ulong MaskLow(ulong bb) => bb ^ (bb - 1);
```

If you want to try it make sure to inline everything. And the Diagonals array just contains 128 bitboard with the diagonals and antidiagonals on an empty board.

You can compute the diagonals in code just like the orthogonals if you want to be 100% algorithmic but the lookup tables is slightly faster.

Code: Select all

```
//diagonal line through square
ulong bbDiagonal = VerticalShift(DIAGONAL, file - rank);
//antidiagonal line through square
ulong bbAntiDiagonal = VerticalShift(ANTIDIAGONAL, 7 - file - rank);
//sign of 'ranks' decides between left shift or right shift. Then convert signed ranks to a positiver number of bits to shift by. Each rank has 8 bits e.g. 1 << 3 == 8
private static ulong VerticalShift(in ulong bb, in int ranks) => ranks > 0 ? bb >> (ranks << 3) : bb << -(ranks << 3);
```

Also if you don't mind me asking, what does your hardware look like.

I use a Ryzen 3600 at 4.2 Ghz. Perft(6) on the startpos runs at 76287K NPS in my implementation.

Zobrist hashing is actually the next thing I'm going to add and I can report back with updated speeds.