Problem with bitboard knight attack generator

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

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

Re: Problem with bitboard knight attack generator

Post by Gerd Isenberg »

ZirconiumX wrote: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
You should be able to fix the problem by debugging and inspecting intermediate results ;-)

What about the ones from cpw Knight Pattern, Multiple Knight Attacks to call it with knightAttacks(1ULL << sq)?
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Problem with bitboard knight attack generator

Post by Gerd Isenberg »

bob wrote: 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;
Bahh, what a mess, horrorfull loops and conditions, even if init stuff only ;-)

Are you a bitboarder? I guess you need some knight fillstuff anyway, so why not using it for simple initialization?

Code: Select all

U64 knightAttacks&#40;U64 knights&#41; &#123;
   U64 l1 = &#40;knights >> 1&#41; & C64&#40;0x7f7f7f7f7f7f7f7f&#41;;
   U64 l2 = &#40;knights >> 2&#41; & C64&#40;0x3f3f3f3f3f3f3f3f&#41;;
   U64 r1 = &#40;knights << 1&#41; & C64&#40;0xfefefefefefefefe&#41;;
   U64 r2 = &#40;knights << 2&#41; & C64&#40;0xfcfcfcfcfcfcfcfc&#41;;
   U64 h1 = l1 | r1;
   U64 h2 = l2 | r2;
   return &#40;h1<<16&#41; | &#40;h1>>16&#41; | &#40;h2<<8&#41; | &#40;h2>>8&#41;;
&#125;
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CookieCat's knight attack bitboard vector initialization

Post by sje »

CookieCat's knight attack bitboard vector initialization

Code: Select all

        &#123; Initialize the knight attack-to-squares bitboard vector &#125;

        for frsq &#58;= 0 to sqmax do
          begin
            BbReset&#40;knightatkbbvec&#91;frsq&#93;);
            for dir &#58;= direne to direse do
              begin
                tosq &#58;= advance&#91;frsq, dir&#93;;
                if tosq <> sqnil then
                  BbSetSq&#40;knightatkbbvec&#91;frsq&#93;, tosq&#41;
              end
          end;
Kings:

Code: Select all

        &#123; Initialize the king attack-to-squares bitboard vector &#125;

        for frsq &#58;= 0 to sqmax do
          begin
            BbReset&#40;kingatkbbvec&#91;frsq&#93;);
            for dir &#58;= dire to dirse do
              begin
                tosq &#58;= advance&#91;frsq, dir&#93;;
                if tosq <> sqnil then
                  BbSetSq&#40;kingatkbbvec&#91;frsq&#93;, tosq&#41;
              end
          end;
And for pawns:

Code: Select all

        &#123; Initialize the pawn attack-to-squares bitboard vector &#125;

        for color &#58;= 0 to colorrmax do
          begin
            man &#58;= synthpawn&#91;color&#93;;
            dir0 &#58;= mantodir0&#91;man&#93;;
            dir1 &#58;= mantodir1&#91;man&#93;;
            for frsq &#58;= 0 to sqmax do
              begin
                BbReset&#40;pawnatkbbvec&#91;color, frsq&#93;);
                for dir &#58;= dir0 to dir1 do
                  begin
                    tosq &#58;= advance&#91;frsq, dir&#93;;
                    if tosq <> sqnil then
                      BbSetSq&#40;pawnatkbbvec&#91;color, frsq&#93;, tosq&#41;
                  end
              end
          end;
ZirconiumX
Posts: 1334
Joined: Sun Jul 17, 2011 11:14 am

Re: Problem with bitboard knight attack generator

Post by ZirconiumX »

@ Gerd: Yes, I was using it for initialization, and no, the CPW method doesn't work either.

@ Steven: Hate to offend you, but PASCAL is about as much use to me as a plastic shoelace is to a plastic shoelace.

Matthew:out
Some believe in the almighty dollar.

I believe in the almighty printf statement.
Jami
Posts: 3
Joined: Sun Nov 13, 2011 9:13 pm

Re: Problem with bitboard knight attack generator

Post by Jami »

Your code worked perfectly for me - but I had to make two changes to test...
1. 1ULL < Square
2. Changed Bitboard to a U64.

Could your definition of Bitboard be the cause?

I would break your 8 lines down into separate statements and single step through them.

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

Re: Problem with bitboard knight attack generator

Post by ZirconiumX »

I use a 32bit system.
My code for testing (Gerd's system):

Code: Select all

#include <iostream>

typedef unsigned long long Bitboard;

Bitboard KnightMoves&#40;Bitboard Knights&#41;
&#123;
	Bitboard l1 = &#40;Knights >> 1&#41; & 0x7F7F7F7F7F7F7F7FULL;
	Bitboard l2 = &#40;Knights >> 2&#41; & 0x3F3F3F3F3F3F3F3FULL;
	Bitboard r1 = &#40;Knights << 1&#41; & 0xFEFEFEFEFEFEFEFEULL;
	Bitboard r2 = &#40;Knights << 2&#41; & 0xFCFCFCFCFCFCFCFCULL;
	Bitboard h1 = l1 | r1;
	Bitboard h2 = l2 | r2;
	return &#40;h1 << 16&#41; | &#40;h1 >> 16&#41; | &#40;h2 << 8&#41; | &#40;h2 >> 8&#41;;
&#125;

int main&#40;)
&#123;
	for &#40;int i = 0; i < 64; i++)
		printf&#40;"(%d&#41; 0x%lluULL,\n", i, KnightMoves&#40;1ULL << i&#41;);
	return 0;
&#125;
Jami, could you dump your code to the forum, so I can examine it?

Matthew:out
Some believe in the almighty dollar.

I believe in the almighty printf statement.
Jami
Posts: 3
Joined: Sun Nov 13, 2011 9:13 pm

Re: Problem with bitboard knight attack generator

Post by Jami »

That works fine as well, but I see the problem:

132096 = 0x00020400

You are displaying the results in decimal!
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Problem with bitboard knight attack generator

Post by Gerd Isenberg »

Hmm, there is something flawed. Can you please compile and run this snippet.

Code: Select all

#include <stdio.h>

// typedef unsigned __int64 U64;    // for the old microsoft compilers
typedef unsigned long long  U64; // supported by MSC 13.00+ and C99
#define C64&#40;constantU64&#41; constantU64##ULL


void printBB&#40;U64 bb&#41;
&#123;
  printf&#40;"0x%08x%08x\n", &#40;int&#41;&#40;bb >> 32&#41;, &#40;int&#41; bb&#41;;
&#125;

U64 knightAttacks&#40;U64 knights&#41; &#123;
  U64 l1 = &#40;knights >> 1&#41; & C64&#40;0x7f7f7f7f7f7f7f7f&#41;;
  printBB&#40;l1&#41;;
  U64 l2 = &#40;knights >> 2&#41; & C64&#40;0x3f3f3f3f3f3f3f3f&#41;;
  printBB&#40;l2&#41;;
  U64 r1 = &#40;knights << 1&#41; & C64&#40;0xfefefefefefefefe&#41;;
  printBB&#40;r1&#41;;
  U64 r2 = &#40;knights << 2&#41; & C64&#40;0xfcfcfcfcfcfcfcfc&#41;;
  printBB&#40;r2&#41;;
  U64 h1 = l1 | r1;
  printBB&#40;h1&#41;;
  U64 h2 = l2 | r2;
  printBB&#40;h2&#41;;
  return &#40;h1<<16&#41; | &#40;h1>>16&#41; | &#40;h2<<8&#41; | &#40;h2>>8&#41;;
&#125;


int main&#40;int argc, char** argv&#41;
&#123;
  printBB&#40;knightAttacks&#40;1&#41;);
  printBB&#40;knightAttacks&#40;C64&#40;1&#41;<<63&#41;);
  return 0;
&#125;
output should look like:

Code: Select all

0x0000000000000000
0x0000000000000000
0x0000000000000002
0x0000000000000004
0x0000000000000002
0x0000000000000004
0x0000000000020400
0x4000000000000000
0x2000000000000000
0x0000000000000000
0x0000000000000000
0x4000000000000000
0x2000000000000000
0x0020400000000000
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Problem with bitboard knight attack generator

Post by Gerd Isenberg »

Jami wrote:That works fine as well, but I see the problem:

132096 = 0x00020400

You are displaying the results in decimal!
hehehe
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: Problem with bitboard knight attack generator

Post by lucasart »

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
Ypou're right, I didn'# pay close enough attention to the "bit filters" ensuring no shifting was goind "through" the edge of the board.

I use a less subtile but simple and generic code however, allowing me to generate at once king, knoght and pawn attacks.

Code: Select all

static void init_KNP_attacks&#40;)
&#123;
	const int K_dir&#91;8&#93;&#91;2&#93; = &#123;&#123;-1,-1&#125;,&#123;-1,0&#125;,&#123;-1,1&#125;,&#123;0,-1&#125;,&#123;0,1&#125;,&#123;1,-1&#125;,&#123;1,0&#125;,&#123;1,1&#125;&#125;;
	const int N_dir&#91;8&#93;&#91;2&#93; = &#123;&#123;-2,-1&#125;,&#123;-2,1&#125;,&#123;-1,-2&#125;,&#123;-1,2&#125;,&#123;1,-2&#125;,&#123;1,2&#125;,&#123;2,-1&#125;,&#123;2,1&#125;&#125;;
	const int P_dir&#91;NB_COLOR&#93;&#91;2&#93;&#91;2&#93; = &#123; &#123;&#123;1,-1&#125;,&#123;1,1&#125;&#125;, &#123;&#123;-1,-1&#125;,&#123;-1,1&#125;&#125; &#125;;

	for &#40;int sq = A1; sq <= H8; sq++) &#123;
		int r = rank&#40;sq&#41;, f = file&#40;sq&#41;;
		KAttacks&#91;sq&#93; = NAttacks&#91;sq&#93; = 0ULL;

		for &#40;int i = 0; i < 8; i++) &#123;
			int dr = K_dir&#91;i&#93;&#91;0&#93;, df = K_dir&#91;i&#93;&#91;1&#93;;
			if &#40;rank_file_ok&#40;r+dr,f+df&#41;)
				set_bit&#40;&KAttacks&#91;sq&#93;, square&#40;r+dr,f+df&#41;);

			dr = N_dir&#91;i&#93;&#91;0&#93;, df = N_dir&#91;i&#93;&#91;1&#93;;
			if &#40;rank_file_ok&#40;r+dr,f+df&#41;)
				set_bit&#40;&NAttacks&#91;sq&#93;, square&#40;r+dr,f+df&#41;);
		&#125;

		PAttacks&#91;White&#93;&#91;sq&#93; = PAttacks&#91;Black&#93;&#91;sq&#93; = 0ULL;
		for &#40;int i = 0; i < 2; i++)
			for &#40;int c = White; c <= Black; c++) &#123;
				int dr = P_dir&#91;c&#93;&#91;i&#93;&#91;0&#93;, df = P_dir&#91;c&#93;&#91;i&#93;&#91;1&#93;;
				if &#40;rank_file_ok&#40;r+dr,f+df&#41;)
					set_bit&#40;&PAttacks&#91;c&#93;&#91;sq&#93;, square&#40;r+dr,f+df&#41;);
			&#125;
	&#125;
&#125;
I might rewrite my code to use the same tricks. They can also be turned into a more generic function allowing king knoght and pawn attackes to be generated.