Problem with bitboard knight attack generator

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

ZirconiumX
Posts: 1334
Joined: Sun Jul 17, 2011 11:14 am

Problem with bitboard knight attack generator

Post by ZirconiumX »

I have been trying to make a bitboard knight attack generator to fill an array of knight attacks.

Code: Select all

Bitboard KnightMoves(int Square)
{
	Bitboard b = 1 << Square, Targets = 0;
	
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; << 17;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; << 10;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; >> 6;
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; >> 15;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; << 15;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; << 6;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; >> 10;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; >> 17;

	return Targets;
&#125;
When I try and generate the array I get some strange figures given, e.g. for square a1 I get 0x132096...

Something at the back of my mind says that I'm suffering from wrap-around issues.

Matthew:out
Some believe in the almighty dollar.

I believe in the almighty printf statement.
Gerd Isenberg
Posts: 2251
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Problem with bitboard knight attack generator

Post by Gerd Isenberg »

What value has a1?

I guess problem is the 32-bit expression 1 << square instead 1ULL << square.

Gerd
jwes
Posts: 778
Joined: Sat Jul 01, 2006 7:11 am

Re: Problem with bitboard knight attack generator

Post by jwes »

ZirconiumX wrote:I have been trying to make a bitboard knight attack generator to fill an array of knight attacks.

Code: Select all

Bitboard KnightMoves&#40;int Square&#41;
&#123;
	Bitboard b = 1 << Square, Targets = 0;
	
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; << 17;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; << 10;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; >> 6;
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; >> 15;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; << 15;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; << 6;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; >> 10;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; >> 17;

	return Targets;
&#125;
When I try and generate the array I get some strange figures given, e.g. for square a1 I get 0x132096...

Something at the back of my mind says that I'm suffering from wrap-around issues.

Matthew:out
One problem is that you are not taking into account the sides of the board, e.g. (b & 0xFCFCFCFCFCFCFCFCULL) << 6 only works for files c-h.
lucasart
Posts: 3238
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: Problem with bitboard knight attack generator

Post by lucasart »

ZirconiumX wrote:I have been trying to make a bitboard knight attack generator to fill an array of knight attacks.

Code: Select all

Bitboard KnightMoves&#40;int Square&#41;
&#123;
	Bitboard b = 1 << Square, Targets = 0;
	
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; << 17;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; << 10;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; >> 6;
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; >> 15;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; << 15;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; << 6;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; >> 10;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; >> 17;

	return Targets;
&#125;
When I try and generate the array I get some strange figures given, e.g. for square a1 I get 0x132096...

Something at the back of my mind says that I'm suffering from wrap-around issues.

Matthew:out
1 << Square is a common mistake. It should be 1ULL << Square. Otherwise you shift a 32-bit int, and you lose all the 32 upper bits, and casting to a uint64_t won't solve the problem.

and as for your algorithm itself, i don't think it's correct.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Problem with bitboard knight attack generator

Post by bob »

ZirconiumX wrote:I have been trying to make a bitboard knight attack generator to fill an array of knight attacks.

Code: Select all

Bitboard KnightMoves&#40;int Square&#41;
&#123;
	Bitboard b = 1 << Square, Targets = 0;
	
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; << 17;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; << 10;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; >> 6;
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; >> 15;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; << 15;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; << 6;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; >> 10;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; >> 17;

	return Targets;
&#125;
When I try and generate the array I get some strange figures given, e.g. for square a1 I get 0x132096...

Something at the back of my mind says that I'm suffering from wrap-around issues.

Matthew:out
I don't follow the bit patterns you are using... Since this only needs to be done at startup, I use this:

Code: Select all


int64_t knight_attacks[64];
static const int knightsq[8] = { -17, -15, -10, -6, 6, 10, 15, 17 };

/*
 initialize knight attack board
 */
  for (i = 0; i < 64; i++) {
    knight_attacks[i] = 0;
    frank = Rank(i);
    ffile = File(i);
    for (j = 0; j < 8; j++) {
      sq = i + knightsq[j];
      if ((sq < 0) || (sq > 63))
        continue;
      trank = Rank(sq);
      tfile = File(sq);
      if ((Abs(frank - trank) > 2) || (Abs(ffile - tfile) > 2))
        continue;
      knight_attacks[i] = knight_attacks[i] | (uint64_t) 1 << sq;
    }
  }
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Problem with bitboard knight attack generator

Post by Sven »

bob wrote:
ZirconiumX wrote:I have been trying to make a bitboard knight attack generator to fill an array of knight attacks.

Code: Select all

Bitboard KnightMoves&#40;int Square&#41;
&#123;
	Bitboard b = 1 << Square, Targets = 0;
	
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; << 17;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; << 10;
	Targets		|= &#40;b & 0x3F3F3F3F3F3F3F3FULL&#41; >> 6;
	Targets		|= &#40;b & 0x7F7F7F7F7F7F7F7FULL&#41; >> 15;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; << 15;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; << 6;
	Targets		|= &#40;b & 0xFCFCFCFCFCFCFCFCULL&#41; >> 10;
	Targets		|= &#40;b & 0xFEFEFEFEFEFEFEFEULL&#41; >> 17;

	return Targets;
&#125;
When I try and generate the array I get some strange figures given, e.g. for square a1 I get 0x132096...

Something at the back of my mind says that I'm suffering from wrap-around issues.

Matthew:out
I don't follow the bit patterns you are using... Since this only needs to be done at startup, I use this:

Code: Select all

int64_t knight_attacks&#91;64&#93;;
static const int knightsq&#91;8&#93; = &#123; -17, -15, -10, -6, 6, 10, 15, 17 &#125;;

/*
 initialize knight attack board
 */
  for &#40;i = 0; i < 64; i++) &#123;
    knight_attacks&#91;i&#93; = 0;
    frank = Rank&#40;i&#41;;
    ffile = File&#40;i&#41;;
    for &#40;j = 0; j < 8; j++) &#123;
      sq = i + knightsq&#91;j&#93;;
      if (&#40;sq < 0&#41; || &#40;sq > 63&#41;)
        continue;
      trank = Rank&#40;sq&#41;;
      tfile = File&#40;sq&#41;;
      if (&#40;Abs&#40;frank - trank&#41; > 2&#41; || &#40;Abs&#40;ffile - tfile&#41; > 2&#41;)
        continue;
      knight_attacks&#91;i&#93; = knight_attacks&#91;i&#93; | &#40;uint64_t&#41; 1 << sq;
    &#125;
  &#125;
I think the bit patterns of Matthew are correct, the only problem "1ULL << Square" has already been mentioned. Also his solution looks quite elegant to me. Personally I would write it like this (assuming a1=0, h1=7 in the comments - the patterns are independent from that):

Code: Select all

Bitboard KnightMoves&#40;int Square&#41;
&#123;
   Bitboard const b = 1ULL << Square;

   return (&#40;b & 0x00007F7F7F7F7F7FULL&#41; << 17&#41;  // up   -up   -right
        | (&#40;b & 0x003F3F3F3F3F3F3FULL&#41; << 10&#41;  // up   -right-right
        | (&#40;b & 0x3F3F3F3F3F3F3F00ULL&#41; >>  6&#41;  // down -right-right
        | (&#40;b & 0x7F7F7F7F7F7F0000ULL&#41; >> 15&#41;  // down -down -right
        | (&#40;b & 0x0000FEFEFEFEFEFEULL&#41; << 15&#41;  // up   -up   -left
        | (&#40;b & 0x00FCFCFCFCFCFCFCULL&#41; <<  6&#41;  // up   -left -left
        | (&#40;b & 0xFCFCFCFCFCFCFC00ULL&#41; >> 10&#41;  // down -left -left
        | (&#40;b & 0xFEFEFEFEFEFE0000ULL&#41; >> 17&#41;; // down -down -left
&#125;
and then something like this:

Code: Select all

for &#40;int i = 0; i < 64; i++) &#123;
   knightAttacks&#91;i&#93; = KnightMoves&#40;i&#41;;
&#125;
Sven
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Problem with bitboard knight attack generator

Post by Sven »

lucasart wrote:and as for your algorithm itself, i don't think it's correct.
Why do you think so?

For each rank those patterns do the following, assuming a1=0 and h1=7:

Code: Select all

For << 17 and >> 15, 7F masks out bit  7   &#40;h-file&#41;.
For << 10 and >>  6, F3 masks out bits 0+1 &#40;a/b-file&#41;.
For << 15 and >> 17, FE masks out bit  0   &#40;a-file&#41;.
For <<  6 and >> 10, FC masks out bits 6+7 &#40;g/h-file&#41;.
Seems ok to me.

Sven
Jami
Posts: 3
Joined: Sun Nov 13, 2011 9:13 pm

Re: Problem with bitboard knight attack generator

Post by Jami »

I think your only problem is the "1 << Square" which should be 1ULL < Square". I tried it here and it works great up to Square = 31.
I am assuming Square = 0 is a1, 1 is b1, etc.

My logic for building the moves is the same, but I build the masks as well. Something like this:

Code: Select all

      NMoves&#91;i&#93; =
         (&#40;src & ~&#40;Rank7 | Rank8 | FileH&#41;) << 17&#41; |  /* Up    2, Right 1 */
         (&#40;src & ~&#40;Rank7 | Rank8 | FileA&#41;) << 15&#41; |  /* Up    2, Left  1 */
         (&#40;src & ~&#40;FileG | FileH | Rank8&#41;) << 10&#41; |  /* Right 2, Up    1 */
         (&#40;src & ~&#40;FileG | FileH | Rank1&#41;) >>  6&#41; |  /* Right 2, Down  1 */
         (&#40;src & ~&#40;Rank1 | Rank2 | FileH&#41;) >> 15&#41; |  /* Down  2, Right 1 */
         (&#40;src & ~&#40;Rank1 | Rank2 | FileA&#41;) >> 17&#41; |  /* Down  2, Left  1 */
         (&#40;src & ~&#40;FileA | FileB | Rank8&#41;) <<  6&#41; |  /* Left  2, Up    1 */
         (&#40;src & ~&#40;FileA | FileB | Rank1&#41;) >> 10&#41;;   /* Left  2, Down  1 */
With comments so I don't lose my mind!
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Problem with bitboard knight attack generator

Post by Sven »

Sven Schüle wrote:
lucasart wrote:and as for your algorithm itself, i don't think it's correct.
Why do you think so?

For each rank those patterns do the following, assuming a1=0 and h1=7:

Code: Select all

For << 17 and >> 15, 7F masks out bit  7   &#40;h-file&#41;.
For << 10 and >>  6, F3 masks out bits 0+1 &#40;a/b-file&#41;.
For << 15 and >> 17, FE masks out bit  0   &#40;a-file&#41;.
For <<  6 and >> 10, FC masks out bits 6+7 &#40;g/h-file&#41;.
Seems ok to me.

Sven
Only if I had quoted the patterns correctly ... I should have written this:

Code: Select all

For << 17 and >> 15, 7F masks out bit  7   &#40;h-file&#41;.
For << 10 and >>  6, 3F masks out bits 6+7 &#40;g/h-file&#41;.
For << 15 and >> 17, FE masks out bit  0   &#40;a-file&#41;.
For <<  6 and >> 10, FC masks out bits 0+1 &#40;a/b-file&#41;.
Sven
ZirconiumX
Posts: 1334
Joined: Sun Jul 17, 2011 11:14 am

Re: Problem with bitboard knight attack generator

Post by ZirconiumX »

The patterns are still wrong:
for a1 (square 0) I get 0x132096ULL, which corresponds to (a1 top left)

Code: Select all

0 1 1 0 1 0 0 1
0 0 0 0 0 1 0 0
1 1 0 0 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
Which is just a mess.

Matthew:out
Some believe in the almighty dollar.

I believe in the almighty printf statement.