Author: Uri Blass
Date: 11:55:02 03/24/04
Go up one level in this thread
On March 24, 2004 at 14:49:07, Uri Blass wrote: >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 I forgot to add that I also check in the same condition that the value of SEE is not too high because value of SEE above 20 means capturing the king so I also can get out of the loop. 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.