Understanding first rank attack state generation

Discussion of chess software programming and technical issues.

Moderators: bob, hgm, Harvey Williamson

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
mar
Posts: 2011
Joined: Fri Nov 26, 2010 1:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Understanding first rank attack state generation

Post by mar » Wed Oct 09, 2019 6:53 pm

My guess is because masking by 2*63 already gives you a value that's already multiplied by two, masking out the LSBit
Martin Sedlak

kalyan4code
Posts: 9
Joined: Sun May 12, 2019 11:41 am
Full name: Kalyankumar Ramaseshan

Re: Understanding first rank attack state generation

Post by kalyan4code » Thu Oct 10, 2019 3:21 am

May be correct ("May be!"). But the following argument makes me think otherwise:
When you generate rank attacks (generate_rank_attacks() - see my post earler for the code) it is invoked as:

Code: Select all

generate_rank_attacks(2 * sq, file);
Ideally every square is multiplied by 2 (the multiplication by 2 is needed since the edge bits should be masked and only 6 bits should be considered) and passed as occupancy to generate_rank_attacks() which then works it way through the file bits stopping at the blocker bit in either directions to generate rank attacks. This is when initializing the rank attacks. But what happens when looking up for the rank attacks when you actually get an rank occupancy bitboard is what is shown in the code below:

Code: Select all

BYTE arrFirstRankAttacks64x8[64*8]; // 512 Bytes = 1/2KByte

U64 rankAttacks(U64 occ, enumSquare sq) {
   unsigned int file = sq &  7;
   unsigned int rkx8 = sq & 56; // rank * 8
   occ = (occ >> rkx8) & 2*63;
   U64 attacks = arrFirstRankAttacks64x8[4*occ + file];
   return attacks << rkx8;
}
What I am still not convinced with my understanding and reasoning is this:

When looking up given the rank occupancy bit board after masking it through right shift rank multiplier (rank * 8 - this gets the rank occupancy to LSBits) and masking off LSBits (2 * 63 = 126 = 0b01111110 - take only 6 bits) the calculation of the index using the formula as shown below is still not very clear and I'm not understanding what's written in CPW page regarding scaling by 4 instead of 8. I think this in first place requires a clarification and second the wiki page should be corrected to read the statement properly so that layman like me can understand much better.

Code: Select all

4*occ + file
Thanks,
Kalyan

Gerd Isenberg
Posts: 2128
Joined: Wed Mar 08, 2006 7:47 pm
Location: Hattingen, Germany

Re: Understanding first rank attack state generation

Post by Gerd Isenberg » Thu Oct 10, 2019 5:52 am

kalyan4code wrote:
Thu Oct 10, 2019 3:21 am

Code: Select all

BYTE arrFirstRankAttacks64x8[64*8]; // 512 Bytes = 1/2KByte

U64 rankAttacks(U64 occ, enumSquare sq) {
   unsigned int file = sq &  7;
   unsigned int rkx8 = sq & 56; // rank * 8
   occ = (occ >> rkx8) & 2*63;
   U64 attacks = arrFirstRankAttacks64x8[4*occ + file];
   return attacks << rkx8;
}
What I am still not convinced with my understanding and reasoning is this:

When looking up given the rank occupancy bit board after masking it through right shift rank multiplier (rank * 8 - this gets the rank occupancy to LSBits) and masking off LSBits (2 * 63 = 126 = 0b01111110 - take only 6 bits) the calculation of the index using the formula as shown below is still not very clear and I'm not understanding what's written in CPW page regarding scaling by 4 instead of 8. I think this in first place requires a clarification and second the wiki page should be corrected to read the statement properly so that layman like me can understand much better.

Code: Select all

4*occ + file
Sorry for the confusion. I will comment the routine a little bit more ...

Code: Select all

unsigned int rankOccX2 = (occ >> rkx8) & 2*63; // 2 times the inner six bit rank occupancy used as index
U64 attacks = arrFirstRankAttacks64x8[4*rankOccX2  + file]; // 8 * rank occupancy 

kalyan4code
Posts: 9
Joined: Sun May 12, 2019 11:41 am
Full name: Kalyankumar Ramaseshan

Re: Understanding first rank attack state generation

Post by kalyan4code » Thu Oct 10, 2019 6:04 am

Sorry for the confusion. I will comment the routine a little bit more ...
Thanks Gerd. That was clear to me already. But still my question remains unanswered:
While looking up the rankattacks array the computation if index uses occupancy multipled by 4 instead of 8, why?

Code: Select all

4*occ + file
Thanks,
Kalyan

Gerd Isenberg
Posts: 2128
Joined: Wed Mar 08, 2006 7:47 pm
Location: Hattingen, Germany

Re: Understanding first rank attack state generation

Post by Gerd Isenberg » Thu Oct 10, 2019 9:38 am

Because of the inner six bit mask with 01111110b, which would usually require an additional shift right 1 for a 0..63 range, is already implicitly multiplied by two (0,2,4,....126). With a two-dimensional array it takes one additional instruction ;-)

Code: Select all

BYTE arrFirstRankAttacks64x8[64][8]; // 512 Bytes = 1/2KByte

U64 rankAttacks(U64 occ, enumSquare sq) {
   unsigned int file = sq &  7;
   unsigned int rkx8 = sq & 56; // rank * 8
   occ = ((occ >> rkx8) >> 1) & 63; // occ = (occ >> (rkx8+1)) & 63;
   U64 attacks = arrFirstRankAttacks64x8[occ][file]; // aka 8*occ + file
   return attacks << rkx8;
}

kalyan4code
Posts: 9
Joined: Sun May 12, 2019 11:41 am
Full name: Kalyankumar Ramaseshan

Re: Understanding first rank attack state generation

Post by kalyan4code » Thu Oct 10, 2019 1:30 pm

Gerd Isenberg wrote:
Thu Oct 10, 2019 9:38 am
Because of the inner six bit mask with 01111110b, which would usually require an additional shift right 1 for a 0..63 range, is already implicitly multiplied by two (0,2,4,....126). With a two-dimensional array it takes one additional instruction ;-)

Code: Select all

BYTE arrFirstRankAttacks64x8[64][8]; // 512 Bytes = 1/2KByte

U64 rankAttacks(U64 occ, enumSquare sq) {
   unsigned int file = sq &  7;
   unsigned int rkx8 = sq & 56; // rank * 8
   occ = ((occ >> rkx8) >> 1) & 63; // occ = (occ >> (rkx8+1)) & 63;
   U64 attacks = arrFirstRankAttacks64x8[occ][file]; // aka 8*occ + file
   return attacks << rkx8;
}
Thanks Gerd. Appreciate this level of clarity described in this CPW page/section.
Thanks,
Kalyan

Post Reply