Moderator: Andres Valverde
Tord Romstad wrote:Right now, I am thinking about the following problem: What is the best way to obtain a bitboard of all passed pawns for one side? The obvious way is to loop through all pawns and check each pawn individually, but this is very slow. It seems that the key to making bitboards fast is to avoid having too many loops through the nonzero bits of a bitboard.
Tord Romstad wrote:I am not interested in solutions involving assembly language. If possible, I would prefer to use code which works for both colours, rather than separate code for black and white pawns.
Reinhard Scharnagl wrote:What did you convince that bitboard programs would be the fastest ?
Alessandro Scotti wrote:Tord Romstad wrote:Right now, I am thinking about the following problem: What is the best way to obtain a bitboard of all passed pawns for one side? The obvious way is to loop through all pawns and check each pawn individually, but this is very slow. It seems that the key to making bitboards fast is to avoid having too many loops through the nonzero bits of a bitboard.
I still loop thru all the pawns, but if needed this part can be moved into the pawn structure hash table so later you only have to scan the list of passed pawns, which is much shorter.
Tord Romstad wrote:I am not interested in solutions involving assembly language. If possible, I would prefer to use code which works for both colours, rather than separate code for black and white pawns.
No assembly needed... I think Gerd's routines are more than fast enough!
0 0 1 1 1 0 0 0
0 0 1 1 1 0 0 0
0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
mathmoi wrote:This is done in only one AND, but you still have to iterate trough the pawns of the side to move.
Tord Romstad wrote:Right now, I am thinking about the following problem: What is the best way to obtain a bitboard of all passed pawns for one side? The obvious way is to loop through all pawns and check each pawn individually, but this is very slow. It seems that the key to making bitboards fast is to avoid having too many loops through the nonzero bits of a bitboard.
/*
* This code computes a bitmask of passed white pawns
*/
U64 mask, passedPawns;
/* generate black's one square pawn moves */
mask = genPawnMoves(BLACK);
/* Duplicate the mask and move it down. This is done three times
to make sure the mask reaches the bottom of the board */
mask |= mask << 8;
mask |= mask << 16;
mask |= mask << 32;
/* get white's passed pawn mask */
passedPawns = ~mask & whitePawns;
toma wrote:My engine (and I think most of bitboard programs) don't use only bitboards but hybrid solutions.
Beside bitboards I have also lists of pieces. So I don't have to scan trough entire bitboard to find pawns. Using the list of pawns and bitboards you can check for free pawns pretty fast.
Tord Romstad wrote:That would work, but I am considering to drop the pawn hash table altogether. Some of the bitboard experts claim that bitboards make pawn structure evaluation so fast that there is no need for a pawn hash table.
Tord Romstad wrote:Where do I find Gerd's routines for this?
const unsigned int lsz64_tbl[64] =
{
63, 30, 3, 32, 59, 14, 11, 33,
60, 24, 50, 9, 55, 19, 21, 34,
61, 29, 2, 53, 51, 23, 41, 18,
56, 28, 1, 43, 46, 27, 0, 35,
62, 31, 58, 4, 5, 49, 54, 6,
15, 52, 12, 40, 7, 42, 45, 16,
25, 57, 48, 13, 10, 39, 8, 44,
20, 47, 38, 22, 17, 37, 36, 26,
};
/*
Bit count function by Gerd Isenberg.
*/
inline int bitCount( Uint64 bb )
{
unsigned w = (unsigned) (bb >> 32);
unsigned v = (unsigned) bb;
v = v - ((v >> 1) & 0x55555555);
w = w - ((w >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
w = (w & 0x33333333) + ((w >> 2) & 0x33333333);
v = (v + (v >> 4)) & 0x0F0F0F0F;
w = (w + (w >> 4)) & 0x0F0F0F0F;
v = ((v+w) * 0x01010101) >> 24;
return v;
}
/*
Bit search functions by Gerd Isenberg.
*/
inline unsigned int bitSearch( BitBoard bb )
{
Uint64 b = bb.data ^ (bb.data - 1);
unsigned int fold = ((unsigned)b) ^ ((unsigned)(b>>32));
return lsz64_tbl[(fold * 0x78291ACF) >> (32-6)];
}
inline unsigned int bitSearchAndReset( BitBoard & bb )
{
Uint64 b = bb.data ^ (bb.data - 1);
bb.data = bb.data & (bb.data - 1);
unsigned int fold = ((unsigned)b) ^ ((unsigned)(b>>32));
return lsz64_tbl[(fold * 0x78291ACF) >> (32-6)];
}
inline int bitScanForward( BitBoard bb )
{
return bb.data != 0 ? (int) bitSearch(bb) : -1;
}
inline int bitScanAndResetForward( BitBoard & bb )
{
return bb.data != 0 ? (int) bitSearchAndReset(bb) : -1;
}
inline int bitCount( const BitBoard & b )
{
return bitCount( b.data );
}
inline int BitBoard::bitScanForward() const {
return ::bitScanForward( data );
}
mathmoi wrote:In reality what you test is : "Is there an opponent paws in front of my pawn or an opponent pawn that could take my pawn."
This is done in only one AND, but you still have to iterate trough the pawns of the side to move.
Alessandro Scotti wrote:Hi Mathieu,
I also check for own pawns in the advance path, i.e. when passed are doubled or tripled I only consider the most advanced as passed.
Tord Romstad wrote:I am not interested in solutions involving assembly language. If possible, I would prefer to use code which works for both colours, rather than separate code for black and white pawns.
No assembly needed... I think Gerd's routines are more than fast enough!
Tord Romstad wrote:Hi all,
I am once again experimenting with bitboards. I have made numerous private rotated bitboard versions of Glaurung over the last year, but they were always slower and less compact than my mailbox versions (even on the 64-bit G5 CPU). The reason is almost certainly that I haven't learnt all the tricks yet. As others have demonstrated, it is definitely possible to write blazingly fast bitboard programs.
Right now, I am thinking about the following problem: What is the best way to obtain a bitboard of all passed pawns for one side? The obvious way is to loop through all pawns and check each pawn individually, but this is very slow. It seems that the key to making bitboards fast is to avoid having too many loops through the nonzero bits of a bitboard.
I am not interested in solutions involving assembly language. If possible, I would prefer to use code which works for both colours, rather than separate code for black and white pawns.
Tord
Reinhard Scharnagl wrote:What did you convince that bitboard programs would be the fastest ?
Reinhard.
Uri Blass wrote:I do not know if this is what you are interested in but
I use bitboards in movei only for pawns and I use Gerd's code that he posted in CCC
Gerd also posted code for backward pawns and maybe for candidate pawns(I am not sure exactly) but Movei is not using it(I remember that I tried backward pawns and it was not productive).
Tord Romstad wrote:Hi all,
I am once again experimenting with bitboards. I have made numerous private rotated bitboard versions of Glaurung over the last year, but they were always slower and less compact than my mailbox versions (even on the 64-bit G5 CPU). The reason is almost certainly that I haven't learnt all the tricks yet. As others have demonstrated, it is definitely possible to write blazingly fast bitboard programs.
Right now, I am thinking about the following problem: What is the best way to obtain a bitboard of all passed pawns for one side? The obvious way is to loop through all pawns and check each pawn individually, but this is very slow. It seems that the key to making bitboards fast is to avoid having too many loops through the nonzero bits of a bitboard.
I am not interested in solutions involving assembly language. If possible, I would prefer to use code which works for both colours, rather than separate code for black and white pawns.
Tord
/*passedPawnEval()
*passed pawn evaluvation
*it is based on the passed pawn PST
*
*the basic idea behind optimization of this is that
*when you find that a pawn is not passed, the opponent
*pawns are not passed either, so you skip doing tests
*for them. This improves performance 2-3x. For the initial
*position, only 4 tests are needed to test if any of the pawns
*are passed isntead of 16 tests.
*
*@param pos - the board position to be evaluvated
*/
int passedPawnEval(const board* pos)
{
int sq, score=0;
U64 BlackPawns, WhitePawns; //static pawn bitboards
U64 BPawns, WPawns; //changing pawn bitboards
BlackPawns=BPawns=pos->Pieces[P]&pos->PiecesSide[BLACK];
WhitePawns=WPawns=pos->Pieces[P]&pos->PiecesSide[WHITE];
while(WPawns)
{
sq=LastOne(WPawns);
WPawns^=toBit[sq];
if(BlackPawns&detectPasserWHITE[sq])
BPawns&=~detectPasserWHITE[sq];
else
{
score+=passedPawnPST[sq];
continue;
}
BPasser:
if(BPawns)
{
sq=LastOne(BPawns);
BPawns^=toBit[sq];
if(WhitePawns&detectPasserBLACK[sq])
WPawns&=~detectPasserBLACK[sq];
else
{
score-=passedPawnPST[flip[sq]];
goto BPasser;
}
}
else
goto WLeft;
}
while(BPawns)
{
sq=LastOne(BPawns);
BPawns^=toBit[sq];
if(!(WhitePawns&detectPasserBLACK[sq]))
score-=passedPawnPST[flip[sq]];
}
return signSide[pos->side]*score;
WLeft:
while(WPawns)
{
sq=LastOne(WPawns);
WPawns^=toBit[sq];
if(!(BlackPawns&detectPasserWHITE[sq]))
score+=passedPawnPST[flip[sq]];
}
return signSide[pos->side]*score;
}
U64 pieceboard, pawnAttacks[2];
...
//Pawn Attacks
pieceboard=piecesBLACK(*pos,P);
pawnAttacks[BLACK]=((pieceboard&0x7F7F7F7F7F7F7F7FULL)>>7)|((pieceboard&0xFEFEFEFEFEFEFEFEULL)>>9);
pieceboard=piecesWHITE(*pos,P);
pawnAttacks[WHITE]=((pieceboard&0x7F7F7F7F7F7F7F7FULL)<<9)|((pieceboard&0xFEFEFEFEFEFEFEFEULL)<<7);
Return to Programming and Technical Discussions
Users browsing this forum: No registered users and 24 guests