Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: To Steffan, Russell and Gerd

Author: Steffan Westcott

Date: 17:41:10 10/26/02

Go up one level in this thread


On October 26, 2002 at 17:06:53, Peter Fendrich wrote:

>That's what I intended to do but when I started to collect material I discovered
>that too much of the old posts are missing and I'm not familiar with terms like
>Kogge-Stone parallel prefix algorithm , hammer and dumb7fill and maybe others.
>They are frequently referred to and without this basic material it doesn't seem
>to make sense to publish the rest. If someone can't supply me with code or
>definitions I have to wait until the archives are updated.
>Peter

Peter,

Let me provide a summary :

The general discussion here is about generation of attack/move bitboards for
sliding pieces by direct calculation. Each routine considers moves/attacks in
one direction only. Each routine considers all pieces on the board ie. generates
data for all moving pieces simultaneously. The routines do their work by direct
manipulation of the basic bitboards. No lookup tables or rotated bitboards are
used. All of these properties may make this approach attractive for some
architectures, with careful engine design. Mention has been made of the imminent
64-bit Hammer core CPU by AMD, which may benefit bitboard algorithms.

Two methods have been examined. The conceptually easier method has been dubbed
here as a 'flood fill' (a term borrowed from computer graphics), where the fill
proceeds in one direction only. A simple example, showing an upward flood fill :


BitBoard ShiftUp(BitBoard b)
{
    return b << 8;
}


BitBoard FillUpOccluded_flood(BitBoard g, BitBoard p)
{
    for(int n = 0; n < 7; n++)
        g |= ShiftUp(g) & p;
    return g;
}


BitBoard RookAttacksUp(BitBoard rooks, BitBoard empty_squares)
{
    return ShiftUp(FillUpOccluded_flood(rooks, empty_squares));
}


BitBoard RookMovesUp(BitBoard friendly_rooks, BitBoard friendly_pieces,
                     BitBoard empty_squares)
{
    return RookAttacksUp(friendly_rooks, empty_squares) & ~friendly_pieces;
}


The other method is inspired by parallel prefix circuits, a hardware design for
fast carry propagation in adders. The Kogge-Stone method lends itself to
convenient implementation in software, here used to propagate sliding chess
pieces rather than carry bits.

On closer inspection of Russell's code, I spotted some errors, alas. So, here is
the correct version, in full :

// Uses this ordering for bits <-> squares
//
// 56 57 58 59 60 61 62 63
// 48 49 50 51 52 53 54 55
// 40 41 42 43 44 45 46 47
// 32 33 34 35 36 37 38 39
// 24 25 26 27 28 29 30 31
// 16 17 18 19 20 21 22 23
//  8  9 10 11 12 13 14 15
//  0  1  2  3  4  5  6  7

typedef unsigned __int64 BitBoard;

///////////////////////////////////////////////////////////////////////////

BitBoard ShiftRight    (BitBoard b) { return (b<<1) & 0xfefefefefefefefe; }
BitBoard ShiftLeft     (BitBoard b) { return (b>>1) & 0x7f7f7f7f7f7f7f7f; }
BitBoard ShiftUp       (BitBoard b) { return  b<<8; }
BitBoard ShiftDown     (BitBoard b) { return  b>>8; }
BitBoard ShiftUpRight  (BitBoard b) { return (b<<9) & 0xfefefefefefefefe; }
BitBoard ShiftUpLeft   (BitBoard b) { return (b<<7) & 0x7f7f7f7f7f7f7f7f; }
BitBoard ShiftDownRight(BitBoard b) { return (b>>7) & 0xfefefefefefefefe; }
BitBoard ShiftDownLeft (BitBoard b) { return (b>>9) & 0x7f7f7f7f7f7f7f7f; }

///////////////////////////////////////////////////////////////////////////

BitBoard FillRightOccluded(BitBoard g, BitBoard p)
{
           p &= 0xfefefefefefefefe;
           g |= p & (g << 1);
           p &=     (p << 1);
           g |= p & (g << 2);
           p &=     (p << 2);
    return g |= p & (g << 4);
}

BitBoard FillLeftOccluded(BitBoard g, BitBoard p)
{
           p &= 0x7f7f7f7f7f7f7f7f;
           g |= p & (g >> 1);
           p &=     (p >> 1);
           g |= p & (g >> 2);
           p &=     (p >> 2);
    return g |= p & (g >> 4);
}

BitBoard FillUpOccluded(BitBoard g, BitBoard p)
{
           g |= p & (g <<  8);
           p &=     (p <<  8);
           g |= p & (g << 16);
           p &=     (p << 16);
    return g |= p & (g << 32);
}

BitBoard FillDownOccluded(BitBoard g, BitBoard p)
{
           g |= p & (g >>  8);
           p &=     (p >>  8);
           g |= p & (g >> 16);
           p &=     (p >> 16);
    return g |= p & (g >> 32);
}

BitBoard FillUpRightOccluded(BitBoard g, BitBoard p)
{
           p &= 0xfefefefefefefefe;
           g |= p & (g <<  9);
           p &=     (p <<  9);
           g |= p & (g << 18);
           p &=     (p << 18);
    return g |= p & (g << 36);
}

BitBoard FillUpLeftOccluded(BitBoard g, BitBoard p)
{
           p &= 0x7f7f7f7f7f7f7f7f;
           g |= p & (g <<  7);
           p &=     (p <<  7);
           g |= p & (g << 14);
           p &=     (p << 14);
    return g |= p & (g << 28);
}

BitBoard FillDownRightOccluded(BitBoard g, BitBoard p)
{
           p &= 0xfefefefefefefefe;
           g |= p & (g >>  7);
           p &=     (p >>  7);
           g |= p & (g >> 14);
           p &=     (p >> 14);
    return g |= p & (g >> 28);
}

BitBoard FillDownLeftOccluded(BitBoard g, BitBoard p)
{
           p &= 0x7f7f7f7f7f7f7f7f;
           g |= p & (g >>  9);
           p &=     (p >>  9);
           g |= p & (g >> 18);
           p &=     (p >> 18);
    return g |= p & (g >> 36);
}


In the above, g = moving piece(s);  p = empty squares

I posted here a long article on the definition of parallel prefix problems, and
how they could be applied to chess programming. Also, in other threads I've
illustrated algorithms featuring direct calculation with bitboard terms, such as
all shortest path finding. If you want them, I have those posts on file, but
none of the thread context they appeared in.

Feel free to use this material.

Cheers,
Steffan



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.