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