home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / code / p_towerh.sit / Towers.lp
Encoding:
Text File  |  1988-10-09  |  21.0 KB  |  688 lines

  1. PROGRAM RotBarcb;
  2. {NOTES:}
  3. {*A bar is a ring on a peg}
  4. {*All bars use the same bitmap to restore what it has erased}
  5. {*A move is when a bar goes from one peg to anther}
  6.     CONST
  7.         kAngle = 9; {angle between each turn of the bar}
  8.         kNumTurn = 5; {90 div 9}
  9.         kBase = 10; {numturn * 2}
  10.         kBarWid = 4; {width of bar div 2}
  11.         kNumFrame = 40; {numturn * 8 }
  12.         kPi = 3.141592654;
  13.         kAlt = 67; {Height when bar should switch directions}
  14.         kPeg1 = 80; {Pos of peg A}
  15.         kPeg2 = 256; {Pos of peg B}
  16.         kPeg3 = 432; {Pos of peg C}
  17.         kVel = 4; {Velocity at which pegs travel}
  18.         kMaxBar = 6; {Maximun number of bars}
  19.         kMaxMove = 2; {Maximun number of bars moving at one time}
  20.         kMaxQue = 100; {maximun number of elements in que}
  21.         kDLOG = 129; {Dialog ID}
  22.  
  23.     TYPE
  24.         tPeg = (A, B, C);
  25.         tBar = 0..kMaxBar;
  26.         tMove = 0..kMaxMove;
  27.         tQueNum = 1..kMaxQue;
  28.         tFrame = 0..kNumFrame;
  29.  
  30.         tElement = RECORD {Each element in the queue holds a move}
  31.                 fFrom : tPeg;
  32.                 fTo : tPeg;
  33.             END;
  34.  
  35. {A stack holds the bars on each peg}
  36.         tStack = RECORD
  37.                 fElements : ARRAY[tBar] OF tBar;
  38.                 fTos : tBar;
  39.             END;
  40.  
  41. {The Que holds the moves waiting to be preformed}
  42.         tQueue = RECORD
  43.                 fElements : ARRAY[tQueNum] OF tElement;
  44.                 fFront, fRear : tQueNum;
  45.             END;
  46.  
  47. {Hold the information for each frame of a bar}
  48.         tBarData = RECORD
  49.                 fRgn : RgnHandle;
  50.                 fOrg : point;
  51.             END;
  52.  
  53. {Hold the information for the bar}
  54. {NOTES:}
  55. {*Memory is radically sacrificed for speed}
  56. {*fAlmost is used to tell MoveBars that the bar has reached its loc but}
  57. {  it still needs to spin}
  58. {*When a bar is at some peg and the bar above spins it will}
  59. {  erase the bars underneath it because they are not part of gSavePort}
  60. {  To fix this we save the bits underneath the bar at a peg in fSaveBits}
  61. {  and restore them after the peg moves}
  62. {*As much information to realated to a bar as possible is stored in tBarInfo}
  63.         tBarInfo = RECORD
  64.                 fFrame : ARRAY[tFrame] OF tBarData; {Hold the frames of the bar}
  65.                 fInd : tFrame;     {Hold the current index into fFrame}
  66.                 fLastInd : tFrame; {Hold the last index into the fFrame}
  67.                 fIndFill : tFrame; {Hold the index to the last horz frame}
  68.                 fRad : integer;    {Hold the radius of the bar}
  69.                 fLoc : point;      {Hold the current location of the bar}
  70.                 fDestLoc : point;  {Hold the destination location}
  71.                 fVel : point;      {Hold the current velocity of the bar}
  72.                 fOldRect : rect;   {Hold the previous position of the bar}
  73.                 fColor : Pattern;  {Hold the color of the bar}
  74.                 fAlmost : boolean; {Used to tell some proc that the bar still needs to spin}
  75.                 fSaveBits : BitMap; {Used to save the bits of gSavePort}
  76.                 fTo : tPeg;        {Destination peg}
  77.             END;
  78.  
  79. {This record stores the stack of bars on it}
  80. {and if this peg is free to move a bar to}
  81.         tPegInfo = RECORD
  82.                 fFree : boolean; {Peg available?}
  83.                 fBars : tStack;  {Stack of bars}
  84.             END;
  85.  
  86.         tBars = ARRAY[tBar] OF tBarInfo; {Hold all bars}
  87.         tPegs = ARRAY[tPeg] OF tPegInfo; {Hold all Pegs}
  88.         tMoveBars = ARRAY[tMove] OF tBar; {Hold moving bars}
  89.         tPegPositions = ARRAY[tPeg] OF integer; {Hold positions of Pegs}
  90.         tBarPositions = ARRAY[tBar] OF integer; {Hold positions of bars}
  91.  
  92.     VAR
  93.         gSavePort : GrafPtr; {Hold the port which saves the image}
  94.         gDrawPort : GrafPtr; {Hold the port to draw in}
  95.         gNumBars : tBar;     {Hold the number of bars}
  96.         gBar : tBars;        {Hold the bars}
  97.         gPeg : tPegs;        {Hold the pegs}
  98.         gMoveQue : tQueue;   {Hold the move queue}
  99.         gMoveBar : tMoveBars; {Hold the moving bars}
  100.         gPegPos : tPegPositions; {Hold the peg positions}
  101.         gBarPos : tBarPositions; {Hold the bar positions}
  102.         gEraseRgn : RgnHandle;   {Hold the erase region in PlotBar to save time}
  103.  
  104. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  105. {Stack routines}
  106. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  107.  
  108. {*****************************************************************************}
  109. {Init the stack pPeg}
  110. {*****************************************************************************}
  111.     PROCEDURE InitStack (pPeg : tPeg);
  112.     BEGIN
  113.         gPeg[pPeg].fBars.fTos := 0;
  114.     END;
  115.  
  116. {*****************************************************************************}
  117. {Push pBar onto the stack of pPeg}
  118. {*****************************************************************************}
  119.     PROCEDURE Push (pBar : tBar;
  120.                                     pPeg : tPeg);
  121.         VAR
  122.             lTemp : rect;
  123.     BEGIN
  124.         WITH gPeg[pPeg].fBars DO
  125.             BEGIN
  126.                 fTos := fTos + 1;
  127.                 fElements[fTos] := pBar;
  128.             END;
  129.         WITH gBar[pBar] DO {We must Draw the bar in gSavePort}
  130.             BEGIN
  131. {Calculate its rectangle on the screen}
  132.                 SetRect(lTemp, fLoc.h - fRad, fLoc.v - 4, fLoc.h + fRad, fLoc.v + 4);
  133.                 SetPort(gSavePort);
  134. {Save gSavePort's bits}
  135.                 CopyBits(gSavePort^.portBits, fSaveBits, lTemp, fSaveBits.bounds, srccopy, NIL);
  136.                 FillRgn(fFrame[fIndFill].fRgn, fColor); {Draw it in gSavePort}
  137.                 SetPort(gDrawPort);
  138.             END;
  139.     END;
  140.  
  141. {*****************************************************************************}
  142. {Get vBar out of the stack of pPeg}
  143. {*****************************************************************************}
  144.     PROCEDURE Pop (VAR vBar : tBar;
  145.                                     pPeg : tPeg);
  146.         VAR
  147.             lTemp : rect;
  148.     BEGIN
  149.         WITH gPeg[pPeg].fBars DO
  150.             BEGIN
  151.                 vBar := fElements[fTos];
  152.                 fTos := fTos - 1;
  153.             END;
  154.         WITH gBar[vBar] DO {Restore the saved bits}
  155.             BEGIN
  156.                 SetRect(lTemp, fLoc.h - fRad, fLoc.v - 4, fLoc.h + fRad, fLoc.v + 4);
  157.                 CopyBits(fSaveBits, gSavePort^.portBits, fSaveBits.bounds, lTemp, srccopy, NIL);
  158.             END;
  159.     END;
  160.  
  161. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  162. {Queue routines}
  163. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  164.  
  165. {*****************************************************************************}
  166. {Init the Queue}
  167. {*****************************************************************************}
  168.     PROCEDURE InitQue;
  169.     BEGIN
  170.         gMoveQue.fFront := 1;
  171.         gMoveQue.fRear := 1;
  172.     END;
  173.  
  174. {*****************************************************************************}
  175. {Get the next index into the queue}
  176. {*****************************************************************************}
  177.     PROCEDURE NextInd (VAR vInd : tQueNum);
  178.     BEGIN
  179.         IF vInd = kMaxQue THEN
  180.             vInd := 1
  181.         ELSE
  182.             vInd := vInd + 1;
  183.     END;
  184.  
  185. {*****************************************************************************}
  186. {Enq this move}
  187. {*****************************************************************************}
  188.     PROCEDURE Enq (pFrom, pTo : tPeg);
  189.     BEGIN
  190.         WITH gMoveQue DO
  191.             BEGIN
  192.                 fElements[fRear].fFrom := pFrom;
  193.                 fElements[fRear].fTo := pTo;
  194.                 NextInd(fRear);
  195.             END;
  196.     END;
  197.  
  198. {*****************************************************************************}
  199. {Deq the next move and put it into vElem}
  200. {*****************************************************************************}
  201.     PROCEDURE Deq (VAR vElem : tElement);
  202.     BEGIN
  203.         WITH gMoveQue DO
  204.             BEGIN
  205.                 vElem := fElements[fFront];
  206.                 NextInd(fFront);
  207.             END;
  208.     END;
  209.  
  210. {*****************************************************************************}
  211. {Get the move to be returned at the next Deq}
  212. {*****************************************************************************}
  213.     PROCEDURE TopElem (VAR vElem : tElement);
  214.     BEGIN
  215.         WITH gMoveQue DO
  216.             vElem := fElements[fFront];
  217.     END;
  218.  
  219. {*****************************************************************************}
  220. {Return true if the que is empty}
  221. {*****************************************************************************}
  222.     FUNCTION EmptyQue : boolean;
  223.     BEGIN
  224.         EmptyQue := gMoveQue.fFront = gMoveQue.fRear;
  225.     END;
  226.  
  227. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  228. {Drawing routines}
  229. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  230.  
  231. {*****************************************************************************}
  232. {Plot pBar using all the info in its record}
  233. {*****************************************************************************}
  234.     PROCEDURE PlotBar (pBar : tBar);
  235.  
  236. {  ***************************************************************************}
  237. {  Move the regions center to the absolute location (pLoch,pLocv)}
  238. {  ***************************************************************************}
  239.         PROCEDURE MoveRgn (pBarData : tBarData;
  240.                                         pLoch, pLocv : integer);
  241.             VAR
  242.                 dh, dv : integer;
  243.         BEGIN
  244.             WITH pBarData.fRgn^^.rgnBBox, pBarData DO
  245.                 BEGIN
  246.                     OffsetRgn(pBarData.fRgn, fOrg.h - left, fOrg.v - top);
  247.                     OffsetRgn(pBarData.fRgn, pLoch, pLocv);
  248.                 END;
  249.         END;
  250.  
  251.     BEGIN
  252.         WITH gBar[pBar] DO
  253.             BEGIN
  254.                 fInd := fInd + 1; {Inc the index}
  255.                 MoveRgn(fFrame[fInd], fLoc.h, fLoc.v); {Move the regionto the new loc}
  256.                 DiffRgn(fFrame[fLastInd].fRgn, fFrame[fInd].fRgn, gEraseRgn); {Calc the erase rgn}
  257.                 FillRgn(fFrame[fInd].fRgn, fColor); {Draw the bar}
  258. {Restore the Bits}
  259.                 CopyBits(gSavePort^.portBits, gDrawPort^.portBits, fOldRect, fOldRect, srccopy, gEraseRgn);
  260.                 fLastInd := fInd;
  261.                 SetRect(fOldRect, fLoc.h - fRad, fLoc.v - fRad, fLoc.h + fRad, fLoc.v + fRad);
  262.                 IF fInd = kNumFrame THEN
  263.                     fInd := 0;
  264.             END;
  265.     END;
  266.  
  267. {*****************************************************************************}
  268. {Start the move in pElem}
  269. {*****************************************************************************}
  270.     PROCEDURE StartMove (pElem : tElement);
  271.         VAR
  272.             lBar : tBar;
  273.             lMove : tMove;
  274.     BEGIN
  275.         gPeg[pElem.fTo].fFree := false; {Mark the dest peg as used}
  276.         pop(lBar, pElem.fFrom); {Get the bar to move}
  277.         WITH gBar[lBar] DO {Init the bar to move}
  278.             BEGIN
  279.                 fAlmost := false;
  280.                 SetPt(fVel, 0, -kVel);
  281.                 SetPt(fDestLoc, gPegPos[pElem.fTo], gBarPos[gPeg[pElem.fTo].fBars.fTos + 1]);
  282.                 fTo := pElem.fTo;
  283.             END;
  284. {Put the bar into the next available slot in gMoveBar}
  285.         lMove := 0;
  286.         REPEAT
  287.             lMove := lMove + 1;
  288.             IF gMoveBar[lMove] = 0 THEN
  289.                 BEGIN
  290.                     gMoveBar[lMove] := lBar;
  291.                     lMove := kMaxMove;
  292.                 END;
  293.         UNTIL lMove = kMaxMove;
  294.     END;
  295.  
  296. {*****************************************************************************}
  297. {Move the bars in gMoveBar}
  298. {*****************************************************************************}
  299.     PROCEDURE MoveBars;
  300.         VAR
  301.             x : tMove;
  302.  
  303. {  ***************************************************************************}
  304. {  Adjust the fLoc field of bar pBar and change direction if neccessary}
  305. {  Return true if bar has arrived at destination}
  306. {  ***************************************************************************}
  307.         FUNCTION MoveTheBar (pBar : tBar) : boolean;
  308.         BEGIN
  309.             MoveTheBar := false;
  310.             WITH gBar[pBar] DO {Adjust the velocity of the bar}
  311.                 BEGIN
  312.                     IF fVel.v = -kVel THEN
  313.                         IF fLoc.v <= kAlt THEN
  314.                             BEGIN
  315.                                 fVel.v := 0;
  316.                                 IF fLoc.h > fDestLoc.h THEN
  317.                                     fVel.h := -kVel
  318.                                 ELSE
  319.                                     fVel.h := kVel;
  320.                             END;
  321.                     IF fVel.v = 0 THEN
  322.                         BEGIN
  323.                             IF fVel.h = kVel THEN
  324.                                 IF fLoc.h >= fDestLoc.h THEN
  325.                                     BEGIN
  326.                                         fVel.h := 0;
  327.                                         fVel.v := kVel;
  328.                                     END;
  329.                             IF fVel.h = -kVel THEN
  330.                                 IF fLoc.h <= fDestLoc.h THEN
  331.                                     BEGIN
  332.                                         fVel.h := 0;
  333.                                         fVel.v := kVel;
  334.                                     END;
  335.                         END;
  336.                     IF fVel.v = kVel THEN
  337.                         IF fLoc.v >= fDestLoc.v THEN
  338.                             fAlmost := true;
  339.                     IF fAlmost THEN {do not adjust fLoc}
  340.                         BEGIN
  341.                             IF (fInd = 10) OR (fInd = 30) THEN
  342.                                 BEGIN
  343.                                     fIndFill := fInd + 1;
  344.                                     MoveTheBar := true;
  345.                                 END;
  346.                         END
  347.                     ELSE {Adjust it}
  348.                         AddPt(fVel, fLoc);
  349.                     PlotBar(pBar); {Plot the bar}
  350.                 END;
  351.         END;
  352.  
  353.     BEGIN
  354. {Update every bar in gMoveBar}
  355.         FOR x := 1 TO kMaxMove DO
  356.             IF gMoveBar[x] > 0 THEN
  357.                 IF MoveTheBar(gMoveBar[x]) THEN {We arrived}
  358.                     BEGIN
  359.                         Push(gMoveBar[x], gBar[gMoveBar[x]].fTo);
  360.                         gPeg[gBar[gMoveBar[x]].fTo].fFree := true;
  361.                         gMoveBar[x] := 0;
  362.                     END;
  363.     END;
  364.  
  365. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  366. {Processing routines}
  367. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  368.  
  369. {*****************************************************************************}
  370. {*****************************************************************************}
  371. {Decide if we can move a bar and return true if nothing left to do}
  372. {NOTE: This is the heart of the whole program}
  373. {*****************************************************************************}
  374. {*****************************************************************************}
  375.     FUNCTION SystemTime : boolean;
  376.         VAR
  377.             lMove : tMove;
  378.             lTempB : boolean;
  379.             lElem : tElement;
  380.     BEGIN
  381.         IF button THEN {We are tired of watching these bars go in circles}
  382.             ExitToShell;
  383.         lTempB := true;
  384. {Is there room to in gMoveBar}
  385.         FOR lMove := 1 TO kMaxMove DO
  386.             lTempB := lTempB AND (gMoveBar[lMove] <> 0);
  387.         IF NOT EmptyQue AND NOT lTempB THEN {A move is possible}
  388.             BEGIN
  389.                 TopElem(lElem);
  390.                 IF gPeg[lElem.fTo].fFree AND gPeg[lElem.fFrom].fFree THEN {Ok to move}
  391.                     BEGIN
  392.                         Deq(lElem);
  393.                         StartMove(lElem);
  394.                     END;
  395.             END;
  396. {Check to see if anything left do}
  397.         lTempB := true;
  398.         FOR lMove := 1 TO kMaxMove DO
  399.             lTempB := lTempB AND (gMoveBar[lMove] = 0);
  400.         SystemTime := EmptyQue AND lTempB;
  401.         MoveBars;
  402.     END;
  403.  
  404. {*****************************************************************************}
  405. {Calculate the moves to preform}
  406. {*****************************************************************************}
  407.     PROCEDURE Hanoi (pNumRings : tBar;
  408.                                     pFrom, pTo, pUsing : tPeg);
  409.     BEGIN
  410.         IF SystemTime THEN
  411.             ;
  412.         IF pNumRings = 1 THEN
  413.             Enq(pFrom, pTo)
  414.         ELSE
  415.             BEGIN
  416.                 hanoi(pNumRings - 1, pFrom, pUsing, pTo);
  417.                 Enq(pFrom, pTo);
  418.                 hanoi(pNumRings - 1, pUsing, pTo, pFrom);
  419.             END;
  420.     END;
  421.  
  422. {*****************************************************************************}
  423. {Init the program}
  424. {*****************************************************************************}
  425.     PROCEDURE Init;
  426.  
  427. {  ***************************************************************************}
  428. {  Get the number of bars to move}
  429. {  ***************************************************************************}
  430.         PROCEDURE GetNumBars;
  431.             VAR
  432.                 lDlog : DialogPtr;
  433.                 lItem : integer;
  434.                 lType : integer;
  435.                 lItemHand : Handle;
  436.                 lBox : Rect;
  437.                 lText : str255;
  438.                 lRslt : longint;
  439.         BEGIN
  440.             lDlog := GetNewDialog(kDLOG, NIL, pointer(-1));
  441.             REPEAT
  442.                 ModalDialog(NIL, lItem);
  443.                 GetDItem(lDlog, 2, ltype, lItemHand, lBox);
  444.                 GetIText(lItemHand, lText);
  445.                 StringToNum(lText, lRslt);
  446.                 gNumBars := integer(lRslt);
  447.             UNTIL (gNumBars <= 6) AND (gNumBars >= 3);
  448.             DisposDialog(lDlog);
  449.         END;
  450.  
  451. {  ***************************************************************************}
  452. {  Draw the Pegs}
  453. {  ***************************************************************************}
  454.         PROCEDURE DrawScreen;
  455.             VAR
  456.                 lTemp : Rect;
  457.         BEGIN
  458.             SetPort(gDrawPort);
  459.             SetRect(lTemp, 8, 235, 152, 243);
  460.             FillRect(lTemp, Black);
  461.             SetRect(lTemp, 184, 235, 328, 243);
  462.             FillRect(lTemp, Black);
  463.             SetRect(lTemp, 360, 235, 504, 243);
  464.             FillRect(lTemp, Black);
  465.             SetRect(lTemp, 76, 99, 84, 235);
  466.             FillRect(lTemp, Black);
  467.             SetRect(lTemp, 252, 99, 260, 235);
  468.             FillRect(lTemp, Black);
  469.             SetRect(lTemp, 428, 99, 436, 235);
  470.             FillRect(lTemp, Black);
  471.         END;
  472.  
  473. {  ***************************************************************************}
  474. {  Calculate the data for the frames of the bars}
  475. {  ***************************************************************************}
  476.         PROCEDURE SetupData;
  477.             VAR
  478.                 lBar : tBar;
  479.                 lFrame : integer;
  480.                 PtA, PtB : point;
  481.  
  482. {   **************************************************************************}
  483. {   Calculate two point tangent to the line pAngle degrees around the circle}
  484. {   **************************************************************************}
  485.             PROCEDURE Get2Tang (pAngle : real;
  486.                                             pRad : integer;
  487.                                             VAR PtA, PtB : point);
  488.                 VAR
  489.                     temp, temp2, xc, yc, m, perpm : real;
  490.             BEGIN
  491.                 yc := pRad * cos(pAngle * pi / 180);
  492.                 xc := pRad * sin(pAngle * pi / 180);
  493.                 perpm := -xc / yc;
  494.                 temp := kBarWid / (perpm * perpm + 1);
  495.                 temp2 := temp * perpm;
  496.                 PtA.h := round(yc - temp2);
  497.                 PtA.v := round(xc - temp);
  498.                 PtB.h := round(yc + temp2);
  499.                 PtB.v := round(xc + temp);
  500.             END;
  501.  
  502. {   **************************************************************************}
  503. {   Transform PtA and PtB into 8 more points}
  504. {   **************************************************************************}
  505.             PROCEDURE BuildData (pInd : integer;
  506.                                             pBar : tBar;
  507.                                             PtA, PtB : point);
  508.  
  509. {    *************************************************************************}
  510. {    Build a region around the given points}
  511. {    *************************************************************************}
  512.                 PROCEDURE InsertElem (pIndex, pP1h, pP1v, pP2h, pP2v : integer);
  513.                 BEGIN
  514.                     WITH gBar[pBar] DO
  515.                         BEGIN
  516.                             fFrame[pIndex].fRgn := NewRgn;
  517.                             OpenRgn;
  518.                             MoveTo(pP1h, pP1v);
  519.                             LineTo(pP2h, pP2v);
  520.                             LineTo(-pP1h, -pP1v);
  521.                             LineTo(-pP2h, -pP2v);
  522.                             LineTo(pP1h, pP1v);
  523.                             CloseRgn(fFrame[pIndex].fRgn);
  524.                             fFrame[pIndex].fOrg := fFrame[pIndex].fRgn^^.rgnBBox.topleft;
  525.                             OffsetRgn(fFrame[pIndex].fRgn, fLoc.h, fLoc.v);
  526.                         END;
  527.                 END;
  528.  
  529.             BEGIN
  530.                 InsertElem(pInd, -PtA.v, PtA.h, -PtB.v, PtB.h);
  531.                 IF pInd <> 6 THEN
  532.                     InsertElem(kBase - pInd + 2, PtA.h, -PtA.v, PtB.h, -PtB.v);
  533.                 InsertElem(kBase + pInd, -PtA.h, -PtA.v, -PtB.h, -PtB.v);
  534.                 IF pInd <> 6 THEN
  535.                     InsertElem(kBase * 2 - pInd + 2, -PtA.v, -PtA.h, -PtB.v, -PtB.h);
  536.                 InsertElem(kBase * 2 + pInd, PtA.v, -PtA.h, PtB.v, -PtB.h);
  537.                 IF pInd <> 6 THEN
  538.                     InsertElem(kBase * 3 - pInd + 2, -PtA.h, PtA.v, -PtB.h, PtB.v);
  539.                 InsertElem(kBase * 3 + pInd, PtA.h, PtA.v, PtB.h, PtB.v);
  540.                 IF pInd <> 1 THEN
  541.                     InsertElem(kBase * 4 - pInd + 2, PtA.v, PtA.h, PtB.v, PtB.h);
  542.             END;
  543.  
  544.         BEGIN
  545.             FOR lBar := 1 TO gNumBars DO
  546.                 WITH gBar[lBar] DO {init the bar}
  547.                     BEGIN
  548.                         fRad := 16 + (lBar - 1) * 8;
  549.                         fInd := 10;
  550.                         fLastInd := 10;
  551.                         fIndFill := 11;
  552.                         fAlmost := false;
  553.                         WITH fSaveBits, bounds DO {Create fSaveBits}
  554.                             BEGIN
  555.                                 SetRect(bounds, 0, 0, fRad * 2, 8);
  556.                                 rowBytes := (((right - left - 1) DIV 16) + 1) * 2;
  557.                                 baseAddr := NewPtr(rowBytes * (bottom - top));
  558.                             END;
  559.                         SetPt(fVel, 0, kVel);
  560.                         SetPt(fLoc, kPeg1, kAlt);
  561.                         SetPt(fDestLoc, kPeg1, (183 + (kMaxBar - gNumBars) * 8) + (lBar * 8));
  562.                         fTo := A;
  563.                         SetRect(fOldRect, fLoc.h - fRad, fLoc.v - fRad, fLoc.h + fRad, fLoc.v + fRad);
  564.                         GetIndPattern(fColor, sysPatListID, lBar + 1);
  565.                         FOR lFrame := 1 TO kNumTurn + 1 DO
  566.                             BEGIN
  567.                                 Get2Tang((lFrame - 1) * kAngle, fRad, PtA, PtB);
  568.                                 BuildData(lFrame, lBar, PtA, PtB);
  569.                             END;
  570.                     END;
  571.         END;
  572.  
  573. {  *****************************************************************************}
  574. {  Setup the Toolbox}
  575. {  *****************************************************************************}
  576.         PROCEDURE InitToolbox;
  577.         BEGIN
  578.             InitGraf(@thePort);
  579.             MoreMasters;
  580.             MoreMasters;
  581.             MoreMasters;
  582.             MoreMasters;
  583.             MoreMasters;
  584.             MoreMasters;
  585.             MoreMasters;
  586.             MoreMasters;
  587.             MaxApplZone;
  588.             InitFonts;
  589.             InitWindows;
  590.             InitCursor;
  591.             HideCursor;
  592.         END;
  593.  
  594. {  *****************************************************************************}
  595. {  Setup gSavePort}
  596. {  *****************************************************************************}
  597.         PROCEDURE SetupSavePort;
  598.         BEGIN
  599.             gSavePort := GrafPtr(NewPtr(sizeof(GrafPort)));
  600.             gEraseRgn := NewRgn;
  601.             OpenPort(gSavePort);
  602.             WITH gSavePort^, portBits, bounds DO
  603.                 BEGIN
  604.                     bounds := gDrawPort^.portBits.Bounds;
  605.                     portRect := bounds;
  606.                     rowBytes := (((right - left - 1) DIV 16) + 1) * 2;
  607.                     baseAddr := NewPtr(rowBytes * (bottom - top));
  608.                     cliprect(portRect);
  609.                     RectRgn(visrgn, portrect);
  610.                 END;
  611.         END;
  612.  
  613. {  *****************************************************************************}
  614. {  Setup the global variables}
  615. {  *****************************************************************************}
  616.         PROCEDURE InitGlobals;
  617.             VAR
  618.                 lBar : tBar;
  619.                 lMove : tMove;
  620.                 lPeg : tPeg;
  621.         BEGIN
  622.             InitQue;
  623.             FOR lPeg := A TO C DO
  624.                 BEGIN
  625.                     InitStack(lPeg);
  626.                     gPeg[lPeg].fFree := true;
  627.                 END;
  628.             FOR lMove := 1 TO kMaxMove DO
  629.                 gMoveBar[lMove] := 0;
  630.             gPegPos[A] := kPeg1;
  631.             gPegPos[B] := kPeg2;
  632.             gPegPos[C] := kPeg3;
  633.             FOR lBar := gNumBars DOWNTO 1 DO
  634.                 BEGIN
  635.                     gMoveBar[1] := lBar;
  636.                     WHILE NOT SystemTime DO
  637.                         ;
  638.                 END;
  639.             FOR lBar := 1 TO gNumBars DO
  640.                 gBarPos[lBar] := gBar[gNumBars - lBar + 1].fDestLoc.v;
  641.         END;
  642.  
  643.     BEGIN
  644.         InitToolbox;
  645.         GetPort(gDrawPort);
  646.         SetUpSavePort;
  647.         DrawScreen;
  648.         CopyBits(gDrawPort^.portBits, gSavePort^.portBits, gDrawPort^.portRect, gSavePort^.portRect, srcCopy, NIL);
  649.         GetNumBars;
  650.         SetUpData;
  651.         InitGlobals;
  652.     END;
  653.  
  654. {*******************************************************************************}
  655. {Make the magic happen by calling Hanoi and then SystemTime until done}
  656. {*******************************************************************************}
  657.     PROCEDURE DoIt;
  658.         VAR
  659.             x : integer;
  660.     BEGIN
  661.         WHILE true DO
  662.             BEGIN
  663.                 Hanoi(gNumBars, A, B, C);
  664.                 WHILE NOT SystemTime DO
  665.                     ;
  666.                 SetPort(gDrawPort);
  667.                 FOR x := 1 TO 16 DO
  668.                     InvertRect(gDrawPort^.PortRect);
  669.                 Hanoi(gNumBars, B, C, A);
  670.                 WHILE NOT SystemTime DO
  671.                     ;
  672.                 SetPort(gDrawPort);
  673.                 FOR x := 1 TO 16 DO
  674.                     InvertRect(gDrawPort^.PortRect);
  675.                 Hanoi(gNumBars, C, A, B);
  676.                 WHILE NOT SystemTime DO
  677.                     ;
  678.                 SetPort(gDrawPort);
  679.                 FOR x := 1 TO 16 DO
  680.                     InvertRect(gDrawPort^.PortRect);
  681.             END;
  682.     END;
  683.  
  684. BEGIN
  685.     Init;
  686.     DoIt;
  687. END.
  688.