[comp.sources.mac] Towers of Hanoi

SHULMAN@sdr.slb.com (Jeffrey Shulman) (05/05/88)

[Towers of Hanoi - Uploaded from Delphi by Jeff Shulman]

Name: TOWERS OF HANOI
Date: 3-APR-1988 17:09 by SOCCERKING

This is the same old towers of hanoi problem but with a few new twists.
If you are interested you can check out the source code.  This program
is simply for your enjoyment and curiosity.  I hope you enjoy it.  Does
not run under MultiFinder.

[Moderator's Note: The application and a PackIt archive of the source
 and Lightspeed Pascal project have been posted in comp.binaries.mac.]

---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Towers.lp
# This archive created: Wed May  4 08:16:04 1988
# By:	Roger L. Long (macintosh@dhw68k.cts.com)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Towers.lp'" '(21552 characters)'
if test -f 'Towers.lp'
then
	echo shar: will not over-write existing file "'Towers.lp'"
else
sed 's/^X//' << \SHAR_EOF > 'Towers.lp'
XPROGRAM RotBarcb;
X{NOTES:}
X{*A bar is a ring on a peg}
X{*All bars use the same bitmap to restore what it has erased}
X{*A move is when a bar goes from one peg to anther}
X	CONST
X		kAngle = 9; {angle between each turn of the bar}
X		kNumTurn = 5; {90 div 9}
X		kBase = 10; {numturn * 2}
X		kBarWid = 4; {width of bar div 2}
X		kNumFrame = 40; {numturn * 8 }
X		kPi = 3.141592654;
X		kAlt = 67; {Height when bar should switch directions}
X		kPeg1 = 80; {Pos of peg A}
X		kPeg2 = 256; {Pos of peg B}
X		kPeg3 = 432; {Pos of peg C}
X		kVel = 4; {Velocity at which pegs travel}
X		kMaxBar = 6; {Maximun number of bars}
X		kMaxMove = 2; {Maximun number of bars moving at one time}
X		kMaxQue = 100; {maximun number of elements in que}
X		kDLOG = 129; {Dialog ID}
X
X	TYPE
X		tPeg = (A, B, C);
X		tBar = 0..kMaxBar;
X		tMove = 0..kMaxMove;
X		tQueNum = 1..kMaxQue;
X		tFrame = 0..kNumFrame;
X
X		tElement = RECORD {Each element in the queue holds a move}
X				fFrom : tPeg;
X				fTo : tPeg;
X			END;
X
X{A stack holds the bars on each peg}
X		tStack = RECORD
X				fElements : ARRAY[tBar] OF tBar;
X				fTos : tBar;
X			END;
X
X{The Que holds the moves waiting to be preformed}
X		tQueue = RECORD
X				fElements : ARRAY[tQueNum] OF tElement;
X				fFront, fRear : tQueNum;
X			END;
X
X{Hold the information for each frame of a bar}
X		tBarData = RECORD
X				fRgn : RgnHandle;
X				fOrg : point;
X			END;
X
X{Hold the information for the bar}
X{NOTES:}
X{*Memory is radically sacrificed for speed}
X{*fAlmost is used to tell MoveBars that the bar has reached its loc but}
X{  it still needs to spin}
X{*When a bar is at some peg and the bar above spins it will}
X{  erase the bars underneath it because they are not part of gSavePort}
X{  To fix this we save the bits underneath the bar at a peg in fSaveBits}
X{  and restore them after the peg moves}
X{*As much information to realated to a bar as possible is stored in tBarInfo}
X		tBarInfo = RECORD
X				fFrame : ARRAY[tFrame] OF tBarData; {Hold the frames of the bar}
X				fInd : tFrame;     {Hold the current index into fFrame}
X				fLastInd : tFrame; {Hold the last index into the fFrame}
X				fIndFill : tFrame; {Hold the index to the last horz frame}
X				fRad : integer;    {Hold the radius of the bar}
X				fLoc : point;      {Hold the current location of the bar}
X				fDestLoc : point;  {Hold the destination location}
X				fVel : point;      {Hold the current velocity of the bar}
X				fOldRect : rect;   {Hold the previous position of the bar}
X				fColor : Pattern;  {Hold the color of the bar}
X				fAlmost : boolean; {Used to tell some proc that the bar still needs to spin}
X				fSaveBits : BitMap; {Used to save the bits of gSavePort}
X				fTo : tPeg;        {Destination peg}
X			END;
X
X{This record stores the stack of bars on it}
X{and if this peg is free to move a bar to}
X		tPegInfo = RECORD
X				fFree : boolean; {Peg available?}
X				fBars : tStack;  {Stack of bars}
X			END;
X
X		tBars = ARRAY[tBar] OF tBarInfo; {Hold all bars}
X		tPegs = ARRAY[tPeg] OF tPegInfo; {Hold all Pegs}
X		tMoveBars = ARRAY[tMove] OF tBar; {Hold moving bars}
X		tPegPositions = ARRAY[tPeg] OF integer; {Hold positions of Pegs}
X		tBarPositions = ARRAY[tBar] OF integer; {Hold positions of bars}
X
X	VAR
X		gSavePort : GrafPtr; {Hold the port which saves the image}
X		gDrawPort : GrafPtr; {Hold the port to draw in}
X		gNumBars : tBar;     {Hold the number of bars}
X		gBar : tBars;        {Hold the bars}
X		gPeg : tPegs;        {Hold the pegs}
X		gMoveQue : tQueue;   {Hold the move queue}
X		gMoveBar : tMoveBars; {Hold the moving bars}
X		gPegPos : tPegPositions; {Hold the peg positions}
X		gBarPos : tBarPositions; {Hold the bar positions}
X		gEraseRgn : RgnHandle;   {Hold the erase region in PlotBar to save time}
X
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X{Stack routines}
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X
X{*****************************************************************************}
X{Init the stack pPeg}
X{*****************************************************************************}
X	PROCEDURE InitStack (pPeg : tPeg);
X	BEGIN
X		gPeg[pPeg].fBars.fTos := 0;
X	END;
X
X{*****************************************************************************}
X{Push pBar onto the stack of pPeg}
X{*****************************************************************************}
X	PROCEDURE Push (pBar : tBar;
X									pPeg : tPeg);
X		VAR
X			lTemp : rect;
X	BEGIN
X		WITH gPeg[pPeg].fBars DO
X			BEGIN
X				fTos := fTos + 1;
X				fElements[fTos] := pBar;
X			END;
X		WITH gBar[pBar] DO {We must Draw the bar in gSavePort}
X			BEGIN
X{Calculate its rectangle on the screen}
X				SetRect(lTemp, fLoc.h - fRad, fLoc.v - 4, fLoc.h + fRad, fLoc.v + 4);
X				SetPort(gSavePort);
X{Save gSavePort's bits}
X				CopyBits(gSavePort^.portBits, fSaveBits, lTemp, fSaveBits.bounds, srccopy, NIL);
X				FillRgn(fFrame[fIndFill].fRgn, fColor); {Draw it in gSavePort}
X				SetPort(gDrawPort);
X			END;
X	END;
X
X{*****************************************************************************}
X{Get vBar out of the stack of pPeg}
X{*****************************************************************************}
X	PROCEDURE Pop (VAR vBar : tBar;
X									pPeg : tPeg);
X		VAR
X			lTemp : rect;
X	BEGIN
X		WITH gPeg[pPeg].fBars DO
X			BEGIN
X				vBar := fElements[fTos];
X				fTos := fTos - 1;
X			END;
X		WITH gBar[vBar] DO {Restore the saved bits}
X			BEGIN
X				SetRect(lTemp, fLoc.h - fRad, fLoc.v - 4, fLoc.h + fRad, fLoc.v + 4);
X				CopyBits(fSaveBits, gSavePort^.portBits, fSaveBits.bounds, lTemp, srccopy, NIL);
X			END;
X	END;
X
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X{Queue routines}
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X
X{*****************************************************************************}
X{Init the Queue}
X{*****************************************************************************}
X	PROCEDURE InitQue;
X	BEGIN
X		gMoveQue.fFront := 1;
X		gMoveQue.fRear := 1;
X	END;
X
X{*****************************************************************************}
X{Get the next index into the queue}
X{*****************************************************************************}
X	PROCEDURE NextInd (VAR vInd : tQueNum);
X	BEGIN
X		IF vInd = kMaxQue THEN
X			vInd := 1
X		ELSE
X			vInd := vInd + 1;
X	END;
X
X{*****************************************************************************}
X{Enq this move}
X{*****************************************************************************}
X	PROCEDURE Enq (pFrom, pTo : tPeg);
X	BEGIN
X		WITH gMoveQue DO
X			BEGIN
X				fElements[fRear].fFrom := pFrom;
X				fElements[fRear].fTo := pTo;
X				NextInd(fRear);
X			END;
X	END;
X
X{*****************************************************************************}
X{Deq the next move and put it into vElem}
X{*****************************************************************************}
X	PROCEDURE Deq (VAR vElem : tElement);
X	BEGIN
X		WITH gMoveQue DO
X			BEGIN
X				vElem := fElements[fFront];
X				NextInd(fFront);
X			END;
X	END;
X
X{*****************************************************************************}
X{Get the move to be returned at the next Deq}
X{*****************************************************************************}
X	PROCEDURE TopElem (VAR vElem : tElement);
X	BEGIN
X		WITH gMoveQue DO
X			vElem := fElements[fFront];
X	END;
X
X{*****************************************************************************}
X{Return true if the que is empty}
X{*****************************************************************************}
X	FUNCTION EmptyQue : boolean;
X	BEGIN
X		EmptyQue := gMoveQue.fFront = gMoveQue.fRear;
X	END;
X
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X{Drawing routines}
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X
X{*****************************************************************************}
X{Plot pBar using all the info in its record}
X{*****************************************************************************}
X	PROCEDURE PlotBar (pBar : tBar);
X
X{  ***************************************************************************}
X{  Move the regions center to the absolute location (pLoch,pLocv)}
X{  ***************************************************************************}
X		PROCEDURE MoveRgn (pBarData : tBarData;
X										pLoch, pLocv : integer);
X			VAR
X				dh, dv : integer;
X		BEGIN
X			WITH pBarData.fRgn^^.rgnBBox, pBarData DO
X				BEGIN
X					OffsetRgn(pBarData.fRgn, fOrg.h - left, fOrg.v - top);
X					OffsetRgn(pBarData.fRgn, pLoch, pLocv);
X				END;
X		END;
X
X	BEGIN
X		WITH gBar[pBar] DO
X			BEGIN
X				fInd := fInd + 1; {Inc the index}
X				MoveRgn(fFrame[fInd], fLoc.h, fLoc.v); {Move the regionto the new loc}
X				DiffRgn(fFrame[fLastInd].fRgn, fFrame[fInd].fRgn, gEraseRgn); {Calc the erase rgn}
X				FillRgn(fFrame[fInd].fRgn, fColor); {Draw the bar}
X{Restore the Bits}
X				CopyBits(gSavePort^.portBits, gDrawPort^.portBits, fOldRect, fOldRect, srccopy, gEraseRgn);
X				fLastInd := fInd;
X				SetRect(fOldRect, fLoc.h - fRad, fLoc.v - fRad, fLoc.h + fRad, fLoc.v + fRad);
X				IF fInd = kNumFrame THEN
X					fInd := 0;
X			END;
X	END;
X
X{*****************************************************************************}
X{Start the move in pElem}
X{*****************************************************************************}
X	PROCEDURE StartMove (pElem : tElement);
X		VAR
X			lBar : tBar;
X			lMove : tMove;
X	BEGIN
X		gPeg[pElem.fTo].fFree := false; {Mark the dest peg as used}
X		pop(lBar, pElem.fFrom); {Get the bar to move}
X		WITH gBar[lBar] DO {Init the bar to move}
X			BEGIN
X				fAlmost := false;
X				SetPt(fVel, 0, -kVel);
X				SetPt(fDestLoc, gPegPos[pElem.fTo], gBarPos[gPeg[pElem.fTo].fBars.fTos + 1]);
X				fTo := pElem.fTo;
X			END;
X{Put the bar into the next available slot in gMoveBar}
X		lMove := 0;
X		REPEAT
X			lMove := lMove + 1;
X			IF gMoveBar[lMove] = 0 THEN
X				BEGIN
X					gMoveBar[lMove] := lBar;
X					lMove := kMaxMove;
X				END;
X		UNTIL lMove = kMaxMove;
X	END;
X
X{*****************************************************************************}
X{Move the bars in gMoveBar}
X{*****************************************************************************}
X	PROCEDURE MoveBars;
X		VAR
X			x : tMove;
X
X{  ***************************************************************************}
X{  Adjust the fLoc field of bar pBar and change direction if neccessary}
X{  Return true if bar has arrived at destination}
X{  ***************************************************************************}
X		FUNCTION MoveTheBar (pBar : tBar) : boolean;
X		BEGIN
X			MoveTheBar := false;
X			WITH gBar[pBar] DO {Adjust the velocity of the bar}
X				BEGIN
X					IF fVel.v = -kVel THEN
X						IF fLoc.v <= kAlt THEN
X							BEGIN
X								fVel.v := 0;
X								IF fLoc.h > fDestLoc.h THEN
X									fVel.h := -kVel
X								ELSE
X									fVel.h := kVel;
X							END;
X					IF fVel.v = 0 THEN
X						BEGIN
X							IF fVel.h = kVel THEN
X								IF fLoc.h >= fDestLoc.h THEN
X									BEGIN
X										fVel.h := 0;
X										fVel.v := kVel;
X									END;
X							IF fVel.h = -kVel THEN
X								IF fLoc.h <= fDestLoc.h THEN
X									BEGIN
X										fVel.h := 0;
X										fVel.v := kVel;
X									END;
X						END;
X					IF fVel.v = kVel THEN
X						IF fLoc.v >= fDestLoc.v THEN
X							fAlmost := true;
X					IF fAlmost THEN {do not adjust fLoc}
X						BEGIN
X							IF (fInd = 10) OR (fInd = 30) THEN
X								BEGIN
X									fIndFill := fInd + 1;
X									MoveTheBar := true;
X								END;
X						END
X					ELSE {Adjust it}
X						AddPt(fVel, fLoc);
X					PlotBar(pBar); {Plot the bar}
X				END;
X		END;
X
X	BEGIN
X{Update every bar in gMoveBar}
X		FOR x := 1 TO kMaxMove DO
X			IF gMoveBar[x] > 0 THEN
X				IF MoveTheBar(gMoveBar[x]) THEN {We arrived}
X					BEGIN
X						Push(gMoveBar[x], gBar[gMoveBar[x]].fTo);
X						gPeg[gBar[gMoveBar[x]].fTo].fFree := true;
X						gMoveBar[x] := 0;
X					END;
X	END;
X
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X{Processing routines}
X{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
X
X{*****************************************************************************}
X{*****************************************************************************}
X{Decide if we can move a bar and return true if nothing left to do}
X{NOTE: This is the heart of the whole program}
X{*****************************************************************************}
X{*****************************************************************************}
X	FUNCTION SystemTime : boolean;
X		VAR
X			lMove : tMove;
X			lTempB : boolean;
X			lElem : tElement;
X	BEGIN
X		IF button THEN {We are tired of watching these bars go in circles}
X			ExitToShell;
X		lTempB := true;
X{Is there room to in gMoveBar}
X		FOR lMove := 1 TO kMaxMove DO
X			lTempB := lTempB AND (gMoveBar[lMove] <> 0);
X		IF NOT EmptyQue AND NOT lTempB THEN {A move is possible}
X			BEGIN
X				TopElem(lElem);
X				IF gPeg[lElem.fTo].fFree AND gPeg[lElem.fFrom].fFree THEN {Ok to move}
X					BEGIN
X						Deq(lElem);
X						StartMove(lElem);
X					END;
X			END;
X{Check to see if anything left do}
X		lTempB := true;
X		FOR lMove := 1 TO kMaxMove DO
X			lTempB := lTempB AND (gMoveBar[lMove] = 0);
X		SystemTime := EmptyQue AND lTempB;
X		MoveBars;
X	END;
X
X{*****************************************************************************}
X{Calculate the moves to preform}
X{*****************************************************************************}
X	PROCEDURE Hanoi (pNumRings : tBar;
X									pFrom, pTo, pUsing : tPeg);
X	BEGIN
X		IF SystemTime THEN
X			;
X		IF pNumRings = 1 THEN
X			Enq(pFrom, pTo)
X		ELSE
X			BEGIN
X				hanoi(pNumRings - 1, pFrom, pUsing, pTo);
X				Enq(pFrom, pTo);
X				hanoi(pNumRings - 1, pUsing, pTo, pFrom);
X			END;
X	END;
X
X{*****************************************************************************}
X{Init the program}
X{*****************************************************************************}
X	PROCEDURE Init;
X
X{  ***************************************************************************}
X{  Get the number of bars to move}
X{  ***************************************************************************}
X		PROCEDURE GetNumBars;
X			VAR
X				lDlog : DialogPtr;
X				lItem : integer;
X				lType : integer;
X				lItemHand : Handle;
X				lBox : Rect;
X				lText : str255;
X				lRslt : longint;
X		BEGIN
X			lDlog := GetNewDialog(kDLOG, NIL, pointer(-1));
X			REPEAT
X				ModalDialog(NIL, lItem);
X				GetDItem(lDlog, 2, ltype, lItemHand, lBox);
X				GetIText(lItemHand, lText);
X				StringToNum(lText, lRslt);
X				gNumBars := integer(lRslt);
X			UNTIL (gNumBars <= 6) AND (gNumBars >= 3);
X			DisposDialog(lDlog);
X		END;
X
X{  ***************************************************************************}
X{  Draw the Pegs}
X{  ***************************************************************************}
X		PROCEDURE DrawScreen;
X			VAR
X				lTemp : Rect;
X		BEGIN
X			SetPort(gDrawPort);
X			SetRect(lTemp, 8, 235, 152, 243);
X			FillRect(lTemp, Black);
X			SetRect(lTemp, 184, 235, 328, 243);
X			FillRect(lTemp, Black);
X			SetRect(lTemp, 360, 235, 504, 243);
X			FillRect(lTemp, Black);
X			SetRect(lTemp, 76, 99, 84, 235);
X			FillRect(lTemp, Black);
X			SetRect(lTemp, 252, 99, 260, 235);
X			FillRect(lTemp, Black);
X			SetRect(lTemp, 428, 99, 436, 235);
X			FillRect(lTemp, Black);
X		END;
X
X{  ***************************************************************************}
X{  Calculate the data for the frames of the bars}
X{  ***************************************************************************}
X		PROCEDURE SetupData;
X			VAR
X				lBar : tBar;
X				lFrame : integer;
X				PtA, PtB : point;
X
X{   **************************************************************************}
X{   Calculate two point tangent to the line pAngle degrees around the circle}
X{   **************************************************************************}
X			PROCEDURE Get2Tang (pAngle : real;
X											pRad : integer;
X											VAR PtA, PtB : point);
X				VAR
X					temp, temp2, xc, yc, m, perpm : real;
X			BEGIN
X				yc := pRad * cos(pAngle * pi / 180);
X				xc := pRad * sin(pAngle * pi / 180);
X				perpm := -xc / yc;
X				temp := kBarWid / (perpm * perpm + 1);
X				temp2 := temp * perpm;
X				PtA.h := round(yc - temp2);
X				PtA.v := round(xc - temp);
X				PtB.h := round(yc + temp2);
X				PtB.v := round(xc + temp);
X			END;
X
X{   **************************************************************************}
X{   Transform PtA and PtB into 8 more points}
X{   **************************************************************************}
X			PROCEDURE BuildData (pInd : integer;
X											pBar : tBar;
X											PtA, PtB : point);
X
X{    *************************************************************************}
X{    Build a region around the given points}
X{    *************************************************************************}
X				PROCEDURE InsertElem (pIndex, pP1h, pP1v, pP2h, pP2v : integer);
X				BEGIN
X					WITH gBar[pBar] DO
X						BEGIN
X							fFrame[pIndex].fRgn := NewRgn;
X							OpenRgn;
X							MoveTo(pP1h, pP1v);
X							LineTo(pP2h, pP2v);
X							LineTo(-pP1h, -pP1v);
X							LineTo(-pP2h, -pP2v);
X							LineTo(pP1h, pP1v);
X							CloseRgn(fFrame[pIndex].fRgn);
X							fFrame[pIndex].fOrg := fFrame[pIndex].fRgn^^.rgnBBox.topleft;
X							OffsetRgn(fFrame[pIndex].fRgn, fLoc.h, fLoc.v);
X						END;
X				END;
X
X			BEGIN
X				InsertElem(pInd, -PtA.v, PtA.h, -PtB.v, PtB.h);
X				IF pInd <> 6 THEN
X					InsertElem(kBase - pInd + 2, PtA.h, -PtA.v, PtB.h, -PtB.v);
X				InsertElem(kBase + pInd, -PtA.h, -PtA.v, -PtB.h, -PtB.v);
X				IF pInd <> 6 THEN
X					InsertElem(kBase * 2 - pInd + 2, -PtA.v, -PtA.h, -PtB.v, -PtB.h);
X				InsertElem(kBase * 2 + pInd, PtA.v, -PtA.h, PtB.v, -PtB.h);
X				IF pInd <> 6 THEN
X					InsertElem(kBase * 3 - pInd + 2, -PtA.h, PtA.v, -PtB.h, PtB.v);
X				InsertElem(kBase * 3 + pInd, PtA.h, PtA.v, PtB.h, PtB.v);
X				IF pInd <> 1 THEN
X					InsertElem(kBase * 4 - pInd + 2, PtA.v, PtA.h, PtB.v, PtB.h);
X			END;
X
X		BEGIN
X			FOR lBar := 1 TO gNumBars DO
X				WITH gBar[lBar] DO {init the bar}
X					BEGIN
X						fRad := 16 + (lBar - 1) * 8;
X						fInd := 10;
X						fLastInd := 10;
X						fIndFill := 11;
X						fAlmost := false;
X						WITH fSaveBits, bounds DO {Create fSaveBits}
X							BEGIN
X								SetRect(bounds, 0, 0, fRad * 2, 8);
X								rowBytes := (((right - left - 1) DIV 16) + 1) * 2;
X								baseAddr := NewPtr(rowBytes * (bottom - top));
X							END;
X						SetPt(fVel, 0, kVel);
X						SetPt(fLoc, kPeg1, kAlt);
X						SetPt(fDestLoc, kPeg1, (183 + (kMaxBar - gNumBars) * 8) + (lBar * 8));
X						fTo := A;
X						SetRect(fOldRect, fLoc.h - fRad, fLoc.v - fRad, fLoc.h + fRad, fLoc.v + fRad);
X						GetIndPattern(fColor, sysPatListID, lBar + 1);
X						FOR lFrame := 1 TO kNumTurn + 1 DO
X							BEGIN
X								Get2Tang((lFrame - 1) * kAngle, fRad, PtA, PtB);
X								BuildData(lFrame, lBar, PtA, PtB);
X							END;
X					END;
X		END;
X
X{  *****************************************************************************}
X{  Setup the Toolbox}
X{  *****************************************************************************}
X		PROCEDURE InitToolbox;
X		BEGIN
X			InitGraf(@thePort);
X			MoreMasters;
X			MoreMasters;
X			MoreMasters;
X			MoreMasters;
X			MoreMasters;
X			MoreMasters;
X			MoreMasters;
X			MoreMasters;
X			MaxApplZone;
X			InitFonts;
X			InitWindows;
X			InitCursor;
X			HideCursor;
X		END;
X
X{  *****************************************************************************}
X{  Setup gSavePort}
X{  *****************************************************************************}
X		PROCEDURE SetupSavePort;
X		BEGIN
X			gSavePort := GrafPtr(NewPtr(sizeof(GrafPort)));
X			gEraseRgn := NewRgn;
X			OpenPort(gSavePort);
X			WITH gSavePort^, portBits, bounds DO
X				BEGIN
X					bounds := gDrawPort^.portBits.Bounds;
X					portRect := bounds;
X					rowBytes := (((right - left - 1) DIV 16) + 1) * 2;
X					baseAddr := NewPtr(rowBytes * (bottom - top));
X					cliprect(portRect);
X					RectRgn(visrgn, portrect);
X				END;
X		END;
X
X{  *****************************************************************************}
X{  Setup the global variables}
X{  *****************************************************************************}
X		PROCEDURE InitGlobals;
X			VAR
X				lBar : tBar;
X				lMove : tMove;
X				lPeg : tPeg;
X		BEGIN
X			InitQue;
X			FOR lPeg := A TO C DO
X				BEGIN
X					InitStack(lPeg);
X					gPeg[lPeg].fFree := true;
X				END;
X			FOR lMove := 1 TO kMaxMove DO
X				gMoveBar[lMove] := 0;
X			gPegPos[A] := kPeg1;
X			gPegPos[B] := kPeg2;
X			gPegPos[C] := kPeg3;
X			FOR lBar := gNumBars DOWNTO 1 DO
X				BEGIN
X					gMoveBar[1] := lBar;
X					WHILE NOT SystemTime DO
X						;
X				END;
X			FOR lBar := 1 TO gNumBars DO
X				gBarPos[lBar] := gBar[gNumBars - lBar + 1].fDestLoc.v;
X		END;
X
X	BEGIN
X		InitToolbox;
X		GetPort(gDrawPort);
X		SetUpSavePort;
X		DrawScreen;
X		CopyBits(gDrawPort^.portBits, gSavePort^.portBits, gDrawPort^.portRect, gSavePort^.portRect, srcCopy, NIL);
X		GetNumBars;
X		SetUpData;
X		InitGlobals;
X	END;
X
X{*******************************************************************************}
X{Make the magic happen by calling Hanoi and then SystemTime until done}
X{*******************************************************************************}
X	PROCEDURE DoIt;
X		VAR
X			x : integer;
X	BEGIN
X		WHILE true DO
X			BEGIN
X				Hanoi(gNumBars, A, B, C);
X				WHILE NOT SystemTime DO
X					;
X				SetPort(gDrawPort);
X				FOR x := 1 TO 16 DO
X					InvertRect(gDrawPort^.PortRect);
X				Hanoi(gNumBars, B, C, A);
X				WHILE NOT SystemTime DO
X					;
X				SetPort(gDrawPort);
X				FOR x := 1 TO 16 DO
X					InvertRect(gDrawPort^.PortRect);
X				Hanoi(gNumBars, C, A, B);
X				WHILE NOT SystemTime DO
X					;
X				SetPort(gDrawPort);
X				FOR x := 1 TO 16 DO
X					InvertRect(gDrawPort^.PortRect);
X			END;
X	END;
X
XBEGIN
X	Init;
X	DoIt;
XEND.
SHAR_EOF
if test 21552 -ne "`wc -c < 'Towers.lp'`"
then
	echo shar: error transmitting "'Towers.lp'" '(should have been 21552 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
---