Author: Tord Romstad
Date: 03:57:13 12/01/03
I am currently rewriting my engine from scratch, with the aim of making it cleaner, more compact, less buggy and easier to read and modify. Right now I am trying to find an efficient way to compute my attack tables. I would appreciate if some of the more skillful programmers here could give some comments on the below code. My tables have 16 bits per square. The lower 8 bits of each entry look exactly like Ed's table, while the next 6 bits contains info about direct attacks (i.e. non-X-ray attacks) for each piece type. The last two bits are currently unused. There are two such tables, indexed by the squares of the board (I use 256 squares): uint16 Attacks[256]; /* Attack table for the side to move */ uint16 XAttacks[256]; /* Attack table for the other side */ Some other information about my data structures: I visualise the 256-square internal representation of the board as a 16x16 board, where the "real" board occupies the left half of the middle eight ranks. This allows me to use a hybrid 0x88/mailbox architecture. In the attack table generation code below, I don't have to worry about writing outside the "real" board, because attack information for these squares will never be used anyway. In addition to the Board[] array, I have a Phalanx-style piece list in the array Pieces[]. The line: for(sq=Pieces[colour].next; sq!=255; sq=Pieces[sq].next) { in my code loops through all the squares occupied by pieces of the given colour. The array Abilities[] contains information about how each piece can move. For instance, Abilities[W_BISHOP] contains DIAG_UP|DIAG_DOWN|SLIDING, Abilities[W_PAWN] contains DIAG_UP, while Abilities[W_KNIGHT] contains KNIGHT_MOVE. This array is used to determine whether an X-ray attack through a given piece in a given direction is possible. My code: void compute_attacks() { int i, colour, *p, sq, tosq, piece; uint16 mask, *attacks; for(p=(int *)(Attacks+64), i=0; i<8; i++, p+=8) *p = *(p+1) = *(p+2) = *(p+3) = 0; for(p=(int *)(XAttacks+64), i=0; i<8; i++, p+=8) *p = *(p+1) = *(p+2) = *(p+3) = 0; attacks = Attacks; for(i=0, colour=Colour; i<2; i++, colour^=1) { for(sq=Pieces[colour].next; sq!=255; sq=Pieces[sq].next) { for(p = &(PieceDirs[Board[sq]][0]); *p; p++) { piece = Board[sq]; mask = PieceMasks[piece]; tosq = sq + *p; while(1) { attacks[tosq] |= mask; attacks[tosq]++; if(!(Abilities[piece] & SLIDING) || Board[tosq] == OUTSIDE || Board[tosq] == WK || Board[tosq] == BK) break; if(Board[tosq]) { if(PieceColour(Board[tosq]) == PieceColour(piece) && (DirectionType[*p] & Abilities[Board[tosq]])) { /* X-ray attack. The &0xFF at the next time masks off * the direct attack bits. */ mask = PieceMasks[max(piece, Board[tosq])] & 0xFF; piece = Board[tosq]; } else break; } tosq += *p; }}} attacks = XAttacks; }} From the initial position, I compute the attack tables about a million times per second with this code. From WAC1, the rate drops to about 700,000 times per second. The high nodes/second count of Rebel (which has similar tables) makes me believe that it is possible to do this many times faster. Tord
This page took 0.01 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.