Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: 0x88 compared to rot BB

Author: Russell Reagan

Date: 16:13:18 01/12/03

Go up one level in this thread


On January 12, 2003 at 17:14:18, Bas Hamstra wrote:

>The
>second function I tested was bool SquareAttacked(int Sq, int ByColor). I was a
>little disappointed to see it is more than 2x slower than my rotated BitBoard
>version.
>
>SquareAttacked per sec:            18181818          8M !!!

I am curious, how are you testing this? Are you using one position and calling
the attack detection function over and over, or by some other method? One
thought I had was that this type of attack detection will *usually* exit quickly
and report that it found no attack. If you are running this test using only one
or a few specific positions, then you might not be testing the *usual* case.
Just a thought.

Also do you have nps numbers for this program yet, compared with some common
programs like Crafty or Yace?

>Below the 0x88 function used for SquareAttacked, which for the moment is the
>fastest I can think of:
>
>bool TBoard::SquareAttacked(int To, int ByColor)
>
>{   int             n,
>                    D,
>                    From,
>                    Type,
>                    Sq,
>                    Count = PieceCount[ByColor];
>
>    if(ByColor==WHITE && Bord[To-17] == 13) return true;
>    if(ByColor==WHITE && Bord[To-15] == 13) return true;
>    if(ByColor==BLACK && Bord[To+17] == 12) return true;
>    if(ByColor==BLACK && Bord[To+15] == 12) return true;
>
>    for(n=0; n<Count; n++)
>    {   From=PieceList[ByColor][n];
>        Type=Bord[From]>>1;
>        if(Type==PAWN) break;
>        if(PseudoAtt[127+To-From] & (1<<Type) )
>        {   if(Type==KING || Type==KNIGHT) return true;
>            D = Dir[127+To-From];
>            for(Sq=From+D; Sq!=To; Sq+=D)
>                if(Bord[Sq]) break;
>            if(Sq==To) return true;
>        }
>    }
>
>    return false;
>}

When I compare your version to the version that Bruce Moreland uses in Gerbil,
there are a few minor differences. First, his attack table is two demensional
and takes the color as one of the indexes, so he eliminates the 4 extra
conditionals that you are using to detect pawn attacks. I'm not sure this would
account for significant slowdowns, but it might be worth a small speed increase.

Another thing I noticed that shouldn't make anything but a tiny difference is
that it would be more efficient to rearrange some logic, for instance, better is
if(Type==KNIGHT || Type==KING) return true;, since the type will more often be a
knight than a king, so the second conditional doesn't have to be evaluated, but
this is certainly no reason for a slowdown. Bruce uses a lookup table to
determine if the piece is a slider or not instead of using two conditionals.

Bruce also rearranges the scanning loop a little, but I think it might only save
1 iteration, and maybe nothing at all (I didn't put much thought into it). Your
functions look basically the same overall. Here is his:

// This determines if "isqDef" is attacked by side "coAtk".
//
// 1. For each	non-dead piece, I will see if it could conceivably attack the
// target square.  A piece can attack a square if one of its rays intersects
// the square.  The 128-element board makes this very easy.  I can take a
// square delta between the attacker and defender, and simply look up in a
// table ("c_argbfRay") to see if a piece of given type has a ray that
// intersects.
//
// With a 64-element board, this will not work, because the delta between h1
// and a2 is the same as the delta between d3 and e3.  With a 128-element
// board, every delta defines a unique relationship between squares.
//
// 2. Once I know that a piece has a ray that intersects, if the piece is not
// a sliding piece, I am done.  Non-sliding pieces are pawns, knights, and
// kings (a king can slide while castling, but that's not a capture).
//
// 3. In the case of sliding pieces (bishop, rook, queen) that have a ray
// that intersects the target square, I look up a step value ("dStep") in
// another table ("c_argdStep"), and just walk the appropriate ray until I
// either hit an interposed piece or arrive at the destination square.
//
// This is an efficient technique because in most cases you know right away
// that an attack can't exist.  In the cases where you know that one might
// exist, it is easy to figure out if one does.

BOOL FAttacked(PCON pcon, int isqDef, int coAtk) {
    int ipi;
    for (ipi = 0; ipi < pcon->argcpi[coAtk]; ipi++) {
        int dStep;
        int isqAtk;
        int pcAtk;
        if (pcon->argpi[coAtk][ipi].fDead)
            continue;
        isqAtk = pcon->argpi[coAtk][ipi].isq;
        pcAtk = pcon->argpi[coAtk][ipi].pc;
        if (c_argbfRay[isqDef - isqAtk + 128] & c_argbfPc[pcAtk][coAtk]) {
            if (!c_argfSliding[pcAtk])
                return fTRUE;
            dStep = c_argdStep[isqDef - isqAtk + 128];
            Assert(dStep != 0);	// Corrupt data check for impossible delta.
            for (;;) {
                isqAtk += dStep;
                Assert(!(isqAtk & 0x88)); // Corrupt data check for off-board.
                if (isqAtk == isqDef)
                    return fTRUE;
                if (pcon->argsq[isqAtk].ppi != NULL)
                    break;
            }
        }
    }
    return fFALSE;
}



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.