I had some awful rook move generation code before, but I refactored that into an interesting bit-shift algorithm.

There are basically two interesting ways to create rook moves. The first is what I call striping, and it involves creating data points for each rank and file on the board. This requires you create 16 longs and can be done very quickly. In fact creating the first rank manually, and then bit-shifting it produces the remaining 7. The same happens with each of the files. Once you've completed this you combine the bits from the rank and file arrays for each spot on the board using integer division and modulus arithmetic on the location offset.

That is one way to do it, or you can generate the rank/file information on the fly for each piece. This is where the bit shifting algorithm comes into play and I'll examine it inline.

private static ulong[] GenerateRookMoves() {

    ulong[] moves = new ulong[64];

    ulong bitMask, bit1, bit2;

   

    for(int i = 0; i < 64; i++) {

        bitMask = 0;

We are looping 64 times for all possible spots. Every spot on the board produces a unique set of move combinations so we can't take any shortcuts. The first bit we create is the rank bit. The rank bit is generated by shiftin a single bit left by 0 to 7 spots. We need the first spot in the rank so we can iterate through all 8 ranks from start to finish. The second bit or file is is generated by getting the first spot in a given file using division and multiplication by 8. Here again, we'll select a bit that is a multiple of 8 starting with 0 and going up to 56.

        bit1 = ((ulong) 1) << (i&7);

        bit2 = ((ulong) 1) << ((i>>3)<<3);

        for(int j = 0; j < 8; j++) {

            bitMask |= bit1 | bit2;

Each of the bits are bitmasked together as we iterate the rank and file. Each rook can perform 15 different moves (14 really, but we'll clip that 15th with the piece blocking bits). Finally two shift operations select the next bits. The rank bit is shifted by 8 to move rank, and the file bit is shifted left by one to move up the file. Seems pretty obvious when you see it.

            bit1 <<= 8;

            bit2 <<= 1;

        }

       

        moves[i] = bitMask;

    }

   

    return moves;

}

Remember, we don't need the maximum amount of speed when generating these arrays because we'll pregenerate them and continuously use them. Certain small devices might be an issue, where you need to generate these on the fly, but remember you can always get just the value you need by constraining the outer loop. Using the first method mentioned with the 16 pre-generated values may also be a great option on a smaller device because you can more quickly get generate all 64 values with only a quarter of the storage. The loop after all, isn't free, even though you are only doing a couple of shift operations. While I'm thinking about it, I should start working on a visualization tool for these things so you can more easily examine the results. Verification is super important and I'm not sure the huge 64 line spit-out showing moves from a given position is the best way to go ;-)

Published Friday, October 22, 2004 5:52 AM by Justin Rogers
Filed under: ,

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)