Author: Vasik Rajlich
Date: 07:45:22 01/21/06
Go up one level in this thread
On January 20, 2006 at 12:24:58, Chan Rasjid wrote: >On January 20, 2006 at 09:02:11, Vasik Rajlich wrote: > >>>static const u64 kDzE4 = 0x0000382838000000; >>>static const u64 nDzE4 = 0x0028440044280000; >>> >>> >>>u64 getNMap(int sq){ >>> static const u64 nMask[2] = {FILE_3TO8, FILE_1TO6}; >>> if (sq >= E4) >>> return (nDzE4 << (sq - E4)) & nMask[FILE64(sq) - 4 >> 31 & 1]; >>> return (nDzE4 >> (E4 - sq)) & nMask[FILE64(sq) - 4 >> 31 & 1]; >>>} >>> >>> >>>u64 getKMap(int sq){ >>> static const u64 kMask[2] = {FILE_2TO8, FILE_1TO7}; >>> if (sq >= E4) >>> return (kDzE4 << (sq - E4)) & kMask[FILE64(sq) - 4 >> 31 & 1]; >>> return (kDzE4 >> (E4 - sq)) & kMask[FILE64(sq) - 4 >> 31 & 1]; >>>} >>> >>>Pawns are simple. > >>I'm a little confused as to what exactly you're doing in the above code. For >>example, getting knight target squares is best done via simply: >> >>unsigned int64 knight_targets = knight_target_array [knight_sq] & >>~same_color_pieces; >> > >The reason is I learn / over-learn from Fruit's code and after reading some >articles about "locality of references". u64 knight_target_array [64] == 4 x 128 >bytes. My getNMap() superficially seems ok, by shifting and masking the N-map of >square E4. Fruit's codes seem not to like jumping about a large address space >and tries to work within 128 bytes; any far variables are "copied" as local at >start of domove(), etc... > Aha, it's what I was afraid of :) >>Anyway, it's not clear that an incremental approach is faster - and it's a hell >>of a lot messier. I just compute everything when I need it. >> > >I think "a lot messier" is psychological. I did it very smoothly without any >major hitch and all about 300 lines not counting 100 lines of asserts. >My debug auoplay plays 100+ games an all asserts(30%) cleared. >When I was doing my 16x16 domove() and undomove(), it gave greater problems. > >There is no incremental updates for P/N/K as long as the full maps inclusive of >all terminal pieces are retained. Only on extracting moves do we do an > & ~same_color_piece otherwise it mess up incremental codes. >The seemingly messy incremental is for the sliding pieces. A loop for 4 types is >done - bishop, rook, Q-as-B, Q-as-R and the codes are the same except for minor >differences. Again all terminal pieces have to be retained otherwise it may mess >up incremental codes. I post my sliding incremental codes below. I only have not >tested if it is fast as the extracting moves part is not completed. Those who >know asm may guess if it's ok. > Aha, thanks for the code. I can't really dig into it right now, but will keep it for future reference. At some point I may try an incremental approach in Rybka. Somehow though I doubt it will give more than a few % speedup (if any). Computing attacks from scratch with bitboards is a pretty straightforward operation. Vas >>>3) QS move generation - In the past debate, it seemed no one mentioned this. >>> 90% of all nodes are QS nodes. Getting BB captures are the simplest. With >>>offset we still have to start from the targets and test by sliding thru empty >>>squares etc. So BB here may have a significantly influential advantage. Is this >>>the "secret of Rybka" ? >>> >> >>I don't know that it's really possible to compare board representations, and a >>few % speedup isn't all that important. Bitboards are certainly very elegant >>when it comes to various forms of "selective move generation". >> >>Vas >> >>>Best Regards, >>>Rasjid > >My main incremenatal generation for sliding pieces :- > >#ifndef STACK_H >#define STACK_H > >const int B_Slide = 0; >const int R_Slide = 1; >const int DirDiag7 = 0; >const int DirDiag9 = 1; >const int DirVert = 0; >const int DirHorz = 1; > >//same for p / b >const int DirStep[2][2] = {//[b/r][dir-index] > 15, 17, > 16, 1 >}; > >struct pkMove_t {//sz 16 > u64 bb;// bit and piece have a 1-1 relation for both P/N, so may delete on >//update also in dirDeleted > u64 bal; > // to get bit, shift back to bits[c][Pawns] >}; > >struct nMove_t {//sz 24 > int from; > int nPC; > u64 bb;// bit and piece have a 1-1 relation for both P/N, so may delete on >//update also in dirDeleted > u64 bal; >}; > > >//size = 48 byte >// b/r need 1 element per pc; q need 2 element per pc. >struct brMove_t {//also for king ? > int from; > int padding; > u64 bb[2];// the brq paths with terminal pcs. > u64 dir[2];//full b/r direction bits > u64 bal;//== bb[0] | bb[1], 2 disjoint sets > //u64 bbFrom == bb[0] & bb[1] >}; > >struct moveStack_t { > brMove_t brq[4][4][1];//[ind][pc >>1, 0 = qR, 1 = b, 2 = r, 3 = qB] > brMove_t kQ[2];//must same type to pass as ptr. > pkMove_t pk[4][1]; > nMove_t n[4][1]; > u64 kN;//King as N > int nN; > int nB; > int nR; > int nQ; > u64 padding1; > >}; > >/* > note - pclist index corrupts by search, so cannot use as index to stack-move >index > */ > >//non recursive search stack >struct stack_t { > move_t moveStack[moveStackSize];//tmp, only for 16x16 to debug BB > move_t pv[MaxHeight]; > moveStack_t bbMoveStack[1];//8 x 128 BB move stack > moveStack_t buf[1];//8 x 128 , save at node start, restore on undo > u64 bits[2][8]; > undo_t undo[1];//128 byte > u64 * allBits; > int depth; > int alpha; > int beta; > int best; > > int bestType; > move_t bestMove; > int pvLength; > move_t * pCurrentMove; > > //buffer - save at domove, restore on undomove; todo - may eliminate ? > sq_t sqFrom;//1st in order > sq_t sqCaptureEP; > sq_t sqFromCastleRook; > int fExt; > > int flag; > int incheck; > int nGeneratedMove; > int nMoveDone; > > //follow 3 pulled out of undo, so undo sz == 128 byte > u64 hashKey; > u64 pawnHashKey; > > int promotePc; > int preAlpha; > > int pad1; >}; > >#endif > > >bool_t genIncrementalBB(board_t * board, stack_t * pS, move_t m, incheck_t * >incheck, sq_t sqCaptureEP, const int c, const int side, u64 all){ > static const int DirStep[2][2] = {//[b/r][dir-index] > 15, 17, // b / q-asB > 16, 1 //r / q-as-R >}; > > int i, j; > moveStack_t * const pMS = pS->bbMoveStack; > brMove_t *pElem; > const int *lp, loopPc[] = {// 7 == King as Queen > 1, 2, 3, 7, 0 > }; > > int nK = 1; > int * const nBRQ[] = { > 0, > &pMS->nB,//no of bishop > &pMS->nR, > &pMS->nQ, > 0, > 0, > 0, > &nK > }; >//todo - tmp, some available from bbDoMove(); > u64 u; > u64 bbTo = SQ_BB(TO(m)); > u64 bbFrom = SQ_BB(FROM(m)); > u64 bbCapture = 0; > u64 bbEP_Capture = 0; > u64 * pAttackBB = board->undo->attackBB[c]; > > memset( board->undo->attackBB[c], 0 , sizeof(board->undo->attackBB[c])); > assert(all & bbTo); > if (!IS_MOVE_CAPTURE(m)){ > if (!IS_MOVE_EP(m)); > else{ > bbEP_Capture = SQ_BB(side ? TO(m) - RankStep : TO(m) + RankStep); > } > }else{ > bbCapture = bbTo; > } > > lp = loopPc; > do{ > //pc = *lp << 1; > for ( i = *nBRQ[*lp] - 1; i >= 0; i--){ > j = *lp;// has continue after j = 0 > j < 7 ? (pElem = pMS->brq[i][j]) : (pElem = pMS->kQ); // j == 7 for K-as Q > u = pElem->bb[0] & pElem->bb[1]; > assert(pElem->bb[0]); > assert(pElem->bb[1]); > assert(u == SQ_BB(pElem->from)); > assert((pElem->bb[0] | pElem->bb[1]) == pElem->bal); > assert(j == 3 ? pElem->from == pMS->brq[i][0]->from : 1); > > if (TO(m) != pElem->from){//may be capt of others > if (u & all);//include cstl rook > else{ > //now the pc moves, get full > assert(c == side); > assert(IS_SQ_EMPTY(board->sq[pElem->from])); > if (j == 7)//dont mix- when the king moves; here allow only castle rook > continue; > > if (!IS_MOVE_CSTL(m)) > pElem->from = TO(m); > else{//cstl rook > assert(j == 2); > assert(TO(m) - FROM(m) & 2); > pElem->from = TO(m) - (TO(m) - FROM(m) >> 1); > } > > if (j&1){// bs / q > getBAttackBB_SQ64(pElem, SQ_TO64(pElem->from), > SQ_BB(pElem->from), all); > assert(pElem->bal == getBMap_SQ(pElem->from, all)); > *(pAttackBB + (j << 1)) |= pElem->bal; > } > if ( j & 2){ > if (j == 2); > else{ > pElem = pMS->brq[i][0];//qR > pElem->from = TO(m); > } > getRAttackBB_SQ64(pElem, SQ_TO64(pElem->from), SQ_BB(pElem->from), all); > assert(pElem->bal == getRMap_SQ(pElem->from, all)); > *(pAttackBB + (j << 1)) |= pElem->bal; >} > >assert(pElem->bal == (pElem->bb[0] | pElem->bb[1])); >continue;//next pc same type >} > >Q_ROOK_CUT: > > assert(bbFrom != (pElem->bb[0] & pElem->bb[1]));//not moved > assert(bbTo != (pElem->bb[0] & pElem->bb[1]));//not captured > > if ( !(pElem->bal & (bbTo ^ bbCapture)) ){//usual not a cut > if ( j < 3 || bbCapture);//ok, also for qR j == 0 > else { > j < 7 ? (pElem = pMS->brq[i][j = 0]) : (j = 0, pElem++);//qR > assert((pElem->bb[0] & pElem->bb[1]) == SQ_BB(pElem->from)); > assert((pElem->bb[0] | pElem->bb[1]) == pElem->bal); > u = pElem->bb[0] & pElem->bb[1]; > assert(u == SQ_BB(pElem->from)); > //must loop to do q-as rook > goto Q_ROOK_CUT; > } > }else {// now there is somthing to cut > u64 *pBB; > assert(u == SQ_BB(pElem->from)); > pBB = pElem->bb; > if (*pBB & bbTo); > else { > pBB++; > assert(*pBB & bbTo); > } > pElem->bal ^= *pBB; > if (bbTo < u){ > *pBB &= BITS_GE(bbTo); > }else{ > assert(bbTo > u); > assert( bbTo & BITS_G(u)); > *pBB &= BITS_LE(bbTo); > } > pElem->bal |= *pBB; > >#ifdef _DEBUG > if (pElem->bal == (db_u1 = pElem->bb[0] | pElem->bb[1])); > else{ > printBB("B-bal", pElem->bal, all); > printBB("BB", db_u1, all); > assert(0); > } >#endif > > } > > if ( j ); > else{ > j = *lp;//reset > j < 7 ? (pElem = pMS->brq[i][j] ) : (pElem = pMS->kQ); > u = pElem->bb[0] & pElem->bb[1]; > } > >Q_ROOK_EXT: >// may NOT both cut and ext 1 dir; diff dir ok > if ( !(pElem->bal & bbFrom) ){//usual not an ext > if ( j < 3);//ok, also for qR j == 0 > else { > j < 7 ? (pElem = pMS->brq[i][j = 0]) : (j = 0, pElem++);//qR > assert((pElem->bb[0] & pElem->bb[1]) == SQ_BB(pElem->from)); > assert((pElem->bb[0] | pElem->bb[1]) == pElem->bal); > u = pElem->bb[0] & pElem->bb[1]; > assert(u == SQ_BB(pElem->from)); > //loop to ext q-as-rook > goto Q_ROOK_EXT; > } > }else{ > i64 lb_ub, v; > u64 *pBB, *pDir; > assert(u == SQ_BB(pElem->from)); > pDir = pElem->dir; > pBB = pElem->bb; > if (*pDir & bbFrom); > else {//ext > pDir++; > pBB++; >} > assert(*pBB & bbFrom); > if (bbFrom < u){ > lb_ub = 1; > if ( !(v = all & *pDir & BITS_L(u)) ); > else { > while ( v & v - 1){ > v &= v - 1; > } > lb_ub = v & -v;//lb > // ( i - j ) > 0 has 1's in bit j and the intervening bits > *pBB |= *pDir & (u - lb_ub);// w/o u ok > }else{ > lb_ub = 0x8000000000000000; > assert(bbFrom > u); > v = *pDir & all & BITS_GE(bbFrom); > if ( v &= -v ){ > lb_ub = v;//ub > } > *pBB |= *pDir & ((lb_ub - u) | lb_ub); > } > pElem->bal |= *pBB; > >#ifdef _DEBUG > if (pElem->bal == (db_u1 = pElem->bb[0] | pElem->bb[1])); > else{ > printBB("R-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0); > } >#endif > > } > > if (bbEP_Capture == 0); > else {//rare special ep case > if (bbFrom != bbEP_Capture){ > bbFrom = bbEP_Capture;//may release ext > j = *lp;//reset > j < 7 ? (pElem = pMS->brq[i][j] ) : (pElem = pMS->kQ); > u = pElem->bb[0] & pElem->bb[1]; > goto Q_ROOK_EXT; > } > bbFrom = SQ_BB(FROM(m));//reset > } > >//no need reset j > >#ifdef _DEBUG >//may assert get map only after all cut, extent. > > j = *lp;//reset > if (j == 1){ > if (pElem->bal == (db_u1 = pElem->bb[0] | pElem->bb[1])); > else{ > printBB("B-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0); > } > > db_u1 = getBMap_SQ(pElem->from, all); > if (db_u1 == pElem->bal); > else{ > printBB("B-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0); > } > } > > if (j == 2){ > if (pElem->bal == (db_u1 = pElem->bb[0] | pElem->bb[1])); > else{ > printBB("R-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0); > } > db_u1 = getRMap_SQ(pElem->from, all); > if (db_u1 == pElem->bal); > else{ > printBB("R-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0);// when EP > } > } > > if (j >= 3){ > if (j == 3) > pElem = pMS->brq[i][3]; > else > pElem = pMS->kQ; > > if (pElem->bal == (db_u1 = pElem->bb[0] | pElem->bb[1])); > else{ > printBB("qB-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0); > } > db_u1 = getBMap_SQ(pElem->from, all); > if (db_u1 == pElem->bal); > else{ > printBB("qB-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0);//bal has error, miss end-pc in all > } > > if (j == 3) > pElem = pMS->brq[i][0]; > else > pElem++;// = pMS->kQ; > if (pElem->bal == (db_u1 = pElem->bb[0] | pElem->bb[1])); > else{ > printBB("qR-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0); > } > > db_u1 = getRMap_SQ(pElem->from, all); > if (db_u1 == pElem->bal); > else{ > printBB("qR-bal", pElem->bal, all); > printBB("getBB", db_u1, all); > assert(0);//bal has error, miss end-pc in all > } > } > >#endif >//end debug > >//sum th attacks of same type > if (j == 1 || j == 2) > *(pAttackBB + (j << 1)) |= pElem->bal; > else if (*lp == 3) > *(pAttackBB + Queen) |= pMS->brq[i][3]->bal | pMS->brq[i][0]->bal; > >//NOT when a capture move > if (c != side && *lp < 7){ > pElem = pMS->brq[i][*lp]; > assert(pElem->bal == (pElem->bb[0] | pElem->bb[1])); > if (pElem->bal & board->bits[side][King]){ > assert(brqAttack88(board, board->piece[side][0], c)); > return False; > } > > assert(*lp == 3 ? (pElem - 3)->bal == ((pElem - 3)->bb[0] | (pElem - 3)->bb[1]) > : 1); > > if (*lp == 3 && (pElem - 3)->bal & board->bits[side][King]){ > assert((pElem - 3)->bal == ((pElem - 3)->bb[0] | (pElem - 3)->bb[1])); > assert( pElem - 3 == pMS->brq[i][0]); > assert(brqAttack88(board, board->piece[side][0], c)); > return False; > } > } > }else{//this pc captured. delete > assert(j < 7); > assert(c != side); > assert(IS_MOVE_CAPTURE(m)); > assert(SQ_PIECE(sqCaptureEP) == (j << 1)); > debug_nCapture++; > > (*nBRQ[j])--; > assert(*nBRQ[j] >= 0); > if (*nBRQ[j] == 0 || *nBRQ[j] == i); > else{//pMS->nBRQ now last index > //dele pc and swap pc of last index > *pElem = *pMS->brq[*nBRQ[j]][j];//swap last > if ( j < 3 ); > else > *pMS->brq[i][0] = *pMS->brq[*nBRQ[j]][0];//swap last q-as-R > assert(IS_SQ_ON(board->sq[pElem->from])); > assert(TO(m) != pElem->from); > assert(SQ_PIECE(board->sq[pElem->from]) == (j << 1)); > assert(SQ_COLOR(board->sq[pElem->from]) == c); > } > assert(pElem->bal == (pElem->bb[0] | pElem->bb[1])); > } > > //next pc of same type > }//for > }while ( *++lp ); > >//etc.. trivial for P / n / K > >return True; >}
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.