The basic principle is:
To sum it up:
I = ((T & O) * M) >> S
NOTE:
I = ((T[P] & O) * M[P]) >> S[P]
The purpose of step #3 is to transform the 64-bit value T & O into a much smaller one, so that a table of a reasonable size can be used.
The Rook can move any amount of positions horizontally but cannot jump over the King.
┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ R │ │ │ k │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ 7 6 5 4 3 2 1 0
How to verify that the following is an illegal move, because the Rook cannot jump over the King?
┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ │ │ │ k │ │ R │ └───┴───┴───┴───┴───┴───┴───┴───┘
NOTE: It is not possible to determine valid moves for sliding pieces by using only bitwise operations.
Here, the position of the piece is in [0 … 7] and the occupancy bitmask is in [0x00 … 0xFF] (as it is 8-bit wide).
reachable_squares = lookup[P][board]
8 * 2^8 = 2048 entries
64 * 2^64 = 1,180,591,620,717,411,303,424 entries
int xPos = 5; // Position of the 'Rook' piece. UINT64 board = 1 << xPos, // Initial board. UINT lookup[]; // Lookup table. void buildLookup() { int i, pos, msk; // Iterate on all possible positions. for(pos=0; pos<8; pos++) { // Iterate on all possible occupancy masks. for(lookup[pos] = [], msk=0; msk<0x100; msk++) { // Initialize to zero. lookup[pos][msk] = 0; // Compute valid moves to the left. for(i=pos+1; i<8 && !(msk & (1<<i)); i++) { lookup[pos][msk] |= 1 << i; } // Compute valid moves to the right. for(i=pos-1; i>=0 && !(msk & (1<<i)); i--) { lookup[pos][msk] |= 1 << i; } } } } bool isReachable(int pos) { // TODO. // Get valid target squares from the lookup table. int target = lookup[xPos][board]; // return (!target & (1 << pos)); int n =7-pos; // Need to work backwards. // Check if pos is valid and reachable. if (n != xPos && (board ^= 1 << n)) return true else return false; // Reachable = (target & (1 << n)). //if ((board & (1 << n) ? 'O' : '') }
NOTE: The table is storing all possible positions of the Rook piece and each possible board (from 00000000 to 11111111).