Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: questions.

Author: Uri Blass

Date: 11:49:07 03/24/04

Go up one level in this thread


On March 24, 2004 at 12:04:36, Tord Romstad wrote:

>On March 24, 2004 at 11:30:49, Daniel Shawul wrote:
>
>>Hi
>>
>>Is it too costy to add checks only for captures in quiescent.
>>In my engine non capture checks decrease nps significantly.May be it is because
>>it is hard [at least for me] to generate only checking moves.But the capture
>>checks seem to work good in test suites and practically no decrease in nps in
>>actual play.Has any one have the same experience.
>
>I've found that generating checks (including non-captures and discovered
>checks) isn't that expensive, and that it pays off.  A few hints:
>
>1. Don't generate checks immediately.  Generate and search captures and
>promotions first.  Only when all captures and promotions have been searched
>and you still don't have a cutoff, consider generating checks.
>
>2. Don't search checks at all qnodes.  If the side to move has a winning
>material advantage, or if one of the captures searched gave a winning
>advantage (but still not big enough to cause a cutoff), searching checks
>is probably not worth the effort.  Other factors to consider is the king
>safety of the opponent (checks are more likely to be effective if the
>opponent's king is exposed) and the path leading to the node (if there
>were many checks, mate threats and other attacking moves in the last few
>plies, checks are more likely to be important).
>
>3. Use your SEE to cull losing checks, like you (probably) already do for
>captures.
>
>>Another completely different question.
>>Can attack tables efficently replace the conventional SEE routine.
>>Ed says in his paper he uses a table look up scheme to find hanging pieces.
>>But what about pinned attackers? [which the conventional SEE handles well].
>>Also i can't see how a table indexed by the two 8-bit variables give an
>>approximation of the SEE outcome.
>>for example if rebel's wb[sq] = 110 11000  [3 white attacks by pawns and
>>knights]. How do i know whether it is 2 pawns and 1 kinght or 2 kinghts and a
>>pawn attacking the square?
>
>You don't.  You simply have to make a guess.  In Gothmog, I always assume
>that the smallest-valued pieces are most numerous.  In the case above, I
>assume 2 pawns and 1 knight.
>
>>I think using this method for see will make the already inaccurate SEE worse.
>>Am i right?
>
>Yes.  If you are worried about it, you can teach your program to recognize
>the cases when the attack table based SEE is likely to be wrong, and use a
>conventional SEE in these cases.  Call the regular SEE when there is a pin,
>or when the number of attackers is bigger than the different types of pieces.
>I did this until very recently, but have now removed it in order to make
>things simpler.  It has no noticable effect at all on Gothmog's strength.
>
>In case you're interested, you'll find the code for my attack-table-based
>SEE below.  My attack tables are currently identical to Ed's, but instead
>of using a lookup table I calculate the SEE value from the attack table
>entries and store the results in a small hash table.  The hash table is
>optional, you can enable or disable it by #defining or #undefining
>SEE_CACHE.  The code is loosely based on the SEE in Crafty (thanks, Bob).
>
>If you find this code useful, you (and everybody else, of course) are free
>to use it in any way you want.
>
>
>#if defined(SEE_CACHE)
>uint32 SeeCache[256];
>uint32 VZob1[256], VZob2[256], PieceZob[13];
>
>void init_see_cache() {
>  int i;
>  for(i=0; i<13; i++) PieceZob[i] = Random32();
>  for(i=0; i<256; i++) VZob1[i] = Random32();
>  for(i=0; i<256; i++) VZob2[i] = Random32();
>  for(i=0; i<256; i++) SeeCache[i] = 0; }
>#endif
>
>
>/* Value of smallest attacking piece */
>uint8 SmallestAttacker[256] = {
>  10, 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
>  5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
>  10, 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
>  5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
>  100, 100, 100, 100, 100, 100, 100, 100, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
>  5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
>  10, 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
>  5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1,
>  3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1 };
>
>
>/* New attack vector with smallest attacker removed */
>uint8 SmallestRemoved[256] = {
>  0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 9, 10, 11, 12, 13, 14, 0, 0, 17, 18, 19, 20,
>  21, 22, 15, 16, 17, 26, 27, 28, 29, 30, 0, 0, 33, 34, 35, 36, 37, 38, 31, 32,
>  33, 42, 43, 44, 45, 46, 31, 32, 33, 50, 51, 52, 53, 54, 47, 48, 49, 50, 59,
>  60, 61, 62, 0, 0, 65, 66, 67, 68, 69, 70, 63, 64, 65, 74, 75, 76, 77, 78, 63,
>  64, 65, 82, 83, 84, 85, 86, 79, 80, 81, 82, 91, 92, 93, 94, 63, 64, 65, 98,
>  99, 100, 101, 102, 95, 96, 97, 98, 107, 108, 109, 110, 95, 96, 97, 98, 115,
>  116, 117, 118, 111, 112, 113, 114, 115, 124, 125, 126, 0, 0, 129, 130, 131,
>  132, 133, 134, 127, 128, 129, 138, 139, 140, 141, 142, 127, 128, 129, 146,
>  147, 148, 149, 150, 143, 144, 145, 146, 155, 156, 157, 158, 127, 128, 129,
>  162, 163, 164, 165, 166, 159, 160, 161, 162, 171, 172, 173, 174, 159, 160,
>  161, 162, 179, 180, 181, 182, 175, 176, 177, 178, 179, 188, 189, 190, 127,
>  128, 129, 194, 195, 196, 197, 198, 191, 192, 193, 194, 203, 204, 205, 206,
>  191, 192, 193, 194, 211, 212, 213, 214, 207, 208, 209, 210, 211, 220, 221,
>  222, 191, 192, 193, 194, 227, 228, 229, 230, 223, 224, 225, 226, 227, 236,
>  237, 238, 223, 224, 225, 226, 227, 244, 245, 246, 239, 240, 241, 242, 243,
>  244, 253 };
>
>
>/* Piece values, P=1, N=B=3, R=5, Q=10, K=100 */
>uint8 CompactPieceValues[16] = {0, 1, 3, 3, 5, 10, 100, 1, 3, 3, 5, 10, 100};
>
>
>/* compute_see() is the attack table based SEE routine.
> * piece = The piece under attack.
> * u1 = WhiteAttacks[square containing piece]
> * u2 = BlackAttacks[square containing piece]
> * Returns the expected value of capturing the piece. */
>
>int compute_see(int piece, int u1, int u2) {
>  int attackers[16];
>  int i=1, colour=BLACK, attacked, pc;
>  int v[2];
>#if defined(SEE_CACHE)
>  uint32 key, index;
>#endif
>
>  if(piece==0) return 0;
>  if(piece<=WK) {v[0] = u2; v[1] = u1;} else {v[0] = u1; v[1] = u2;};
>  if(v[0]==0) return 0;
>  if(v[1]==0) return CompactPieceValues[piece];
>
>#if defined(SEE_CACHE)
>  key = PieceZob[piece]^VZob1[u1]^VZob2[u2];
>  index = key&0xFF;
>  if((SeeCache[index]&0xFFFFFF00)==(key&0xFFFFFF00))
>    return SeeCache[index]&0xFF;
>#endif
>
>  attackers[0] = CompactPieceValues[piece];
>  attacked = SmallestAttacker[v[0]];
>  v[0] = SmallestRemoved[v[0]];
>
>  do {
>    pc = SmallestAttacker[v[colour]];
>    v[colour] = SmallestRemoved[v[colour]];
>    attackers[i] = -attackers[i-1]+attacked;
>    attacked = pc;
>    i++;
>    colour^=1;
>  } while(v[colour]);
>
>  while(--i)
>    if(attackers[i] > -attackers[i-1]) attackers[i-1] = -attackers[i];
>  if(attackers[0]<0) attackers[0] = 0;
>
>#if defined(SEE_CACHE)
>  SeeCache[index] = (key&0xFFFFFF00)|attackers[0];
>#endif
>
>  return attackers[0]; }
>
>
>/* End of code */
>
>
>Tord


I do not understand your arrays

What is the reason that SmallestAttacker[0]=10?
Based on Rebel attack table there should be no attackers in that case.

Note that I also has similiar code to Crafty to calculate SEE but I decided to
have in my code before i++ when I translate it to your varaibles:

If (i>1)&&(attackers[i]>attackers[i-2]+attacked)
{
 i++;
 break;
}

The logic is that there are cases when the rest of the pieces are simply not
relevant to decide about the value of SEE.

If I have BxP QXB RxQ then it is clear that the value of see is one pawn and I
do not need to calculate more captures in the same square.

I generalized this example to find the formula that I give here.
Note that I do not know if it helps Crafty in speed because the if command may
make things slower but I decided that for my slow SEE it is probably better to
check if I can generate a cut off based on previous captures in order not to
calculate the smallest attacker again.

I almost do not use SEE in my program today and I guess that I may compare speed
with the if and without the if when I decide to use it more.

Uri



This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.