home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / BlobMgr / Blob Manager Demo 5 / DemoWolf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-02-17  |  8.6 KB  |  405 lines  |  [TEXT/MACA]

  1. /*
  2.     Blob Manager Demonstration:  Wolf & Goats module
  3.  
  4.     This is played on a checkerboard.  The wolf starts in one corner,
  5.     the four goats on the opposite row.  All moves are into adjoining
  6.     diagonal squares.  The wolf can move forward or backward, the goats
  7.     only forward.  The goats try to trap the wolf so he can't move,
  8.     while the wolf tries to get past the goats to the other side.
  9.  
  10.     This game is a variant of fox & geese.
  11.  
  12.     1 August 1986        Paul DuBois
  13. */
  14.  
  15.  
  16. # include    "BlobDemo.h"
  17.  
  18.  
  19. # define    rows        8        /* number of rows on board */
  20. # define    columns        8        /* number of columns on board */
  21. # define    pieceSize    20        /* size of each piece */
  22. # define    vMessage    165        /* vertical position of message */
  23.  
  24.  
  25.  
  26.  
  27. static GrafPtr            wolfPort;
  28.  
  29.  
  30. static BlobSetHandle    boardBlobs = nil;
  31. static BlobHandle        board[columns][rows];
  32. static BlobSetHandle    donors = nil;
  33. static BlobHandle        wolf;
  34. static BlobHandle        goat;
  35. static BlobHandle        current;
  36. static BlobSetHandle    misc;
  37. static BlobHandle        resetBlob;    /* simulated control */
  38. static int                hWolf;
  39. static int                vWolf;
  40.  
  41. static int                hMid;
  42. static Boolean            pause;
  43. static Str255            statusStr = "\p";
  44.  
  45.  
  46.  
  47. static StatusMesg (s)
  48. Str255    s;
  49. {
  50. Rect    r;
  51.  
  52.     SetRect (&r, 0, vMessage, wolfPort->portRect.right - 25, vMessage + 12);
  53.     TextBox    (s+1, (long) s[0], &r, 1);
  54.     StrCpy (statusStr, s);
  55. }
  56.  
  57.  
  58. /*
  59.     The donor set consists of two blobs:  the wolf blob and the
  60.     goat blob.
  61. */
  62.  
  63. static MakeDonors ()
  64. {
  65. Rect        r;
  66.  
  67.     donors = NewBlobSet ();
  68.     SetRect (&r, 0, 0, pieceSize - 1, pieceSize - 1);
  69.     wolf = NewBlob (donors, false, infiniteGlue, false, 0L);
  70.     OpenBlob ();
  71.     PaintRect (&r);
  72.     PenMode (patBic);
  73.     PenSize (2, 2);
  74.     FrameOval (&r);
  75.     PenNormal ();
  76.     CloseRectBlob (wolf, &r, &r);
  77.     goat = NewBlob (donors, false, infiniteGlue, false, 0L);
  78.     OpenBlob ();
  79.     PaintRect (&r);
  80.     EraseOval (&r);
  81.     CloseRectBlob (goat, &r, &r);
  82. }
  83.  
  84.  
  85.  
  86. /*
  87.     Make a simulated push button.  It looks like a regular button,
  88.     except that it's oriented vertically rather than horizontally.
  89.     The ShowPen call is necessary since both OpenBlob and OpenRgn
  90.     perform implicit HidePen's - without ShowPen, nothing will
  91.     be drawn!  Then must balance with HidePen after drawing.
  92. */
  93.  
  94. static MakeButton ()
  95. {
  96. Rect        r;
  97.  
  98.     misc = NewBlobSet ();
  99.     SetRect (&r, 0, 0, 20, 90);
  100.     OffsetRect (&r, wolfPort->portRect.right - 25,
  101.                     (wolfPort->portRect.bottom - 90 - 25) / 2);
  102.     resetBlob = NewVButtonBlob (misc, &r, "\pReset", true, 0L);
  103. }
  104.  
  105.  
  106. /*
  107.     Board position drawing procedure.  All positions are drawn the
  108.     same - a black rectangle.  However, the unused positions are set
  109.     dimmed by InitBoard, so the drawing mechanisms make them gray.
  110.     For the drag region of used positions,
  111.     this proc is only called if the position has no piece (i.e., no
  112.     glob) because the pieces are picture blobs.
  113.  
  114.     For these reasons, bSrc and bDst are always equal when
  115.     DrawBoardPos is called.
  116. */
  117.  
  118. static DrawBoardPos (bSrc, bDst, partCode)
  119. BlobHandle    bSrc, bDst;
  120. int            partCode;        /* ignored - always draw entire blob */
  121. {
  122. Rect    r;
  123.  
  124.     r = BStatBox (bDst);
  125.     PaintRect (&r);
  126. }
  127.  
  128.  
  129. /*
  130.     Build the board, which consists of alternating black and gray
  131.     squares.  They are actually the same as far as the drawing proc
  132.     goes, but the gray squares are set to be dimmed so that the
  133.     normal drawing mechanisms do the work of making the two types
  134.     of square look distinct.  The fact that the gray squares are
  135.     dimmed also makes the hit-testing mechanisms ignore them.
  136. */
  137.  
  138. static InitBoard ()
  139. {
  140. int            h, v;
  141. Rect        r, r2;
  142. BlobHandle    b;
  143.  
  144.     boardBlobs = NewBlobSet ();
  145.     for (v = 0; v < rows; v++)
  146.     {
  147.         for (h = 0; h < columns; h++)
  148.         {
  149.             b = NewBlob (boardBlobs, false, 0, false, 0L);
  150.             board[h][v] = b;
  151.             SetRect (&r, 0, 0, pieceSize, pieceSize);
  152.             OffsetRect (&r, h * pieceSize, v * pieceSize);
  153.             r2 = r;
  154.             InsetRect (&r2, 1, 1);
  155.             SetProcRectBlob (b, DrawBoardPos, &r2, &r);
  156.  
  157.             /*
  158.                 All unused postions have coordinates that sum to an
  159.                 odd number.
  160.             */
  161.  
  162.             if ((h + v) % 2 == 1)
  163.                 SetBDrawMode (b, inFullBlob, dimDraw);
  164.         }
  165.     }
  166.     ShowBlobSet (boardBlobs);
  167. }
  168.  
  169.  
  170. /*
  171.     Set the board to the initial configuration
  172. */
  173.  
  174. static Reset ()
  175. {
  176. int        i;
  177.  
  178.     UnglueGlobSet (boardBlobs);        /* clear all globs */
  179.     GlueGlob (wolf, board[hWolf = 0][vWolf = 0]);
  180.     for (i = 1; i < columns; i += 2)
  181.         GlueGlob (goat, board[i][rows - 1]);
  182.     current = wolf;
  183.     StatusMesg ("\pWolf's Move");
  184.     pause = false;
  185. }
  186.  
  187.  
  188. static WolfPause (msg)
  189. StringPtr    msg;
  190. {
  191.     StatusMesg (msg);
  192.     pause = true;
  193. }
  194.  
  195.  
  196. /*
  197.     Given a blob handle, find the board position that corresponds to it.
  198.     This is used to map hits in the blob set (a list) to the position in
  199.     the board (a 2-d array).
  200. */
  201.  
  202. static BoardPos (b, h, v)
  203. BlobHandle    b;
  204. int            *h, *v;
  205. {
  206. int        i, j;
  207.  
  208.     for (i = 0; i < columns; ++i)
  209.     {
  210.         for (j = 0; j < rows; ++j)
  211.         {
  212.             if (board[i][j] == b)
  213.             {
  214.                 *h = i;
  215.                 *v = j;
  216.                 return;
  217.             }
  218.         }
  219.     }
  220.     /* shouldn't ever get here */
  221. }
  222.  
  223.  
  224. /*
  225.     Check whether a board position is empty.  The coordinates must be
  226.     legal, the position must be used in the current configuration,
  227.     and the position must have a marble in it.
  228. */
  229.  
  230. static Boolean BoardPosEmpty (h, v)
  231. int        h, v;
  232. {
  233.     return (h >= 0 && h < columns && v >= 0 && v < rows
  234.             && (h + v) % 2 == 0
  235.             && BGlob (board[h][v]) == nil);
  236. }
  237.  
  238.  
  239. /*
  240.     Test whether a piece can move or not.  The goats can only move
  241.     forward (which for them means to a lower-numbered row), while the
  242.     wolf can move forward or backward.
  243. */
  244.  
  245. static Boolean CanMove (h, v)
  246. int        h, v;
  247. {
  248. BlobHandle    g;
  249.  
  250.     g = BGlob (board[h][v]);
  251.     if (g == goat && v == 0)
  252.         return (false);        /* goats can't move from row zero */
  253.     return (BoardPosEmpty (h - 1, v - 1)
  254.             || BoardPosEmpty (h + 1, v - 1)
  255.             || (g == wolf
  256.                 && (BoardPosEmpty (h - 1, v + 1)
  257.                     || BoardPosEmpty (h + 1, v + 1))));
  258. }
  259.  
  260.  
  261.  
  262. static Mouse (pt, t, mods)
  263. Point    pt;
  264. long    t;
  265. int        mods;
  266. {
  267. Str255            s;
  268. int                i;
  269.  
  270.  
  271.     if (TestBlob (resetBlob, pt))
  272.     {
  273.         if (BTrackMouse (resetBlob, pt, inFullBlob))
  274.             Reset ();
  275.     }
  276.     else if (!pause)
  277.     {
  278.         BlobClick (pt, t, nil, boardBlobs);
  279.         if (BClickResult () == bcXfer)
  280.         {
  281.             if (!CanMove (hWolf, vWolf))    /* wolf locked in? */
  282.                 WolfPause ("\pGoats Win");
  283.             else if (vWolf == rows - 1)    /* wolf made it */
  284.                 WolfPause ("\pWolf Wins");
  285.             else
  286.             {
  287.                 current = (current == wolf ? goat : wolf);
  288.                 StatusMesg (current == wolf ?
  289.                                 "\pWolf's Move" : "\pGoats' Move");
  290.             }
  291.         }
  292.     }
  293. }
  294.  
  295.  
  296.  
  297. /*
  298.     When a piece is clicked on, the advisory checks whether the piece has
  299.     any legal moves available to it.  If so, it returns true, so that
  300.     BlobClick is allowed to drag the piece.  After the piece has been
  301.     dragged, the advisory checks whether the position it was dragged to
  302.     is legal, and returns true if so.
  303.  
  304.     Messages passed to the advisory follow the pattern
  305.  
  306.     { { advRClick advRClick* } advXfer* }*
  307.  
  308.     where * means 0 or more instances of the thing *'ed.  In particular,
  309.     the advXfer message is never seen without a preceding advRClick.
  310. */
  311.  
  312. static Boolean Advisory (mesg, b)
  313. int            mesg;
  314. BlobHandle    b;
  315. {
  316. static int    h, v;    /* static to save board position of click on piece */
  317. int            h2, v2;
  318. Boolean        result;
  319.  
  320.     switch (mesg)
  321.     {
  322.  
  323.     case advRClick:    /* first click on piece */
  324.         if (BGlob (b) != current)
  325.             return (false);            /* can only move current piece(s) */
  326.         BoardPos (b, &h, &v);    /* find where it is */
  327.         return (CanMove (h, v));
  328.  
  329.     case advXfer:    /* Mouse released after dragging piece */
  330.  
  331.         BoardPos (b, &h2, &v2);
  332.         result = ((h2 == h - 1 && v2 == v - 1)
  333.             || (h2 == h + 1 && v2 == v - 1)
  334.             || (current == wolf
  335.                 && ((h2 == h - 1 && v2 == v + 1)
  336.                     || (h2 == h + 1 && v2 == v + 1))));
  337.         if (result == true && current == wolf)
  338.         {
  339.             hWolf = h2;        /* update wolf's position */
  340.             vWolf = v2;
  341.         }
  342.         return (result);
  343.     }
  344. }
  345.  
  346.  
  347.  
  348. /*
  349.     Activate the window:  Set the advisory function and set the permissions
  350.     to transfer-only.  Clear, replace, duplication and swap are off.
  351.     Since replace is off, the advisory doesn't have to check whether
  352.     the dragged piece was dragged onto a blob that already has a glob.
  353.  
  354.     Deactivate the window:  Clear the advisory.
  355. */
  356.  
  357. static Activate (active)
  358. Boolean    active;
  359. {
  360.  
  361.     if (active)
  362.     {
  363.         SetDragRects (wolfPort);
  364.         SetBCPermissions (false, true, false, false, false);    /* xfer only */
  365.         SetBCAdvisory (Advisory);
  366.     }
  367.     else
  368.     {
  369.         SetBCAdvisory (nil);
  370.     }
  371. }
  372.  
  373.  
  374. static Update (resized)
  375. Boolean    resized;
  376. {
  377.     DrawBlobSet (boardBlobs);
  378.     DrawBlob (resetBlob, inFullBlob);
  379.     StatusMesg (statusStr);
  380. }
  381.  
  382.  
  383. WolfInit    ()
  384. {
  385. Rect    r;
  386.  
  387.     SkelWindow (wolfPort = GetDemoWind (wolfWindRes),
  388.                 Mouse,            /* mouse clicks */
  389.                 nil,            /* key clicks */
  390.                 Update,            /* updates */
  391.                 Activate,        /* activate/deactivate events */
  392.                 nil,            /* close window */
  393.                 DoWClobber,        /* dispose of window */
  394.                 nil,            /* idle proc */
  395.                 false);            /* irrelevant, since no idle proc */
  396.  
  397.     hMid = wolfPort->portRect.right / 2;
  398.  
  399.     MakeDonors ();
  400.     InitBoard ();
  401.     MakeButton ();
  402.     Reset ();
  403.     ValidRect (&wolfPort->portRect);
  404. }
  405.