Comparison data of Crafty vs Rybka that I promised 2 days ag

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Movei added to Crafty vs Rybka comaprison data

Post by Gerd Isenberg »

Gerd Isenberg wrote: Ok, that don't covers left-to-right mirroring, but what about to flip the complete board after each make/unmake vertically - to make side to move always the "white" side?

That takes almost one bswap for each bitboard and some trick for the hashkey. The additional advantage beside "symmetrical" search would be, that you need to generate only "white" pawn-moves, ep, promotion etc. and that you gain more hash-hits in symmetrical positions ;-)
This is what I had in mind - all color flipped zobrist-keys are byte-swapped as well:

Code: Select all

zobrist[piece][color][sq] == flipVertical(zobrist[piece][color^1][sq^56])

 color = {0:white, 1:black}
 piece = {pawn,knight,bishop,rook,queen,king}
 sq    = {0..63 for a1..h8}

Code: Select all

makeMove (there are only "white" moves, which may capture "black" pieces):

  do the usual incremental update stuff of the board, castle rights, 
  file of possible ep-captures and hashkeys

  flip the board
  (for instance flipVertical four bitboards of a quadbitboard)

  swap castle rights

  flipVertical the hashkeys

  "White" to move again
To cover left-to-right mirroring, what about to keep the "white" king of the side to move always on the e-h files (or the left-right half of the board, where the king was initially placed in chess960). That would require two redundant or ply two distant board-structures and hashkeys - vertically flipped for black to move and not flipped for white to move. Each board may be independently mirrored, indicated by a flag. Only if the king rarely moves from e to d or vice versa (or castles crossing this boarder), a horizontal mirror of the appropriate board, hashkey and ep-file must be applied.

Code: Select all

zobrist[piece][color][sq] == mirrorHorizontal(zobrist[piece][color][sq^7])
As mentioned, the advantage is not only symmetrical search, but pure white move-generation, and "simpler" eval with white to move always and white king on one wing only as well.

Guess one has to take some more care by chosing the randoms for the zobrist keys...

Code: Select all

/**
 * Flip a bitboard vertically, swap rank 1 with 8...
 * @param b any bitboard
 * @return bitboard b flipped
 */
u64 flipVertical(u64 b) {
    return _byteswap_uint64(b);
}

Code: Select all

/**
 * mirror a bitboard horizontally about the centre files,
 * file a is mapped to file h and vice versa.
 * @author Steffan Westcott
 * @param b any bitboard
 * @return bitboard b mirrored horizontally
 */
u64 mirrorHorizontal (u64 b) {
    const u64 k1 = 0x5555555555555555;
    const u64 k2 = 0x3333333333333333;
    const u64 k4 = 0x0f0f0f0f0f0f0f0f;
    b ^= k4 & (b ^ _rotl64(b, 8));
    b ^= k2 & (b ^ _rotl64(b, 4));
    b ^= k1 & (b ^ _rotl64(b, 2));
    return _rotr64(b,7);
}
Gerd
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Movei added to Crafty vs Rybka comaprison data

Post by Gerd Isenberg »

Dann Corbit wrote:
It still seems odd that there should be such a striking difference in tree shape. After all, the pv nodes should determine the shape of the tree. Why doesn't move ordering correct the problem?

Other programs seem to be affected much less. Is it a defect due to the use of bitboards for game state? We should wonder why array type representations do not suffer from the same defect. After all, they have to choose some sort of order for generation also.
Even smallest differences in move ordering may amplify to enormous differences in search behaviour. Mailbox programs may simpler generate moves in symmetrical order. Symmetrical piecelist are an issue as well.
Uri Blass
Posts: 10269
Joined: Thu Mar 09, 2006 12:37 am
Location: Tel-Aviv Israel

Re: Movei added to Crafty vs Rybka comaprison data

Post by Uri Blass »

I think that the main advantage is better detecting of bugs.

It is possible that the search is simply not symmetric between white and black not because of not symmetric order of moves but because of a bug and you do some pruning for white when you do not do it for black.

It may be possible to see that there is a bug easily if you design symmetric search in the first place when you may miss the fact that you have a bug when your search is not supposed to be symmetric.

I think that being able to detect bugs is more important than speed so I think that if I rewrite movei I certainly will try a design of symmetric search in the first place.

Uri
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Movei added to Crafty vs Rybka comaprison data

Post by bob »

aha. Yes that bug is present, always has been, and I did not consider it worth spending a lot of time on...

There's more than enough errors in the q-search already. I doubt this produces a measurable effect.
Edsel Apostol
Posts: 803
Joined: Mon Jul 17, 2006 5:53 am
Full name: Edsel Apostol

Re: Movei added to Crafty vs Rybka comaprison data

Post by Edsel Apostol »

Code: Select all

/********************************************************/
/* this is the position solved by the first SEE */

8  . . . . . b k . 
7  . . . . q p . . 
6  . . R . . . p . 
5  . . r . p . N p 
4  . . p . N . . . 
3  . r . . . . . P 
2  . . . . . P P . 
1  . . Q . . . K . 

   a b c d e f g h 

FEN 5bk1/4qp2/2R3p1/2r1p1Np/2p1N3/1r5P/5PP1/2Q3K1 b - -
1. 0000 BLACK, Castle = 0, Ep = -1, Fifty = 0, Ev = 390, Ph = 17, Ch = F,
H = 0x095786bccec27f94, PH = 0x4b7f411ac2454bbe, MH = 0x8df84a0c65cd6c2c


8  _ _ _ _ _ _ _ _ 
7  _ _ _ _ _ _ _ _ 
6  _ _ _ _ _ _ _ _ 
5  _ _ 1 _ _ _ _ _ 
4  _ _ _ _ 1 _ _ _ 
3  _ 1 _ _ _ _ _ _ 
2  _ _ _ _ _ _ _ _ 
1  _ _ 1 _ _ _ _ _ 

   a b c d e f g h 

move = c4c3

from = 26, pc = 1, slist[0] = 0, dir = 8, lastvalue = 100
lsb = 28, pc = 2, slist[1] = 100, dir = 0, lastvalue = 325
lsb = 17, pc = 4, slist[2] = 225, dir = -1, lastvalue = 500
lsb = 2, pc = 5, slist[3] = 275, dir = -8, lastvalue = 975
lsb = 34, pc = 4, slist[4] = 700, dir = 8, lastvalue = 500
lsb = 42, pc = 4, slist[5] = -200, dir = 8, lastvalue = 500
slist[5] = -200, -slist[4] = -700
slist[4] = 200, -slist[3] = -275
slist[3] = -200, -slist[2] = -225
slist[2] = 200, -slist[1] = -100
slist[1] = -200, -slist[0] = 0
slist[0] = 0

/********************************************************/
/* this is the flipped position solved by the first SEE */

8  . . q . . . k . 
7  . . . . . p p . 
6  . R . . . . . p 
5  . . P . n . . . 
4  . . R . P . n P 
3  . . r . . . P . 
2  . . . . Q P . . 
1  . . . . . B K . 

   a b c d e f g h 

FEN 2q3k1/5pp1/1R5p/2P1n3/2R1P1nP/2r3P1/4QP2/5BK1 w - -
0. ..0000 WHITE, Castle = 0, Ep = -1, Fifty = 0, Ev = 385, Ph = 17, Ch = F,
H = 0x24f8156e7adc9be5, PH = 0x7844c95a8db575be, MH = 0x4e9f270cd0c76f2c


8  _ _ 1 _ _ _ _ _ 
7  _ _ _ _ _ _ _ _ 
6  _ 1 _ _ _ _ _ _ 
5  _ _ _ _ 1 _ _ _ 
4  _ _ 1 _ _ _ _ _ 
3  _ _ _ _ _ _ _ _ 
2  _ _ _ _ _ _ _ _ 
1  _ _ _ _ _ _ _ _ 

   a b c d e f g h 

move = c5c6

from = 34, pc = 1, slist[0] = 0, dir = -8, lastvalue = 100
lsb = 36, pc = 2, slist[1] = 100, dir = 0, lastvalue = 325
lsb = 26, pc = 4, slist[2] = 225, dir = -8, lastvalue = 500
lsb = 18, pc = 4, slist[3] = 275, dir = -8, lastvalue = 500
lsb = 41, pc = 4, slist[4] = 225, dir = -1, lastvalue = 500
lsb = 58, pc = 5, slist[5] = 275, dir = 8, lastvalue = 975
slist[5] = 275, -slist[4] = -225
slist[4] = -275, -slist[3] = -275
slist[3] = 275, -slist[2] = -225
slist[2] = -275, -slist[1] = -100
slist[1] = 100, -slist[0] = 0
slist[0] = -100


/********************************************************/
/* this is the position solved by the second SEE */

8  . . . . . b k . 
7  . . . . q p . . 
6  . . R . . . p . 
5  . . r . p . N p 
4  . . p . N . . . 
3  . r . . . . . P 
2  . . . . . P P . 
1  . . Q . . . K . 

   a b c d e f g h 

FEN 5bk1/4qp2/2R3p1/2r1p1Np/2p1N3/1r5P/5PP1/2Q3K1 b - -
1. 0000 BLACK, Castle = 0, Ep = -1, Fifty = 0, Ev = 390, Ph = 17, Ch = F,
H = 0x095786bccec27f94, PH = 0x4b7f411ac2454bbe, MH = 0x8df84a0c65cd6c2c

from = 26, to = 18, pc = 1, capt = 0

8  _ _ _ _ _ _ _ _ 
7  _ _ _ _ _ _ _ _ 
6  _ _ _ _ _ _ _ _ 
5  _ _ 1 _ _ _ _ _ 
4  _ _ _ _ 1 _ _ _ 
3  _ 1 _ _ _ _ _ _ 
2  _ _ _ _ _ _ _ _ 
1  _ _ 1 _ _ _ _ _ 

   a b c d e f g h 

move = c4c3

see 0: sq = c4, capval = 0, lastval = 100
see 1: sq = e4, capval = 100, lastval = 325
see 2: sq = b3, capval = 225, lastval = 500
see 3: sq = c1, capval = 275, lastval = 975
see 4: sq = c5, capval = 700, lastval = 500
see 5: sq = c6, capval = -200, lastval = 500
value 5 = 200, bestvalue = 700
value 4 = -200, bestvalue = 275
value 3 = 200, bestvalue = 225
value 2 = -200, bestvalue = 100
see 2: sq = c5, capval = 225, lastval = 500
see 3: sq = c6, capval = 275, lastval = 500
see 4: sq = b3, capval = 225, lastval = 500
see 5: sq = c1, capval = 275, lastval = 975
value 5 = -275, bestvalue = 225
value 4 = 275, bestvalue = 275
value 3 = -275, bestvalue = 225
value 2 = 275, bestvalue = -200
value 1 = 200, bestvalue = 0
final see value = 0


/********************************************************/
/* this is the flipped position solved by the second SEE */


8  . . q . . . k . 
7  . . . . . p p . 
6  . R . . . . . p 
5  . . P . n . . . 
4  . . R . P . n P 
3  . . r . . . P . 
2  . . . . Q P . . 
1  . . . . . B K . 

   a b c d e f g h 

FEN 2q3k1/5pp1/1R5p/2P1n3/2R1P1nP/2r3P1/4QP2/5BK1 w - -
0. ..0000 WHITE, Castle = 0, Ep = -1, Fifty = 0, Ev = 385, Ph = 17, Ch = F,
H = 0x24f8156e7adc9be5, PH = 0x7844c95a8db575be, MH = 0x4e9f270cd0c76f2c

from = 34, to = 42, pc = 1, capt = 0

8  _ _ 1 _ _ _ _ _ 
7  _ _ _ _ _ _ _ _ 
6  _ 1 _ _ _ _ _ _ 
5  _ _ _ _ 1 _ _ _ 
4  _ _ 1 _ _ _ _ _ 
3  _ _ _ _ _ _ _ _ 
2  _ _ _ _ _ _ _ _ 
1  _ _ _ _ _ _ _ _ 

   a b c d e f g h 

move = c5c6

see 0: sq = c5, capval = 0, lastval = 100
see 1: sq = e5, capval = 100, lastval = 325
see 2: sq = c4, capval = 225, lastval = 500
see 3: sq = c3, capval = 275, lastval = 500
see 4: sq = b6, capval = 225, lastval = 500
see 5: sq = c8, capval = 275, lastval = 975
value 5 = -275, bestvalue = 225
value 4 = 275, bestvalue = 275
value 3 = -275, bestvalue = 225
value 2 = 275, bestvalue = 100
see 2: sq = b6, capval = 225, lastval = 500
see 3: sq = c8, capval = 275, lastval = 975
see 4: sq = c4, capval = 700, lastval = 500
see 5: sq = c3, capval = -200, lastval = 500
value 5 = 200, bestvalue = 700
value 4 = -200, bestvalue = 275
value 3 = 200, bestvalue = 225
value 2 = -200, bestvalue = 100
value 1 = 200, bestvalue = 0
final see value = 0

Code: Select all

/* this returns the bitboard of all pieces attacking a certain square */
u64 attackingPiecesAll(const position_t *pos, u32 sq){
    u64 attackers = 0;
    
    ASSERT(pos != NULL);
    ASSERT(squareIsOk(sq));
    
    attackers |= PawnCaps[sq][BLACK] & pos->pawns & pos->color[WHITE];
    attackers |= PawnCaps[sq][WHITE] & pos->pawns & pos->color[BLACK];
    attackers |= KnightMoves[sq] & pos->knights;
    attackers |= KingMoves[sq] & pos->kings;
    attackers |= bishopAttacksBB(sq, pos->occupied) & (pos->bishops | pos->queens);
    attackers |= rookAttacksBB(sq, pos->occupied) & (pos->rooks | pos->queens);
    return attackers;
}

/* this returns the bitboard of sliding pieces attacking in a direction 
behind the piece attacker */
u64 behindFigure(u64 QR, u64 QB, u64 occupied, u32 from, int dir){
    
    ASSERT(squareIsOk(from));
    
    switch(dir){
        case -9: return diagonalAttacks(occupied, from) & QB & DirA[0][from];
        case -1: return rankAttacks(occupied, from) & QR & DirA[1][from];
	    case 7: return antiDiagAttacks(occupied, from) & QB & DirA[2][from];
	    case 8: return fileAttacks(occupied, from) & QR & DirA[3][from];
        case 9: return diagonalAttacks(occupied, from) & QB & DirA[4][from];
        case 1: return rankAttacks(occupied, from) & QR & DirA[5][from];
        case -7: return antiDiagAttacks(occupied, from) & QB & DirA[6][from];
        case -8: return fileAttacks(occupied, from) & QR & DirA[7][from];
        default: return 0;
    }
}

/* this is the first SEE routine */

int swapdebug(const position_t *pos, u32 m){
    static const u32 pcval[] = {0, 100, 325, 325, 500, 975, 10000};
    u32 to = moveTo(m);
    u32 from = moveFrom(m);
    u32 pc = movePiece(m);
    u32 lastvalue = pcval[pc];
    u32 n = 1;
    u32 lsb;
    u32 c = pos->side^1;
    int dir = Direction[to][from];
    int slist[32];
    u32 kpos[2];
    u64 attack;

    ASSERT(pos != NULL);
    ASSERT(moveIsOk(m));
    
    kpos[WHITE] = getFirstBit(pos->kings & pos->color[WHITE]);
    kpos[BLACK] = getFirstBit(pos->kings & pos->color[BLACK]);
     
    attack = attackingPiecesAll(pos, to);
    if(!(pc == PAWN && moveCapture(m) == EMPTY)){
        attack ^= BitMask[from];
    }    
    
    slist[0] = pcval[moveCapture(m)];
    
    if(pc == PAWN && PAWN_RANK(from, pos->side) == Rank7) 
            lastvalue = pcval[QUEEN] - pcval[PAWN];
        
    if(dir && pc != KING){ 
        attack |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
        pos->occupied, from, dir);
    }
   
    if(isEnPassant(m)){
        attack |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
        pos->occupied, to, Direction[to][to + ((pos->side == WHITE) ? -8 : 8)]);   
    }
    
    displayBit(attack, 8);
    Print(8, "from = %d, pc = %d, slist[0] = %d, dir = %d, lastvalue = %d\n",
        from, pc, slist[0], dir, lastvalue);
    
    while(attack){
        if(attack & pos->pawns & pos->color[c]){ 
            lsb = getFirstBit(attack & pos->pawns & pos->color[c]); 
            pc = PAWN;
        }else if(attack & pos->knights & pos->color[c]){ 
            lsb = getFirstBit(attack & pos->knights & pos->color[c]); 
            pc = KNIGHT;
        }else if(attack & pos->bishops & pos->color[c]){ 
            lsb = getFirstBit(attack & pos->bishops & pos->color[c]); 
            pc = BISHOP;
        }else if(attack & pos->rooks & pos->color[c]){ 
            lsb = getFirstBit(attack & pos->rooks & pos->color[c]); 
            pc = ROOK;
        }else if(attack & pos->queens & pos->color[c]){ 
            lsb = getFirstBit(attack & pos->queens & pos->color[c]); 
            pc = QUEEN;
        }else if(attack & pos->kings & pos->color[c]){ 
            lsb = getFirstBit(attack & pos->kings & pos->color[c]); 
            pc = KING;
        }else break;
        
        slist[n] = -slist[n-1] + lastvalue;
        if(pc == PAWN && PAWN_RANK(lsb, c) == Rank7) 
            lastvalue = pcval[QUEEN] - pcval[PAWN];
	    else lastvalue = pcval[pc];
        dir = Direction[to][lsb];
        
        Print(8, "lsb = %d, pc = %d, slist[%d] = %d, dir = %d, lastvalue = %d\n",
        lsb, pc, n, slist[n], dir, lastvalue);
        
        if(dir && pc != KING) 
            attack |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
            pos->occupied, lsb, dir);
        attack ^= BitMask[lsb];
        n++;
        c ^= 1;        
    }
    while(--n){
        Print(8, "slist[%d] = %d, -slist[%d] = %d\n", n, slist[n], n-1, -slist[n-1]);
        if(slist[n] > -slist[n-1]) 
            slist[n-1] = -slist[n];
    }
    Print(8, "slist[0] = %d\n", slist[0]);
    return slist[0];
}

Code: Select all

/* this is the second SEE */
int see(const position_t *pos, u32 move){
    int from = moveFrom(move);
    int to = moveTo(move);
    int pc = movePiece(move);
    int capt = moveCapture(move);
    int lastval = PcVal[pc];
    int capval = PcVal[capt];
    u64 attacks = attackingPiecesAll(pos, to);
    u64 attackers, defenders;
    int temp;
    
    if(!(pc == PAWN && capt == EMPTY)){
        attacks ^= BitMask[from];
    }    

    if(pc == PAWN && PAWN_RANK(from, pos->side) == Rank7) 
        lastval = PcVal[QUEEN] - PcVal[PAWN];
    
    if(Direction[to][from] && pc != KING){ 
        attacks |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
        pos->occupied, from, Direction[to][from]);
    }
   
    if(isEnPassant(move)){
        attacks |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
        pos->occupied, to, Direction[to][to + ((pos->side == WHITE) ? -8 : 8)]);   
    }
    
    Print(8, "from = %d, to = %d, pc = %d, capt = %d\n",
    from, to, pc, capt);
    displayBit(attacks, 8); 
    
    attackers = attacks & pos->color[pos->side];
    defenders = attacks & ~attackers;
    
    Print(8, "see %d: sq = %s, capval = %d, lastval = %d\n", 0, sq2Str(from), 
        capval, lastval); 
    temp = newswap(pos, attackers, defenders, capval, lastval, to, pos->side^1, 1);    
    Print(8, "final see value = %d\n\n", temp); 
    return temp; 
}

int newswap(const position_t *pos, u64 dfndrs, u64 atkrs, int capval, 
int lastval, int to, int side, int ply){
    int pc, value, sq, tempvalue, lastpiece = EMPTY, bestvalue = capval,
    hasbehind = FALSE;
    u64 atkrsclone = atkrs;
    u64 temp;
    
    while(atkrsclone){
        sq = getLeastAtkr(pos, &pc, &atkrsclone); 
           
        if(pc == PAWN && PAWN_RANK(sq, side) == Rank7) 
            lastval = PcVal[QUEEN] - PcVal[PAWN];
        
        temp = 0;
        if(Direction[to][sq] && pc != KING){ 
            temp = behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
            pos->occupied, sq, Direction[to][sq]);
            hasbehind = TRUE;
        }
        
        if(lastpiece != EMPTY){
            if(pc != lastpiece) return bestvalue;
            if(!hasbehind) continue;
        }    
        
        lastpiece = pc;
        
        tempvalue = -capval + lastval;
        Print(8, "see %d: sq = %s, capval = %d, lastval = %d\n", 
            ply, sq2Str(sq), tempvalue, PcVal[pc]); 
            
        value = -newswap(pos, ((atkrs & ~BitMask[sq]) | temp & pos->color[side]), 
            (dfndrs | temp & pos->color[side^1]), tempvalue, PcVal[pc], 
            to, side^1, ply+1);
            
        Print(8, "value %d = %d, bestvalue = %d\n", ply, value, bestvalue); 

        if&#40;value < bestvalue&#41; bestvalue = value; 
    &#125;    
    return bestvalue;
&#125;

int getLeastAtkr&#40;const position_t *pos, int *pc, u64 *atkrs&#41;&#123;
    int sq;
    u64 x;
    
    if&#40;x = pos->pawns & *atkrs&#41;&#123;
        *pc = PAWN;
    &#125;else if&#40;x = &#40;pos->knights|pos->bishops&#41; & *atkrs&#41;&#123;
        *pc = KNIGHT;
    &#125;else if&#40;x = pos->rooks & *atkrs&#41;&#123;
        *pc = ROOK;
    &#125;else if&#40;x = pos->queens & *atkrs&#41;&#123;
        *pc = QUEEN;
    &#125;else if&#40;x = pos->kings & *atkrs&#41;&#123;
        *pc = KING;
    &#125;else&#123;
        ASSERT&#40;FALSE&#41;;    
    &#125;          
    sq = getFirstBit&#40;x&#41;;   
    *atkrs ^= BitMask&#91;sq&#93;; 
    return sq;
&#125;
Note that in my engine I uses a1 = 0, ..., h8 = 63, pawn = 1, ..., king = 6.

Notice that the value of the first SEE on the position is 0 while the value of the first SEE on the flipped position is -100. This is where I failed in my Eval Symmetry test.

I think that 0 is the correct value.

In the value of the second SEE for the position and its flipped counterpart, it returns 0 for both sides.

I have not tested this much though. I don't know if the added accuracy can compensate for the little speed loss.

By the way, the routine I wrote is just the first working version so it might have bugs and it can still be optimized. It is also possible that it can include checks someday, or it could develop into a Super SOMA type of routine and maybe replace the quiescent search altogether. Just my crazy ideas. :)
Dann Corbit
Posts: 12538
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Movei added to Crafty vs Rybka comaprison data

Post by Dann Corbit »

concerning:
Edsel Apostol wrote:

Code: Select all

&#123;snip&#125;

int getLeastAtkr&#40;const position_t *pos, int *pc, u64 *atkrs&#41;&#123;
    int sq;
    u64 x;
    
    if&#40;x = pos->pawns & *atkrs&#41;&#123;
        *pc = PAWN;
    &#125;else if&#40;x = &#40;pos->knights|pos->bishops&#41; & *atkrs&#41;&#123;
        *pc = KNIGHT;
    &#125;else if&#40;x = pos->rooks & *atkrs&#41;&#123;
        *pc = ROOK;
    &#125;else if&#40;x = pos->queens & *atkrs&#41;&#123;
        *pc = QUEEN;
    &#125;else if&#40;x = pos->kings & *atkrs&#41;&#123;
        *pc = KING;
    &#125;else&#123;
        ASSERT&#40;FALSE&#41;;    
    &#125;          
    sq = getFirstBit&#40;x&#41;;   
    *atkrs ^= BitMask&#91;sq&#93;; 
    return sq;
&#125;
Why not:

Code: Select all

int getLeastAtkr&#40;const position_t *pos, int *pc, u64 *atkrs&#41;&#123;
    int sq;
    u64 x;
    
    if&#40;x = pos->pawns & *atkrs&#41;&#123;
        *pc = PAWN;
    &#125;else if&#40;x = &#40;pos->knights&#41; & *atkrs&#41;&#123;
        *pc = KNIGHT;
    &#125;else if&#40;x = &#40;pos->bishops&#41; & *atkrs&#41;&#123;
        *pc = BISHOP;
    &#125;else if&#40;x = pos->rooks & *atkrs&#41;&#123;
        *pc = ROOK;
    &#125;else if&#40;x = pos->queens & *atkrs&#41;&#123;
        *pc = QUEEN;
    &#125;else if&#40;x = pos->kings & *atkrs&#41;&#123;
        *pc = KING;
    &#125;else&#123;
        ASSERT&#40;FALSE&#41;;    
    &#125;          
    sq = getFirstBit&#40;x&#41;;   
    *atkrs ^= BitMask&#91;sq&#93;; 
    return sq;
&#125;

It seems to me that returning an ambiguous piece could be harmful in some situtations (e.g. if you should ever use it for something other than pure counting).
Edsel Apostol
Posts: 803
Joined: Mon Jul 17, 2006 5:53 am
Full name: Edsel Apostol

Re: Movei added to Crafty vs Rybka comaprison data

Post by Edsel Apostol »

Dann Corbit wrote:concerning:
Edsel Apostol wrote:

Code: Select all

&#123;snip&#125;

int getLeastAtkr&#40;const position_t *pos, int *pc, u64 *atkrs&#41;&#123;
    int sq;
    u64 x;
    
    if&#40;x = pos->pawns & *atkrs&#41;&#123;
        *pc = PAWN;
    &#125;else if&#40;x = &#40;pos->knights|pos->bishops&#41; & *atkrs&#41;&#123;
        *pc = KNIGHT;
    &#125;else if&#40;x = pos->rooks & *atkrs&#41;&#123;
        *pc = ROOK;
    &#125;else if&#40;x = pos->queens & *atkrs&#41;&#123;
        *pc = QUEEN;
    &#125;else if&#40;x = pos->kings & *atkrs&#41;&#123;
        *pc = KING;
    &#125;else&#123;
        ASSERT&#40;FALSE&#41;;    
    &#125;          
    sq = getFirstBit&#40;x&#41;;   
    *atkrs ^= BitMask&#91;sq&#93;; 
    return sq;
&#125;
Why not:

Code: Select all

int getLeastAtkr&#40;const position_t *pos, int *pc, u64 *atkrs&#41;&#123;
    int sq;
    u64 x;
    
    if&#40;x = pos->pawns & *atkrs&#41;&#123;
        *pc = PAWN;
    &#125;else if&#40;x = &#40;pos->knights&#41; & *atkrs&#41;&#123;
        *pc = KNIGHT;
    &#125;else if&#40;x = &#40;pos->bishops&#41; & *atkrs&#41;&#123;
        *pc = BISHOP;
    &#125;else if&#40;x = pos->rooks & *atkrs&#41;&#123;
        *pc = ROOK;
    &#125;else if&#40;x = pos->queens & *atkrs&#41;&#123;
        *pc = QUEEN;
    &#125;else if&#40;x = pos->kings & *atkrs&#41;&#123;
        *pc = KING;
    &#125;else&#123;
        ASSERT&#40;FALSE&#41;;    
    &#125;          
    sq = getFirstBit&#40;x&#41;;   
    *atkrs ^= BitMask&#91;sq&#93;; 
    return sq;
&#125;

It seems to me that returning an ambiguous piece could be harmful in some situtations (e.g. if you should ever use it for something other than pure counting).
Hi Dan,

I think that the KNIGHT and BISHOP have the same level or value as a Least Valuable Attacker so I merge them into one. In the old SEE it is always the knight first that is being tried. It might be possible that the bishop instead of the knight when tried first in the capture sequence will result into a more accurate value for the SEE.

Maybe my logic is wrong but that's how I think of it. :)

Edsel Apostol (Twisted Logic)
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Movei added to Crafty vs Rybka comaprison data

Post by Gerd Isenberg »

Gerd Isenberg wrote:

Code: Select all

makeMove &#40;there are only "white" moves, which may capture "black" pieces&#41;&#58;

  do the usual incremental update stuff of the board, castle rights, 
  file of possible ep-captures and hashkeys

  flip the board with swapped colors
  &#40;for instance flipVertical four bitboards of a quadbitboard&#41;

  swap castle rights

  flipVertical the hashkeys

  "White" to move again
Of course the color bitboards need to swap as well for vertical flip.

A 64-char mailbox array might be color flipped quite efficiently with sse2-instructions. Some assembly on the fly assuming empty squares are zero and bit 0 of the pieces are their color:

Code: Select all

; rcx &#40;ecx&#41; - pointer to 128-bit aligned source board array
; rdx &#40;edx&#41; - pointer to 128-bit aligned  destination 
;                  for the color  flipped board
 pxor    xmm4, xmm4 ; zero
 pcmpeqb xmm5, xmm5 ; -1
; get the source board into four xmm registers
 movdqa  xmm0, &#91;rcx&#93;
 movdqa  xmm1, &#91;rcx+16&#93;
 movdqa  xmm2, &#91;rcx+32&#93;
 movdqa  xmm3, &#91;rcx+48&#93;
; empty squares becomes 0xff, pieces 00
 pcmpeqb xmm0, xmm4
 pcmpeqb xmm1, xmm4
 pcmpeqb xmm2, xmm4
 pcmpeqb xmm3, xmm4
; add one to get the color flipper bit
 psubb   xmm0, xmm5
 psubb   xmm1, xmm5
 psubb   xmm2, xmm5
 psubb   xmm3, xmm5
; flip the colors of all pieces
 pxor    xmm0, &#91;rcx&#93;
 pxor    xmm1, &#91;rcx+16&#93;
 pxor    xmm2, &#91;rcx+32&#93;
 pxor    xmm3, &#91;rcx+48&#93;
; swap consecutive ranks
 pshufd  xmm0, xmm0, 0x4e
 pshufd  xmm1, xmm1, 0x4e
 pshufd  xmm2, xmm2, 0x4e
 pshufd  xmm3, xmm3, 0x4e
; store as flipped board
 movdqa  &#91;rdx&#93;, xmm3
 movdqa  &#91;rdx+16&#93;, xmm2
 movdqa  &#91;rdx+32&#93;, xmm1
 movdqa  &#91;rdx+48&#93;, xmm0