home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / Kibitz / Notation.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-19  |  37.9 KB  |  1,640 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        notation.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved. */
  9.  
  10.  
  11.  
  12. /*****************************************************************************/
  13.  
  14.  
  15.  
  16. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  17. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  18. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  19.  
  20. #ifndef __MEMORY__
  21. #include <Memory.h>
  22. #endif
  23.  
  24. #ifndef __RESOURCES__
  25. #include <Resources.h>
  26. #endif
  27.  
  28. #ifndef __TEXTEDITCONTROL__
  29. #include <TextEditControl.h>
  30. #endif
  31.  
  32. #ifndef __TOOLUTILS__
  33. #include <ToolUtils.h>
  34. #endif
  35.  
  36. #ifndef __UTILITIES__
  37. #include <Utilities.h>
  38. #endif
  39.  
  40. extern GameListHndl    gGenMovesHndl;
  41. extern Boolean        gDescriptive;
  42.  
  43. static Boolean    Descriptive(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr);
  44. static Boolean    Algebraic(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr);
  45. static short    IsAlgebraic  (FileRecHndl frHndl, Ptr cptr, short len, short *rfrom, short *rto, short *rpromote);
  46. static short    IsDescriptive(FileRecHndl frHndl, Ptr cptr, short len, short *rfrom, short *rto, short *rpromote);
  47. static Boolean    MoveCausesCheck(FileRecHndl game, short from, short to);
  48.  
  49.  
  50.  
  51. /*****************************************************************************/
  52.  
  53.  
  54.  
  55. #pragma segment Window
  56. Boolean    AnnotateMove(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr)
  57. {
  58.     if (gDescriptive)
  59.         return(Descriptive(frHndl, doMoveNum, gameIndex, pstr));
  60.     else
  61.         return(Algebraic(frHndl, doMoveNum, gameIndex, pstr));
  62. }
  63.  
  64.  
  65.  
  66. /*****************************************************************************/
  67.  
  68.  
  69.  
  70. #pragma segment Window
  71. static Boolean    Descriptive(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr)
  72. {
  73.     short            from, to, piece;
  74.     short            i, r, c, rr, cc, rrr, ccc, fff, ttt, ppp;
  75.     short            color, check, ck, opFrom;
  76.     short            fromSide, fromCol, fromRow, toSide, toCol, toRow, toPiece;
  77.     short            c0, c1;
  78.     Boolean            fullDo;
  79.     GameListHndl    gameMoves;
  80.     MoveListHndl    legalMoves;
  81.  
  82.     color = WhosMove(frHndl);
  83.  
  84.     GenerateLegalMoves(frHndl);
  85.     legalMoves = (*frHndl)->doc.legalMoves;
  86.  
  87.     gameMoves = (*frHndl)->doc.gameMoves;
  88.     from = (**gameMoves)[doMoveNum].moveFrom;
  89.     to   = (**gameMoves)[doMoveNum].moveTo;
  90.  
  91.     check = MoveCausesCheck(frHndl, from, to);
  92.  
  93.     if (!from) {
  94.         GetIndString(pstr, rGameStat, to);
  95.         while (pstr[1] == ' ') BlockMove(pstr + 2, pstr + 1, --pstr[0]);
  96.         return(false);
  97.     }
  98.  
  99.     r  = from / 10;
  100.     c  = from - 10 * r - 1;
  101.     r -= 2;
  102.  
  103.     rr  = to / 10;
  104.     cc  = to - 10 * rr - 1;
  105.     rr -= 2;
  106.  
  107.     piece = (*frHndl)->doc.theBoard[from];
  108.     if (piece < 0) piece = -piece;
  109.     if (piece > BK) piece -= KSIDEPIECE;
  110.  
  111.     pstr[0] = 0;
  112.  
  113.     if (piece == KING) {
  114.         i = c - cc;
  115.         if (i == 2) {
  116.             pcpy(pstr, "\pO-O-O");
  117.             piece = EMPTY;
  118.         }
  119.         if (i == -2) {
  120.             pcpy(pstr, "\pO-O");
  121.             piece = EMPTY;
  122.         }
  123.     }
  124.  
  125.     opFrom   = 0;
  126.     fromSide = -1;
  127.     fromCol  = -1;
  128.     fromRow  = -1;
  129.  
  130.     toPiece = (*frHndl)->doc.theBoard[to];
  131.     if (toPiece < 0) toPiece = -toPiece;
  132.     if (toPiece > BK) toPiece -= KSIDEPIECE;
  133.  
  134.     if (!toPiece)
  135.         if (piece == PAWN)
  136.             if (to == (*frHndl)->doc.enPasMove)
  137.                 toPiece = PAWN;
  138.  
  139.     toSide = -1;
  140.     toCol  = -1;
  141.     toRow  = -1;
  142.  
  143.     if (piece) {
  144.         pstr[++pstr[0]] = " PNBRQK"[piece];
  145.         for (i = 0; i < (*frHndl)->doc.numLegalMoves; ++i) {
  146.             fff = (**legalMoves)[i].moveFrom;
  147.             ttt = (**legalMoves)[i].moveTo;
  148.             if (ttt == to) {
  149.                 if (fff != from) {
  150.                     ck = MoveCausesCheck(frHndl, fff, ttt);
  151.                     if (ck == check) {
  152.                         ppp = (*frHndl)->doc.theBoard[fff];
  153.                         if (ppp < 0) ppp = -ppp;
  154.                         if (ppp > BK) ppp -= KSIDEPIECE;
  155.                         if (ppp == piece) {
  156.                             fromRow = r;
  157.                             rrr  = fff / 10;
  158.                             ccc  = fff - 10 * rrr - 1;
  159.                             rrr -= 2;
  160.                             if ((rrr == r) || (opFrom)) {
  161.                                 if ((ccc != c) || (opFrom)) {
  162.                                     c0 = c;
  163.                                     if (c0 > 4) c0 = 7 - c0;
  164.                                     fromRow = r;
  165.                                     fromCol = c0;
  166.                                     c1 = ccc;
  167.                                     if (c1 > 4) c1 = 7 - c1;
  168.                                     if (c0 == c1) {
  169.                                         if (ccc != c) {
  170.                                             if (c > 4) fromSide = 1;
  171.                                             if (c < 3) fromSide = 0;
  172.                                         }
  173.                                     }
  174.                                 }
  175.                             }
  176.                             opFrom = fff;
  177.                         }
  178.                     }
  179.                 }
  180.             }
  181.         }
  182.  
  183.         for (i = 0; i < (*frHndl)->doc.numLegalMoves; ++i) {
  184.             fff = (**legalMoves)[i].moveFrom;
  185.             ttt = (**legalMoves)[i].moveTo;
  186.             ppp = (*frHndl)->doc.theBoard[fff];
  187.             if (ppp < 0) ppp = -ppp;
  188.             if (ppp > BK) ppp -= KSIDEPIECE;
  189.             if (ppp == piece) {
  190.                 ck = MoveCausesCheck(frHndl, fff, ttt);
  191.                 if (ck == check) {
  192.                     ppp = (*frHndl)->doc.theBoard[ttt];
  193.                     if (ppp < 0) ppp = -ppp;
  194.                     if (ppp > BK) ppp -= KSIDEPIECE;
  195.                     if (!ppp)
  196.                         if (piece == PAWN)
  197.                             if (ttt == (*frHndl)->doc.enPasMove)
  198.                                 ppp = PAWN;
  199.  
  200.                     if (ppp == toPiece) {
  201.                         fullDo = ((!toPiece) && (ttt == to)) ? true : false;
  202.                         rrr  = ttt / 10;
  203.                         ccc  = ttt - 10 * rrr - 1;
  204.                         rrr -= 2;
  205.                         if ((ccc != cc) && (rrr != rr)) toRow = rr;
  206.                         if (ccc == cc) {
  207.                             if ((rrr != rr) || (fullDo)) {
  208.                                 toRow = rr;
  209.                             }
  210.                         }
  211.                         if (rrr == rr) {
  212.                             if ((ccc != cc) || (fullDo)) {
  213.                                 c0 = cc;
  214.                                 if (c0 > 4) c0 = 7 - c0;
  215.                                 toRow = rr;
  216.                                 toCol = cc;
  217.                                 c1 = ccc;
  218.                                 if (c1 > 4) c1 = 7 - c1;
  219.                                 if (c0 == c1) {
  220.                                     if (ccc != cc) {
  221.                                         if (cc > 4) toSide = 1;
  222.                                         if (cc < 3) toSide = 0;
  223.                                     }
  224.                                 }
  225.                             }
  226.                         }
  227.                     }
  228.                 }
  229.             }
  230.         }
  231.  
  232.         if (opFrom) {
  233.             pstr[++pstr[0]] = '(';
  234.             if (fromSide != -1)
  235.                 pstr[++pstr[0]] = "QK"[fromSide];
  236.             if (fromCol != -1)
  237.                 pstr[++pstr[0]] = "RNBQKBNR"[fromCol];
  238.             if (fromRow != -1) {
  239.                 if (color == WHITE) fromRow = 7 - fromRow;
  240.                 pstr[++pstr[0]] = "12345678"[fromRow];
  241.             }
  242.             pstr[++pstr[0]] = ')';
  243.         }
  244.  
  245.         if (toPiece) {
  246.             pstr[++pstr[0]] = 'x';
  247.             pstr[++pstr[0]] = " PNBRQK"[toPiece];
  248.             if ((toRow == -1) && (toCol == -1) && (toSide == -1)) toPiece = 0;
  249.         }
  250.         else {
  251.             pstr[++pstr[0]] = '-';
  252.             if (toRow != -1)  toPiece = -1;
  253.             if (toCol != -1)  toPiece = -1;
  254.             if (toSide != -1) toPiece = -1;
  255.         }
  256.  
  257.         if (toPiece) {
  258.             if (toPiece > 0) pstr[++pstr[0]] = '(';
  259.             if (toSide != -1)
  260.                 pstr[++pstr[0]] = "QK"[toSide];
  261.             if (toCol != -1)
  262.                 pstr[++pstr[0]] = "RNBQKBNR"[toCol];
  263.             if (toRow != -1) {
  264.                 if (color == WHITE) toRow = 7 - toRow;
  265.                 pstr[++pstr[0]] = "12345678"[toRow];
  266.             }
  267.             if (toPiece > 0) pstr[++pstr[0]] = ')';
  268.         }
  269.     }
  270.  
  271.     if (piece == PAWN) {
  272.         to = (**gameMoves)[doMoveNum].promoteTo;
  273.         if (to) {
  274.             if (to < 0) to = -to;
  275.             pstr[++pstr[0]] = '=';
  276.             pstr[++pstr[0]] = "  NBRQ"[to];
  277.         }
  278.     }
  279.  
  280.     if (check)
  281.         pstr[++pstr[0]] = '+';
  282.  
  283.     return(doMoveNum == gameIndex - 1);
  284. }
  285.  
  286.  
  287.  
  288. /*****************************************************************************/
  289.  
  290.  
  291.  
  292. #pragma segment Window
  293. static Boolean    Algebraic(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr)
  294. {
  295.     short            from, to, piece, extend, rowMatch, colMatch;
  296.     short            i, r, c, rr, cc, rrr, ccc, fff, ttt, ppp;
  297.     short            color, kingLoc;
  298.     GameListHndl    gameMoves;
  299.     MoveListHndl    legalMoves;
  300.  
  301.     gameMoves = (*frHndl)->doc.gameMoves;
  302.     from = (**gameMoves)[doMoveNum].moveFrom;
  303.     to   = (**gameMoves)[doMoveNum].moveTo;
  304.  
  305.     if (!from) {
  306.         GetIndString(pstr, rGameStat, to);
  307.         while (pstr[1] == ' ') BlockMove(pstr + 2, pstr + 1, --pstr[0]);
  308.         return(false);
  309.     }
  310.  
  311.     r  = from / 10;
  312.     c  = from - 10 * r - 1;
  313.     r -= 2;
  314.  
  315.     rr  = to / 10;
  316.     cc  = to - 10 * rr - 1;
  317.     rr -= 2;
  318.  
  319.     piece = (*frHndl)->doc.theBoard[from];
  320.     if (piece < 0) piece = -piece;
  321.     if (piece > BK) piece -= KSIDEPIECE;
  322.  
  323.     pstr[0] = 0;
  324.     if (piece == PAWN) {
  325.         if (c != cc) {
  326.             pstr[++pstr[0]] = "abcdefgh"[c];
  327.             pstr[++pstr[0]] = 'x';
  328.         }
  329.     }
  330.     if (piece == KING) {
  331.         i = c - cc;
  332.         if (i == 2) {
  333.             pcpy(pstr, "\pO-O-O");
  334.             piece = EMPTY;
  335.         }
  336.         if (i == -2) {
  337.             pcpy(pstr, "\pO-O");
  338.             piece = EMPTY;
  339.         }
  340.     }
  341.  
  342.     if (piece > PAWN) {
  343.         rowMatch = colMatch = extend = false;
  344.         GenerateLegalMoves(frHndl);
  345.         legalMoves = (*frHndl)->doc.legalMoves;
  346.         for (i = 0; i < (*frHndl)->doc.numLegalMoves; ++i) {
  347.             fff = (**legalMoves)[i].moveFrom;
  348.             ttt = (**legalMoves)[i].moveTo;
  349.             if ((ttt == to) && (fff != from)) {
  350.                 ppp = (*frHndl)->doc.theBoard[fff];
  351.                 if (ppp < 0) ppp = -ppp;
  352.                 if (ppp > BK) ppp -= KSIDEPIECE;
  353.                 if (ppp != piece) continue;
  354.                 rrr  = fff / 10;
  355.                 ccc  = fff - 10 * rrr - 1;
  356.                 rrr -= 2;
  357.                 extend = true;
  358.                 if (r == rrr) rowMatch = true;
  359.                 if (c == ccc) colMatch = true;
  360.             }
  361.         }
  362.         if ((extend) && (!colMatch)) rowMatch |= extend;
  363.         pstr[++pstr[0]] = "  NBRQK"[piece];
  364.         if (rowMatch)
  365.             pstr[++pstr[0]] = "abcdefgh"[c];
  366.         if (colMatch)
  367.             pstr[++pstr[0]] = "87654321"[r];
  368.         i = (*frHndl)->doc.theBoard[to];
  369.         if (!i)
  370.             if (piece == PAWN)
  371.                 if (to == (*frHndl)->doc.enPasMove)
  372.                     i = PAWN;
  373.         if ((i) && (i != OBNDS)) pstr[++pstr[0]] = 'x';
  374.     }
  375.  
  376.     if (piece) {
  377.         pstr[++pstr[0]] = "abcdefgh"[cc];
  378.         pstr[++pstr[0]] = "87654321"[rr];
  379.     }
  380.     if (piece == PAWN) {
  381.         to = (**gameMoves)[doMoveNum].promoteTo;
  382.         if (to) {
  383.             if (to < 0) to = -to;
  384.             pstr[++pstr[0]] = '=';
  385.             pstr[++pstr[0]] = "  NBRQ"[to];
  386.         }
  387.     }
  388.  
  389.     if (doMoveNum < (*frHndl)->doc.numGameMoves) {
  390.         RepositionBoard(frHndl, doMoveNum + 1, false);
  391.         kingLoc = (*frHndl)->doc.king[color = WhosMove(frHndl)].kingLoc;
  392.         if (SquareAttacked(frHndl, kingLoc, color)) pstr[++pstr[0]] = '+';
  393.         RepositionBoard(frHndl, doMoveNum, false);
  394.     }
  395.  
  396.     return(doMoveNum == gameIndex - 1);
  397. }
  398.  
  399.  
  400.  
  401. /*****************************************************************************/
  402.  
  403.  
  404.  
  405. #pragma segment Window
  406. void    MovesToOutBox(FileRecHndl frHndl, EventRecord *event)
  407. {
  408.     short        txtIndx, numGameMoves, gameIndex, startColor;
  409.     short        move, moveColor, moveNum, i, selStart, selEnd, condensed;
  410.     Boolean        needCR;
  411.     Str255        txt;
  412.     Handle        txtHndl;
  413.     TEHandle    teHndl;
  414.     WindowPtr    oldPort;
  415.  
  416.     txtHndl = NewHandle(32000);
  417.     if (!txtHndl) return;
  418.     txtIndx = 0;
  419.  
  420.     condensed = (event->modifiers & optionKey);
  421.  
  422.     numGameMoves = (*frHndl)->doc.numGameMoves;
  423.     gameIndex    = (*frHndl)->doc.gameIndex;
  424.     teHndl       = (*frHndl)->doc.message[kMessageOut];
  425.     startColor   = (*frHndl)->doc.startColor;
  426.  
  427.     txt[0] = 0;
  428.     needCR = false;
  429.     for (move = gameIndex; move < numGameMoves; ++move) {
  430.         moveColor = ((move + startColor) & 0x01);
  431.         moveNum   = ((move + startColor) / 2 + 1);
  432.         if ((needCR) && (!moveColor)) {
  433.             i = (condensed) ? 32 : 13;
  434.             (*txtHndl)[txtIndx++] = i;
  435.             needCR = false;
  436.         }
  437.         if ((!moveColor) || (move == gameIndex)) {
  438.             pcpydec(txt, i = (move / 2 + 1));
  439.             pcat(txt, "\p)  ");
  440.             if ((condensed) || (i > 9)) txt[0]--;
  441.             BlockMove(txt + 1, *txtHndl + txtIndx, txt[0]);
  442.             txtIndx += txt[0];
  443.             needCR = true;
  444.         }
  445.         if ((moveColor) && (move == gameIndex)) {
  446.             if (condensed) {
  447.                 BlockMove("...,", *txtHndl + txtIndx, 4);
  448.                 txtIndx += 4;
  449.             }
  450.             else {
  451.                 if (gDescriptive) {
  452.                     BlockMove("...             ", *txtHndl + txtIndx, 13);
  453.                     txtIndx += 13;
  454.                 } else {
  455.                     BlockMove("...      ", *txtHndl + txtIndx, 8);
  456.                     txtIndx += 8;
  457.                 }
  458.             }
  459.             needCR = true;
  460.         }
  461.         RepositionBoard(frHndl, move, false);
  462.  
  463.         AnnotateMove(frHndl, move, 0, txt);
  464.         if (move < numGameMoves - 1) {
  465.             if (condensed) {
  466.                 if (!moveColor) txt[++(txt[0])] = ',';
  467.             }
  468.             else {
  469.                 if (!moveColor) pcat(txt, "\p               ");
  470.                 if (gDescriptive) {
  471.                     if (txt[0] > 13) txt[0] = 13;
  472.                 }
  473.                 else {
  474.                     if (txt[0] > 8 ) txt[0] = 8;
  475.                 }
  476.             }
  477.         }
  478.         BlockMove(txt + 1, *txtHndl + txtIndx, txt[0]);
  479.         txtIndx += txt[0];
  480.         needCR = true;
  481.     }
  482.  
  483.     LockHandleHigh(txtHndl);
  484.     oldPort = SetFilePort(frHndl);
  485.  
  486.     CTENewUndo(CTEViewFromTE(teHndl), true);
  487.     TEDelete(teHndl);
  488.     selStart = (*teHndl)->selStart;
  489.     TEInsert(*txtHndl, txtIndx, teHndl);
  490.     selEnd = (*teHndl)->selStart;
  491.     TESetSelect(selStart, selEnd, teHndl);
  492.     TESelView(teHndl);
  493.     CTEAdjustTEBottom(teHndl);
  494.     CTEAdjustScrollValues(teHndl);
  495.     (*frHndl)->fileState.docDirty = true;
  496.  
  497.     SetPort(oldPort);
  498.     DisposeHandle(txtHndl);
  499.  
  500.     RepositionBoard(frHndl, gameIndex, false);
  501. }
  502.  
  503.  
  504.  
  505. /*****************************************************************************/
  506.  
  507.  
  508.  
  509. #pragma segment Window
  510. void    MovesFromText(FileRecHndl frHndl, Handle txtHndl, short txtLen,
  511.                       short beg, short end, Boolean slideMoves)
  512. {
  513.     WindowPtr        oldPort;
  514.     short            gameIndex, txtIndx, commentCount;
  515.     short            numUsed, nu, numLglMoves, lastChar, c0, c1, i;
  516.     short            from, to, promoteTo, f, t;
  517.     long            tick;
  518.     char            *cptr;
  519.     MoveListHndl    lglMoves;
  520.     static char        goodFirstChar[] = "Oo01abcdefghPNBRQK";
  521.  
  522.     oldPort  = SetFilePort(frHndl);
  523.     if (end == beg) end = txtLen;
  524.  
  525.     GenerateLegalMoves(frHndl);
  526.     gameIndex = (*frHndl)->doc.gameIndex;
  527.     txtIndx = beg;
  528.     commentCount = 0;
  529.  
  530.     tick = TickCount();
  531.     HLock(txtHndl);
  532.  
  533.     for (;; txtIndx += numUsed) {
  534.  
  535.         if (!commentCount) {
  536.             numLglMoves = (*frHndl)->doc.numLegalMoves;
  537.             lglMoves    = (*frHndl)->doc.legalMoves;
  538.             if (!numLglMoves) break;
  539.                 /* Can't accept any moves, as there are no legal moves. */
  540.         }
  541.  
  542.         lastChar = end - txtIndx - 1;
  543.         if (lastChar < 1) break;
  544.             /* An algebraic move is at least 2 characters. */
  545.  
  546.         cptr = *txtHndl + txtIndx;
  547.         c0 = cptr[0];
  548.         numUsed = 1;        /* Always use at least 1 character per pass. */
  549.  
  550.         if (c0 == '[') {
  551.             ++commentCount;
  552.             continue;
  553.         }
  554.  
  555.         if (c0 == ']') {
  556.             if (commentCount) --commentCount;
  557.             continue;
  558.         }
  559.  
  560.         if (commentCount) continue;
  561.  
  562.         for (i = 0; goodFirstChar[i]; ++i)
  563.             if (c0 == goodFirstChar[i]) break;
  564.         if (!goodFirstChar[i]) continue;
  565.             /* Not good first character, so check next char. */
  566.  
  567.         from = to = 0;
  568.         for (;;) {        /* Used to break from for jump purposes. */
  569.  
  570.             if (i < 3) {        /* First character is castling character... */
  571.                 if (lastChar < 2) break;
  572.                     /* Not enough characters for kside castling. */
  573.                 if (cptr[numUsed] != '-') break;        /* Isn't a castle. */
  574.                 if (cptr[numUsed + 1] != '1') {            /* Isn't a black-wins notation. */
  575.                     if (cptr[++numUsed] != c0) break;    /* Isn't a castle. */
  576.                     from = (WhosMove(frHndl)) ? 25 : 95;
  577.                     to   = from + 2;
  578.                     if (lastChar < 4) {
  579.                         ++numUsed;
  580.                         break;
  581.                     }        /* Not enough characters for qside castling, so try kside. */
  582.                     if (cptr[++numUsed] != '-') break;        /* Isn't a castle. */
  583.                     if (cptr[++numUsed] != c0) break;        /* Isn't a castle. */
  584.                     to -= 4;
  585.                     ++numUsed;
  586.                     break;        /* Try qside castle. */
  587.                 }
  588.             }
  589.  
  590.             i -= 2;
  591.             if (i < 2) {    /* May be end-of-game notation. (1-0, 1/2, 0-1) */
  592.                 if (lastChar < 2) break;
  593.                     /* Not enough characters for end-of-game notation. */
  594.                 c1 = cptr[numUsed];
  595.                 if (c1 == '-') {
  596.                     if (cptr[numUsed + 1] == ('1' - i)) to = kWhiteResigns + i;
  597.                 }
  598.                 else if (c1 == '/') {
  599.                     if (cptr[numUsed + 1] == '2') to = kDrawGame;
  600.                 }
  601.                 if (to) EndTheGame(frHndl, to);
  602.                 to = 0;
  603.                 break;        /* Done processing this character, either way. */
  604.             }
  605.  
  606.             nu = IsAlgebraic(frHndl, cptr, lastChar, &from, &to, &promoteTo);
  607.             if (from != -1) {
  608.                 numUsed += (nu - 1);
  609.                 break;
  610.             }
  611.             else {
  612.                 nu = IsDescriptive(frHndl, cptr, lastChar, &from, &to, &promoteTo);
  613.                 if (from != -1) {
  614.                     numUsed += (nu - 1);
  615.                     break;
  616.                 }
  617.             }
  618.             break;
  619.         }
  620.  
  621.         for (i = 0; i < numLglMoves; ++i) {
  622.             f = (**lglMoves)[i].moveFrom;
  623.             t = (**lglMoves)[i].moveTo;
  624.             if ((f == from) && (t == to)) break;
  625.         }
  626.         if (i < numLglMoves) {
  627.             from = (**lglMoves)[i].moveFrom;
  628.             to   = (**lglMoves)[i].moveTo;
  629.             if (slideMoves) SlideThePiece(frHndl, from, to);
  630.             MakeMove(frHndl, from, to, promoteTo);
  631.             GenerateLegalMoves(frHndl);
  632.             ImageDocument(frHndl, true);
  633.             AdjustGameSlider(frHndl);
  634.             UpdateGameStatus(frHndl);
  635.             if (tick + 30 < TickCount()) {        /* Send max 1 AppleEvent per 1/2 sec. */
  636.                 tick = TickCount();
  637.                 if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kScrolling, nil);
  638.             }
  639.         }
  640.         else {
  641.             if ((!from) && (!to)) {
  642.                 if (numUsed > 1) --numUsed;
  643.                 for (;;) {
  644.                     c0 = cptr[numUsed++];
  645.                     if (numUsed >= lastChar) break;
  646.                     if ((c0 >= 'A') && (c0 <= 'Z')) continue;
  647.                     if ((c0 >= 'a') && (c0 <= 'z')) continue;
  648.                     if ((c0 >= '0') && (c0 <= '9')) continue;
  649.                     break;
  650.                 }
  651.             }
  652.         }
  653.     }
  654.  
  655.     HUnlock(txtHndl);
  656.  
  657.     if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kResync, nil);
  658. }
  659.  
  660.  
  661.  
  662.  
  663. /*****************************************************************************/
  664.  
  665.  
  666.  
  667. #pragma segment Window
  668. void    MakeVerbose(FileRecHndl frHndl, StringPtr pstr)
  669. {
  670.     Str255                result;
  671.     Str32                piece, from, verb, to, epi;
  672.     short                i, enPas, pp, ff, tt, gameIndex;
  673.     Boolean                inParens;
  674.     GameListHndl        gameMoves;
  675.     static StringPtr    cols[] = {"\peigh,", "\pbee,", "\psea,", "\pdee,",
  676.                               "\pe,", "\pef,", "\pgee,", "\pH,"};
  677.  
  678.     if (!pstr[0]) return;
  679.  
  680.     result[0] = from[0] = to[0] = epi[0] = 0;
  681.  
  682.     enPas = false;
  683.     gameMoves = (*frHndl)->doc.gameMoves;
  684.     gameIndex = (*frHndl)->doc.gameIndex;
  685.     ff = (**gameMoves)[gameIndex].moveFrom;
  686.     tt = (**gameMoves)[gameIndex].moveTo;
  687.     pp = (*frHndl)->doc.theBoard[ff];
  688.     if (pp < 0) pp = -pp;
  689.     if (pp > BK) pp -= KSIDEPIECE;
  690.     if (pp == PAWN) {
  691.         pp = (*frHndl)->doc.theBoard[tt];
  692.         if (pp < 0) pp = -pp;
  693.         if (pp > BK) pp -= KSIDEPIECE;
  694.         if (!pp)
  695.             if (tt == (*frHndl)->doc.enPasMove)
  696.                 enPas = true;
  697.     }
  698.  
  699.     pcpy(piece, "\ppaun ");
  700.     pcpy(verb,  "\ptoo, ");
  701.  
  702.     if (pstr[i = 1] < 'Z') {
  703.         if (pstr[i] == 'O') {
  704.             ++i;
  705.             if (pstr[0] < 3) return;
  706.             pcpy(result, "\pcastle ");
  707.             if (pstr[0] < 4) {
  708.                 pcat(result, "\p king side");
  709.                 pcpy(pstr, result);
  710.                 return;
  711.             }
  712.             if (pstr[4] == '+') {
  713.                 pcat(result, "\p king side, check");
  714.                 pcpy(pstr, result);
  715.                 return;
  716.             }
  717.             pcat(result, "\p kweenn side");
  718.             if (pstr[0] >= 6) {
  719.                 if (pstr[6] == '+') pcat(result, "\p, check");
  720.                 pcpy(pstr, result);
  721.             }
  722.             pcpy(pstr, result);
  723.             return;
  724.         }
  725.  
  726.         if (pstr[i] == 'P') pcpy(piece, "\ppaun ");
  727.         if (pstr[i] == 'N') pcpy(piece, "\pknight ");
  728.         if (pstr[i] == 'B') pcpy(piece, "\pbishop ");
  729.         if (pstr[i] == 'R') pcpy(piece, "\prook ");
  730.         if (pstr[i] == 'Q') pcpy(piece, "\pkweenn ");
  731.         if (pstr[i] == 'K') pcpy(piece, "\pking ");
  732.         ++i;
  733.     }
  734.  
  735.     if (i > pstr[0]) return;
  736.  
  737.     if (gDescriptive) {
  738.         inParens = false;
  739.         for (i = 1; i <= pstr[0]; ++i) {
  740.             switch (pstr[i]) {
  741.                 case 'P':
  742.                     pcat(result, "\p pawn ");
  743.                     break;
  744.                 case 'N':
  745.                     pcat(result, "\p knight ");
  746.                     break;
  747.                 case 'B':
  748.                     pcat(result, "\p bishop ");
  749.                     break;
  750.                 case 'R':
  751.                     pcat(result, "\p rook ");
  752.                     break;
  753.                 case 'Q':
  754.                     pcat(result, "\p kweenn ");
  755.                     break;
  756.                 case 'K':
  757.                     pcat(result, "\p king ");
  758.                     break;
  759.                 case '1':
  760.                 case '2':
  761.                 case '3':
  762.                 case '4':
  763.                 case '5':
  764.                 case '6':
  765.                 case '7':
  766.                 case '8':
  767.                     pcatchr(result, pstr[i], 1);
  768.                     if (inParens)
  769.                         pcatchr(result, ',', 1);
  770.                     pcatchr(result, ' ', 1);
  771.                     inParens = false;
  772.                     break;
  773.                 case '(':
  774.                     inParens = true;
  775.                     pcat(result, "\p, at, ");
  776.                     break;
  777.                 case ')':
  778.                     inParens = false;
  779.                     break;
  780.                 case '-':
  781.                     pcat(result,  "\p too ");
  782.                     break;
  783.                 case 'x':
  784.                     pcat(result, "\p takes ");
  785.                     break;
  786.                 case '=':
  787.                     if (enPas) {
  788.                         pcat(result, "\p, en paw saunt ");
  789.                         enPas = false;
  790.                     }
  791.                     pcat(result, "\p, promote too ");
  792.                     break;
  793.                 case '+':
  794.                     if (enPas) {
  795.                         pcat(result, "\p, en paw saunt ");
  796.                         enPas = false;
  797.                     }
  798.                     pcat(result, "\p, check");
  799.                     break;
  800.             }
  801.         }
  802.  
  803.         if (enPas) {
  804.             pcat(result, "\p, en paw saunt ");
  805.             enPas = false;
  806.         }
  807.  
  808.         pcpy(pstr, result);
  809.         return;
  810.     }
  811.  
  812.     if ((pstr[i] >= '1') && (pstr[i] <= '8')) {
  813.         if (pstr[0] > (i + 1)) {
  814.             pcpy(from, "\pat, ");
  815.             pcatchr(from, pstr[i++], 1);
  816.             pcat(from, "\p, ");
  817.         }
  818.     }
  819.  
  820.     if ((pstr[i] >= 'a') && (pstr[i] <= 'h')) {
  821.         if (pstr[0] > (i + 1)) {
  822.             if ((pstr[i + 1] < '1') || (pstr[i + 1] > '8')) {
  823.                 pcpy(from, "\pat, ");
  824.                 pcat(from, cols[pstr[i++] - 'a']);
  825.                 pcatchr(from, ' ', 1);
  826.             }
  827.         }
  828.     }
  829.  
  830.     if (i > pstr[0]) return;
  831.  
  832.     if (pstr[i] == 'x') {
  833.         pcpy(verb, "\ptakes, ");
  834.         ++i;
  835.     }
  836.  
  837.     if (i > pstr[0]) return;
  838.  
  839.     if ((pstr[i] >= 'a') && (pstr[i] <= 'h')) {
  840.         pcat(to, cols[pstr[i++] - 'a']);
  841.         pcatchr(to, ' ', 1);
  842.     }
  843.  
  844.     if (i > pstr[0]) return;
  845.  
  846.     if ((pstr[i] >= '1') && (pstr[i] <= '8')) {
  847.         pcatchr(to, pstr[i++], 1);
  848.         pcatchr(to, ' ', 1);
  849.     }
  850.  
  851.     if (i <= pstr[0]) {
  852.         if (pstr[i] == '=') {
  853.             pcat(epi, "\p, promote too ");
  854.             if (++i > pstr[0]) return;
  855.             if (pstr[i] == 'N') pcat(epi, "\pknight ");
  856.             if (pstr[i] == 'B') pcat(epi, "\pbishop ");
  857.             if (pstr[i] == 'R') pcat(epi, "\prook ");
  858.             if (pstr[i] == 'Q') pcat(epi, "\pkweenn ");
  859.             ++i;
  860.         }
  861.     }
  862.  
  863.     if (i <= pstr[0]) {
  864.         if (pstr[i] == '+')
  865.             pcat(epi, "\p, check");
  866.     }
  867.  
  868.     pcpy(pstr, piece);
  869.     pcat(pstr, from);
  870.     pcat(pstr, verb);
  871.     pcat(pstr, to);
  872.     pcat(pstr, epi);
  873. }
  874.  
  875.  
  876.  
  877. /*****************************************************************************/
  878.  
  879.  
  880.  
  881. #pragma segment Window
  882. void    SayTheMove(FileRecHndl frHndl)
  883. {
  884.     Handle    txt;
  885.     Str255    pstr;
  886.     short    i;
  887.     Boolean    move;
  888.  
  889.     if (!(*frHndl)->doc.doSpeech) return;
  890.  
  891.     MakeMove(frHndl, -1, 0, 0);
  892.  
  893.     i = (*frHndl)->doc.gameIndex;
  894.     if (gDescriptive)
  895.         move = Descriptive(frHndl, i, i + 1, pstr);
  896.     else
  897.         move = Algebraic(frHndl, i, i + 1, pstr);
  898.     if (move) MakeVerbose(frHndl, pstr);
  899.  
  900.     MakeMove(frHndl, 1, 0, 0);
  901.  
  902.     switch (i = GameStatus(frHndl)) {
  903.         case kYouWin:
  904.         case kYouLose:
  905.             pcat(pstr, "\p mate");
  906.             break;
  907.     }
  908.  
  909.     txt = NewHandle(pstr[0]);
  910.     BlockMove(pstr + 1, *txt, pstr[0]);
  911.     SayText(nil, txt, (*frHndl)->doc.theVoice);
  912.     DisposeHandle(txt);
  913. }
  914.  
  915.  
  916.  
  917. /*****************************************************************************/
  918.  
  919.  
  920.  
  921. #pragma segment Window
  922. static short    IsAlgebraic(FileRecHndl frHndl, Ptr cptr, short lastChar, short *rfrom, short *rto, short *rpromote)
  923. {
  924.     short            numUsed, numLglMoves, c0, c1, i, j, k, numMatch;
  925.     short            from, to, fromRow, fromCol, toRow, toCol, piece, f, t, r, c;
  926.     Boolean            take, check;
  927.     MoveListHndl    lglMoves;
  928.     static char        goodFirstChar[] = "abcdefghPNBRQK";
  929.  
  930.     *rfrom = *rto = -1;                        /* Not algebraic move flag. */
  931.     *rpromote = QUEEN;
  932.  
  933.     if (lastChar < 1) return(1);            /* An algebraic move is at least 2 characters. */
  934.  
  935.     c0 = cptr[0];
  936.     numUsed = 1;                            /* Always use at least 1 character per pass. */
  937.  
  938.     numLglMoves = (*frHndl)->doc.numLegalMoves;
  939.     lglMoves    = (*frHndl)->doc.legalMoves;
  940.  
  941.     for (i = 0; goodFirstChar[i]; ++i)
  942.         if (c0 == goodFirstChar[i]) break;
  943.  
  944.     if (!goodFirstChar[i]) return(numUsed);        /* Just used first char. */
  945.  
  946.     fromRow = fromCol = -1;
  947.     toRow   = toCol   = -1;
  948.     from = to = 0;
  949.     take = check = false;
  950.         /* From may be square or piece. */
  951.         /* To will be square. */
  952.         /* If to stays 0, then to = from, and from = PAWN.  More on this later. */
  953.  
  954.     for (;;) {        /* Used to break from for jump purposes. */
  955.  
  956.         if (i < 8) {        /* It is probably a pawn move.  The form is one of   */
  957.                             /* the following: e4, dxe, dxe4, d3xe4, d3e4, d3-e4. */
  958.                             /* Due to this, it can't be decided yet as to        */
  959.                             /* whether we are looking at the from or the to      */
  960.                             /* location.                                         */
  961.  
  962.             from = PAWN;
  963.             fromCol = i;    /* Might end up the toCol, so keep this in mind. */
  964.             c1 = cptr[numUsed];
  965.             if ((c1 >= '1') && (c1 <= '8')) {
  966.                 fromRow = 7 - (c1 - '1');    /* Might end up the toRow. */
  967.                 if (++numUsed > lastChar) break;
  968.                 c1 = cptr[numUsed];
  969.             }
  970.             if ((c1 == 'x') || (c1 == 'X')) take = true;
  971.             if ((take) || (c1 == '-')) {
  972.                 if (++numUsed > lastChar) break;
  973.                 c0 = cptr[numUsed];
  974.                 if ((c0 < 'a') || (c0 > 'h')) break;
  975.                 toCol = c0 - 'a';
  976.                 if (numUsed >= lastChar) break;
  977.                 else {
  978.                     c1 = cptr[++numUsed];
  979.                     if ((c1 >= '1') && (c1 <= '8')) {
  980.                         toRow = 7 - (c1 - '1');
  981.                         to = 10 * toRow + toCol + START_IBNDS;
  982.                         from = PAWN;        /* Assume it is a pawn move. */
  983.                         if ((fromRow != -1) && (fromCol != -1))
  984.                             from = 10 * fromRow + fromCol + START_IBNDS;
  985.                                 /* Move is of form d3-e4, so it doesn't have to be a pawn. */
  986.                         break;
  987.                     }
  988.                 }
  989.             }
  990.             else {
  991.                 if (fromRow != -1) {            /* Of the form e4. */
  992.                     if ((c1 < 'a') || (c1 > 'h')) {
  993.                         from = PAWN;
  994.                         to = 10 * fromRow + fromCol + START_IBNDS;
  995.                         fromRow = fromCol = -1;        /* No hint of where from. */
  996.                     }
  997.                     else {
  998.                         toCol = c1 - 'a';
  999.                         c0 = c1;
  1000.                         if (++numUsed > lastChar) break;
  1001.                         c1 = cptr[numUsed];
  1002.                         if ((c1 >= '1') && (c1 <= '8')) {
  1003.                             toRow = 7 - (c1 - '1');
  1004.                             to = 10 * toRow + toCol + START_IBNDS;
  1005.                             from = PAWN;        /* Assume it is a pawn move. */
  1006.                             if ((fromRow != -1) && (fromCol != -1))
  1007.                                 from = 10 * fromRow + fromCol + START_IBNDS;
  1008.                                     /* Move is of form d3e4, so it doesn't have to be a pawn. */
  1009.                             ++numUsed;
  1010.                             break;
  1011.                         }
  1012.                     }
  1013.                 }
  1014.                 break;
  1015.             }
  1016.         }
  1017.  
  1018.         else from = i - 7;        /* Remember which kind of piece. */
  1019.  
  1020.         c0 = cptr[numUsed];
  1021.  
  1022.         if (c0 == '(') {    /* Parens are optional -- just skip them. */
  1023.             if (++numUsed > lastChar) break;
  1024.             c0 = cptr[numUsed];
  1025.         }
  1026.  
  1027.         if ((c0 >= 'a') && (c0 <= 'h')) {
  1028.             fromCol = c0 - 'a';
  1029.             if (++numUsed > lastChar) break;
  1030.             c0 = cptr[numUsed];
  1031.         }
  1032.         if ((c0 >= 'a') && (c0 <= 'h')) {
  1033.             toCol = c0 - 'a';
  1034.             if (++numUsed > lastChar) break;
  1035.             c1 = cptr[numUsed];
  1036.             if ((c1 >= '1') && (c1 <= '8')) {
  1037.                 toRow = 7 - (c1 - '1');
  1038.                 to = 10 * toRow + toCol + START_IBNDS;
  1039.                 ++numUsed;
  1040.             }
  1041.             break;
  1042.         }
  1043.         if ((c0 >= '1') && (c0 <= '8')) {
  1044.             fromRow = 7 - (c0 - '1');
  1045.             if (++numUsed > lastChar) break;
  1046.             c0 = cptr[numUsed];
  1047.         }
  1048.  
  1049.         if (c0 == ')') {    /* Parens are optional -- just skip them. */
  1050.             if (++numUsed > lastChar) break;
  1051.             c0 = cptr[numUsed];
  1052.         }
  1053.  
  1054.         if ((c0 == 'x') || (c0 == 'X')) take = true;
  1055.         if ((take) || (c0 == '-')) {
  1056.             if ((c0 == 'x') || (c0 == 'X') || (c0 == '-')) ++numUsed;
  1057.             if (numUsed > lastChar) break;
  1058.             c0 = cptr[numUsed];
  1059.         }
  1060.  
  1061.         if ((c0 >= 'a') && (c0 <= 'h')) {
  1062.             toCol = c0 - 'a';
  1063.             if (++numUsed > lastChar) break;
  1064.             c1 = cptr[numUsed];
  1065.             if ((c1 >= '1') && (c1 <= '8')) {
  1066.                 toRow = 7 - (c1 - '1');
  1067.                 to = 10 * toRow + toCol + START_IBNDS;
  1068.                 ++numUsed;
  1069.             }
  1070.             break;
  1071.         }
  1072.         else {
  1073.             if ((fromRow != -1) && (fromCol != -1)) {
  1074.                 to = 10 * fromRow + fromCol + START_IBNDS;
  1075.                 fromRow = fromCol = -1;        /* No hint of where from. */
  1076.             }
  1077.             break;
  1078.         }
  1079.  
  1080.         break;
  1081.     }
  1082.  
  1083.     if ((!to) && (toRow == -1) && (toCol == -1)) {
  1084.         if ((fromRow != -1) && (fromCol != -1)) {
  1085.             to = 10 * fromRow + fromCol + START_IBNDS;
  1086.             fromRow = fromCol = -1;
  1087.         }
  1088.     }
  1089.  
  1090.     if ((to) || (toRow > -1) || (toCol > -1)) {
  1091.         if (numUsed < lastChar) {
  1092.             c0 = cptr[numUsed]; 
  1093.             if (c0 == '=') {
  1094.                 if (++numUsed <= lastChar) {
  1095.                     c0 = cptr[numUsed];
  1096.                     if (c0 == 'N') *rpromote = KNIGHT;
  1097.                     if (c0 == 'B') *rpromote = BISHOP;
  1098.                     if (c0 == 'R') *rpromote = ROOK;
  1099.                     if ((c0 == 'N') || (c0 == 'B') || (c0 == 'R') || (c0 == 'Q'))
  1100.                         if (++numUsed <= lastChar)
  1101.                             c0 = cptr[numUsed];
  1102.                 }
  1103.             }
  1104.         }
  1105.     }
  1106.     if (c0 == '+') {
  1107.          check = true;
  1108.         if (++numUsed <= lastChar) c0 = cptr[numUsed];
  1109.     }
  1110.  
  1111.     for (numMatch = 0, j = 0; j < 2; ++j) {
  1112.         for (i = 0; i < numLglMoves; ++i) {
  1113.             f = (**lglMoves)[i].moveFrom;
  1114.             t = (**lglMoves)[i].moveTo;
  1115.  
  1116.             if (to >= START_IBNDS) {            /* If we have a fully formed to...               */
  1117.                 if (to != t) continue;            /* If to is different than this move, next move. */
  1118.             }
  1119.             else {
  1120.                 if (to) {
  1121.                     piece = (*frHndl)->doc.theBoard[t];
  1122.                     if (piece < 0) piece = -piece;
  1123.                     if (piece > BK) piece -= KSIDEPIECE;
  1124.                     if (piece != to) continue;
  1125.                 }
  1126.                 if ((!to) && (toRow == -1) && (toCol == -1)) continue;
  1127.                 r = (t - START_IBNDS) / 10;
  1128.                 c = t - START_IBNDS - 10 * r;
  1129.                 if (toRow == -1) r = -1;
  1130.                 if (toCol == -1) c = -1;
  1131.                 if ((toRow != r) || (toCol != c)) continue;
  1132.                 if (take) {
  1133.                     k = (**lglMoves)[i].moveTo;
  1134.                     if (!(*frHndl)->doc.theBoard[k]) continue;
  1135.                 }
  1136.             }
  1137.  
  1138.             if (from >= START_IBNDS) {
  1139.                 if (from == f) {
  1140.                     if (!j) ++numMatch;
  1141.                     else {
  1142.                         if (numMatch < 2) break;
  1143.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1144.                     }
  1145.                 }
  1146.                 continue;
  1147.             }
  1148.             piece = (*frHndl)->doc.theBoard[f];
  1149.             if (piece < 0) piece = -piece;
  1150.             if (piece > BK) piece -= KSIDEPIECE;
  1151.             if (piece == from) {
  1152.                 r = (f - START_IBNDS) / 10;
  1153.                 c = f - START_IBNDS - 10 * r;
  1154.                 if (fromRow == -1) r = -1;
  1155.                 if (fromCol == -1) c = -1;
  1156.                 if ((fromRow == r) && (fromCol == c)) {
  1157.                     if (!j) ++numMatch;
  1158.                     else {
  1159.                         if (numMatch < 2) break;
  1160.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1161.                     }
  1162.                 }
  1163.             }
  1164.         }
  1165.     }
  1166.  
  1167.     if (i < numLglMoves) {
  1168.         *rfrom = (**lglMoves)[i].moveFrom;
  1169.         *rto   = (**lglMoves)[i].moveTo;
  1170.     };
  1171.  
  1172.     return(numUsed);
  1173. }
  1174.  
  1175.  
  1176.  
  1177. /*****************************************************************************/
  1178.  
  1179.  
  1180.  
  1181. #pragma segment Window
  1182. static short    IsDescriptive(FileRecHndl frHndl, Ptr cptr, short lastChar, short *rfrom, short *rto, short *rpromote)
  1183. {
  1184.     short            numUsed, numLglMoves, c0, i, j, k, numMatch;
  1185.     short            from, to, fromRow, fromCol, fromCol2, toRow, toCol, toCol2;
  1186.     short            piece, f, t, r, c, color;
  1187.     Boolean            take, check;
  1188.     MoveListHndl    lglMoves;
  1189.     static char        goodPieceChar[] = "PNBRQK";
  1190.     static char        goodFTChar[]    = "PNBRQK12345678";
  1191.  
  1192.     *rfrom = *rto = -1;                        /* Not algebraic move flag. */
  1193.     *rpromote = QUEEN;
  1194.  
  1195.     color = WhosMove(frHndl);                /* Who's move it is. */
  1196.  
  1197.     if (lastChar < 1) return(1);            /* An algebraic move is at least 2 characters. */
  1198.  
  1199.     c0 = cptr[0];
  1200.     numUsed = 1;                            /* Always use at least 1 character per pass. */
  1201.  
  1202.     numLglMoves = (*frHndl)->doc.numLegalMoves;
  1203.     lglMoves    = (*frHndl)->doc.legalMoves;
  1204.  
  1205.     for (i = 0; goodPieceChar[i]; ++i) if (c0 == goodPieceChar[i]) break;
  1206.     if (!goodPieceChar[i]) return(numUsed);        /* Just used first char. */
  1207.  
  1208.     fromRow = fromCol = fromCol2 = -1;
  1209.     toRow   = toCol   = toCol2   = -1;
  1210.     from = to = 0;
  1211.     take = check = false;
  1212.         /* From may be square or piece. */
  1213.         /* To will be square. */
  1214.         /* If to stays 0, then to = from, and from = PAWN.  More on this later. */
  1215.  
  1216.     for (;;) {        /* Used to break from for jump purposes. */
  1217.  
  1218.         from = i + 1;        /* Remember which kind of piece. */
  1219.  
  1220.         c0 = cptr[numUsed];
  1221.         if (from == QUEEN) {
  1222.             if (c0 == 'R')
  1223.                 from = ROOK;
  1224.             if (c0 == 'N')
  1225.                 from = KNIGHT;
  1226.             if (c0 == 'B')
  1227.                 from = BISHOP;
  1228.             if (from != QUEEN)
  1229.                 if (++numUsed > lastChar)
  1230.                     return(numUsed);
  1231.             c0 = cptr[numUsed];
  1232.         }
  1233.         if (from == KING) {
  1234.             if (c0 == 'R')
  1235.                 from = ROOK + KSIDEPIECE;
  1236.             if (c0 == 'N')
  1237.                 from = KNIGHT + KSIDEPIECE;
  1238.             if (c0 == 'B')
  1239.                 from = BISHOP + KSIDEPIECE;
  1240.             if (from != KING)
  1241.                 if (++numUsed > lastChar)
  1242.                     return(numUsed);
  1243.             c0 = cptr[numUsed];
  1244.         }
  1245.  
  1246.         if (c0 == '(') {
  1247.             if (++numUsed > lastChar) return(numUsed);
  1248.             c0 = cptr[numUsed];
  1249.  
  1250.             for (j = 1; goodFTChar[j]; ++j) if (c0 == goodFTChar[j]) break;
  1251.             if (!goodFTChar[j]) return(numUsed);        /* Just used first char. */
  1252.  
  1253.             if (c0 == 'R') {
  1254.                 fromCol  = 0;
  1255.                 fromCol2 = 7;
  1256.             }
  1257.             if (c0 == 'N') {
  1258.                 fromCol  = 1;
  1259.                 fromCol2 = 6;
  1260.             }
  1261.             if (c0 == 'B') {
  1262.                 fromCol  = 2;
  1263.                 fromCol2 = 5;
  1264.             }
  1265.             if (c0 == 'Q') {
  1266.                 fromCol  = 3;
  1267.                 fromCol2 = 3;
  1268.             }
  1269.             if (c0 == 'K') {
  1270.                 fromCol  = 4;
  1271.                 fromCol2 = 4;
  1272.             }
  1273.             if (fromCol != -1) {
  1274.                 if (++numUsed > lastChar) return(numUsed);
  1275.                 c0 = cptr[numUsed];
  1276.             }
  1277.  
  1278.             if (c0 == 'R') {
  1279.                 if (fromCol == 3) {
  1280.                     fromCol  = 0;
  1281.                     fromCol2 = 0;
  1282.                 }
  1283.                 if (fromCol == 4) {
  1284.                     fromCol  = 7;
  1285.                     fromCol2 = 7;
  1286.                 }
  1287.                 if (fromCol != fromCol2)  return(numUsed);
  1288.                 if (++numUsed > lastChar) return(numUsed);
  1289.                 c0 = cptr[numUsed];
  1290.             }
  1291.             if (c0 == 'N') {
  1292.                 if (fromCol == 3) {
  1293.                     fromCol  = 1;
  1294.                     fromCol2 = 1;
  1295.                 }
  1296.                 if (fromCol == 4) {
  1297.                     fromCol  = 6;
  1298.                     fromCol2 = 6;
  1299.                 }
  1300.                 if (fromCol != fromCol2)  return(numUsed);
  1301.                 if (++numUsed > lastChar) return(numUsed);
  1302.                 c0 = cptr[numUsed];
  1303.             }
  1304.             if (c0 == 'B') {
  1305.                 if (fromCol == 3) {
  1306.                     fromCol  = 2;
  1307.                     fromCol2 = 2;
  1308.                 }
  1309.                 if (fromCol == 4) {
  1310.                     fromCol  = 5;
  1311.                     fromCol2 = 5;
  1312.                 }
  1313.                 if (fromCol != fromCol2)  return(numUsed);
  1314.                 if (++numUsed > lastChar) return(numUsed);
  1315.                 c0 = cptr[numUsed];
  1316.             }
  1317.  
  1318.             if ((c0 >= '1') && (c0 <= '8')) {
  1319.                 fromRow = '8' - c0;
  1320.                 if (color == BLACK) fromRow = 7 - fromRow;
  1321.                 if (++numUsed > lastChar) return(numUsed);
  1322.                 c0 = cptr[numUsed];
  1323.             }
  1324.  
  1325.             if (c0 == ')') {
  1326.                 if (++numUsed > lastChar) return(numUsed);
  1327.                 c0 = cptr[numUsed];
  1328.             }
  1329.         }
  1330.  
  1331.         if ((c0 == 'x') || (c0 == 'X')) {
  1332.             take = true;
  1333.             if (++numUsed > lastChar) return(numUsed);
  1334.             c0 = cptr[numUsed];
  1335.             for (i = 0; goodPieceChar[i]; ++i) if (c0 == goodPieceChar[i]) break;
  1336.             if (!goodPieceChar[i]) return(numUsed);
  1337.             to = i + 1;
  1338.             if (++numUsed > lastChar) break;
  1339.             c0 = cptr[numUsed];
  1340.  
  1341.             switch (to) {
  1342.                 case ROOK:
  1343.                     if (c0 == 'P') {
  1344.                         to     = PAWN;
  1345.                         toCol  = 0;
  1346.                         toCol2 = 7;
  1347.                         if (++numUsed > lastChar) break;
  1348.                         c0 = cptr[numUsed];
  1349.                     }
  1350.                     break;
  1351.                 case KNIGHT:
  1352.                     if (c0 == 'P') {
  1353.                         to     = PAWN;
  1354.                         toCol  = 1;
  1355.                         toCol2 = 6;
  1356.                         if (++numUsed > lastChar) break;
  1357.                         c0 = cptr[numUsed];
  1358.                     }
  1359.                     break;
  1360.                 case BISHOP:
  1361.                     if (c0 == 'P') {
  1362.                         to     = PAWN;
  1363.                         toCol  = 2;
  1364.                         toCol2 = 5;
  1365.                         if (++numUsed > lastChar) break;
  1366.                         c0 = cptr[numUsed];
  1367.                     }
  1368.                     break;
  1369.                 case QUEEN:
  1370.                     if (c0 == 'R')
  1371.                         to = ROOK;
  1372.                     if (c0 == 'N')
  1373.                         to = KNIGHT;
  1374.                     if (c0 == 'B')
  1375.                         to = BISHOP;
  1376.                     if (to != QUEEN)
  1377.                         if (++numUsed > lastChar)
  1378.                             break;
  1379.                     c0 = cptr[numUsed];
  1380.                     if (c0 == 'P') {
  1381.                         to     = PAWN;
  1382.                         toCol  = 3;
  1383.                         toCol2 = 3;
  1384.                         if (++numUsed > lastChar) break;
  1385.                         c0 = cptr[numUsed];
  1386.                     }
  1387.                     break;
  1388.                 case KING:
  1389.                     if (c0 == 'R')
  1390.                         to = ROOK + KSIDEPIECE;
  1391.                     if (c0 == 'N')
  1392.                         to = KNIGHT + KSIDEPIECE;
  1393.                     if (c0 == 'B')
  1394.                         to = BISHOP + KSIDEPIECE;
  1395.                     if (to != KING)
  1396.                         if (++numUsed > lastChar)
  1397.                             break;
  1398.                     c0 = cptr[numUsed];
  1399.                     if (c0 == 'P') {
  1400.                         to     = PAWN;
  1401.                         toCol  = 4;
  1402.                         toCol2 = 4;
  1403.                         if (++numUsed > lastChar) break;
  1404.                         c0 = cptr[numUsed];
  1405.                     }
  1406.                     break;
  1407.             }
  1408.             if (numUsed > lastChar) break;
  1409.         }
  1410.  
  1411.         if ((c0 == '-') || (c0 == '(')) {
  1412.             if (++numUsed > lastChar) return(numUsed);
  1413.             c0 = cptr[numUsed];
  1414.  
  1415.             if (c0 == '-') {
  1416.                 for (j = 1; goodPieceChar[j]; ++j) if (c0 == goodPieceChar[j]) break;
  1417.                 if (!goodPieceChar[j]) return(numUsed);        /* Just used first char. */
  1418.             }
  1419.             if (c0 == '(') {
  1420.                 for (j = 1; goodFTChar[j]; ++j) if (c0 == goodFTChar[j]) break;
  1421.                 if (!goodFTChar[j]) return(numUsed);        /* Just used first char. */
  1422.             }
  1423.  
  1424.             if (c0 == 'R') {
  1425.                 toCol  = 0;
  1426.                 toCol2 = 7;
  1427.             }
  1428.             if (c0 == 'N') {
  1429.                 toCol  = 1;
  1430.                 toCol2 = 6;
  1431.             }
  1432.             if (c0 == 'B') {
  1433.                 toCol  = 2;
  1434.                 toCol2 = 5;
  1435.             }
  1436.             if (c0 == 'Q') {
  1437.                 toCol  = 3;
  1438.                 toCol2 = 3;
  1439.             }
  1440.             if (c0 == 'K') {
  1441.                 toCol  = 4;
  1442.                 toCol2 = 4;
  1443.             }
  1444.             if (toCol != -1) {
  1445.                 if (++numUsed > lastChar) return(numUsed);
  1446.                 c0 = cptr[numUsed];
  1447.             }
  1448.  
  1449.             if (c0 == 'R') {
  1450.                 if (toCol == 3) {
  1451.                     toCol  = 0;
  1452.                     toCol2 = 0;
  1453.                 }
  1454.                 if (toCol == 4) {
  1455.                     toCol  = 7;
  1456.                     toCol2 = 7;
  1457.                 }
  1458.                 if (toCol != toCol2)  return(numUsed);
  1459.                 if (++numUsed > lastChar) return(numUsed);
  1460.                 c0 = cptr[numUsed];
  1461.             }
  1462.             if (c0 == 'N') {
  1463.                 if (toCol == 3) {
  1464.                     toCol  = 1;
  1465.                     toCol2 = 1;
  1466.                 }
  1467.                 if (toCol == 4) {
  1468.                     toCol  = 6;
  1469.                     toCol2 = 6;
  1470.                 }
  1471.                 if (toCol != toCol2)  return(numUsed);
  1472.                 if (++numUsed > lastChar) return(numUsed);
  1473.                 c0 = cptr[numUsed];
  1474.             }
  1475.             if (c0 == 'B') {
  1476.                 if (toCol == 3) {
  1477.                     toCol  = 2;
  1478.                     toCol2 = 2;
  1479.                 }
  1480.                 if (toCol == 4) {
  1481.                     toCol  = 5;
  1482.                     toCol2 = 5;
  1483.                 }
  1484.                 if (toCol != toCol2)  return(numUsed);
  1485.                 if (++numUsed > lastChar) return(numUsed);
  1486.                 c0 = cptr[numUsed];
  1487.             }
  1488.  
  1489.             if ((c0 >= '1') && (c0 <= '8')) {
  1490.                 toRow = '8' - c0;
  1491.                 if (color == BLACK) toRow = 7 - toRow;
  1492.                 if (++numUsed > lastChar) break;
  1493.                 c0 = cptr[numUsed];
  1494.             }
  1495.  
  1496.             if (c0 == ')') {
  1497.                 if (++numUsed > lastChar) break;
  1498.                 c0 = cptr[numUsed];
  1499.             }
  1500.         }
  1501.  
  1502.         break;
  1503.     }
  1504.  
  1505.     if ((to) || (toRow > -1) || (toCol > -1)) {
  1506.         if (numUsed < lastChar) {
  1507.             c0 = cptr[numUsed]; 
  1508.             if (c0 == '=') {
  1509.                 if (++numUsed <= lastChar) {
  1510.                     c0 = cptr[numUsed];
  1511.                     if (c0 == 'N') *rpromote = KNIGHT;
  1512.                     if (c0 == 'B') *rpromote = BISHOP;
  1513.                     if (c0 == 'R') *rpromote = ROOK;
  1514.                     if ((c0 == 'N') || (c0 == 'B') || (c0 == 'R') || (c0 == 'Q'))
  1515.                         if (++numUsed <= lastChar)
  1516.                             c0 = cptr[numUsed];
  1517.                 }
  1518.             }
  1519.         }
  1520.     }
  1521.     if (c0 == '+') {
  1522.          check = true;
  1523.         if (++numUsed <= lastChar) c0 = cptr[numUsed];
  1524.     }
  1525.  
  1526.     for (numMatch = 0, j = 0; j < 2; ++j) {
  1527.         for (i = 0; i < numLglMoves; ++i) {
  1528.             f = (**lglMoves)[i].moveFrom;
  1529.             t = (**lglMoves)[i].moveTo;
  1530.  
  1531.             if (to >= START_IBNDS) {            /* If we have a fully formed to...               */
  1532.                 if (to != t) continue;            /* If to is different than this move, next move. */
  1533.             }
  1534.             else {
  1535.                 if (to) {
  1536.                     piece = (*frHndl)->doc.theBoard[t];
  1537.                     if (piece < 0) piece = -piece;
  1538.                     if (to <= BK)
  1539.                         if (piece > BK)
  1540.                             piece -= KSIDEPIECE;
  1541.                     if (piece != to) continue;
  1542.                 }
  1543.                 if ((!to) && (toRow == -1) && (toCol == -1)) continue;
  1544.                 r = (t - START_IBNDS) / 10;
  1545.                 c = t - START_IBNDS - 10 * r;
  1546.                 if (toRow == -1) r = -1;
  1547.                 if (toCol == -1) c = -1;
  1548.                     if (
  1549.                     (toRow != r) ||
  1550.                     ((toCol != c) && (toCol2 != c))
  1551.                 ) continue;
  1552.                 if (take) {
  1553.                     k = (**lglMoves)[i].moveTo;
  1554.                     if (!(*frHndl)->doc.theBoard[k]) continue;
  1555.                 }
  1556.             }
  1557.  
  1558.             if (from >= START_IBNDS) {
  1559.                 if (from == f) {
  1560.                     if (!j) ++numMatch;
  1561.                     else {
  1562.                         if (numMatch < 2) break;
  1563.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1564.                     }
  1565.                 }
  1566.                 continue;
  1567.             }
  1568.             piece = (*frHndl)->doc.theBoard[f];
  1569.             if (piece < 0) piece = -piece;
  1570.             if (from <= BK)
  1571.                 if (piece > BK)
  1572.                     piece -= KSIDEPIECE;
  1573.             if (piece == from) {
  1574.                 r = (f - START_IBNDS) / 10;
  1575.                 c = f - START_IBNDS - 10 * r;
  1576.                 if (fromRow == -1) r = -1;
  1577.                 if (fromCol == -1) c = -1;
  1578.                 if (
  1579.                     (fromRow == r) &&
  1580.                     ((fromCol == c) || (fromCol2 == c))
  1581.                 ) {
  1582.                     if (!j) ++numMatch;
  1583.                     else {
  1584.                         if (numMatch < 2) break;
  1585.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1586.                     }
  1587.                 }
  1588.             }
  1589.         }
  1590.     }
  1591.  
  1592.     if (i < numLglMoves) {
  1593.         *rfrom = (**lglMoves)[i].moveFrom;
  1594.         *rto   = (**lglMoves)[i].moveTo;
  1595.     };
  1596.  
  1597.     return(numUsed);
  1598. }
  1599.  
  1600.  
  1601.  
  1602. /*****************************************************************************/
  1603.  
  1604.  
  1605.  
  1606. #pragma segment Window
  1607. Boolean    MoveCausesCheck(FileRecHndl game, short from, short to)
  1608. {
  1609.     short            numGameMoves, color, check;
  1610.     Boolean            docDirty;
  1611.     GameListHndl    gameMoves;
  1612.     long            size;
  1613.  
  1614.     gameMoves    = (*game)->doc.gameMoves;
  1615.     numGameMoves = (*game)->doc.numGameMoves;
  1616.     docDirty     = (*game)->fileState.docDirty;
  1617.  
  1618.     SetHandleSize((Handle)gGenMovesHndl, size = GetHandleSize((Handle)gameMoves));
  1619.     BlockMove(*(Handle)gameMoves, *(Handle)gGenMovesHndl, size);
  1620.     (*game)->doc.gameMoves = gGenMovesHndl;            /* Protect the game moves list. */
  1621.  
  1622.     color = (WhosMove(game) ^ 1);                        /* Who's move it is. */
  1623.  
  1624.     MakeMove(game, from, to, QUEEN);
  1625.     check = SquareAttacked(game,
  1626.         (*game)->doc.king[color].kingLoc, color);
  1627.     UnmakeMove(game);
  1628.  
  1629.     (*game)->doc.gameMoves      = gameMoves;
  1630.     (*game)->doc.numGameMoves   = numGameMoves;
  1631.     (*game)->fileState.docDirty = docDirty;
  1632.         /* Restore things the way we were.  We are done with MakeMove services. */
  1633.  
  1634.     if (check) return(true);
  1635.     else       return(false);
  1636. }
  1637.  
  1638.  
  1639.  
  1640.