beginner bitboard bug question

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

PK
Posts: 895
Joined: Mon Jan 15, 2007 11:23 am
Location: Warsza

beginner bitboard bug question

Post by PK »

Suppose that bitboards are mapped so that H1 = 0. There is a loop initializing 64 bitboards denoting single square and a function printing a bitboard. One of them is wrong, since when I print any bitboard, only the upper part of the diagram is filled - the rest is all zeroes. Where's the bug?

--------

U64 bbSQ[64]

for (int i=0;i<32;i++) {
bbSQ = 0x0000000000000001<<i & 0x00000000FFFFFFFF;
bbSQ[i+32] = 0x0000000100000000<<i;
}

--------

void util_printBB(U64 bb) {

for (int i=0; i < 64; i++) {
int number = ( bb & bbSQ );
if ( number != 0) number = 1; // we need just yes or no
printf(" %d", number);
if ( (i + 1) % 8 == 0 ) printf("\n"); // take care of board edges
}
}
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: beginner bitboard bug question

Post by sje »

It might be helpful to express all 64 bit hexadecimal constants with a "ull" suffix. Or "ULL" if you prefer.

Example: bb = 0x0123456789abcdefull;
Harald Johnsen

Re: beginner bitboard bug question

Post by Harald Johnsen »

int number = ( bb & bbSQ );

U64 number = ( bb & bbSQ );

Note that the compiler told you that if ints are not 64 bits.

HJ.
Gerd Isenberg
Posts: 2251
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: beginner bitboard bug question

Post by Gerd Isenberg »

PK wrote:Suppose that bitboards are mapped so that H1 = 0. There is a loop initializing 64 bitboards denoting single square and a function printing a bitboard. One of them is wrong, since when I print any bitboard, only the upper part of the diagram is filled - the rest is all zeroes. Where's the bug?

--------

U64 bbSQ[64]

for (int i=0;i<32;i++) {
bbSQ = 0x0000000000000001<<i & 0x00000000FFFFFFFF;
bbSQ[i+32] = 0x0000000100000000<<i;
}

--------

void util_printBB(U64 bb) {

for (int i=0; i < 64; i++) {
int number = ( bb & bbSQ );
if ( number != 0) number = 1; // we need just yes or no
printf(" %d", number);
if ( (i + 1) % 8 == 0 ) printf("\n"); // take care of board edges
}
}


As Harald already mentioned your number type was not sufficient.
I wouldwrite it that way, also to avoid problems with 64-bit constants ...
Otherwise, as Steven mentioned 64-bit constants may require a suffix, see the C64 macro in cpw.

Code: Select all

U64 bbSQ&#91;64&#93;;

void initbbSQ&#40;)
&#123;
   bbSQ&#91;0&#93; = 1; 
   for &#40;int i=1; i<64; i++) 
      bbSQ&#91;i&#93; = 2*bbSQ&#91;i-1&#93;;
&#125;

// INLINE 
int /*bool*/ isBitSet&#40;U64 bb, int idx&#41;
&#123;
   return &#40;bb & bbSQ&#91;i&#93;) != 0;
&#125;

void util_printBB&#40;U64 bb&#41;
&#123;
   static char digit&#91;&#93; = "01"; // ".1";
   for &#40;int i=0; i < 64; i++)
   &#123;
      printf&#40;" %c", digit&#91;isBitSet&#40;bb, i )&#93;); //printf&#40;" %d", isBitSet&#40;bb, i ));
      if ( &#40;i % 8&#41; == 7 ) 
          printf&#40;"\n"); // take care of board edges
   &#125;
&#125;
In C the boolean result of a relational operation is {0, 1}, which might be treated as bool {false, true}, (unsigned) char, short, int, long or long long and used as an index.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: beginner bitboard bug question

Post by bob »

PK wrote:Suppose that bitboards are mapped so that H1 = 0. There is a loop initializing 64 bitboards denoting single square and a function printing a bitboard. One of them is wrong, since when I print any bitboard, only the upper part of the diagram is filled - the rest is all zeroes. Where's the bug?

--------

U64 bbSQ[64]

for (int i=0;i<32;i++) {
bbSQ = 0x0000000000000001<<i & 0x00000000FFFFFFFF;
bbSQ[i+32] = 0x0000000100000000<<i;
}

--------

void util_printBB(U64 bb) {

for (int i=0; i < 64; i++) {
int number = ( bb & bbSQ );
if ( number != 0) number = 1; // we need just yes or no
printf(" %d", number);
if ( (i + 1) % 8 == 0 ) printf("\n"); // take care of board edges
}
}


Your constants above are 32 bit values. use constants of the form:

nnnnnnnnnnnnnnnnnnULL, as otherwise the compiler will truncate to 32 bits before it does anything at all...
Harald
Posts: 318
Joined: Thu Mar 09, 2006 1:07 am

Re: beginner bitboard bug question

Post by Harald »

Hi

There are a few usefull defines and functions for you. I use them with MSVC++. It begins with macros for constants and for printf formats.

Code: Select all

#define C64&#40;c&#41; c##ui64
#define U64_F "I64u"
#define X64_F "016I64x"
#define X64_S "I64x"
With GCC this may be

Code: Select all

#define C64&#40;c&#41; c##ULL
I also use this typedef

Code: Select all

typedef unsigned __int64 uint64;
typedef uint64 Bits64;
and a bitboard class

Code: Select all

class Bitboard
&#123;
  private&#58;
    Bits64 bb_;  // This is the real 64 bit Bitboard. The rest ist just class stuff.
  public&#58;
    // ...
&#125;;
May be you have to change it a bit for other compilers.
You may even wrap it in some #ifdef ... #endif blocks.

Here ist the fun stuff:

Code: Select all

#include "..."
using namespace std;

/**
Construct a bitboard from a 2 byte coordinate string. Only one bit is set.
Construct a bitboard from a 16 byte hex-string. 
Construct a bitboard from a 64 byte 01-string. 
Construct a bitboard from a 8 lines 8 rows 01-string. 
*/
Bitboard&#58;&#58;Bitboard&#40; const string &s )
&#123;
    bb_ = 0;
    if ( s.size&#40;) == 2 )
        coordinate&#40; s );
    else if ( s.size&#40;) == 16 )
        hex&#40; s );
    else if ( s.size&#40;) == 64 )
        txt01&#40; s );
    else
        txt8lines&#40; s );
&#125;

/**
Assign a bitboard from a 2 byte coordinate string. Only one bit is set.
Assign a bitboard from a 16 byte hex-string. 
Assign a bitboard from a 64 byte 01-string. 
Assign a bitboard from a 8 lines 8 rows 01-string. 
*/
Bitboard &Bitboard&#58;&#58;operator=( const string &s )
&#123;
    bb_ = 0;
    if ( s.size&#40;) == 2 )
        coordinate&#40; s );
    else if ( s.size&#40;) == 16 )
        hex&#40; s );
    else if ( s.size&#40;) == 64 )
        txt01&#40; s );
    else
        txt8lines&#40; s );
    return *this;
&#125;

/**
Get a 16 byte hex-string from a bitboard. 
*/
string Bitboard&#58;&#58;hex&#40;) const
&#123;
    char buf&#91;17&#93;;
    sprintf&#40; buf, "%"X64_F"", bb_ );
    return string&#40;buf&#41;;
&#125;

/**
Get a bitboard from a 16 byte hex-string. 
*/
void Bitboard&#58;&#58;hex&#40; const string &txt )
&#123;
    bb_ = 0;
    if ( txt.size&#40;) != 16 )
    &#123;
        logf << "error&#58; txt01 " << txt << endl;
        return;
    &#125;
    if ( txt.find_first_not_of&#40; "0123456789abcdefABCDEF" ) != string&#58;&#58;npos )
    &#123;
        logf << "error&#58; txt01 " << txt << endl;
        return;
    &#125;
    sscanf&#40; txt.c_str&#40;), "%"X64_S"", &bb_ );
&#125;

/**
Get a 64 byte 01-string from a bitboard. 
*/
string Bitboard&#58;&#58;txt01&#40;) const
&#123;
    string txt;
    Bits64 s = C64&#40;1&#41; << 63;
    while ( s > 0 )
    &#123;
        txt += ( bb_ & s ? '1' &#58; '0' );
        s >>= 1;
    &#125;
    return txt;
&#125;

/**
Get a bitboard from a 64 byte 01-string. 
*/
void Bitboard&#58;&#58;txt01&#40; const string &txt )
&#123;
    bb_ = 0;
    if ( txt.size&#40;) != 64 )
    &#123;
        logf << "error&#58; txt01 " << txt << endl;
        return;
    &#125;
    if ( txt.find_first_not_of&#40; "01" ) != string&#58;&#58;npos )
    &#123;
        logf << "error&#58; txt01 " << txt << endl;
        return;
    &#125;
    Bits64 s = C64&#40;1&#41; << 63;
    for ( int i = 0; i < 64; ++i, s >>= 1 )
    &#123;
        if ( txt&#91;i&#93; == '1' )
            bb_ |= s;
    &#125;
&#125;

/**
Get a 8 lines 8 rows 01-string from a bitboard. 
*/
string Bitboard&#58;&#58;txt8lines&#40;) const
&#123;
    string txt;
    int z = 0;
    Bits64 s = C64&#40;1&#41; << 63;
    while ( s > 0 )
    &#123;
        txt += ( bb_ & s ? '1' &#58; '0' );
        s >>= 1;
        if ( (++z % 8&#41; == 0 && s > 0 )
            txt += '\n';
    &#125;
    return txt;
&#125;

/**
Get a bitboard from a 8 lines 8 rows 01-string. 
*/
void Bitboard&#58;&#58;txt8lines&#40; const string &txt )
&#123;
    bb_ = 0;
    if ( txt.size&#40;) < 8 * 8 + 7 )
    &#123;
        logf << "error&#58; txt8lines " << txt << endl;
        return;
    &#125;
    if ( txt.find_first_not_of&#40; "01 \t\n" ) != string&#58;&#58;npos )
    &#123;
        logf << "error&#58; txt8lines " << txt << endl;
        return;
    &#125;
    Bits64 s = C64&#40;1&#41; << 63;
    int i = 0;
    while ( i < txt.size&#40;) && s > 0 )
    &#123;
        char c = txt&#91;i++&#93;;
        if ( c < '0' )
            continue;
        if ( c == '1' )
            bb_ |= s;
        s >>= 1;
    &#125;
    if ( s != 0 )
    &#123;
        logf << "error&#58; txt8lines " << txt << endl;
        return;
    &#125;
&#125;

/**
Get a 2 byte coordinate string from a bitboard with only one bit set. 
If more or less bits are set the result is "??". 
The normal results are "a1", ..., "h8".
*/
string Bitboard&#58;&#58;coordinate&#40;) const
&#123;
    if ( !only_1_bit&#40;) )
    &#123;
        logf << "coordinate ?? " << hex&#40;) << endl;
        return "??";
    &#125;
    byte ep = msb_nr&#40;);
    string s;
    s += "hgfedcba"&#91;ep % 8&#93;;
    s += "12345678"&#91;ep / 8&#93;;
    return s;
&#125;

/**
Get bitboard from a 2 byte coordinate string. Only one bit is set. 
If the coordinates are invalid the bitboard is empty &#40;0&#41;. 
Valid coordinate strings are "a1", ..., "h8".
*/
void Bitboard&#58;&#58;coordinate&#40; const string &s )
&#123;
    bb_ = 0;
    if ( s.size&#40;) != 2 )
    &#123;
        logf << "error&#58; coordinate " << s << endl;
        return;
    &#125;
    int line = s&#91;0&#93;;
    if ( line >= 'a' && line <= 'h' )
        line = 'h' - line;
    else if ( line >= 'A' && line <= 'H' )
        line = 'H' - line;
    else
    &#123;
        logf << "error&#58; coordinate " << s << endl;
        return;
    &#125;
    int row = s&#91;1&#93;;
    if ( row >= '1' && row <= '8' )
        row = row - '1';
    else
    &#123;
        logf << "error&#58; coordinate " << s << endl;
        return;
    &#125;
    bb_ = set_one_bit&#40; row * 8 + line );
&#125;
Perhaps you find something useful in it.

Harald
PK
Posts: 895
Joined: Mon Jan 15, 2007 11:23 am
Location: Warsza

Re: beginner bitboard bug question

Post by PK »

Thank You very much for Your help and code samples.

I have another Microsoft-specific question: how to disable all those silly gets/scanf warnings? As You can see from the above example, I have a problem with finding real ones, which would be easier without all that garbage.

Pawel Koziol
User avatar
xsadar
Posts: 147
Joined: Wed Jun 06, 2007 10:01 am
Location: United States
Full name: Mike Leany

Re: beginner bitboard bug question

Post by xsadar »

PK wrote:Thank You very much for Your help and code samples.

I have another Microsoft-specific question: how to disable all those silly gets/scanf warnings? As You can see from the above example, I have a problem with finding real ones, which would be easier without all that garbage.

Pawel Koziol
I'm afraid your gets() warnings are real ones, and your scanf() warnings may be as well (although I can't be certain without knowing what they are). You can disable these warnings, but in this case, I think it may be just a band-aid that hides the real problem. Usually fixing the issue that causes the warning is better than disabling the warning.

In your specific case, you should use fgets() instead of gets(), since it allows you to specify the maximum number of characters to read, while gets() does not. Overflowing your buffer would be bad. See here for information on why gets is bad (particularly under "BUGS"): http://www.rt.com/man/gets.3.html

If you're using scanf() to input strings of arbitrary length, you might consider specifying a maximum field width. Again, overflowing your buffer would be bad.

If you absolutely MUST disable a warning, here's one way to do it in MSVC: http://msdn.microsoft.com/en-us/library ... 80%29.aspx

When reasonable, I would recommend suppressing the warning for one line over disabling it completely.
Harald Johnsen

Re: beginner bitboard bug question

Post by Harald Johnsen »

PK wrote:Thank You very much for Your help and code samples.

I have another Microsoft-specific question: how to disable all those silly gets/scanf warnings? As You can see from the above example, I have a problem with finding real ones, which would be easier without all that garbage.

Pawel Koziol
define that for example :
/D _CRT_SECURE_NO_DEPRECATE

HJ.