[mod.mac.sources] BlobDemo4 - Blob Manager Demo source

dubois@uwmacc.UUCP (Paul DuBois) (02/01/87)

#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	BlobDemo/DemoStates.c
#	BlobDemo/DemoSwap.c
#	BlobDemo/DemoToh.c
#	BlobDemo/DemoTtt.c
#	BlobDemo/DemoWind.c
mkdir BlobDemo
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoStates.c
X/*
X	Blob Manager Demonstration:  States and Capitals module
X
X	This module is an example of an extremely simple interrogative
X	scenario.  The original thirteen colonies of the United States must
X	be matched with their capital cities.  There is a single button that
X	says "Give Up?"  If the user clicks the button, the answer is shown,
X	the button's title changes to "Resume", and the scenario is frozen
X	until the button is clicked.  Then the answer is cleared, the capitals
X	are shuffled, and the user may start over.
X
X	If the correct answers are all gotten, the button again changes to
X	"Resume" and the scenario is frozen until the button is clicked.
X
X	The module is unexciting; it's meant as a basic illustration, rather
X	than anything useful.  There are lots of bells and whistles that
X	could be added.
X
X	26 July 1986		Paul DuBois
X*/
X
X
X# include	"BlobDemo.h"
X# include	<ControlMgr.h>
X
X
X# define	nStates		13
X
X# define	hState1		220
X# define	hState2		110
X# define	vState		16
X# define	stateXOff	10
X# define	stateYOff	5
X# define	hCapital	85
X# define	vCapital	16
X# define	capXOff		225
X# define	capYOff		5
X
X
Xstruct info
X{
X	char	*stateName;
X	char	*capName;
X};
X
X
X
Xstatic GrafPtr			statesPort;
Xstatic BlobSetHandle	donors;		/* donor blobs */
Xstatic BlobSetHandle	receptors;	/* receptor blobs */
Xstatic ControlHandle	giveUp;
Xstatic Boolean			paused = false;
X
Xstatic struct info		scPair[nStates] =
X{
X	{ "\pConnecticut",		"\pHartford" },
X	{ "\pDelaware",			"\pDover" },
X	{ "\pGeorgia",			"\pAtlanta" },
X	{ "\pMaryland",			"\pAnnapolis" },
X	{ "\pMassachusetts",	"\pBoston" },
X	{ "\pNew Hampshire",	"\pConcord" },
X	{ "\pNew Jersey",		"\pTrenton" },
X	{ "\pNorth Carolina",	"\pRaleigh" },
X	{ "\pNew York",			"\pAlbany" },
X	{ "\pPennsylvania",		"\pHarrisburg" },
X	{ "\pRhode Island",		"\pProvidence" },
X	{ "\pSouth Carolina",	"\pColumbia" },
X	{ "\pVirginia",			"\pRichmond" }
X};
X
X
Xstatic Activate (active)
XBoolean	active;
X{
X	if (active)
X	{
X		SetDragRects (statesPort);
X		SetBCPermissions (true, true, false, true, true);
X	}
X}
X
X
Xstatic Update ()
X{
X	DrawControls (statesPort);
X	DrawBlobSet (receptors);
X	DrawBlobSet (donors);
X}
X
X
Xstatic Mouse (pt, t, mods)
XPoint	pt;
Xlong	t;
Xint		mods;
X{
XBlobHandle	b, d;
XControlHandle	ctl;
X
X	if (FindControl	(pt, statesPort, &ctl))
X	{
X		if (TrackControl (ctl, pt, nil))
X		{
X			if (paused)		/* either all answers are correct, or we're */
X			{				/* showing the answer.  Either way, restore */
X				ThawBlobSet (receptors);	/* to start state */
X				ThawBlobSet (donors);
X				ZUnglueGlobSet (receptors);
X				ShuffleBlobSet (receptors);
X				ShuffleBlobSet (donors);
X				SetCTitle (giveUp, "\pGive Up?");
X				ValidRect (&statesPort->portRect);
X				paused = false;
X			}
X			else		/* user gives up - show answer */
X			{
X				for (b = FirstBlob (receptors); b != nil; b = NextBlob (b))
X					ZGlueGlob (FirstBMatch (b), b);
X				FreezeBlobSet (receptors);
X				FreezeBlobSet (donors);
X				SetCTitle (giveUp, "\pResume");
X				paused = true;
X			}
X		}
X	}
X	else
X	{
X		BlobClick (pt, t, donors, receptors);
X		if (!paused && BlobSetQuiet (receptors))	/* answers correct? */
X		{
X			FreezeBlobSet (receptors);
X			FreezeBlobSet (donors);
X			SetCTitle (giveUp, "\pResume");
X			paused = true;
X		}
X	}
X}
X
X
X/*
X	Make blobs
X*/
X
X
XMakeBlobs ()
X{
Xint			i;
XRect		r, r2;
XBlobHandle	b1, b2;
X
X	donors = NewBlobSet ();
X	receptors = NewBlobSet ();
X	for (i = 0; i < nStates; ++i)
X	{
X		b1 = NewBlob (donors, false, 1, false, 0L);
X		b2 = NewBlob (receptors, false, 0, true, 0L);
X		NewBlobMatch (b1, b2);		/* attach the answer */
X
X		OpenBlob ();	/* draw donor blob */
X		SetRect (&r, 0, 0, hCapital, vCapital);
X		TextBox (&scPair[i].capName[1], (long) scPair[i].capName[0], &r, 1);
X		CloseRectBlob (b1, &r, &r);
X		MoveBlob (b1, inFullBlob,  capXOff, capYOff + (vCapital + 1) * i);
X
X		OpenBlob ();
X		SetRect (&r, 0, 0, hState1, vState);
X		SetRect (&r2, 0, 0, hState2, vState);
X		TextBox (&scPair[i].stateName[1], (long) scPair[i].stateName[0], &r2, 1);
X		SetRect (&r2, 0, 0, hCapital, vCapital);
X		OffsetRect (&r2, hState2 + 5, 0);
X		EraseRect (&r2);
X		FrameRect (&r2);
X		CloseRectBlob (b2, &r2, &r);
X		MoveBlob (b2, inFullBlob,  stateXOff, stateYOff + (vState + 2) * i);
X	}
X	ShuffleBlobSet (donors);
X	EnableBlobSet (receptors);
X	EnableBlobSet (donors);
X}
X
X
XStatesInit	()
X{
XRect	r;
X
X	SkelWindow (statesPort = GetDemoWind (statesWindRes),
X				Mouse,			/* mouse clicks */
X				nil,			/* key clicks */
X				Update,			/* updates */
X				Activate,		/* activate/deactivate events */
X				nil,			/* close window */
X				DoWClobber,		/* dispose of window */
X				nil,			/* idle proc */
X				false);			/* irrelevant, since no idle proc */
X
X/*
X	Make blobs.  Generally have to make donors before receptors.
X*/
X	MakeBlobs ();
X
X	r = statesPort->portRect;
X	SetRect (&r, r.left + 5, r.bottom - 25, r.left + 75, r.bottom - 5);
X	giveUp = NewControl (statesPort, &r, "\pGive Up?", true, 0, 0, 0,
X							pushButProc, nil);
X
X	Update ();
X	ValidRect (&statesPort->portRect);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoSwap.c
X/*
X	Blob Manager Demonstration:  Coin Swap module
X
X	This has a linear board with either 5, 7 or 9 pieces.  The middle
X	piece is always empty, the pieces on one end are filled with black
X	coins, the pieces on the other end are filled with white coins.
X	The object is to swap the coins.  A coin can slide into an empty
X	piece next to it, or jump over a single coin to land on an empty
X	piece.
X
X	A menu allows the number of coins to be chosen.  To win, the coins
X	have to be swapped in a specific number of moves.
X
X	26 July 1986		Paul DuBois
X*/
X
X
X# include	"BlobDemo.h"
X# include	<MenuMgr.h>
X
X# define	vMessage	10
X# define	vPiece		30
X# define	maxPieces	9
X# define	pieceSize	24
X# define	pieceGap	1
X
X
Xstatic GrafPtr			swapPort;
Xstatic MenuHandle		cnfgMenu;
Xstatic BlobSetHandle	donors = nil;
Xstatic BlobSetHandle	receptors = nil;
Xstatic int				hMid;
Xstatic Str255			statusStr = "\p";
X
Xstatic int				nPieces = 5;
Xstatic int				nMoves = 8;
Xstatic BlobHandle		piece[maxPieces];
Xstatic int				moves;
Xstatic Boolean			pause;
X	
X
Xstatic StatusMesg (s)
XStr255	s;
X{
XRect	r;
X
X	SetRect (&r, hMid - 60, vMessage, hMid + 60, vMessage+16);
X	TextBox	(s+1, (long) s[0], &r, 1);
X	StrCpy (statusStr, s);
X}
X
X
X/*
X	Reset to start state.  This recreates the board each time.  All the
X	blobs in the board require explicit matches except the middle one.
X*/
X
Xstatic Reset ()
X{
XBlobHandle	b;
XRect		r;
Xint			i, h;
XStr255		s;
X
X	InvalRect (&swapPort->portRect);	/* force update when done resetting */
X	pause = false;
X	moves = nMoves;
X	MovesLeft (moves, s);
X	StatusMesg (s);
X
X	if (receptors != nil)				/* clobber any existing receptor set */
X	{
X		HideBlobSet (receptors);
X		DisposeBlobSet (receptors);
X	}
X	receptors = NewBlobSet ();
X
X	h = hMid - (nPieces * (pieceSize + pieceGap) - pieceGap) / 2;
X	for (i = 0; i < nPieces; ++i)
X	{
X		b = NewBlob (receptors, false, 0, i != (nPieces - 1) / 2, 0L);
X		piece[i] = b;
X		OpenBlob ();
X		SetRect (&r, h, vPiece, h + pieceSize, vPiece + pieceSize);
X		EraseRect (&r);
X		FrameRect (&r);
X		CloseRectBlob (b, &r, &r);
X		h += pieceSize + pieceGap;
X		if (i < (nPieces - 1) / 2)
X		{
X			GlueGlob (GetBlobHandle (donors, 0), b);
X			NewBlobMatch (GetBlobHandle (donors, 1), b);
X		}
X		else if (i > (nPieces - 1) / 2)
X		{
X			GlueGlob (GetBlobHandle (donors, 1), b);
X			NewBlobMatch (GetBlobHandle (donors, 0), b);
X		}
X	}
X	EnableBlobSet (receptors);
X}
X
X
Xstatic SwapPause (msg)
XStringPtr	msg;
X{
X	StatusMesg (msg);
X	pause = true;
X}
X
X
Xstatic Mouse (pt, t, mods)
XPoint	pt;
Xlong	t;
Xint		mods;
X{
XStr255			s;
Xregister int	i;
X
X/*
X	Freeze all the pieces that can't be moved, then call BlobClick.
X*/
X	for (i = 0; i < nPieces; ++i)
X	{
X		ThawBlob (piece[i]);
X		if (BGlob (piece[i]) == nil) continue;
X		if (i > 0 && BGlob (piece[i-1]) == nil) continue;
X		if (i > 1 && BGlob (piece[i-2]) == nil) continue;
X		if (i < nPieces - 1 && BGlob (piece[i+1]) == nil) continue;
X		if (i < nPieces - 2 && BGlob (piece[i+2]) == nil) continue;
X		FreezeBlob (piece[i]);
X	}
X	if (!pause)
X	{
X		BlobClick (pt, t, donors, receptors);
X		if (BClickResult () == bcXfer)
X		{
X			if (--moves == 0)
X			{
X				if (BlobSetQuiet (receptors))
X					SwapPause ("\pYou Win");
X				else
X					SwapPause ("\pYou Lose");
X			}
X			else
X			{
X				MovesLeft (moves, s);
X				StatusMesg (s);
X			}
X		}
X	}
X}
X
X
X/*
X	Select configuration:  4, 6, or 8 coins (2, 3, or 4 on each side).
X	If the number of coins on each side is n, the number of moves
X	to solve is (n+1)^2 - 1.
X*/
XDoConfiguration (item)
Xint		item;
X{
X	nPieces = 2 * item + 3;			/* 1->5, 2->7, 3->9 pieces */
X	nMoves = (item + 2) * (item + 2) - 1;
X	Reset ();
X}
X
X
Xstatic Activate (active)
XBoolean	active;
X{
X	if (active)
X	{
X		SetDragRects (swapPort);
X		SetBCPermissions (false, true, false, false, false);	/* xfer only */
X		cnfgMenu = GetMenu (swapCnfgMenuRes);
X		SkelMenu (cnfgMenu, DoConfiguration, DoMClobber);
X	}
X	else
X		SkelRmveMenu (cnfgMenu);
X}
X
X
Xstatic Update (resized)
XBoolean	resized;
X{
X	DrawBlobSet (receptors);
X	StatusMesg (statusStr);
X}
X
X
X/*
X	Make donor blobs.
X*/
X
Xstatic MakeDonors ()
X{
XBlobHandle	b;
XRect		r;
X
X	donors = NewBlobSet ();
X	b = NewBlob (donors, false, infiniteGlue, false, 0L);
X	OpenBlob ();
X	SetRect (&r, 0, 0, pieceSize, pieceSize);
X	EraseRect (&r);
X	FrameRect (&r);
X	InsetRect (&r, 2, 2);
X	PaintOval (&r);
X	InsetRect (&r, -2, -2);
X	CloseRectBlob (b, &r, &r);
X	b = NewBlob (donors, false, infiniteGlue, false, 0L);
X	OpenBlob ();
X	PaintRect (&r);
X	InsetRect (&r, 2, 2);
X	EraseOval (&r);
X	InsetRect (&r, -2, -2);
X	CloseRectBlob (b, &r, &r);
X}
X
X
XSwapInit	()
X{
X	SkelWindow (swapPort = GetDemoWind (swapWindRes),
X				Mouse,			/* mouse clicks */
X				nil,			/* key clicks */
X				Update,			/* updates */
X				Activate,		/* activate/deactivate events */
X				nil,			/* close window */
X				DoWClobber,		/* dispose of window */
X				nil,			/* idle proc */
X				false);			/* irrelevant, since no idle proc */
X
X	hMid = swapPort->portRect.right / 2;
X
X	MakeDonors ();
X	Reset ();
X	Update ();
X	ValidRect (&swapPort->portRect);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoToh.c
X/*
X	Blob Manager Demonstration:  Tower of Hanoi
X
X	26 July 1986	Paul DuBois
X*/
X
X# include	"BlobDemo.h"
X
X
X# define	xBase		17	/* upper left corner of apparatus base */
X# define	yBase		130
X# define	baseHeight	12	/* length is computed */
X# define	slotHeight	18	/* size of disk slots */
X# define	slotWidth	100
X# define	slotHGap	20	/* horiz. gap between slots	*/
X# define	slotVGap	0	/* vert. gap between slots */
X# define	hExtra		20	/* extra space at ends of base */
X# define	nDisks		6	/* number of disks */
X# define	postWidth	12	/* height is computed */
X	
X
Xstatic GrafPtr			tohPort;
Xstatic BlobSetHandle	donors;
Xstatic BlobSetHandle	receptors;
Xstatic BlobHandle		tower[3][nDisks];	/* induced data structure */
X
X
X
Xstatic DrawApparatus ()
X{
Xint	postHeight, baseWidth, h, v, i;
XRect	r;
X
X	postHeight = nDisks * (slotHeight + slotVGap) + postWidth/2;
X	h = xBase + hExtra + slotWidth/2 - postWidth/2;
X	SetRect (&r, h, yBase - postHeight, h + postWidth, yBase+postWidth/2);
X
X	for (i = 0; i < 3; ++i)
X	{
X		FillRoundRect (&r, postWidth, postWidth, gray);
X		FrameRoundRect (&r, postWidth, postWidth);
X		OffsetRect (&r, slotWidth + slotHGap, 0);
X	}
X
X	baseWidth = 3 * slotWidth + 2 * slotHGap + 2 * hExtra;
X	SetRect (&r, xBase, yBase, xBase + baseWidth, yBase + baseHeight);
X	FillRect (&r, dkGray);
X	FrameRect (&r);
X}
X
X
X/*
X	If a disk was moved onto a pile, but has empty slots under it,
X	drop it until it can't go any farther.
X*/
X
Xstatic DropDisk ()
X{
Xregister int	i, j;
X
X	for (i = 0; i < 3; ++i)
X	{
X		for (j = nDisks - 1; j > 0; --j)	/* don't check bottom pos */
X		{
X			if (BGlob (tower[i][j]) != nil)
X			{
X				if (BGlob (tower[i][j-1]) == nil)
X					TransferGlob (tower[i][j], tower[i][j-1]);
X			}
X		}
X	}
X}
X
X
Xstatic Mouse (pt, t, mods)
XPoint	pt;
Xlong	t;
Xint		mods;
X{
X
X	BlobClick (pt, t, nil, receptors);
X	DropDisk ();
X}
X
X
X/*
X	The advisory functions as follows:  receptor clicks are checked
X	and if the click isn't in the top disk of a pile, the click is
X	ignored (message advRClick).  When a receptor is dragged somewhere
X	else, it must be to a pile in which the disk under it is larger -
X	can't drag onto a smaller disk (message advXfer).
X*/
X
Xstatic Boolean Advisory (mesg, b)
Xint			mesg;
XBlobHandle	b;
X{
XBlobHandle	g;
Xint			index, pile, piece, i;
Xstatic int	srcRank;
X
X	index = GetBlobIndex (b, receptors);
X	pile = index / nDisks;		/* 0 .. 2 */
X	piece = index % nDisks;		/* 0 .. nDisks-1 */
X	
X	switch (mesg)
X	{
X		case advRClick:
X		{
X			if (piece < nDisks - 1 && BGlob (NextBlob (b)) != nil)
X				return (false);
X			srcRank = GetBRefCon (BGlob (b));	/* rank of dragged piece */
X			break;
X		}
X		case advXfer:
X		{
X			for (i = 0; i < piece; ++i)
X			{
X				if ((g = BGlob (tower[pile][i])) != nil)
X				{
X					if (GetBRefCon (g) > srcRank)
X						return (false);
X				}
X			}
X			break;
X		}
X	}
X	return (true);
X}
X
X
Xstatic Update (resized)
XBoolean	resized;
X{
X	DrawControls (tohPort);
X	DrawApparatus ();
X	DrawBlobSet (receptors);
X}
X
X
Xstatic Activate (active)
XBoolean	active;
X{
X	if (active)
X	{
X		SetDragRects (tohPort);
X		SetBCPermissions (false, true, false, false, false);
X		SetBCAdvisory (Advisory);
X	}
X	else
X		SetBCAdvisory (nil);
X}
X
X/*
X	Call this before static MakeDonors
X*/
X
Xstatic MakeReceptors ()
X{
Xint			i, j, h, v;
XBlobHandle	b;
XRect		r, r2, r3;
X
X	receptors = NewBlobSet ();
X	for (i = 0; i < 3; ++i)
X	{
X		for (j = 0; j < nDisks; ++j)
X		{
X			b = NewBlob (receptors, false, 0, false, 0L);
X			tower[i][j] = b;
X			OpenBlob ();
X			SetRect (&r, 0, 0, slotWidth, slotHeight);
X			h = slotWidth/2 - postWidth/2;
X			SetRect (&r2, h, -1, h + postWidth, slotHeight+1);
X			FillRect (&r2, gray);	/* fill in post area */
X			SetRect (&r3, 0, 0, h, slotHeight);	/* erase on sides of post */
X			EraseRect (&r3);
X			SetRect (&r3, h + postWidth, 0, slotWidth, slotHeight);
X			EraseRect (&r3);
X			FrameRect (&r2);
X			r2 = r;
X			InsetRect (&r2, 0, 1);
X			CloseRectBlob (b, &r2, &r);
X			h = xBase + hExtra + i * (slotWidth + slotHGap);
X			v = yBase - (j+1) * (slotHeight + slotVGap);
X			MoveBlob (b, inFullBlob, h, v);
X		}
X	}
X}
X
X
X/*
X	Make donors.  These are the pieces that get moved.  They're always
X	attached to some receptor, and just float from one receptor to
X	another.  The rank of each piece is stored in the reference constant
X	field.  The bottom piece is 0, the top is nDisks-1.
X*/
X
Xstatic MakeDonors ()
X{
Xint			i, j;
XBlobHandle	b;
XRect		r, r2;
X
X	donors = NewBlobSet ();
X	for (i = 0; i < nDisks; ++i)
X	{
X		b = NewBlob (donors, false, 1, false,
X									(long) i);	/* refCon is disk rank */
X		OpenBlob ();
X		SetRect (&r, 0, 0, slotWidth, slotHeight);
X		j = 20 + (nDisks-i-1) * 4;
X		SetRect (&r2, slotWidth/2 - j, 1, slotWidth/2 + j, slotHeight-1);
X		EraseRect (&r);
X		FrameRoundRect (&r2, slotHeight, slotHeight);
X		CloseRectBlob (b, &r, &r);
X		GlueGlob (b, tower[0][i]);	/* glue to first column */
X	}
X
X}
X
X
XTohInit ()
X{
X	SkelWindow (tohPort = GetDemoWind (tohWindRes),
X				Mouse,			/* mouse clicks */
X				nil,			/* key clicks */
X				Update,			/* updates */
X				Activate,		/* activate/deactivate events */
X				nil,			/* close window */
X				DoWClobber,		/* dispose of window */
X				nil,			/* idle proc */
X				false);			/* irrelevant, since no idle proc */
X				
X	MakeReceptors ();
X	MakeDonors ();
X	EnableBlobSet (receptors);
X	Update ();
X	ValidRect (&tohPort->portRect);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoTtt.c
X/*
X	Blob Manager Demonstration:  Tic-Tac-Toe
X	
X	25 July 1986	Paul DuBois
X*/
X
X# include	"BlobDemo.h"
X# include	<ControlMgr.h>
X
X
X# define	barWidth	3	/* board line size */
X# define	bSqSize		30	/* board square size */
X# define	pSqSize		28	/* playing piece square size */
X# define	yOffMesg	4
X# define	yOffPiece	24	/* offset of top of pieces */
X# define	xOffBoard	25
X# define	yOffBoard	59
X# define	xMid		73	/* xOffBoard + 1.5(bSqSize) + barWidth */
X# define	yOffBut		165
X
X
Xstatic GrafPtr			tttPort;
Xstatic BlobSetHandle	tttReceptors;	/* receptor blobs (board) */
Xstatic BlobSetHandle	tttDonors;		/* donor blobs (pieces) */
Xstatic BlobHandle		xBlob;			/* handles to each piece */
Xstatic BlobHandle		oBlob;
X
Xstatic Boolean			haveWin;
Xstatic Boolean			wait = false;
Xstatic ControlHandle	restartCtl;
Xstatic int				moves;
Xstatic int				firstPlayer = 0;
Xstatic Str255			statusStr;
X	
X
XTttStatusMesg (s)
XStr255	s;
X{
XRect	r;
X
X	SetRect (&r, xMid-40, yOffMesg, xMid+40, yOffMesg+20);
X	TextBox	(s+1, (long) s[0], &r, 1);
X	StrCpy (statusStr, s);
X}
X
X
XTttGameOver (mesg)
XStr255	mesg;
X{
X	HiliteControl (restartCtl, 0);
X	TttStatusMesg (mesg);
X	wait = true;
X}
X
X
X
XTttSelectPlayer	()
X{
XBlobHandle	b;
Xint			i;
X
X	i = (moves + firstPlayer) % 2;	   /* 0	= X, 1 = O */
X	HiliteBlob (GetBlobHandle (tttDonors, i), inFullBlob, normalDraw);
X	HiliteBlob (GetBlobHandle (tttDonors, 1 - i), inFullBlob, dimDraw);
X	if (i)
X		TttStatusMesg ("\pO's Move");
X	else
X		TttStatusMesg ("\pX's Move");
X/*
X	Freeze board except for positions occupied by current player and
X	empty positions.
X	This allows pieces to be played either by playing the piece at
X	the top, or by duplicating them on the board.  (Can't drag onto
X	another of own pieces, since replace transactions are disallowed.)
X*/
X	ThawBlobSet (tttReceptors);
X	for (b = FirstBlob (tttReceptors); b != nil; b = NextBlob (b))
X	{
X		if (BGlob (b) != nil && BGlob (b) != GetBlobHandle (tttDonors, i))
X			FreezeBlob (b);
X	}
X}
X
X
XTttRestart ()
X{
X	HiliteControl (restartCtl, 255);
X	ZUnglueGlobSet (tttReceptors);
X	HiliteBlobSet (tttReceptors, inFullBlob, normalDraw);
X	moves =	0;
X	TttSelectPlayer	();
X	wait = false;
X}
X
X
X/*
X	Dim the board positions that are not part of the win.  Dim them all
X	on "cat's game."
X*/
X
XTttShowWinner (pos)
Xint	pos;
X{
Xint	i;
XBlobHandle	b;
X
X	for (i = 0; i < 9; ++i)
X	{
X		b = GetBlobHandle (tttReceptors, i);
X		if ((pos % 2) == 0)		 /* this pos not part of win */
X			HiliteBlob (b, inFullBlob, dimDraw);	/* so dim it */
X		pos >>= 1;
X	}
X}
X
XTttTestConfig (pos,	testPos)
Xint	pos, testPos;
X{
Xint	i;
XBlobHandle	b;
X
X	if ((pos & testPos) == testPos) /*	have a win */
X	{
X		haveWin	= true;
X		TttShowWinner (testPos);
X	}
X}
X
X
XTttTestWin (b, boardPos)
XBlobHandle	b;
Xint		boardPos;
X{
X	if (!haveWin)	 /*	don't bother if	other player already won */
X	{
X		TttTestConfig (boardPos, 0x007); /*	top row	*/
X		TttTestConfig (boardPos, 0x038); /*	middle row */
X		TttTestConfig (boardPos, 0x1c0); /*	bottom row */
X		TttTestConfig (boardPos, 0x049); /*	left column	*/
X		TttTestConfig (boardPos, 0x092); /*	middle column */
X		TttTestConfig (boardPos, 0x124); /*	right column */
X		TttTestConfig (boardPos, 0x111); /*	diagonal */
X		TttTestConfig (boardPos, 0x054); /*	diagonal */
X		if (haveWin)
X		{
X			if (b == xBlob)
X			{
X				TttGameOver ("\pX Wins"); /* loser goes	first next time	*/
X				firstPlayer = 1;
X			}
X			else
X			{
X				TttGameOver ("\pO Wins");
X				firstPlayer = 0;
X			}
X		}
X	}
X}
X
X
XTttBoardPos (b)
XBlobHandle	b;
X{
Xint	i, mask, result;
XBlobHandle	b2;
X
X	result = 0;
X	mask = 1;
X	for (i = 0; i < 9; ++i)
X	{
X		b2 = GetBlobHandle (tttReceptors, i);
X		if ((**b2).glob == b)		 /* board occupied by desired piece	*/
X			result |= mask;
X		mask <<= 1;
X	}
X	return (result);
X}
X
X
XTttCheckStatus ()
X{
Xint	xbPos, obPos;
X
X	haveWin = false;
X	xbPos = TttBoardPos (xBlob);
X	obPos = TttBoardPos (oBlob);
X	TttTestWin (xBlob, xbPos);
X	TttTestWin (oBlob, obPos);
X	if (!haveWin)			 /* no win, but board might be full now */
X	{
X		if ((xbPos | obPos) == 0x1ff)
X		{
X			TttShowWinner (0);
X			TttGameOver ("\pCat's Game");
X			firstPlayer = 1 - firstPlayer; /* alternate on a draw */
X		}
X	}
X}
X
X
XTttMouse (pt, t, mods)
XPoint	pt;
Xlong	t;
Xint	mods;
X{
Xint				result;
XControlHandle	ctl;
X
X	if (FindControl	(pt, tttPort, &ctl))
X	{
X		if (TrackControl (ctl, pt, nil))
X		{
X			TttRestart ();
X		}
X	}
X	else if	(!wait)
X	{
X		BlobClick (pt, t, tttDonors, tttReceptors);
X		result = BClickResult ();
X		if (result == bcGlue || result == bcDup)
X		{
X			++moves;
X			TttCheckStatus ();
X			if (!wait)	 /*	no win yet */
X			{
X				TttSelectPlayer	();
X			}
X		}
X	}
X}
X
XTttUpdate (resized)
XBoolean	resized;
X{
X	DrawControls (tttPort);
X	TttStatusMesg (statusStr);
X	DrawGrid (3, 3,	xOffBoard, yOffBoard, bSqSize, bSqSize,	barWidth, barWidth);
X	DrawBlobSet (tttDonors);
X	DrawBlobSet (tttReceptors);
X}
X
X
XTttActivate	(active)
XBoolean	active;
X{
X	if (active)
X	{
X		SetDragRects (tttPort);
X		SetBCPermissions (false, false, true, false, false);
X	}
X}
X
X
X/*
X	Make receptor blobs
X*/
X	
XTttMakeRBlob (r)
XRect	*r;
X{
XBlobHandle	b;
X
X	b = NewBlob (tttReceptors, false, 0, false, 0L);
X	OpenBlob ();
X	EraseRect (r);
X	InsetRect (r, 1, 1);
X	FrameRect (r);
X	InsetRect (r, 2, 2);
X	FrameRect (r);
X	InsetRect (r, -2, -2);
X	CloseRectBlob (b, r, r);
X}
X
X
XTttMakeReceptors ()
X{
X	tttReceptors =	NewBlobSet ();
X	MakeBlobGrid (3, 3, xOffBoard, yOffBoard, bSqSize, bSqSize,
X					barWidth, barWidth, &TttMakeRBlob);
X}
X
X
X/*
X	Make donor blobs
X*/
X
XTttMakeDBlob (b, ch, x, y)
XBlobHandle	*b;
Xint		ch, x, y;
X{
XRect	r;
X
X	*b = NewBlob (tttDonors, false, 9, false, 0L);
X	OpenBlob ();
X	SetRect (&r, 0, 0, pSqSize, pSqSize);
X	OffsetRect (&r, x, y);
X	EraseRect (&r);
X	PenSize	(2, 2);
X	FrameRect (&r);
X	PenNormal ();
X	MoveTo (r.left+pSqSize/2-4, r.bottom-pSqSize/2+5);
X	DrawChar ((char) ch);
X	CloseRectBlob (*b, &r, &r);
X}
X
X
XTttMakeDonors ()
X{
X	tttDonors = NewBlobSet ();
X	TttMakeDBlob (&xBlob, 'X', xMid-pSqSize-5, yOffPiece);
X	TttMakeDBlob (&oBlob, 'O', xMid+5, yOffPiece);
X}
X
X
XTttInit	()
X{
XRect	r;
X
X	tttPort = GetDemoWind (tttWindRes);
X	SkelWindow (tttPort,
X				TttMouse,		/* mouse clicks */
X				nil,			/* key clicks */
X				TttUpdate,		/* updates */
X				TttActivate,	/* activate/deactivate events */
X				nil,			/* close window */
X				DoWClobber,		/* dispose of window */
X				nil,			/* idle proc */
X				false);			/* irrelevant, since no idle proc */
X
X	TttMakeReceptors ();
X	TttMakeDonors ();
X	EnableBlobSet (tttReceptors);
X	EnableBlobSet (tttDonors);
X	SetRect (&r, xMid-45, yOffBut, xMid+45, yOffBut+20);
X	restartCtl = NewControl (tttPort, &r, "\pRestart", true, 0, 0, 0,
X								pushButProc, nil);
X	TttRestart ();
X	TttUpdate ();
X	ValidRect (&tttPort->portRect);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoWind.c
X/*
X	Blob Manager Demonstration:  Window routines
X*/
X
X# include	"BlobDemo.h"
X# include	<WindowMgr.h>
X
X
X
X
X/*
X	Get a window for a demo module.  Pass the resource number of the
X	window.  Set the font to Chicago 12-point, and add the window's
X	title to the Windows menu.
X*/
X
XGrafPtr GetDemoWind (resNum)
Xint		resNum;
X{
XGrafPtr	thePort;
X
X	thePort = (GrafPtr) GetNewWindow (resNum, nil, -1L);
X	SetPort (thePort);
X	TextFont (0);
X	TextSize (0);
X	return (thePort);
X}
X
X
X/*
X	Generic window handler clobber proc for TransSkel stuff
X*/
X
XDoWClobber ()
X{
XWindowPtr	theWind;
X
X	GetPort ((GrafPtr *) &theWind);
X	CloseWindow (theWind);				/* should be DisposeWindow? */
X}
X
X
X/*
X	Set window's default blob dragging rects:  limit rect is portRect
X	of window's grafPort, slop rect is wide open rectangle.
X*/
X
XSetDragRects (thePort)
XGrafPtr	thePort;
X{
XRect	rSlop;
X
X	SetRect (&rSlop, -30000, -30000, 30000, 30000);
X	SetBDragRects (&thePort->portRect, &rSlop);
X}SHAR_EOF
exit