TweetFollow Us on Twitter

Aug 95 Challenge
Volume Number:11
Issue Number:8
Column Tag:Programmer’s Challenge

Programmer’s Challenge

By Bob Boonstra, Westford, Massachusetts

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Diff-Warrior

Authors frequently use a software tool to compare different versions of the same document and identify what changes have been made between versions. Something like the well-known diff utility for programmers, but operating on a words instead of a lines. This month your Challenge is to write a simplified version of such a file comparison tool.

The prototype of the code you should write is:

#define ulong unsigned long

typedef enum { 
/* describes type of text change between old and new versions of text */
  deletedText=0, insertedText, movedText } DiffType;

typedef struct {
DiffType type;
/* The meaning of the remaining fields depends on type.
    For type == deletedText:
    rangeStart -   offset in oldText of first char deleted
    rangeEnd -     offset in oldText of last char deleted
    position -  offset in newText before which text would be inserted to convert 
    newText into oldText
    For type == insertedText:
    rangeStart -   offset in newText of first char inserted
    rangeEnd -     offset in newText of last char inserted
    position -  offset in oldText before which text would be inserted to convert 
    oldText into newText
    For type == movedText:
    rangeStart-    offset in oldText of first char moved
    rangeEnd-      offset in oldText of last char moved
     position-  offset in oldText before which text would be inserted to convert 
    oldText into newText
*/
ulong rangeStart; 
ulong rangeEnd;
ulong position; 
} DiffRec;

short /* numDiffsFound */ FindWordDifferences (
char *oldText,     /* pointer to old version of text */
char *newText,     /* pointer to new version of text */
ulong numOldChars, /* number of characters in oldText */
ulong numNewChars, /* number of characters in newText */
DiffRec diffs[],   /* pointer to preallocated array where text differences are to 
  be stored */
ulong maxDiffRecs  /* number of DiffRecs preallocated */
);

FindWordDifferences should store a DiffRec in the diffs array for each sequence of words that were deleted or moved from oldText, and for each sequence inserted into newText. So, for example, if newText and oldText contained the following characters

oldText->The quick brown fox jumps over the lazy dog.
newText->The brown and white lazy fawn jumps over the dog.

you would return the value 5 and store the following into the diffs array:

diffs[0]={deletedText,  4, 9, 4}  (deleted "quick ")
diffs[1]={insertedText,10,19,16}  (inserted "and white ")
diffs[2]={movedText,   35,39,16}  (moved "lazy ")
diffs[3]={deletedText, 16,18,25}  (deleted "fox")
diffs[4]={insertedText,25,28,16}  (inserted "fawn")

The solution to this problem is clearly not unique. For example, each problem has a trivial solution where all of the oldText is deleted, and all of the newText is inserted. To encourage nontrivial and optimal solutions, selection of the winner will be based on the quality of the FindWordDifferences job you do, as well as how quickly you find a solution. Quality will be measured first by the number of characters deleted, inserted, and moved (the sum of the (rangeEnd-rangeStart+1) values in your DiffRec array), and next on the number of differences found (numDiffsFound), with smaller being better in both cases. The fastest solution within 10% of the best quality score (both parameters) will be declared the winner. These criteria place a premium on finding movedText (as opposed to deletedText / insertedText pairs) and on finding larger contiguous sections of inserted / deleted text (as opposed to sequences of smaller changes).

Now for the fine print. Notice that the comparison is based on words, not just on characters (look at “fox” and “fawn” above), so be careful when calculating offsets. Words are delimited by white space (spaces, CR, NL, tabs), or punctuation. Extra/missing white space and/or punctuation should also result in a DiffRec. Your solution should be case sensitive (i.e., “The” is different from “the”). You may not change the input text pointed to by newText and oldText. The DiffRec offsets calculated by your program should apply to the unchanged input oldText and newText (i.e., they should be independent of changes implied by any other DiffRecs). Correctness will be determined by using the DiffRecs you produce to convert the oldText into the newText, and vice versa (ignoring CRs and NLs). In doing the conversions, the DiffRecs will be applied in order of decreasing position / rangeStart value, and (in case of duplicates) in reverse order of the DiffRec array. Testing will use text files averaging 5-20K characters in size, and at least one test case will exceed 64K.

Thanks to the generosity of Metrowerks, who provided a copy of CodeWarrior for use in the Challenge, and in response to requests from several readers, this Challenge will be scored using the CodeWarrior compiler. The target instruction set is the 680x0 family; I’ll be testing on a 68040. (We’ll have a PowerPC Challenge in a couple of months.)

Finally, I want to express the gratitude that all Challenge participants feel toward Mike Scanlin for his excellent work writing this column. I am honored to have the opportunity to take over and hope to maintain the high standard Mike set. If any of you have suggestions on how to make the column and the Challenge even better, please send them to me at one of the Programmer’s Challenge e-mail addresses, or directly to boonstra@ultranet.com.

Two Months Ago Winner

Apparently there are at least a few chess players among MacTech Challenge readers. Of the six entries I received for the Check Checkmate Challenge, four worked correctly. Congratulations to Gary Beith (Largo, FL) for his efficient and instructive solution. Gary’s win is especially notable because this is his first entry in the Programmer’s Challenge.

Here are the times and code sizes for the entries that worked correctly. Numbers in parens after a person’s name indicate that person’s cumulative point total for all previous Challenges, not including this one:

Name time code

Gary Beith 188 4282

Ernst Munter (60) 260 19810

Xan Gregg (24) 639 4242

David Rees 2919 2604

Gary’s solution demonstrates several features associated with efficient solutions. He employs an appropriate representation of the problem data, including a chessboard representation that includes a border area, allowing efficient computation of chess moves with a minimum of special code for board boundaries. Gary takes maximal advantage of the untimed initialization routine, setting up move tables for each type of chesspiece. The problem statement provides opportunities for optimization; in this case, the problem is a legal chess position, and Gary uses that to determine whether a move places the opponent’s king in check. He applies knowledge of the problem domain to limit the number of possibilities his code examines, for example, by identifying which pieces are pinned and which axes of movement need not be considered, and in constraining the possible moves for the case of a king in check. Gary’s solution is not only an excellent one for the specific problem posed, but offers an instructive approach to Challenges in general. Nice job!

Top 20 Contestants of All Time

Here are the Top 20 Contestants for the 36 Programmer’s Challenges to date. The numbers below include points awarded for this month’s entrants. (Note: ties are listed alphabetically by last name - there are 25 people listed this month because 6 people have 20 points each.)

1. [Name deleted] 176

2. Karsh, Bill 71

3. Munter, Ernst 70

4. Stenger, Allen 65

5. Larsson, Gustav 60

6. Riha, Stepan 51

7. Goebel, James 49

8. Nepsund, Ronald 47

9. Cutts, Kevin 46

10. Mallett, Jeff 44

11. Kasparian, Raffi 42

12. Vineyard, Jeremy 40

13. Darrah, Dave 31

14. Gregg, Xan 31

15. Landry, Larry 29

16. Elwertowski, Tom 24

17. Lee, Johnny 22

18. Noll, Robert 22

19. Anderson, Troy 20

20. Beith, Gary 20

21. Burgoyne, Nick 20

22. Galway, Will 20

23. Israelson, Steve 20

24. Landweber, Greg 20

25. Pinkerton, Tom 20

There are three ways to earn points: (1) scoring in the top 5 of any Challenge, (2) being the first person to find a bug in a published winning solution or, (3) being the first person to suggest a Challenge that I use. The points you can win are:

1st place 20 points

2nd place 10 points

3rd place 7 points

4th place 4 points

5th place 2 points

finding bug 2 points

suggesting Challenge 2 points

Here is Gary’s winning solution:


ChessMoveEnumerator.c

Copyright ©1995 Gary Beith

/* =========================================================
Objective: To determine all legal moves (excluding castling and en passant captures) available for a given 
chess position.  It is NOT required to single out intelligent moves!
========================================================= */

/* ---------------------------------------------------------
    Items required by the problem statement
--------------------------------------------------------- */

#pragma options ( mc68020, !mc68881, require_protos )
#pragma options ( pack_enums, align_arrays )

typedef enum { rowA = 0, rowB, rowC, rowD, rowE, rowF, rowG, 
    rowH } Row;
typedef enum { col1 = 0, col2, col3, col4, col5, col6, col7,
    col8 } Col;
typedef enum { whiteSide = 0, blackSide } Side;
typedef enum { king = 0, queen, rook, bishop, knight, pawn }
    ChessPiece;

typedef struct Square {
 Row    row;
 Col    col;
} Square;

typedef struct PiecePosition {
 Square sq;
 Side   side;
 ChessPiece piece;
} PiecePosition;

typedef struct ChessMove {
 Square fromSq;
 Square toSq;
 BooleanmoveIsCapture;
 BooleanopponentPlacedInCheck;
} ChessMove;

short /* numberOfMoves */ LegalChessMoves(
 PiecePosition piecePositionArray[],
 short  numberOfPieces,
 Side   sideToMove,
 ChessMovelegalMoveArray[],
 void   *privateDataPtr
);

void InitChess(void *privateDataPtr);


/* =========================================================
    From here on, I’m on my own :-)
========================================================= */

#define kMaxChessPiece    pawn

typedef Square *SquarePtr;
typedef PiecePosition *PiecePosPtr;
typedef ChessMove *ChessMovePtr;

typedef enum {
 stmPawnSq0 = 0, stmPawnSq1, stmPieceSq0, stmPieceSq1,
 offBoardSq0, offBoardSq1, emptySq0, emptySq1,
 oppPieceSq0, oppPieceSq1, oppPawnSq0, oppPawnSq1
} MySquare, *MySquarePtr;

/* 
The attack flag is used to denote squares near the King known to be under attack, thus preventing the King 
from moving to them.  State “0” for each square type represents attack flag not set, state “1” represents 
flag set.  The attack mask is used to clear the flag when testing for empty squares.
 */
#define kAttackFlag0x01
#define kAttackMask0x0e

typedef char MySquareIncr, *MySqIncrPtr;
typedef unsigned char MyAxis, *MyAxisPtr;
typedef short MySquareDiff, *MySqDiffPtr;

typedef struct {
 MySqIncrPtrsqIncrArrayPtr;
 MyAxisPtraxisArrayPtr;
 short  numberOfAxes;
} MyPieceTable;

typedef struct {
 MySquarePtrsqPtr;
 MyPieceTable    pcTable;
 Square fromSq;
 MyAxis discAxis, pinAxis;
} MyPiece, *MyPiecePtr, **MyPieceHandle;

typedef struct {
 MyPieceHandle   pcHandle;
 MyPieceTable    pcTable;
 MySquare sqType;
} MyPieceInfo, *MyPcInfoPtr;

/* 
    My internal square numbering scheme:
  ** Opponent **
 [175] -   -   - .... -   - [185]
   -   -   -   - .... -   -   -   -   -   -   - [174]
   -   - (145) - .... - (152) -   -   -   -   -   -
  < six more rows here >
   -   - ( 33) - .... - ( 40) -   -   -   -   -   -
 [ 15] -   -   - .... -   -   -   -   -   -   -   -
     [  0] -   - .... -   -   -   -   -   -   - [ 14]
  ** Side to move **

Numbers in parentheses indicate corners of the actual chess board.  Some reasons for choosing this scheme:
1.A border of at least two off-board squares is provided around the board to facilitate the determination of 
valid Knight moves.
2.Adjacent squares in a column have an absolute index difference of 16 (efficient power of 2).  A difference 
of at least 15 was required so that index values for squares in the same row would always differ by less than 
those for squares in different rows.
3.The perspective of the side to move is used rather than that of either White or Black exclusively.  This 
enables the identical move enumeration algorithm to be used for either side - differences such as pawn movement 
direction are accounted for when converting from and to the problem statement’s board format.
*/
#define kLowerLeftSqIndex 33
#define kMin4thRankSqIndex81
#define kMin5thRankSqIndex97
#define kMin8thRankSqIndex145
#define kUpperRightSqIndex152
#define kMaxSqIndex185

/* Maximum square index differential on the board = kUpperRightSqIndex - kLowerLeftSqIndex */
#define kMaxSqDiff 119

/* 
For purposes of this program, “long move” pieces are defined as consisting of Queens, Rooks, and Bishops. 
 These pieces may move as many unobstructed spaces in each of their permitted directions as are available 
on the board.  The maximum counts given for long move pieces and Knights allow for the potential for all 
eight Pawns to romote to such pieces.
*/
#define kMaxLongMovePieces13
#define kMaxKnights10
#define kMaxPawns8
 
typedef struct {
 MyPiecePtr endSTMKingPtr, endOppKingPtr,
 endSTMLMPiecePtr, endOppLMPiecePtr,
 endSTMKnightPtr, endOppKnightPtr,
 endSTMPawnPtr;
 MySquare sqArray[kMaxSqIndex + 1];
} MyChessBoard;

typedef struct {
 MyChessBoard  chessBoard, emptyBoard;
 MyPiecestmKing, oppKing,
 stmLMPieceArray[kMaxLongMovePieces],
 oppLMPieceArray[kMaxLongMovePieces],
 stmKnightArray[kMaxKnights],
 oppKnightArray[kMaxKnights],
 stmPawnArray[kMaxPawns];
 MyPiecePtr pcPtrArray[kMaxSqIndex + 1];
 Square whiteSqArray[kMaxSqIndex + 1],
 blackSqArray[kMaxSqIndex + 1];
 SquarePtrstmSqArrayPtr;
 MyPieceInfostmPcInfoArray[kMaxChessPiece + 1],
 oppPcInfoArray[kMaxChessPiece + 1];
 MySquareIncr  queenSqIncrArray[2 * kMaxSqDiff + 1],
 rookSqIncrArray[2 * kMaxSqDiff + 1],
 bishopSqIncrArray[2 * kMaxSqDiff + 1];
 BooleanknightMoveArray[2 * kMaxSqDiff + 1];
 MyAxis queenAxisArray[4], rookAxisArray[2],
 bishopAxisArray[2];
 MySquareDiff  knightSqDiffArray[8],
 kingSqDiffArray[8];
} MyData, *MyDataPtr;

Local function prototypes

void SetUpMyChessBoard(MyDataPtr dataPtr,
  PiecePosition piecePositionArray[],
  short numberOfPieces,
  Side sideToMove);

short FindChecksAndPins(MyDataPtr dataPtr,
 MySquarePtr *checkSqHandle,
 MySquareIncr *checkSqIncrPtr);

void EnumerateNonKingMoves(MyDataPtr dataPtr,
 ChessMovePtr *moveHandle);

void EnumerateNonKingCapturesOfCheckingPiece(      
 MyDataPtr dataPtr,
 MySquarePtr checkSqPtr,
 ChessMovePtr *moveHandle);

void EnumerateInterpositionMoves(MyDataPtr dataPtr,
 MySquarePtr checkSqPtr,
   MySquareIncr checkSqIncr,
   ChessMovePtr *moveHandle);

void EnumerateKingMoves(MyDataPtr dataPtr,
 ChessMovePtr *moveHandle);


LegalChessMoves

/* =========================================================
    Timed legal move enumeration routine
========================================================= */

short LegalChessMoves(PiecePosition piecePositionArray[],
 short numberOfPieces,
 Side sideToMove,
 ChessMove legalMoveArray[],
 void *privateDataPtr)
{
 MyDataPtrdataPtr = privateDataPtr;
 short  numberOfChecks;
 MySquarePtrcheckSqPtr;
 MySquareIncr    checkSqIncr;
 ChessMovePtr    movePtr = legalMoveArray;

 SetUpMyChessBoard(dataPtr, piecePositionArray,
 numberOfPieces, sideToMove);

 numberOfChecks = FindChecksAndPins(dataPtr, &checkSqPtr,
  &checkSqIncr);


 if (numberOfChecks == 0)
 {
 EnumerateNonKingMoves(dataPtr, &movePtr);
 }
 else if (numberOfChecks == 1)
 {
 EnumerateNonKingCapturesOfCheckingPiece(dataPtr,              
 checkSqPtr,
 &movePtr);
 if (checkSqIncr)
 {
 EnumerateInterpositionMoves(dataPtr, checkSqPtr,
 checkSqIncr, &movePtr);
 }
 }
    /* else if (numberOfChecks == 2)
     Only King moves are possible (if any exist). */

 EnumerateKingMoves(dataPtr, &movePtr);

 return (movePtr - legalMoveArray); /* Number of moves */
}


SetUpMyChessBoard

void SetUpMyChessBoard(MyDataPtr dataPtr,
  PiecePosition piecePositionArray[],
  short numberOfPieces,
  Side sideToMove)
{
 PiecePosPtrposPtr, endPosPtr;
 short  sqIndex;
 MyPcInfoPtrpcInfoPtr;
 MySquarePtrsqPtr;
 MyPiecePtr pcPtr;

 dataPtr->chessBoard = dataPtr->emptyBoard;

 posPtr = piecePositionArray;
 endPosPtr = posPtr + numberOfPieces;


 if (sideToMove) /* == blackSide */
 {
 dataPtr->stmSqArrayPtr = dataPtr->blackSqArray;
 do
 {
 sqIndex = kUpperRightSqIndex -
 ((posPtr->sq.row << 4) + posPtr->sq.col);

 pcInfoPtr = (posPtr->side) ?
 dataPtr->stmPcInfoArray + posPtr->piece :
 dataPtr->oppPcInfoArray + posPtr->piece;

 sqPtr  = dataPtr->chessBoard.sqArray + sqIndex;
 if ((*sqPtr = pcInfoPtr->sqType) != oppPawnSq0)
 {
 dataPtr->pcPtrArray[sqIndex] =
 pcPtr = (*pcInfoPtr->pcHandle)++;

 pcPtr->sqPtr = sqPtr;
 pcPtr->pcTable = pcInfoPtr->pcTable;
 pcPtr->fromSq = posPtr->sq;
 pcPtr->discAxis = pcPtr->pinAxis = 0;
 }
 }
 while (++posPtr != endPosPtr);
 }
 else
 {
 dataPtr->stmSqArrayPtr = dataPtr->whiteSqArray;
 do
 {
 sqIndex = kLowerLeftSqIndex +
 ((posPtr->sq.row << 4) + posPtr->sq.col);

 pcInfoPtr = (posPtr->side) ?
 dataPtr->oppPcInfoArray + posPtr->piece :
 dataPtr->stmPcInfoArray + posPtr->piece;

 sqPtr  = dataPtr->chessBoard.sqArray + sqIndex;
 if ((*sqPtr = pcInfoPtr->sqType) != oppPawnSq0)
 {
 dataPtr->pcPtrArray[sqIndex] =
 pcPtr = (*pcInfoPtr->pcHandle)++;

 pcPtr->sqPtr = sqPtr;
 pcPtr->pcTable = pcInfoPtr->pcTable;
 pcPtr->fromSq = posPtr->sq;
 pcPtr->discAxis = pcPtr->pinAxis = 0;
 }
 }
 while (++posPtr != endPosPtr);
 }
}


FindChecksAndPins

short FindChecksAndPins(MyDataPtr dataPtr,
 MySquarePtr *checkSqHandle,
 MySquareIncr *checkSqIncrPtr)
{
 MySquarePtrkingSqPtr, sqPtr;
 MyPiecePtr endPcPtr, pcPtr;
 short  sqIncr, stmPcSqIndex, numberOfChecks = 0;

/* 
Since I must report all moves which place the opponent in check, I first scan for possible discovered checks. 
 These occur when only one piece (which must belong to the side to move) stands between one of the mover’s 
long move pieces and the enemy King, and that piece is moved off of the line of attack.  Because I am only 
required to analyze legal positions, I know that at least one piece will exist on any such line of attack.
*/
 kingSqPtr = dataPtr->oppKing.sqPtr;

 endPcPtr = dataPtr->chessBoard.endSTMLMPiecePtr;
 for (pcPtr = dataPtr->stmLMPieceArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 sqPtr = pcPtr->sqPtr;
 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [kingSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 continue;/* King not “in line” with this piece */

 sqPtr += sqIncr;
 stmPcSqIndex = 0;
 while (*sqPtr <= emptySq1) /* Not opponent’s piece */
 {
 if (*sqPtr < emptySq0)   /* Is mover’s piece */
 {
 if (stmPcSqIndex)
 break; /* More than one piece in its path */

 stmPcSqIndex = sqPtr - dataPtr->chessBoard.sqArray;
 }

 if ((sqPtr += sqIncr) == kingSqPtr)
 {
    /* Record line of attack for future reference */
 dataPtr->pcPtrArray[stmPcSqIndex]->discAxis =
 (sqIncr < 0) ? -sqIncr : +sqIncr;
 break;
 }
 }
 }

/* 
A similar analysis determines if any pieces are“pinned," i.e., they stand in the way of an attack on the mover’s 
King by an enemy piece.  A pinned piece can move only along the line of attack (if such a move is permitted 
for the piece; in particular, a pinned Knight is never able to move).
*/
 kingSqPtr = dataPtr->stmKing.sqPtr;

 endPcPtr = dataPtr->chessBoard.endOppLMPiecePtr;
 for (pcPtr = dataPtr->oppLMPieceArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 sqPtr = pcPtr->sqPtr;
 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [kingSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 continue;

 if ((sqPtr += sqIncr) == kingSqPtr)
 {
/* 
Piece is adjacent to King.  The King may capture it if it is not protected by another piece.  However, no interposition 
moves are possible.
*/
 sqPtr[+sqIncr] |= kAttackFlag;
 *checkSqHandle = pcPtr->sqPtr;
 *checkSqIncrPtr = 0;
 numberOfChecks++;
 continue;
 }

 stmPcSqIndex = 0;
 while (*sqPtr <= emptySq1)
 {
 if (*sqPtr < emptySq0)
 {
 if (stmPcSqIndex)
 break;

 stmPcSqIndex = sqPtr - dataPtr->chessBoard.sqArray;
 }

 if ((sqPtr += sqIncr) == kingSqPtr)
 {
 if (stmPcSqIndex) /* Pinned piece was found */
 {
 dataPtr->pcPtrArray[stmPcSqIndex]->pinAxis =
 (sqIncr < 0) ? -sqIncr : +sqIncr;
 }
 else
 {
/* 
King is in check “from a distance.”  If the King moves, it must leave the line of attack, which is recorded so 
that interposition moves can be determined later on.
*/
 sqPtr[+sqIncr] |= kAttackFlag;
 sqPtr[-sqIncr] |= kAttackFlag;
 *checkSqHandle = pcPtr->sqPtr;
 *checkSqIncrPtr = sqIncr;
 numberOfChecks++;
 }

 break;
 }
 }
 }

/* 
The maximum number of checks possible is two, only one of which can come from a Pawn or Knight.
*/
 if (numberOfChecks < 2)
 {
/* 
Per ANSI standard, a sequence point occurs after the evaluation of each operand of the Logical Or and Logical 
And operators.  Therefore, I can validly rely on the value of sqPtr being set in exactly the order specified 
in the next expression (and others like it). That is not generally true of most other operators.
*/
 if ((*(sqPtr = kingSqPtr + 15) >= oppPawnSq0) ||
 (*(sqPtr += 2) >= oppPawnSq0))
 {
 *checkSqHandle = sqPtr;
 *checkSqIncrPtr = 0;
 numberOfChecks++;
 }
 else
 {
 endPcPtr = dataPtr->chessBoard.endOppKnightPtr;
 for (pcPtr = dataPtr->oppKnightArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 sqPtr = pcPtr->sqPtr;
 if (dataPtr->knightMoveArray
 [kingSqPtr - sqPtr + kMaxSqDiff])
 {
 *checkSqHandle = sqPtr;
 *checkSqIncrPtr = 0;
 numberOfChecks++;
 break;
 }
 }
 }
 }

 return numberOfChecks;
}


EnumerateNonKingMoves

void EnumerateNonKingMoves(MyDataPtr dataPtr,
  ChessMovePtr *moveHandle)
{
 MySquarePtroppKingSqPtr, toSqPtr, sqPtr;
 MyPiecePtr endPcPtr, pcPtr;
 MyAxisPtraxisPtr, endAxisPtr;
 short  toSqIncr, sqIncr, toSqIndex;
 ChessMovePtr    movePtr = *moveHandle;
 MySqDiffPtrsqDiffPtr, endSqDiffPtr;

 oppKingSqPtr = dataPtr->oppKing.sqPtr;

 endPcPtr = dataPtr->chessBoard.endSTMLMPiecePtr;
 for (pcPtr = dataPtr->stmLMPieceArray;
  pcPtr < endPcPtr; pcPtr++)
 {
/* 
The move table for long move pieces consists of a set of axes of movement for the particular type of piece 
(i.e., Queen, Rook, or Bishop).  The positive and negative values of each axis are used as square increments, 
beginning at the piece’s current square pointer, and continuing until further movement is blocked by another 
piece or by the end ofthe board. In the event the blockage is caused by an oppenent’s piece, one additional 
move results; that of capturing the piece by moving onto its square.
*/
 axisPtr = pcPtr->pcTable.axisArrayPtr;
 endAxisPtr = axisPtr + pcPtr->pcTable.numberOfAxes;
 do
 {
 if (pcPtr->pinAxis && (pcPtr->pinAxis != *axisPtr))
 continue; /* Piece is pinned on some other axis */

 toSqIncr = *axisPtr;
 do
 {
 toSqPtr = pcPtr->sqPtr;
 do
 {
 if (*(toSqPtr += toSqIncr) < emptySq0)
 break; /* Square off-board or holds own piece */

 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq =
 dataPtr->stmSqArrayPtr
 [toSqPtr - dataPtr->chessBoard.sqArray];
 movePtr->moveIsCapture = (*toSqPtr > emptySq1);

/* 
If a long move piece has a discovered check axis, it is not able to move along that axis.  Otherwise, it would 
be checking the enemy King, and the position would not be legal with this side to move.  Therefore, any move 
of such a piece will result in a discovered check.
*/
 if (pcPtr->discAxis)
 {
 (movePtr++)->opponentPlacedInCheck = true;
 continue;
 }

 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [oppKingSqPtr - toSqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 continue;
 }

/* 
Scan along the path to the enemy King from the target square for this move.  If the first occupied square 
is that of the King, a check will result from the move; otherwise, no check.
*/
 sqPtr = toSqPtr;
 do
 {
 sqPtr += sqIncr;
 }
 while ((*sqPtr & kAttackMask) == emptySq0);

 (movePtr++)->opponentPlacedInCheck =
 (sqPtr == oppKingSqPtr);
 }
 while (*toSqPtr <= emptySq1);
 }
 while ((toSqIncr = -toSqIncr) < 0);
 }
 while (++axisPtr != endAxisPtr);
 }

 endPcPtr = dataPtr->chessBoard.endSTMKnightPtr;
 for (pcPtr = dataPtr->stmKnightArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 if (pcPtr->pinAxis)
 continue;

 toSqPtr = pcPtr->sqPtr;

/* 
Unlike long move pieces, each move of a Knight may be evaluated independently from all of its other moves. 
 Thus, the move table consists of a set of relative square differentials, each added in turn to the previous 
move’s square pointer, rather than basing all of the moves on the Knight’s current square pointer.
*/
 sqDiffPtr = dataPtr->knightSqDiffArray;
 endSqDiffPtr = sqDiffPtr + 8;
 do
 {
 if (*(toSqPtr += *sqDiffPtr) >= emptySq0)
 {
 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq =
 dataPtr->stmSqArrayPtr
 [toSqPtr - dataPtr->chessBoard.sqArray];
 movePtr->moveIsCapture = (*toSqPtr > emptySq1);
 (movePtr++)->opponentPlacedInCheck =
 (pcPtr->discAxis ||
  dataPtr->knightMoveArray
  [oppKingSqPtr - toSqPtr + kMaxSqDiff]);
 }
 }
 while (++sqDiffPtr != endSqDiffPtr);
 }

 endPcPtr = dataPtr->chessBoard.endSTMPawnPtr;
 for (pcPtr = dataPtr->stmPawnArray;
  pcPtr < endPcPtr; pcPtr++)
 {
/* 
Pawns require two different move evaluations; one for captures, and a different one for non-capture moves.
*/
 for (toSqIncr = 15; toSqIncr <= 17; toSqIncr += 2)
 {
 if ((pcPtr->pinAxis &&
  (pcPtr->pinAxis != toSqIncr)) ||
 (*(toSqPtr = pcPtr->sqPtr + toSqIncr) <=
  emptySq1))
 {
 continue; /* Pawn pinned or no capture available */
 }

 toSqIndex = toSqPtr - dataPtr->chessBoard.sqArray;

 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = dataPtr->stmSqArrayPtr[toSqIndex];
 movePtr->moveIsCapture = true;

 if (pcPtr->discAxis)
 {
 (movePtr++)->opponentPlacedInCheck = true;
 continue;
 }

 if (toSqIndex < kMin8thRankSqIndex)
 {
 (movePtr++)->opponentPlacedInCheck =
 (((toSqPtr + 15) == oppKingSqPtr) ||
  ((toSqPtr + 17) == oppKingSqPtr));
 continue;
 }

/* 
Pawn promotion brings up two interesting points.  One, the value of “opponentPlacedInCheck” becomes 
ambiguous, since the Pawn can promote to a Queen, Rook, Bishop, or Knight, and the squares that it attacks 
will vary accordingly.  Since a Pawn most often promotes to a Queen, I have chosen to set “opponentPlacedInCheck” 
on that basis.  The second point concerns the “ghost image” of the Pawn after it moves.  In other cases, 
it does not matter that the piece being moved is still recorded as being on its original square, since a line 
of attack to the enemy King which goes through that square must be blocked anyway; otherwise, the piece 
would have checked the King from its original square, and the position would be illegal.  In the case of a promoted 
Pawn, however, this assumption does not hold true.  Therefore, I compare the square pointer with the Pawn’s 
original position; if they match, I treat the square as though it were empty.
*/
 sqIncr = dataPtr->queenSqIncrArray
  [oppKingSqPtr - toSqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 continue;
 }

 sqPtr = toSqPtr;
 do
 {
 sqPtr += sqIncr;
 }
 while (((*sqPtr & kAttackMask) == emptySq0) ||
  (sqPtr == pcPtr->sqPtr));

 (movePtr++)->opponentPlacedInCheck =
 (sqPtr == oppKingSqPtr);
 }

 if (pcPtr->pinAxis & 0x0f) /* i.e., axis not 0 or 16 */
 continue;

/* 
Ordinarily, the Pawn advances only one square, but it may continue to a second square if it is not blocked 
and has not yet reached the fourth rank.
*/
 toSqPtr = pcPtr->sqPtr;
 do
 {
 if ((*(toSqPtr += 16) & kAttackMask) != emptySq0)
 break;

 toSqIndex = toSqPtr - dataPtr->chessBoard.sqArray;

 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = dataPtr->stmSqArrayPtr[toSqIndex];
 movePtr->moveIsCapture = false;

 if (pcPtr->discAxis & 0x0f)
 {
 (movePtr++)->opponentPlacedInCheck = true;
 continue;
 }

 if (toSqIndex < kMin8thRankSqIndex)
 {
 (movePtr++)->opponentPlacedInCheck =
 (((toSqPtr + 15) == oppKingSqPtr) ||
  ((toSqPtr + 17) == oppKingSqPtr));
 continue;
 }

 sqIncr = dataPtr->queenSqIncrArray
  [oppKingSqPtr - toSqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 break;
 }

 sqPtr = toSqPtr;
 do
 {
 sqPtr += sqIncr;
 }
 while (((*sqPtr & kAttackMask) == emptySq0) ||
  (sqPtr == pcPtr->sqPtr));

 (movePtr++)->opponentPlacedInCheck =
 (sqPtr == oppKingSqPtr);
 break;
 }
 while (toSqIndex < kMin4thRankSqIndex);
 }

 *moveHandle = movePtr;
}


EnumerateNonKingCapturesOfCheckingPiece

void EnumerateNonKingCapturesOfCheckingPiece
  (MyDataPtr dataPtr,
   MySquarePtr checkSqPtr,
 ChessMovePtr *moveHandle)
{
 MySquarePtroppKingSqPtr, sqPtr;
 short  checkSqIndex, sqIncr, fromSqIncr;
 Square checkSq;
 MyPiecePtr endPcPtr, pcPtr;
 ChessMovePtr    movePtr = *moveHandle;

 oppKingSqPtr = dataPtr->oppKing.sqPtr;

 checkSqIndex = checkSqPtr - dataPtr->chessBoard.sqArray;
 checkSq = dataPtr->stmSqArrayPtr[checkSqIndex];

 endPcPtr = dataPtr->chessBoard.endSTMLMPiecePtr;
 for (pcPtr = dataPtr->stmLMPieceArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 if (pcPtr->pinAxis)
 continue;

 sqPtr = pcPtr->sqPtr;
 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [checkSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 continue;

 do
 {
 sqPtr += sqIncr;
 }
 while((*sqPtr & kAttackMask) == emptySq0);

 if (sqPtr != checkSqPtr)
 continue;

 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = checkSq;
 movePtr->moveIsCapture = true;

 if (pcPtr->discAxis)
 {
 (movePtr++)->opponentPlacedInCheck = true;
 continue;
 }

 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [oppKingSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 continue;
 }

 do
 {
 sqPtr += sqIncr;
 }
 while ((*sqPtr & kAttackMask) == emptySq0);

 (movePtr++)->opponentPlacedInCheck =
 (sqPtr == oppKingSqPtr);
 }

 endPcPtr = dataPtr->chessBoard.endSTMKnightPtr;
 for (pcPtr = dataPtr->stmKnightArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 if (pcPtr->pinAxis == 0)
 {
 if (dataPtr->knightMoveArray
 [checkSqPtr - pcPtr->sqPtr + kMaxSqDiff])
 {
 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = checkSq;
 movePtr->moveIsCapture = true;
 (movePtr++)->opponentPlacedInCheck =
 (pcPtr->discAxis ||
  dataPtr->knightMoveArray
  [oppKingSqPtr - checkSqPtr + kMaxSqDiff]);
 }
 }
 }

 for (fromSqIncr = 15; fromSqIncr <= 17; fromSqIncr += 2)
 {
 if (*(sqPtr = checkSqPtr - fromSqIncr) > stmPawnSq1)
 continue; /* Square does not contain mover’s Pawn */

 pcPtr = dataPtr->pcPtrArray
 [sqPtr - dataPtr->chessBoard.sqArray];
 if (pcPtr->pinAxis)
 continue;

 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = checkSq;
 movePtr->moveIsCapture = true;

 if (pcPtr->discAxis)
 {
 (movePtr++)->opponentPlacedInCheck = true;
 continue;
 }

 sqPtr = checkSqPtr;
 if (checkSqIndex < kMin8thRankSqIndex)
 {
 (movePtr++)->opponentPlacedInCheck =
 (((sqPtr + 15) == oppKingSqPtr) ||
  ((sqPtr + 17) == oppKingSqPtr));
 continue;
 }

 sqIncr = dataPtr->queenSqIncrArray
  [oppKingSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 continue;
 }

 do
 {
 sqPtr += sqIncr;
 }
 while (((*sqPtr & kAttackMask) == emptySq0) ||
  (sqPtr == pcPtr->sqPtr));

 (movePtr++)->opponentPlacedInCheck =
 (sqPtr == oppKingSqPtr);
 }

 *moveHandle = movePtr;
}


EnumerateInterpositionMoves

void EnumerateInterpositionMoves(MyDataPtr dataPtr,
  MySquarePtr checkSqPtr,
  MySquareIncr checkSqIncr,
  ChessMovePtr *moveHandle)
{
 MySquarePtroppKingSqPtr, toSqPtr, sqPtr;
 short  toSqIndex, sqIncr;
 Square toSq;
 MyPiecePtr endPcPtr, pcPtr;
 ChessMovePtr    movePtr = *moveHandle;

 oppKingSqPtr = dataPtr->oppKing.sqPtr;

/* 
This “monster” do-loop repeats for each square which lies between the checking piece and the mover’s King.
*/
 toSqPtr = checkSqPtr + checkSqIncr;
 do
 {
 toSqIndex = toSqPtr - dataPtr->chessBoard.sqArray;
 toSq = dataPtr->stmSqArrayPtr[toSqIndex];

 endPcPtr = dataPtr->chessBoard.endSTMLMPiecePtr;
 for (pcPtr = dataPtr->stmLMPieceArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 if (pcPtr->pinAxis)
 continue;

 sqPtr = pcPtr->sqPtr;
 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [toSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 continue;

 while ((sqPtr += sqIncr) != toSqPtr)
 {
 if ((*sqPtr & kAttackMask) != emptySq0)
 goto NextLMPiece; /* Break while, continue for */
 }

 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = toSq;
 movePtr->moveIsCapture = false;
 
 if (pcPtr->discAxis)
 {
 (movePtr++)->opponentPlacedInCheck = true;
 continue;
 }
 
 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [oppKingSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 continue;
 }
 
 do
 {
 sqPtr += sqIncr;
 }
 while ((*sqPtr & kAttackMask) == emptySq0);
 
 (movePtr++)->opponentPlacedInCheck =
 (sqPtr == oppKingSqPtr);

 NextLMPiece:
 ;
 }
 
 endPcPtr = dataPtr->chessBoard.endSTMKnightPtr;
 for (pcPtr = dataPtr->stmKnightArray;
  pcPtr < endPcPtr; pcPtr++)
 {
 if (pcPtr->pinAxis == 0)
 {
 if (dataPtr->knightMoveArray
 [toSqPtr - pcPtr->sqPtr + kMaxSqDiff])
 {
 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = toSq;
 movePtr->moveIsCapture = false;
 (movePtr++)->opponentPlacedInCheck =
 (pcPtr->discAxis ||
  dataPtr->knightMoveArray
  [oppKingSqPtr - toSqPtr + kMaxSqDiff]);
 }
 }
 }

/* 
Pawn interposition is not possible if the square in the same column in the previous row does not contain a 
mover’s Pawn, AND any one of the following is true:
1.The square where interposition is to take place is not on the fourth rank,
2.The square in the same column on the third rank is not empty,
3.The square in the same column on the second rank does not contain a mover’s Pawn.
*/
 if ((*(sqPtr = toSqPtr - 16) > stmPawnSq1) &&
 ((toSqIndex >= kMin5thRankSqIndex) ||
  (toSqIndex < kMin4thRankSqIndex) ||
  ((*sqPtr & kAttackMask) != emptySq0) ||
  (*(sqPtr -= 16) > stmPawnSq1)))
 {
 continue;
 }

 pcPtr = dataPtr->pcPtrArray
 [sqPtr - dataPtr->chessBoard.sqArray];
 if (pcPtr->pinAxis)
 continue;

 movePtr->fromSq = pcPtr->fromSq;
 movePtr->toSq = toSq;
 movePtr->moveIsCapture = false;

 if (pcPtr->discAxis & 0x0f)
 {
 (movePtr++)->opponentPlacedInCheck = true;
 continue;
 }

 sqPtr = toSqPtr;
 if (toSqIndex < kMin8thRankSqIndex)
 {
 (movePtr++)->opponentPlacedInCheck =
 (((sqPtr + 15) == oppKingSqPtr) ||
  ((sqPtr + 17) == oppKingSqPtr));
 continue;
 }

 sqIncr = dataPtr->queenSqIncrArray
  [oppKingSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 continue;
 }

 do
 {
 sqPtr += sqIncr;
 }
 while (((*sqPtr & kAttackMask) == emptySq0) ||
  (sqPtr == pcPtr->sqPtr));

 (movePtr++)->opponentPlacedInCheck =
 (sqPtr == oppKingSqPtr);
 }
 while (*(toSqPtr += checkSqIncr) >= emptySq0);

 *moveHandle = movePtr;
}


EnumerateKingMoves

void EnumerateKingMoves(MyDataPtr dataPtr,
 ChessMovePtr *moveHandle)
{
 MySquarePtrstmKingSqPtr, sqPtr, toSqPtr;
 short  discAxis, sqIncr;
 MySqDiffPtrsqDiffPtr, endSqDiffPtr;
 MyPiecePtr endPcPtr, pcPtr;
 ChessMovePtr    movePtr = *moveHandle;

 stmKingSqPtr = dataPtr->stmKing.sqPtr;
 discAxis = dataPtr->stmKing.discAxis;

 sqPtr = dataPtr->oppKing.sqPtr;
 sqIncr = stmKingSqPtr - sqPtr;
 if ((sqIncr >= -34) && (sqIncr <= +34))
 {
/* 
The opposing King might be within range of squares to which this King could move, so set the attack flag 
for all squares the opposing King attacks.  This will include some squares to which this King cannot move 
- it did not seem worth the trouble to code a fancy algorithm which ensures that only     squares to which this 
King can move have the attack flag set.  In most normal chess positions (excluding the endgame), the two 
Kings are at opposite ends of the board, so this code won’t be executed very often anyway.
*/
 sqDiffPtr = dataPtr->kingSqDiffArray;
 endSqDiffPtr = sqDiffPtr + 8;
 do
 {
 *(sqPtr += *sqDiffPtr) |= kAttackFlag;
 }
 while (++sqDiffPtr != endSqDiffPtr);
 }

 toSqPtr = stmKingSqPtr;

 sqDiffPtr = dataPtr->kingSqDiffArray;
 endSqDiffPtr = sqDiffPtr + 8;
 do
 {
/* 
The King cannot move to this square if:
1.It is off-board or occupied by mover’s own piece,
2.It is flagged as known to be under attack,
3.It is within capture range of an enemy Pawn.
*/
 if ((*(toSqPtr += *sqDiffPtr) < emptySq0) ||
 (*toSqPtr & kAttackFlag) ||
 (*(sqPtr = toSqPtr + 15) >= oppPawnSq0) ||
 (*(sqPtr += 2) >= oppPawnSq0))
 {
 continue;
 }

    /* 
    The square is also blocked if a long move piece or Knight attacks the square.
    */
 endPcPtr = dataPtr->chessBoard.endOppLMPiecePtr;
 for (pcPtr = dataPtr->oppLMPieceArray;
    pcPtr < endPcPtr; pcPtr++)
 {
 sqPtr = pcPtr->sqPtr;
 sqIncr = pcPtr->pcTable.sqIncrArrayPtr
  [toSqPtr - sqPtr + kMaxSqDiff];
 if (sqIncr)
 {
 do
 {
 if ((sqPtr += sqIncr) == toSqPtr)
 goto NextKingMove;

/* 
Set an “audit trail” of attacked squares for this piece.  Most of these attack flags will be useless, but they 
cost very little to set, and they make the test for empty squares easier.  If one does happen to fall in a square 
next to the mover’s King, it will save time by removing that square from consideration immediately.
*/
 *sqPtr |= kAttackFlag;
 }
 while (*sqPtr == emptySq1);
 }
 }

 endPcPtr = dataPtr->chessBoard.endOppKnightPtr;
 for (pcPtr = dataPtr->oppKnightArray;
    pcPtr < endPcPtr; pcPtr++)
 {
 if (dataPtr->knightMoveArray
 [toSqPtr - pcPtr->sqPtr + kMaxSqDiff])
 {
 goto NextKingMove;
 }
 }

 movePtr->fromSq = dataPtr->stmKing.fromSq;
 movePtr->toSq =
 dataPtr->stmSqArrayPtr
 [toSqPtr - dataPtr->chessBoard.sqArray];
 movePtr->moveIsCapture = (*toSqPtr > emptySq1);

    /* 
    The only checks which can result from a King move are checks.
    */
 if (discAxis == 0)
 {
 (movePtr++)->opponentPlacedInCheck = false;
 }
 else
 {
 sqIncr = toSqPtr - stmKingSqPtr;
 (movePtr++)->opponentPlacedInCheck =
 ((discAxis != sqIncr) && (discAxis != -sqIncr));
 }

 NextKingMove:
 ;
 }
 while (++sqDiffPtr != endSqDiffPtr);

 *moveHandle = movePtr;
}


InitChess

/* =========================================================
    Untimed initialization routine
========================================================= */

void InitChess(void *privateDataPtr)
{
 MyDataPtrdataPtr = privateDataPtr;
 MySquarePtrsqPtr;
 int    index, sqRow, sqCol;
 SquarePt whiteSqPtr, blackSqPtr;
 MySqIncrPtrposQueenSqIncrPtr, negQueenSqIncrPtr,
 posRookSqIncrPtr, negRookSqIncrPtr,
 posBishopSqIncrPtr, negBishopSqIncrPtr;
 Boolean*posKnightMovePtr, *negKnightMovePtr;

/* 
Quoting from the problem statement: “The privateDataPtr parameter will be the same pointer provided to 
InitChess."  Therefore, I can set pointers based on its value in my private data structure.  This would not 
be possible if the parameter were guaranteed only to point to a copy of the same data, but not necessarily 
to have the same value.
*/
 dataPtr->emptyBoard.endSTMKingPtr = &dataPtr->stmKing;
 dataPtr->emptyBoard.endOppKingPtr = &dataPtr->oppKing;
 dataPtr->emptyBoard.endSTMLMPiecePtr =
 dataPtr->stmLMPieceArray;
 dataPtr->emptyBoard.endOppLMPiecePtr =
 dataPtr->oppLMPieceArray;
 dataPtr->emptyBoard.endSTMKnightPtr =
 dataPtr->stmKnightArray;
 dataPtr->emptyBoard.endOppKnightPtr =
 dataPtr->oppKnightArray;
 dataPtr->emptyBoard.endSTMPawnPtr =
 dataPtr->stmPawnArray;

    /* 
    Initialize the empty chess board structure and the square coordinate arrays.
    */
 sqPtr = dataPtr->emptyBoard.sqArray;
 for (index = 0; index <= kMaxSqIndex; index++)
 {
 *sqPtr++ = offBoardSq0;
 }

 sqPtr = dataPtr->emptyBoard.sqArray + kLowerLeftSqIndex;
 whiteSqPtr = dataPtr->whiteSqArray + kLowerLeftSqIndex;
 blackSqPtr = dataPtr->blackSqArray + kUpperRightSqIndex;
 for (sqRow = 0; sqRow < 8; sqRow++)
 {
 for (sqCol = 0; sqCol < 8; sqCol++)
 {
 *sqPtr++ = emptySq0;
 whiteSqPtr->row = sqRow;
 blackSqPtr->row = sqRow;
 (whiteSqPtr++)->col = sqCol;
 (blackSqPtr--)->col = sqCol;
 }
 sqPtr += 8; whiteSqPtr += 8; blackSqPtr -= 8;
 }

    /* 
    Initialize the piece information arrays.
    */
 dataPtr->stmPcInfoArray[king].pcHandle =
 &dataPtr->chessBoard.endSTMKingPtr;
 dataPtr->stmPcInfoArray[king].sqType = stmPieceSq0;

 dataPtr->stmPcInfoArray[queen].pcHandle =
 &dataPtr->chessBoard.endSTMLMPiecePtr;
 dataPtr->stmPcInfoArray[queen].pcTable.sqIncrArrayPtr =
 dataPtr->queenSqIncrArray;
 dataPtr->stmPcInfoArray[queen].pcTable.axisArrayPtr =
 dataPtr->queenAxisArray;
 dataPtr->stmPcInfoArray[queen].pcTable.numberOfAxes = 4;
 dataPtr->stmPcInfoArray[queen].sqType = stmPieceSq0;

 dataPtr->stmPcInfoArray[rook].pcHandle =
 &dataPtr->chessBoard.endSTMLMPiecePtr;
 dataPtr->stmPcInfoArray[rook].pcTable.sqIncrArrayPtr =
 dataPtr->rookSqIncrArray;
 dataPtr->stmPcInfoArray[rook].pcTable.axisArrayPtr =
 dataPtr->rookAxisArray;
 dataPtr->stmPcInfoArray[rook].pcTable.numberOfAxes = 2;
 dataPtr->stmPcInfoArray[rook].sqType = stmPieceSq0;

 dataPtr->stmPcInfoArray[bishop].pcHandle =
 &dataPtr->chessBoard.endSTMLMPiecePtr;
 dataPtr->stmPcInfoArray[bishop].pcTable.sqIncrArrayPtr =
 dataPtr->bishopSqIncrArray;
 dataPtr->stmPcInfoArray[bishop].pcTable.axisArrayPtr =
 dataPtr->bishopAxisArray;
 dataPtr->stmPcInfoArray[bishop].pcTable.numberOfAxes = 2;
 dataPtr->stmPcInfoArray[bishop].sqType = stmPieceSq0;

 dataPtr->stmPcInfoArray[knight].sqType = stmPieceSq0;
 dataPtr->stmPcInfoArray[knight].pcHandle =
 &dataPtr->chessBoard.endSTMKnightPtr;

 dataPtr->stmPcInfoArray[pawn].pcHandle =
 &dataPtr->chessBoard.endSTMPawnPtr;
 dataPtr->stmPcInfoArray[pawn].sqType = stmPawnSq0;

 dataPtr->oppPcInfoArray[king].pcHandle =
 &dataPtr->chessBoard.endOppKingPtr;
 dataPtr->oppPcInfoArray[king].sqType = oppPieceSq0;

 dataPtr->oppPcInfoArray[queen].pcHandle =
 &dataPtr->chessBoard.endOppLMPiecePtr;
 dataPtr->oppPcInfoArray[queen].pcTable.sqIncrArrayPtr =
 dataPtr->queenSqIncrArray;
 dataPtr->oppPcInfoArray[queen].pcTable.axisArrayPtr =
 dataPtr->queenAxisArray;
 dataPtr->oppPcInfoArray[queen].pcTable.numberOfAxes = 4;
 dataPtr->oppPcInfoArray[queen].sqType = oppPieceSq0;

 dataPtr->oppPcInfoArray[rook].pcHandle =
 &dataPtr->chessBoard.endOppLMPiecePtr;
 dataPtr->oppPcInfoArray[rook].pcTable.sqIncrArrayPtr =
 dataPtr->rookSqIncrArray;
 dataPtr->oppPcInfoArray[rook].pcTable.axisArrayPtr =
 dataPtr->rookAxisArray;
 dataPtr->oppPcInfoArray[rook].pcTable.numberOfAxes = 2;
 dataPtr->oppPcInfoArray[rook].sqType = oppPieceSq0;

 dataPtr->oppPcInfoArray[bishop].pcHandle =
 &dataPtr->chessBoard.endOppLMPiecePtr;
 dataPtr->oppPcInfoArray[bishop].pcTable.sqIncrArrayPtr =
 dataPtr->bishopSqIncrArray;
 dataPtr->oppPcInfoArray[bishop].pcTable.axisArrayPtr =
 dataPtr->bishopAxisArray;
 dataPtr->oppPcInfoArray[bishop].pcTable.numberOfAxes = 2;
 dataPtr->oppPcInfoArray[bishop].sqType = oppPieceSq0;

 dataPtr->oppPcInfoArray[knight].pcHandle =
 &dataPtr->chessBoard.endOppKnightPtr;
 dataPtr->oppPcInfoArray[knight].sqType = oppPieceSq0;

 dataPtr->oppPcInfoArray[pawn].sqType = oppPawnSq0;

    /* 
    Initialize the piece movement look-up tables.
    */
 posQueenSqIncrPtr = negQueenSqIncrPtr =
 dataPtr->queenSqIncrArray + kMaxSqDiff;
 posRookSqIncrPtr = negRookSqIncrPtr =
 dataPtr->rookSqIncrArray + kMaxSqDiff;
 posBishopSqIncrPtr = negBishopSqIncrPtr =
 dataPtr->bishopSqIncrArray + kMaxSqDiff;
 posKnightMovePtr = negKnightMovePtr =
 dataPtr->knightMoveArray + kMaxSqDiff;

 for (sqRow = 0; sqRow < 8; sqRow++)
 {
 *posQueenSqIncrPtr++= 0;
 *negQueenSqIncrPtr--= 0;
 *posRookSqIncrPtr++ = 0;
 *negRookSqIncrPtr-- = 0;
 *posBishopSqIncrPtr++  = 0;
 *negBishopSqIncrPtr--  = 0;
 *posKnightMovePtr++ = false;
 *negKnightMovePtr-- = false;

 for (sqCol = sqRow ? -7 : +1; sqCol < 8; sqCol++)
 {
 if (sqRow == 0)
 {
 *posQueenSqIncrPtr++= + 1;
 *negQueenSqIncrPtr--= - 1;
 *posRookSqIncrPtr++ = + 1;
 *negRookSqIncrPtr-- = - 1;
 *posBishopSqIncrPtr++  =   0;
 *negBishopSqIncrPtr--  =   0;
 *posKnightMovePtr++ = false;
 *negKnightMovePtr-- = false;
 }
 else if (sqRow + sqCol == 0)
 {
 *posQueenSqIncrPtr++= +15;
 *negQueenSqIncrPtr--= -15;
 *posRookSqIncrPtr++ =   0;
 *negRookSqIncrPtr-- =   0;
 *posBishopSqIncrPtr++  = +15;
 *negBishopSqIncrPtr--  = -15;
 *posKnightMovePtr++ = false;
 *negKnightMovePtr-- = false;
 }
 else if (sqCol == 0)
 {
 *posQueenSqIncrPtr++= +16;
 *negQueenSqIncrPtr--= -16;
 *posRookSqIncrPtr++ = +16;
 *negRookSqIncrPtr-- = -16;
 *posBishopSqIncrPtr++  =   0;
 *negBishopSqIncrPtr--  =   0;
 *posKnightMovePtr++ = false;
 *negKnightMovePtr-- = false;
 }
 else if (sqRow == sqCol)
 {
 *posQueenSqIncrPtr++= +17;
 *negQueenSqIncrPtr--= -17;
 *posRookSqIncrPtr++ =   0;
 *negRookSqIncrPtr-- =   0;
 *posBishopSqIncrPtr++  = +17;
 *negBishopSqIncrPtr--  = -17;
 *posKnightMovePtr++ = false;
 *negKnightMovePtr-- = false;
 }
 else
 {
 *posQueenSqIncrPtr++= 0;
 *negQueenSqIncrPtr--= 0;
 *posRookSqIncrPtr++ = 0;
 *negRookSqIncrPtr-- = 0;
 *posBishopSqIncrPtr++  = 0;
 *negBishopSqIncrPtr--  = 0;

/* A Knight moves only to those squares within two rows and columns that a Queen cannot reach. */
 if ((sqRow < 3) &&
 (sqCol > -3) && (sqCol < 3))
 {
 *posKnightMovePtr++ = true;
 *negKnightMovePtr-- = true;
 }
 else
 {
 *posKnightMovePtr++ = false;
 *negKnightMovePtr-- = false;
 }
 }
 }
 }

 dataPtr->queenAxisArray[0] =  1;
 dataPtr->queenAxisArray[1] = 15;
 dataPtr->queenAxisArray[2] = 16;
 dataPtr->queenAxisArray[3] = 17;

 dataPtr->rookAxisArray[0]=  1;
 dataPtr->rookAxisArray[1]= 16;

 dataPtr->bishopAxisArray[0]= 15;
 dataPtr->bishopAxisArray[1]= 17;
 
 dataPtr->knightSqDiffArray[0]= -33;
 dataPtr->knightSqDiffArray[1]= + 2;
 dataPtr->knightSqDiffArray[2]= +13;
 dataPtr->knightSqDiffArray[3]= + 4;
 dataPtr->knightSqDiffArray[4]= +28;
 dataPtr->knightSqDiffArray[5]= + 4;
 dataPtr->knightSqDiffArray[6]= +13;
 dataPtr->knightSqDiffArray[7]= + 2;

 dataPtr->kingSqDiffArray[0]= -17;
 dataPtr->kingSqDiffArray[1]= + 1;
 dataPtr->kingSqDiffArray[2]= + 1;
 dataPtr->kingSqDiffArray[3]= +14;
 dataPtr->kingSqDiffArray[4]= + 2;
 dataPtr->kingSqDiffArray[5]= +14;
 dataPtr->kingSqDiffArray[6]= + 1;
 dataPtr->kingSqDiffArray[7]= + 1;
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Pinegrow 6.23 - Mockup and design web pa...
Pinegrow (was Pinegrow Web Designer) is desktop app that lets you mockup and design webpages faster with multi-page editing, CSS and LESS styling, and smart components for Bootstrap, Foundation,... Read more
WhatsApp 2.2149.4 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Microsoft Remote Desktop 10.7.4 - Connec...
Microsoft Remote Desktop for Mac is an application that allows connecting to virtual apps or another PC remotely. Discover the power of Windows with Remote Desktop designed to help you manage your... Read more
ffWorks 2.6.7 - Convert multimedia files...
ffWorks, focused on simplicity, brings a fresh approach to the use of FFmpeg, allowing you to create ultra-high-quality movies without the need to write a single line of code on the command-line.... Read more
Opera 82.0.4227.58 - High-performance We...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more
Day One 6.15 - Maintain a daily journal.
Day One is an easy, great-looking way to use a journal / diary / text-logging application. Day One is well designed and extremely focused to encourage you to write more through quick Menu Bar entry,... Read more
Default Folder X 5.6.3 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click on... Read more
OmniOutliner Pro 5.9.2 - Pro version of...
OmniOutliner Pro is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more
OmniOutliner Essentials 5.9.2 - Organize...
OmniOutliner Essentials (was OmniOutliner) is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually... Read more
QuickBooks 19.0.11.984 - Financial manag...
QuickBooks helps you manage your business easily and efficiently. Organize your finances all in one place, track money going in and out of your business, and spot areas where you can save. Built for... Read more

Latest Forum Discussions

See All

The Best Wordle Clone in Town – The Touc...
In this week’s episode of The TouchArcade Show we dig into the drama of the moment which is the cloning and subsequent gloating about the cloning of the lovely little free word game Wordle. This leads into some additional drama about how PUGB Mobile... | Read more »
TouchArcade Game of the Week: ‘Cards Inf...
There’s nothing I love more than a perfect mobile game. What do I mean by that? Well, no game is actually perfect, but there’s something special about a game you know you can just whip out at a moment’s notice and dive into, and you know it will... | Read more »
‘Micro RPG’ Bringing Streamlined RPG Goo...
Originally announced on our forums more than 3 years ago, Micro RPG is an upcoming mobile game from a two-person studio that goes by the name JoliYeti Games and, as the title implies, it looks to offer all the fun of an RPG but in a more condensed... | Read more »
SwitchArcade Round-Up: ‘Kensei: The Seco...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 14th, 2022. Yesterday was a big day, but today shows that we’re still warming up the engines for this year. There are a handful of new releases, but nothing nearly as... | Read more »
Mobile MMORPG Shooter ‘Avatar: Reckoning...
Archosaur Games, Tencent, Lightstorm Entertainment, and Disney have just revealed a mobile MMORPG shooter Avatar: Reckoning. Avatar: Reckoning will be published by Level Infinite when it hits iOS and Android. It is an official Avatar game developed... | Read more »
‘Crashlands+’ Is Out Now on Apple Arcade...
The brilliant Crashlands from Butterscotch Shenanigans was confirmed to arrive on Apple Arcade as an App Store Great in the form of Crashlands+ () a little while ago and it has just released worldwide. If it isn’t live yet, it should roll out in... | Read more »
SwitchArcade Round-Up: ‘Eschatos’, ‘To B...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 13th, 2022. It’s a Thursday, and we’ve got a pretty hefty bag of new releases to dig into. There are always some fun surprises, and this week that came in the form of SNK Vs... | Read more »
‘Crush the Castle Legacy Collection’ Lau...
Ever since Angry Birds broke into the mainstream and became a household name more than a decade ago, there’s always been a small niche of people on the sidelines who would pipe up to remind everybody that “Crush the Castle did it first!" Indeed, the... | Read more »
Non-Violent Stealth Game ‘El Hijo – A Wi...
Over a year ago, Handy Games brought the non-violent stealth game El Hijo – A Wild West Tale to Switch, PS4, Xbox, PC, and Stadia. El Hijo – A Wild West Tale has been developed by Honig Studios and Quantumfrog. You play as El Hijo, a six year old,... | Read more »
‘ZED BLADE’ from SNK and Hamster Is Out...
After a bit of a break likely due to the holiday season, we’ve gotten a new title in the ACA NeoGeo series on iOS and Android. SNK and Hamster originally brought the series to mobile with Samurai Shodown IV, Alpha Mission II, and Metal Slug 5.... | Read more »

Price Scanner via MacPrices.net

Get an Apple Watch Series 7 for $50 off MSRP,...
Amazon has Apple Watch Series 7 models on sale for $50 off MSRP including free shipping. Their prices are the lowest available for Apple Watch Series 7 models today: – 41mm Apple Watch Series 7 GPS... Read more
Here are the details of Apple’s 2022 Educatio...
Need a new Apple Mac or iPad for school? Whether you’re a student, teacher, or staff member, you can use your .edu email address when ordering at Apple Education to take up to $400 off the price of a... Read more
Amazon is blowing out 2020 21″ iMacs for only...
Amazon has clearance 2020 21″ iMacs (2.3GHz Dual-Core i5, 8GB RAM, 256GB SSD) on sale right now for $599.99 including free shipping. Original MSRP for this model was $1099. Amazon expects delivery in... Read more
Find the best deal on an Apple MacBook using...
In the market for a new 13″ MacBook Air, 13″ MacBook Pro, 14″ MacBook Pro, or 16″ MacBook Pro with M1, M1 Pro, or M1 Max Apple Silicon? Use our Apple award-winning and exclusive price trackers to... Read more
Red Pocket Mobile is offering the Apple iPhon...
Switch to Red Pocket Mobile and get an Apple iPhone 13 Pro for $50 off MSRP, plus get free 6 months of Unlimited nationwide 5G service with the purchase of any iPhone 13. Red Pocket Mobile is a... Read more
24″ M1 iMacs on sale for $1249, $50 off Apple...
Amazon has base 24″ M1 iMacs (8-Core CPU/7-Core GPU/8GB RAM/256GB SSD) on sale today for $1249 shipped. Their price is $50 off Apple’s MSRP, and it’s the lowest price available for a new 24″ M1 iMac... Read more
Open-Box 16″ M1 Pro MacBook Pros available fo...
QuickShip Electronics has open-box return 16″ M1 Pro MacBook Pros in stock and on sale for $200-$300 off MSRP on their eBay store right now with free express delivery. According to QuickShip, “The... Read more
Stock Alert! Order a new 16″ M1 Pro MacBook P...
New 16″ MacBook Pros with Apple’s M1 Pro and M1 Max CPUs have been very hard to find, largely due to current global supply constraints. However, B&H Photo is reporting stock of Space Gray... Read more
Apple has maxed-out 13″ M1 MacBook Airs (16GB...
Save $250 on maxed-out 13″ M1 MacBook Airs today at Apple (16GB RAM/1TB SSD) with Certified Refurbished models available for $1399 in Space Gray and Gold colors. Regular price for this configuration... Read more
New promo at Xfinity Mobile: $400 off any App...
Xfinity Mobile is offering any new Apple iPhone for $400 off MSRP for new customers. This includes the iPhone 13. Price for the phone, including the discount, is spread monthly over a 24 month term... Read more

Jobs Board

Registered Nurse (RN) Employee Health PSJH -...
…is calling for a Registered Nurse (RN) Employee Health PSJH to our location in Apple Valley, CA.** We are seeking a Registered Nurse (RN) Employee Health PSJH to be Read more
Systems Administrator - Pearson (United State...
…and troubleshoot Windows operating systems (workstation and server), laptop computers, Apple iPads, Chromebooks and printers** + **Administer and troubleshoot all Read more
IT Assistant Level 1- IT Desktop Support Anal...
…providing tier-1 or better IT help desk support in a large Windows and Apple environment * Experience using IT Service Desk Management Software * Knowledge of IT Read more
Human Resources Business Partner PSJH - Provi...
…**is calling a** **Human Resources Business Partner, PSJH** **to our location in Apple Valley, CA.** **Applicants that meet qualifications will receive a text with Read more
Manager Community Health Investment Programs...
…is calling a Manager Community Health Investment Programs PSJH to our location in Apple Valley, CA.** **Qualified candidates will be invited to do a self-paced video Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.