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.