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.