home *** CD-ROM | disk | FTP | other *** search
- /*
- Blob Manager Demonstration: Wolf & Goats module
-
- This is played on a checkerboard. The wolf starts in one corner,
- the four goats on the opposite row. All moves are into adjoining
- diagonal squares. The wolf can move forward or backward, the goats
- only forward. The goats try to trap the wolf so he can't move,
- while the wolf tries to get past the goats to the other side.
-
- This game is a variant of fox & geese.
-
- 1 August 1986 Paul DuBois
- */
-
-
- # include "BlobDemo.h"
-
-
- # define rows 8 /* number of rows on board */
- # define columns 8 /* number of columns on board */
- # define pieceSize 20 /* size of each piece */
- # define vMessage 165 /* vertical position of message */
-
-
-
-
- static GrafPtr wolfPort;
-
-
- static BlobSetHandle boardBlobs = nil;
- static BlobHandle board[columns][rows];
- static BlobSetHandle donors = nil;
- static BlobHandle wolf;
- static BlobHandle goat;
- static BlobHandle current;
- static BlobSetHandle misc;
- static BlobHandle resetBlob; /* simulated control */
- static int hWolf;
- static int vWolf;
-
- static int hMid;
- static Boolean pause;
- static Str255 statusStr = "\p";
-
-
-
- static StatusMesg (s)
- Str255 s;
- {
- Rect r;
-
- SetRect (&r, 0, vMessage, wolfPort->portRect.right - 25, vMessage + 12);
- TextBox (s+1, (long) s[0], &r, 1);
- StrCpy (statusStr, s);
- }
-
-
- /*
- The donor set consists of two blobs: the wolf blob and the
- goat blob.
- */
-
- static MakeDonors ()
- {
- Rect r;
-
- donors = NewBlobSet ();
- SetRect (&r, 0, 0, pieceSize - 1, pieceSize - 1);
- wolf = NewBlob (donors, false, infiniteGlue, false, 0L);
- OpenBlob ();
- PaintRect (&r);
- PenMode (patBic);
- PenSize (2, 2);
- FrameOval (&r);
- PenNormal ();
- CloseRectBlob (wolf, &r, &r);
- goat = NewBlob (donors, false, infiniteGlue, false, 0L);
- OpenBlob ();
- PaintRect (&r);
- EraseOval (&r);
- CloseRectBlob (goat, &r, &r);
- }
-
-
-
- /*
- Make a simulated push button. It looks like a regular button,
- except that it's oriented vertically rather than horizontally.
- The ShowPen call is necessary since both OpenBlob and OpenRgn
- perform implicit HidePen's - without ShowPen, nothing will
- be drawn! Then must balance with HidePen after drawing.
- */
-
- static MakeButton ()
- {
- Rect r;
-
- misc = NewBlobSet ();
- SetRect (&r, 0, 0, 20, 90);
- OffsetRect (&r, wolfPort->portRect.right - 25,
- (wolfPort->portRect.bottom - 90 - 25) / 2);
- resetBlob = NewVButtonBlob (misc, &r, "\pReset", true, 0L);
- }
-
-
- /*
- Board position drawing procedure. All positions are drawn the
- same - a black rectangle. However, the unused positions are set
- dimmed by InitBoard, so the drawing mechanisms make them gray.
- For the drag region of used positions,
- this proc is only called if the position has no piece (i.e., no
- glob) because the pieces are picture blobs.
-
- For these reasons, bSrc and bDst are always equal when
- DrawBoardPos is called.
- */
-
- static DrawBoardPos (bSrc, bDst, partCode)
- BlobHandle bSrc, bDst;
- int partCode; /* ignored - always draw entire blob */
- {
- Rect r;
-
- r = BStatBox (bDst);
- PaintRect (&r);
- }
-
-
- /*
- Build the board, which consists of alternating black and gray
- squares. They are actually the same as far as the drawing proc
- goes, but the gray squares are set to be dimmed so that the
- normal drawing mechanisms do the work of making the two types
- of square look distinct. The fact that the gray squares are
- dimmed also makes the hit-testing mechanisms ignore them.
- */
-
- static InitBoard ()
- {
- int h, v;
- Rect r, r2;
- BlobHandle b;
-
- boardBlobs = NewBlobSet ();
- for (v = 0; v < rows; v++)
- {
- for (h = 0; h < columns; h++)
- {
- b = NewBlob (boardBlobs, false, 0, false, 0L);
- board[h][v] = b;
- SetRect (&r, 0, 0, pieceSize, pieceSize);
- OffsetRect (&r, h * pieceSize, v * pieceSize);
- r2 = r;
- InsetRect (&r2, 1, 1);
- SetProcRectBlob (b, DrawBoardPos, &r2, &r);
-
- /*
- All unused postions have coordinates that sum to an
- odd number.
- */
-
- if ((h + v) % 2 == 1)
- SetBDrawMode (b, inFullBlob, dimDraw);
- }
- }
- ShowBlobSet (boardBlobs);
- }
-
-
- /*
- Set the board to the initial configuration
- */
-
- static Reset ()
- {
- int i;
-
- UnglueGlobSet (boardBlobs); /* clear all globs */
- GlueGlob (wolf, board[hWolf = 0][vWolf = 0]);
- for (i = 1; i < columns; i += 2)
- GlueGlob (goat, board[i][rows - 1]);
- current = wolf;
- StatusMesg ("\pWolf's Move");
- pause = false;
- }
-
-
- static WolfPause (msg)
- StringPtr msg;
- {
- StatusMesg (msg);
- pause = true;
- }
-
-
- /*
- Given a blob handle, find the board position that corresponds to it.
- This is used to map hits in the blob set (a list) to the position in
- the board (a 2-d array).
- */
-
- static BoardPos (b, h, v)
- BlobHandle b;
- int *h, *v;
- {
- int i, j;
-
- for (i = 0; i < columns; ++i)
- {
- for (j = 0; j < rows; ++j)
- {
- if (board[i][j] == b)
- {
- *h = i;
- *v = j;
- return;
- }
- }
- }
- /* shouldn't ever get here */
- }
-
-
- /*
- Check whether a board position is empty. The coordinates must be
- legal, the position must be used in the current configuration,
- and the position must have a marble in it.
- */
-
- static Boolean BoardPosEmpty (h, v)
- int h, v;
- {
- return (h >= 0 && h < columns && v >= 0 && v < rows
- && (h + v) % 2 == 0
- && BGlob (board[h][v]) == nil);
- }
-
-
- /*
- Test whether a piece can move or not. The goats can only move
- forward (which for them means to a lower-numbered row), while the
- wolf can move forward or backward.
- */
-
- static Boolean CanMove (h, v)
- int h, v;
- {
- BlobHandle g;
-
- g = BGlob (board[h][v]);
- if (g == goat && v == 0)
- return (false); /* goats can't move from row zero */
- return (BoardPosEmpty (h - 1, v - 1)
- || BoardPosEmpty (h + 1, v - 1)
- || (g == wolf
- && (BoardPosEmpty (h - 1, v + 1)
- || BoardPosEmpty (h + 1, v + 1))));
- }
-
-
-
- static Mouse (pt, t, mods)
- Point pt;
- long t;
- int mods;
- {
- Str255 s;
- int i;
-
-
- if (TestBlob (resetBlob, pt))
- {
- if (BTrackMouse (resetBlob, pt, inFullBlob))
- Reset ();
- }
- else if (!pause)
- {
- BlobClick (pt, t, nil, boardBlobs);
- if (BClickResult () == bcXfer)
- {
- if (!CanMove (hWolf, vWolf)) /* wolf locked in? */
- WolfPause ("\pGoats Win");
- else if (vWolf == rows - 1) /* wolf made it */
- WolfPause ("\pWolf Wins");
- else
- {
- current = (current == wolf ? goat : wolf);
- StatusMesg (current == wolf ?
- "\pWolf's Move" : "\pGoats' Move");
- }
- }
- }
- }
-
-
-
- /*
- When a piece is clicked on, the advisory checks whether the piece has
- any legal moves available to it. If so, it returns true, so that
- BlobClick is allowed to drag the piece. After the piece has been
- dragged, the advisory checks whether the position it was dragged to
- is legal, and returns true if so.
-
- Messages passed to the advisory follow the pattern
-
- { { advRClick advRClick* } advXfer* }*
-
- where * means 0 or more instances of the thing *'ed. In particular,
- the advXfer message is never seen without a preceding advRClick.
- */
-
- static Boolean Advisory (mesg, b)
- int mesg;
- BlobHandle b;
- {
- static int h, v; /* static to save board position of click on piece */
- int h2, v2;
- Boolean result;
-
- switch (mesg)
- {
-
- case advRClick: /* first click on piece */
- if (BGlob (b) != current)
- return (false); /* can only move current piece(s) */
- BoardPos (b, &h, &v); /* find where it is */
- return (CanMove (h, v));
-
- case advXfer: /* Mouse released after dragging piece */
-
- BoardPos (b, &h2, &v2);
- result = ((h2 == h - 1 && v2 == v - 1)
- || (h2 == h + 1 && v2 == v - 1)
- || (current == wolf
- && ((h2 == h - 1 && v2 == v + 1)
- || (h2 == h + 1 && v2 == v + 1))));
- if (result == true && current == wolf)
- {
- hWolf = h2; /* update wolf's position */
- vWolf = v2;
- }
- return (result);
- }
- }
-
-
-
- /*
- Activate the window: Set the advisory function and set the permissions
- to transfer-only. Clear, replace, duplication and swap are off.
- Since replace is off, the advisory doesn't have to check whether
- the dragged piece was dragged onto a blob that already has a glob.
-
- Deactivate the window: Clear the advisory.
- */
-
- static Activate (active)
- Boolean active;
- {
-
- if (active)
- {
- SetDragRects (wolfPort);
- SetBCPermissions (false, true, false, false, false); /* xfer only */
- SetBCAdvisory (Advisory);
- }
- else
- {
- SetBCAdvisory (nil);
- }
- }
-
-
- static Update (resized)
- Boolean resized;
- {
- DrawBlobSet (boardBlobs);
- DrawBlob (resetBlob, inFullBlob);
- StatusMesg (statusStr);
- }
-
-
- WolfInit ()
- {
- Rect r;
-
- SkelWindow (wolfPort = GetDemoWind (wolfWindRes),
- Mouse, /* mouse clicks */
- nil, /* key clicks */
- Update, /* updates */
- Activate, /* activate/deactivate events */
- nil, /* close window */
- DoWClobber, /* dispose of window */
- nil, /* idle proc */
- false); /* irrelevant, since no idle proc */
-
- hMid = wolfPort->portRect.right / 2;
-
- MakeDonors ();
- InitBoard ();
- MakeButton ();
- Reset ();
- ValidRect (&wolfPort->portRect);
- }
-