Computer Chess Club Archives


Search

Terms

Messages

Subject: C++ chess toolkit code example: check evasion move generation

Author: Steven Edwards

Date: 21:28:35 08/18/03


The C++ chess programming toolkit "CT"  foundation classes continue in their
slow but hopefully sure development. I've included here a sample: the
GeneratePsuedolegalEvasionMoveList method of the CTBBDB (bitboard database)
class.  It has proven fairly effective at avoiding generating psuedolegal but
illegal moves except for perhaps an occasional invalid en passant capture.  I'll
be fixing this later.


CTMoveList *CTBBDB::GeneratePsuedolegalEvasionMoveList(const CTTRIndex
theTRIndex,
    const CTBoard &theBoard, const CTBaseEnv &theBaseEnv) const
{
    CTMoveList *theMoveListPtr = new (theTRIndex) CTMoveList(theTRIndex);
    const CTColor theActiveColor = theBaseEnv.GetActiveColor();
    CTColor thePassiveColor;
    CTMan theActivePawnMan, theActiveKingMan;
    CTSq theActiveKingSq;
    CTRank theSecondRank, theFourthRank, theEighthRank;
    CTDir theAdvDir;
    CTBB theAttackerBB, theActiveManLocusBB, theActivePawnBB, theFlightBB;
    CTBB thePinnedBB, theFrozenBB;
    bool isSingleCheck;

    // Set variables according to active color

    if (IsWhite(theActiveColor))
    {
        thePassiveColor = CTColorBlack;
        theActivePawnMan = CTManWhitePawn;
        theActiveKingMan = CTManWhiteKing;
        theActiveKingSq = RefLocusByMan(CTManWhiteKing).First();
        theSecondRank = CTRank2;
        theFourthRank = CTRank4;
        theEighthRank = CTRank8;
        theAdvDir = CTDirN;
        theAttackerBB = RefAttackToSq(theActiveKingSq) &
RefLocusByColor(CTColorBlack);
        theActiveManLocusBB = RefLocusByColor(CTColorWhite);
        theActivePawnBB = RefLocusByMan(CTManWhitePawn);
        theFlightBB = RefAttackFrSq(theActiveKingSq) - theActiveManLocusBB -
RefAttackByColor(CTColorBlack);
        thePinnedBB = KingPin(CTColorWhite, theActiveKingSq);
        theFrozenBB = Frozen(CTColorWhite, theActiveKingSq, thePinnedBB);
    }
    else
    {
        thePassiveColor = CTColorWhite;
        theActivePawnMan = CTManBlackPawn;
        theActiveKingMan = CTManBlackKing;
        theActiveKingSq = RefLocusByMan(CTManBlackKing).First();
        theSecondRank = CTRank7;
        theFourthRank = CTRank5;
        theEighthRank = CTRank1;
        theAdvDir = CTDirS;
        theAttackerBB = RefAttackToSq(theActiveKingSq) &
RefLocusByColor(CTColorWhite);
        theActiveManLocusBB = RefLocusByColor(CTColorBlack);
        theActivePawnBB = RefLocusByMan(CTManBlackPawn);
        theFlightBB = RefAttackFrSq(theActiveKingSq) - theActiveManLocusBB -
RefAttackByColor(CTColorWhite);
        thePinnedBB = KingPin(CTColorBlack, theActiveKingSq);
        theFrozenBB = Frozen(CTColorBlack, theActiveKingSq, thePinnedBB);
    };

    const unsigned int theAttackerCount = theAttackerBB.Count();
    CTSq theAttackerSq;
    CTMan theAttackerMan;
    bool theAttackerIsOnPromotionRank;

    // Set other locals according to double check status

    if (theAttackerCount > 1) isSingleCheck = false;
    else
    {
        // Only one attacker to the king

        isSingleCheck = true;
        theAttackerSq = theAttackerBB.First();
        theAttackerMan = theBoard.GetSqMan(theAttackerSq);
        theAttackerIsOnPromotionRank = (CTMapNCSqToRank(theAttackerSq) ==
theEighthRank);
    };

    // Attempt non en passant capture of a singleton attacker (no king moves)

    if (isSingleCheck)
    {
        // Get the set of potential capturing men (unpinned only)

        CTBB theCapturingDefenderBB =
            (RefAttackToSq(theAttackerSq) & theActiveManLocusBB) - thePinnedBB;

        // The king doesn't capture in this phase

        theCapturingDefenderBB.ResetSq(theActiveKingSq);

        // Is there at least one potential capturing man?

        if (theCapturingDefenderBB.IsNotEmpty())
        {
            CTSq theCapturingDefenderSq;

            // Try each potential capturing man

            while (IsNotNil(theCapturingDefenderSq =
theCapturingDefenderBB.Next()))
            {
                // Get the potential capturing man

                const CTMan theCapturingDefenderMan =
theBoard.GetSqMan(theCapturingDefenderSq);

                // If a promotion is impossible, then generate a regular capture

                if ((theCapturingDefenderMan != theActivePawnMan) ||
!theAttackerIsOnPromotionRank)
                    theMoveListPtr->
                        ATM(theCapturingDefenderSq, theAttackerSq,
theCapturingDefenderMan, theAttackerMan);
                else
                {
                    // Generate capturing promotions

                    for (unsigned int mscIndex = CTMSCPromoteToQueen;
                        mscIndex >= CTMSCPromoteToKnight; mscIndex--)
                        theMoveListPtr->
                            ATM(theCapturingDefenderSq, theAttackerSq,
                                theCapturingDefenderMan, theAttackerMan,
CTMSC(mscIndex));
                };
            };
        };
    };

    // Attempt king moves

    {
        // Attempt a capture of a singleton attacker by the king

        if (isSingleCheck && theFlightBB.IsSet(theAttackerSq))
        {
            // Generate the king capture of the singleton attacker

            theMoveListPtr->ATM(theActiveKingSq, theAttackerSq,
theActiveKingMan, theAttackerMan);

            // Remove the capture target square from the flight square set

            theFlightBB.ResetSq(theAttackerSq);
        };

        // Remove shadow flight squares

        CTBB theAtkFlightBB = theAttackerBB;
        CTSq theAtkFlightSq;

        while (IsNotNil(theAtkFlightSq = theAtkFlightBB.Next()))
        {
            // Only sweep attackers create shadows

            if (RefLocusSweep().IsSet(theAtkFlightSq))
            {
                // Get the shadow direction

                const CTDir theRetreatFlightDir =
CTK::DirSqSqVec[theAtkFlightSq][theActiveKingSq];

                // Get the square (if any) in the shadow

                const CTSq theRetreatFlightSq =
CTK::NextSqDirVec[theActiveKingSq][theRetreatFlightDir];

                // If there is a shadow square, remove it from the set of flight
squares

                if (IsNotNil(theRetreatFlightSq))
theFlightBB.ResetSq(theRetreatFlightSq);
            };
        };

        // Is there at least one flight square?

        if (theFlightBB.IsNotEmpty())
        {
            CTSq theFlightSq;

            // Generate move to flight squares; may include captures

            while (IsNotNil(theFlightSq = theFlightBB.Next()))
                theMoveListPtr->
                    ATM(theActiveKingSq, theFlightSq, theActiveKingMan,
theBoard.GetSqMan(theFlightSq));
        };
    };

    // Attempt interposition of a singleton sweep attacker (all are non
captures)

    if (isSingleCheck && RefLocusSweep().IsSet(theAttackerSq))
    {
        // Get the interposition pathway

        const CTBB theFixedPathBB =
CTBB::InterSqSqBBVec[theActiveKingSq][theAttackerSq];

        // Check for at least one interposition square

        if (theFixedPathBB.IsNotEmpty())
        {
            // Try non pawn interpositions

            {
                CTBB thePathBB = theFixedPathBB;
                CTSq thePathSq;

                while (IsNotNil(thePathSq = thePathBB.Next()))
                {
                    // Who can interpose? (No frozen men allowed)

                    CTBB theInterposeDefenderBB =
                        (RefAttackToSq(thePathSq) & theActiveManLocusBB) -
theActivePawnBB - theFrozenBB;

                    // The king can't interpose

                    theInterposeDefenderBB.ResetSq(theActiveKingSq);

                    // Are there any possible non pawn interposers?

                    if (theInterposeDefenderBB.IsNotEmpty())
                    {
                        CTSq theInterposeDefenderSq;

                        // Generate each non pawn interposition

                        while (IsNotNil(theInterposeDefenderSq =
theInterposeDefenderBB.Next()))
                            theMoveListPtr->
                                ATM(theInterposeDefenderSq, thePathSq,
                                    theBoard.GetSqMan(theInterposeDefenderSq));
                    };
                };
            };

            // Are there any potential pawn interposers?

            if (theActivePawnBB.IsNotEmpty())
            {
                // Try single advance pawn interpositions (unfrozen)

                CTBB theInterposeDefenderPawn1BB = theActivePawnBB -
theFrozenBB;
                CTSq theInterposeDefenderPawn1Sq;

                while (IsNotNil(theInterposeDefenderPawn1Sq =
theInterposeDefenderPawn1BB.Next()))
                {
                    // Get the single advance square

                    const CTSq theSingleAdvSq =
CTK::NextSqDirVec[theInterposeDefenderPawn1Sq][theAdvDir];

                    // Is the single advance square in the interposition path?

                    if (theFixedPathBB.IsSet(theSingleAdvSq))
                    {
                        // Is the single advance a non promotion?

                        if (CTMapNCSqToRank(theSingleAdvSq) != theEighthRank)
                            theMoveListPtr->
                                ATM(theInterposeDefenderPawn1Sq, theSingleAdvSq,
theActivePawnMan);
                        else
                        {
                            // Generate single advance promotions

                            for (unsigned int mscIndex = CTMSCPromoteToQueen;
                                mscIndex >= CTMSCPromoteToKnight; mscIndex--)
                                theMoveListPtr->
                                    ATM(theInterposeDefenderPawn1Sq,
theSingleAdvSq, theActivePawnMan,
                                        CTManVacant, CTMSC(mscIndex));
                        };
                    };
                };

                // Try double advance pawn interpositions to fourth rank squares

                const CTBB theFourthRankPathBB = theFixedPathBB &
CTBB::RankBBVec[theFourthRank];

                // Is there at least one interposition square

                if (theFourthRankPathBB.IsNotEmpty())
                {
                    // Get all the unfrozen pawns on the second rank

                    CTBB theInterposeDefenderPawn2BB =
                        (theActivePawnBB & CTBB::RankBBVec[theSecondRank]) -
theFrozenBB;

                    // Is there at least one pawn on the second rank?

                    if (theInterposeDefenderPawn2BB.IsNotEmpty())
                    {
                        CTSq theInterposeDefenderPawn2Sq;

                        // Get each pawn on the second rank

                        while (IsNotNil(theInterposeDefenderPawn2Sq =
theInterposeDefenderPawn2BB.Next()))
                        {
                            // Get the single advance square on the third rank

                            const CTSq theSingleAdvSq =
CTK::NextSqDirVec[theInterposeDefenderPawn2Sq][theAdvDir];

                            // Is the single advance square on the third rank
vacant?

                            if (RefLocusMerge().IsReset(theSingleAdvSq))
                            {
                                const CTSq theDoubleAdvSq =
CTK::NextSqDirVec[theSingleAdvSq][theAdvDir];

                                // Get the double advance square on the fourth
rank and check if vacant

                                if (theFourthRankPathBB.IsSet(theDoubleAdvSq))
                                    theMoveListPtr->
                                        ATM(theInterposeDefenderPawn2Sq,
theDoubleAdvSq, theActivePawnMan);
                            };
                        };
                    };
                };
            };
        };
    };

    // Attempt en passant capture

    if (IsNotNil(theBaseEnv.GetEnPassantSq()))
    {
        // Get the pointer to the possible capturing pawn squares

        CTSq *theFrSqPtr =
CTK::NextPawnColorSqPtrVec[thePassiveColor][theBaseEnv.GetEnPassantSq()];
        CTSq theFrSq;

        // Examine each possible capturing pawn square

        while (IsNotNil(theFrSq = *theFrSqPtr++))
        {
            // Is there a potential unfrozen capturing pawn?

            if (theActivePawnBB.IsSet(theFrSq) && theFrozenBB.IsReset(theFrSq))
                theMoveListPtr->
                    ATM(theFrSq, theBaseEnv.GetEnPassantSq(), theActivePawnMan,
CTManVacant, CTMSCEnPassant);
        };
    };

    return (theMoveListPtr);
}




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.