Make and Unmake implementation

Code, algorithms, languages, construction...
Post Reply
CDaley11
Posts: 42
Joined: Thu Jan 10, 2013 6:23 am
Real Name: Christian Daley

Make and Unmake implementation

Post by CDaley11 » Fri Feb 01, 2013 1:37 am

After some helpful posts by the members on this forum and also looking through many online resources I successfully integrated magic bitboards into my engine. Even though magic bitboards are very fast my engine still runs very slowly and only gets about 60k nps. I've done some logging and tests and I've concluded that it is my make / unmake methods that are horrible slow, as I anticipated. Currently, I have a Move_t struct type that represents a move, it has four pieces of information on it: 1. From, a bitboard with only one bit marked which is the square that the piece is moving from. 2. To, same as from except for the square the piece is moving to. 3. PieceType, the type of piece that is doing the moving. 4. MoveType, the type of move (regular, capture, castle, etc). In my make move method I simple XOR the from and to bits for the relevant piece type. But then it wastes valuable time doing things such as checking to see if castling rights have been compromised, or checking if the move is a capture. If it is a capture it has to loop through the opponents bitboards and see what king of piece it's capturing. Also I have a struct type called Undo_t which stores the data for unmaking moves. I make it store all the bitboards and also the castling rights and enPassant square. All of these move and undo structs are initialized in an array that acts as a stack based on depth of search and the startup of the program so that no new structs have to be created during search. But this whole process seems to be really slow, is there some tips/tricks for speeding up this part? I can post my full make/unmake code if needed.

BB+
Posts: 1484
Joined: Thu Jun 10, 2010 4:26 am

Re: Make and Unmake implementation

Post by BB+ » Fri Feb 01, 2013 10:28 am

If it is a capture it has to loop through the opponents bitboards and see what king of piece it's capturing.
Many programs have a 64-entry array that has a indicator of the current piece on a square (if any). E.g., I think Crafty has -6 to -1 for Black, 0 for nothing, 1 to 6 for White. One has to update this array every make/unmake, but overall it seems to be a win (and can also be useful in eval).

Removing castling rights can be done by noting if: a) the moving piece was a King; or b) the move was to or from a1/h1/a8/h8. The latter can be aided by an 64-entry array that has a 4-bit bit-mask that is always completely set, except for the 4 corner squares where 1 bit is missing.

Gerd Isenberg
Posts: 37
Joined: Wed Jul 07, 2010 11:11 pm
Real Name: Gerd Isenberg

Re: Make and Unmake implementation

Post by Gerd Isenberg » Sun Feb 03, 2013 10:24 pm

CDaley11 wrote:Even though magic bitboards are very fast my engine still runs very slowly and only gets about 60k nps. I've done some logging and tests and I've concluded that it is my make / unmake methods that are horrible slow, as I anticipated. Currently, I have a Move_t struct type that represents a move, it has four pieces of information on it: 1. From, a bitboard with only one bit marked which is the square that the piece is moving from. 2. To, same as from except for the square the piece is moving to. 3. PieceType, the type of piece that is doing the moving. 4. MoveType, the type of move (regular, capture, castle, etc).
Don't keep bitboards inside a move struct, that is overkill. Max 32-bit for a full qualified move - from:6, to:6, piece:3, captured piece:3, and promo- and/or special move flags:2, leaves 12 bits for a ordering score or something. 16-bit are enough for a move in lists and tt.

Post Reply