[comp.sources.amiga] v89i119: maze - build and solve mazes

page%swap@Sun.COM (Bob Page) (05/09/89)

Submitted-by: utoddl@uncece.edu (Todd M. Lewis)
Posting-number: Volume 89, Issue 119
Archive-name: fun/maze.1

Here's a little ditty that builds mazes and lets you solve them.  This
one is in C, and I even went back and made sure the comments were
usually close to what the code might have done at one time.  I used
Manx, but conversion to other compilers should be trivial.

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	about.c
#	maze.c
#	stdhead.c
#	makefile
# This is archive 1 of a 1-part kit.
# This archive created: Mon May  8 16:58:06 1989
echo "extracting about.c"
sed 's/^X//' << \SHAR_EOF > about.c
X#include <exec/types.h>
X#include <graphics/view.h>
X#include <intuition/intuition.h>
X#include <functions.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X
Xextern struct Window *window;
Xextern ULONG RangeRand();
Xextern struct TextAttr font;
X
Xcycle(color) int color;
X{   struct ColorMap *cm;
X    struct ViewPort *vp;
X    UWORD orig, r, g, b, ro, go, bo;
X    int i;
X
X    vp = ViewPortAddress( window );
X    cm = vp -> ColorMap;
X
X    orig = GetRGB4( cm, (LONG) color );
X    b = (bo = (orig     ) & 15);
X    g = (go = (orig >> 4) & 15);
X    r = (ro = (orig >> 8) & 15);
X
X    for (i=0; i<1000; i++) {
X        r = RangeRand(2L) * 15;
X        g = RangeRand(2L) * 15;
X        b = RangeRand(2L) * 15;
X        SetRGB4(vp,(LONG)color,(LONG)r,(LONG)g,(LONG)b);
X        }
X    SetRGB4(vp,(LONG)color,(LONG)ro,(LONG)go,(LONG)bo);
X    }
X
X#define reqW  544
X#define reqH  152
X#define centerX(chars) (reqW/2 - (chars)*8/2)
X#define centerXright(chars) (reqW - 111 - (chars)*8/2)
X#define centerXleft(chars) (111 - (chars)*8/2)
X
XSHORT reqborderXY[] = { 2,1, 541,1, 541,150, 2,150, 2,1 };
X
Xstruct Border reqborder = {
X        0,0,        /* LeftEdge, TopEdge */
X        1,1,        /* FrontPen, BackPen */
X        JAM1,       /* DrawMode */
X        5,          /* Count */
X        reqborderXY,/* SHORT *XY */
X        NULL,       /* NextBorder */
X        };
X
XSHORT gadborderXY[] = { 2,1, 97,1, 97,28, 2,28, 2,1 };
X
Xstruct Border gadborder = {
X        2,1,        /* LeftEdge, TopEdge */
X        1,2,        /* FrontPen, BackPen */
X        JAM2,       /* DrawMode */
X        5,          /* Count */
X        gadborderXY,   /* SHORT *XY */
X        NULL,       /* NextBorder */
X        };
X
Xstruct IntuiText gadtext = {
X        1,2,      /* FrontPen, BackPen */
X        JAM1,     /* DrawMode */
X        18,11,    /* LeftEdge, TopEdge */
X        &font,     /* TextAttr *ITextFont */
X        (UBYTE *) "Continue", /* IText */
X        NULL,     /* struct IntuiText *NextText */
X        };
X
Xstruct Gadget aboutgad = {
X        NULL,          /* NextGadget */
X        222,117,100,30,  /* LeftEdge, TopEdge, Width, Height */
X        GADGHNONE,         /* Flags */
X        ENDGADGET | TOGGLESELECT,  /* Activation Flags */
X        REQGADGET | BOOLGADGET, /* GadgetType */
X        (APTR)&gadborder,       /* GadgetRender */
X        NULL,       /* SelectRender */
X        &gadtext,       /* GadgetText   */
X        NULL,       /* MutualExclude */
X        NULL,       /* SpecialInfo  */
X        0,          /* GadgetID     */
X        NULL,       /* UserData     */
X        };
X
Xstruct IntuiText  ab_txt8= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        20,102,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "Comments and suggestions are welcome.", /* IText */
X        NULL,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt7= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        20,92,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "writing it.  Please feel free to share it with your friends.", /* IText */
X        &ab_txt8,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt6= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        20,82,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "   I hope you enjoy playing this game as much as I enjoyed", /* IText */
X        &ab_txt7,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_inst3= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        20,68,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "give you a hint.  Select new mazes from the menu.  Good luck!", /* IText */
X        &ab_txt6,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_inst2= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        20,59,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "red spot to the dark red spot.  The left mouse button will", /* IText */
X        &ab_inst3,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_inst1= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        20,50,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "   Move the mouse pointer through the maze from the bright", /* IText */
X        &ab_inst2,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_left2= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerXleft(19),120,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "Usenet Distribution", /* IText */
X        &ab_inst1,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_left1= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerXleft(12),130,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "Spring, 1989", /* IText */
X        &ab_left2,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt5= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerXright(24),140,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "utoddl@ecsvax.uncecs.edu", /* IText */
X        &ab_left1,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt4= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerXright(20),130,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "utoddl@ecsvax.BITNET", /* IText */
X        &ab_txt5,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt3= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerXright(21),120,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "Author: Todd M. Lewis", /* IText */
X        &ab_txt4,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt2= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerX(32),35,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "The Disk Magazine for the Amiga.", /* IText */
X        &ab_txt3,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt1= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerX(30),25,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "First distributed on JUMPDISK,", /* IText */
X        &ab_txt2,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText  ab_txt0= {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerX(33),15,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "Copyright (c) 1988, Todd M. Lewis", /* IText */
X        &ab_txt1,   /* struct IntuiText *NextText */
X        };
Xstruct IntuiText firsttext = {
X        3,2,    /* FrontPen, BackPen */
X        JAM1,   /* DrawMode */
X        centerX(27),6,    /* LeftEdge, TopEdge */
X        &font,   /* TextAttr *ITextFont */
X        (UBYTE *) "TML's AmigaMaze version 1.2", /* IText */
X        &ab_txt0,   /* struct IntuiText *NextText */
X        };
X
Xstruct Requester aboutreq;
X
Xabout()
X{   struct IntuiMessage *msg;
X    int class;
X
X    InitRequester( &aboutreq );
X
X    aboutreq.LeftEdge   = 4;
X    aboutreq.TopEdge    = 15;
X    aboutreq.Width      = reqW;
X    aboutreq.Height     = reqH;
X    aboutreq.ReqGadget  = &aboutgad;
X    aboutreq.ReqText    = &firsttext;
X    aboutreq.ReqBorder  = &reqborder;
X    aboutreq.BackFill   = 2;      /* BLACK */
X
X    if (Request( &aboutreq, window )) {
X       do {
X             Wait( 1L << window->UserPort->mp_SigBit );
X             while (msg = (struct IntuiMessage *)GetMsg( window->UserPort )) {
X                 class = msg->Class;
X                 ReplyMsg(msg);
X                 }
X             } while ( class != REQCLEAR );
X       }
X   }
X
SHAR_EOF
echo "extracting maze.c"
sed 's/^X//' << \SHAR_EOF > maze.c
X#include <exec/types.h>
X#include <intuition/intuition.h>
X#include <functions.h>
X#include <graphics/gfxmacros.h>
X#include <graphics/text.h>
Xstruct IntuitionBase *IntuitionBase;
Xstruct GfxBase       *GfxBase;
X
Xstruct RastPort  tmpRPactual;
Xstruct RastPort *tmpRP = &tmpRPactual;
Xstruct BitMap    tmpBM;
X
Xstruct TextAttr font = {
X        (STRPTR)"topaz.font",   /* Font Name */
X        TOPAZ_EIGHTY,    /* Font Height */
X        FS_NORMAL,      /* Font Style */
X        FPF_ROMFONT     /* Preferences */
X        };
X
X#define tmpBMxy 60L
X
X#define windowW 552L
X#define windowH 183L
X
Xstruct NewWindow nw = {
X      6, 12, windowW, windowH,      /* EDGES, SIZE */
X      0, 1,                         /* PENS */
X      CLOSEWINDOW,                  /* IDCMPFlags */
X      WINDOWDRAG  | WINDOWDEPTH |   /* Flags (requested window features)*/
X        WINDOWCLOSE | ACTIVATE | REPORTMOUSE,
X      NULL,                         /* gadgets */
X      NULL,                         /* checkmark image */
X      NULL,                         /* title */
X      NULL,                         /* screen */
X      NULL,                         /* bitmap */
X      0,0,0,0,                      /* min and max w and h */
X      WBENCHSCREEN,                 /* TYPE */
X      };
X
X
Xstruct IntuiText it_GiveUp = {
X        0,1,        /* frontpen, backpen */
X        JAM1,       /* drawmode */
X        1,1,        /* leftedge, topedge */
X        &font,       /* TextAttr * ITextFont */
X        (UBYTE *)" Give Up! ",  /* IText */
X        NULL,       /* NextText */
X        };
Xstruct MenuItem mi_GiveUp = {
X        (struct MenuItem *) NULL,
X        0,40,                        /* LeftEdge, TopEdge */
X        21*9,10,                    /* Width, Height */
X        ITEMTEXT | HIGHCOMP | ITEMENABLED,        /* Flags */
X        0,                          /* Mutual Exclude */
X        (APTR)&it_GiveUp,           /* ItemFill */
X        NULL,                       /* SelectFill */
X        0,                          /* Command    */
X        NULL,                       /* Subitem */
X        0,                          /* NextSelect */
X        };
X
Xstruct IntuiText it_3Level = {
X        0,1,        /* frontpen, backpen */
X        JAM1,       /* drawmode */
X        1,1,        /* leftedge, topedge */
X        &font,       /* TextAttr * ITextFont */
X        (UBYTE *)"New 3-Level Maze",  /* IText */
X        NULL,       /* NextText */
X        };
Xstruct MenuItem mi_3Level = {
X        (struct MenuItem *) &mi_GiveUp,
X        0,30,                        /* LeftEdge, TopEdge */
X        21*9,10,                    /* Width, Height */
X        ITEMTEXT | HIGHCOMP | ITEMENABLED,        /* Flags */
X        0,                          /* Mutual Exclude */
X        (APTR)&it_3Level,           /* ItemFill */
X        NULL,                       /* SelectFill */
X        0,                          /* Command    */
X        NULL,                       /* Subitem */
X        0,                          /* NextSelect */
X        };
X
Xstruct IntuiText it_2Level = {
X        0,1,        /* frontpen, backpen */
X        JAM1,       /* drawmode */
X        1,1,        /* leftedge, topedge */
X        &font,       /* TextAttr * ITextFont */
X        (UBYTE *)"New 2-Level Maze",  /* IText */
X        NULL,       /* NextText */
X        };
Xstruct MenuItem mi_2Level = {
X        (struct MenuItem *) &mi_3Level,
X        0,20,                      /* LeftEdge, TopEdge */
X        21*9,10,                    /* Width, Height */
X        ITEMTEXT | HIGHCOMP | ITEMENABLED,        /* Flags */
X        0,                          /* Mutual Exclude */
X        (APTR)&it_2Level,           /* ItemFill */
X        NULL,                       /* SelectFill */
X        0,                          /* Command    */
X        NULL,                       /* Subitem */
X        0,                          /* NextSelect */
X        };
Xstruct IntuiText it_1Level = {
X        0,1,        /* frontpen, backpen */
X        JAM1,       /* drawmode */
X        1,1,        /* leftedge, topedge */
X        &font,       /* TextAttr * ITextFont */
X        (UBYTE *)"New 1-Level Maze",  /* IText */
X        NULL,       /* NextText */
X        };
Xstruct MenuItem mi_1Level = {
X        (struct MenuItem *)&mi_2Level,
X        0,10,                      /* LeftEdge, TopEdge */
X        21*9,10,                    /* Width, Height */
X        ITEMTEXT | HIGHCOMP | ITEMENABLED,        /* Flags */
X        0,                          /* Mutual Exclude */
X        (APTR)&it_1Level,            /* ItemFill */
X        NULL,                       /* SelectFill */
X        0,                          /* Command    */
X        NULL,                       /* Subitem */
X        0,                          /* NextSelect */
X        };
X
Xstruct IntuiText it_About = {
X        0,1,        /* frontpen, backpen */
X        JAM1,       /* drawmode */
X        1,1,        /* leftedge, topedge */
X        &font,       /* TextAttr * ITextFont */
X        (UBYTE *)"About TML's AmigaMaze",  /* IText */
X        NULL,      /* NextText */
X        };
Xstruct MenuItem mi_About = {
X        (struct MenuItem *) &mi_1Level,
X        0,0,                      /* LeftEdge, TopEdge */
X        21*9,10,                    /* Width, Height */
X        ITEMTEXT | HIGHCOMP | ITEMENABLED,        /* Flags */
X        0,                          /* Mutual Exclude */
X        (APTR)&it_About,            /* ItemFill */
X        NULL,                       /* SelectFill */
X        0,                          /* Command    */
X        NULL,                       /* Subitem */
X        0,                         /* NextSelect */
X        };
Xstruct Menu menu = {
X        (struct Menu *) NULL,    /* NEXT menu */
X        0, 0, 12*9, 0,           /* LeftEdge, TopEdge, Width, Height */
X        MENUENABLED,             /* Flags */
X        (BYTE *) "Maze Control", /* MenuName */
X        (struct MenuItem *)&mi_About,            /* First item */
X        0,0,0,0,                /* JazzX,JazzY, BeatX, BeatY */
X        };
X
Xstruct Window *window;
X
X/* BEWARE: NOWHERE has a dual nature, being used as a doesn't-go-anywhere
X   indicator, and also as an invalid level marker!!!   */
X#define NOWHERE -1
X#define SOUTH    0
X#define EAST     1
X#define WEST     2
X#define NORTH    3
X
X#define SOLVED   -3
X
X#define DIRECTIONS 4
X#define MAXLEVELS  3
X#define BOARDMAXX 36
X#define BOARDMAXY 29
X/*** the following are "inpath" stata. (see struct square) *******/
X#define NOTTRAVERSED  1
X#define EDGE          2
X#define LASTPIECE     3 + 32
X#define FIRSTPIECE    3 + 64
X#define CURPIECE      3 + 96
X#define TRAVERSED     3
X
X#define MIDCMP1 CLOSEWINDOW|MOUSEMOVE|MOUSEBUTTONS|MENUPICK|MENUVERIFY
X#define MIDCMP2 REQCLEAR
X#define MIDCMP3 CLOSEWINDOW
X
Xextern ULONG RangeRand();
Xextern int about();
Xextern int cycle();
X
Xtypedef struct {
X       int conlev[ DIRECTIONS ]; /** level connected to in each dir. **/
X       int inpath;  /** Also the color this should be drawn in.  **/
X       int compass; /** Which direction to go to get home from here **/
X       } square;
X
Xtypedef square BOARD[ BOARDMAXX+1 ][ BOARDMAXY+1 ][ MAXLEVELS ];
X
XBOARD board;
X
Xstruct RastPort *rp;
X
Xint StartX, StartY, StartLevel;
Xint EndX,   EndY,   EndLevel;
X
Xint CurX,   CurY,   CurLevel;
Xint NewX,   NewY,   NewLevel;
Xint MouseX, MouseY;
Xint MinLevel, MaxLevel;
Xint BoardMaxX = BOARDMAXX;
Xint BoardMaxY = BOARDMAXY;
Xint SquareXsize = 34;
Xint SquareYsize = 18;
X
X/* We need to have some Fill patterns for various places.  Here goes... */
XUSHORT Pat_Normal[] = {  /** the normal filled pattern **/
X       0xffff,  /* plane 1 pattern */
X       0xffff,
X       0xffff,  /* plane 2 pattern */
X       0xffff  };
X
XUSHORT Pat_P1[] = {  /** first dithered filled pattern **/
X       0x5555,  /* plane 1 pattern */
X       0xaaaa,
X       0xffff,  /* plane 2 pattern */
X       0xffff  };
X
XUSHORT Pat_P2[] = {  /** second dithered filled pattern **/
X       0xffff,  /* plane 1 pattern */
X       0xffff,
X       0x5555,  /* plane 2 pattern */
X       0xaaaa   };
X
XsetHint(ShowHint)
Xint ShowHint;
X{
X    char *s;
X    int  oldBPen;
X
X    if (ShowHint) {
X       switch ( board[CurX][CurY][CurLevel].compass) {
X          case NORTH :   s = " HINT: Go North!                "; break;
X          case SOUTH :   s = " HINT: Go South!                "; break;
X          case EAST  :   s = " HINT: Go East!                 "; break;
X          case WEST  :   s = " HINT: Go West!                 "; break;
X          case SOLVED:   s = " CONGRATULATIONS!               "; break;
X          default    :   s = " Hmm.  I don't know.            "; break;
X          }
X       }
X      else {
X       s = " (Press Left Button for a hint.)";
X       }
X    Move(rp, 20L, 180L);
X    SetAPen(rp, 1L);
X    oldBPen = rp -> BgPen;
X    SetBPen(rp, 0L);
X    SetDrMd(rp, (LONG)JAM2);
X    Text(rp, s, 32L);
X    SetBPen(rp, (LONG)oldBPen);
X    }
X
Xshowside(ax,ay, bx,by, cx,cy, dx,dy, color)
XLONG ax,ay, bx,by, cx,cy, dx,dy, color;
X{
X    SetAPen(  tmpRP, color);   /* The shape isn't allways a rect., so */
X    SetOPen(  tmpRP, color);   /*  we can't use RectFill() here...  */
X    BNDRYOFF( tmpRP);          /* Boundaries look bad w/ patterns...*/
X    switch (color) {
X       case CURPIECE     :
X       case TRAVERSED    : SetAfPt( tmpRP, Pat_P2,-1L); break;
X       case LASTPIECE    : SetAfPt( tmpRP, Pat_P1,-1L); break;
X       case NOTTRAVERSED :
X       case FIRSTPIECE   :
X       default           : SetAfPt( tmpRP, Pat_Normal,-1L); break;
X       }
X
X    AreaMove( tmpRP, ax,ay);
X    AreaDraw( tmpRP, bx,by);
X    AreaDraw( tmpRP, cx,cy);
X    AreaDraw( tmpRP, dx,dy);
X    AreaEnd(  tmpRP);
X    SetAPen(  tmpRP, (LONG)EDGE);
X    Move(     tmpRP, ax,  ay);
X    Draw(     tmpRP, bx,  by);
X    Draw(     tmpRP, bx+1,by);
X    Draw(     tmpRP, ax+1,ay);
X    Move(     tmpRP, cx,  cy);
X    Draw(     tmpRP, dx,  dy);
X    Draw(     tmpRP, dx+1,dy);
X    Draw(     tmpRP, cx+1,cy);
X    }
X
Xputedge(ax,ay,bx,by)
XLONG ax,ay,bx,by;
X{
X    SetAPen(tmpRP,(LONG)EDGE);
X    Move(tmpRP,ax,  ay);
X    Draw(tmpRP,bx,  by);
X    Draw(tmpRP,bx+1,by);
X    Draw(tmpRP,ax+1,ay);
X    }
X
XLONG renderColor(x, y, z, x1, y1, z1)
Xint x, y, z, x1, y1, z1;
X{   int color;
X    color = board[x][y][z].inpath;
X    if (!(z == MaxLevel-1 && (color == FIRSTPIECE || color == LASTPIECE)))
X       if ((color == NOTTRAVERSED) ||
X           (board[x1][y1][z1].inpath == NOTTRAVERSED))
X           color = NOTTRAVERSED;
X    return((LONG)color);
X    }
X
X#define XDIF 6
X#define YDIF 3
X
Xrender(x,y)
Xint x, y;
X{
X   LONG ax,ay, bx,by, cx,cy, dx,dy, color;
X   int level, Bleft, Btop, deltaX, deltaY, tmpL;
X   int left, right, bottom, top;
X
X   /* clear the temporary bitmap */
X   SetAPen( tmpRP, 0L);
X   SetBPen( tmpRP, 0L);
X   RectFill( tmpRP, 0L, 0L, (LONG)SquareXsize, (LONG)SquareYsize );
X
X   Bleft  =  4 + (x - 1) * SquareXsize;
X   Btop   = 11 + (y - 1) * SquareYsize;
X
X   left   = 0;
X   right  = SquareXsize - 1;
X   top    = 0;
X   bottom = SquareYsize - 1;
X
X   for (level=MinLevel; level<MaxLevel; level++) {
X       if (references(x, y, level) == 0)
X          continue; /* This level doesn't go anywhere. */
X
X       deltaY = YDIF * level  + 1;
X       deltaX = XDIF * level  + 1;
X
X       /**** Fill in the middle part first ****/
X       ax = right - deltaX;         ay = top + deltaY;
X       bx = left  + deltaX;         by = ay;
X       cx = bx;                     cy = bottom - deltaY;
X       dx = ax;                     dy = cy;
X       color = board[x][y][level].inpath;
X       showside(ax,ay,bx,by,cx,cy,dx,dy,color);
X
X       /**** Do the NORTH side of this level first ****/
X       ax = right-deltaX;      ay = top + deltaY;
X       bx = ax;                by = top;
X       cx = left +deltaX;      cy = by;
X       dx = cx;                dy = ay;
X       tmpL  = board[x][y][level].conlev[NORTH];
X       if ( tmpL == NOWHERE) {
X            putedge(ax,ay,dx,dy);
X            goto DrawWest;
X            }
X       color = renderColor(x,y,level,x,y-1,tmpL);
X       if (tmpL != level && level == 1) {
X            bx = bx - XDIF*(tmpL - 1);
X            cx = cx + XDIF*(tmpL - 1);
X            }
X       showside(ax,ay,bx,by,cx,cy,dx,dy,color);
X
X       /**** Do the WEST side of this level next ****/
X       DrawWest:
X       ax = left + deltaX;      ay = top + deltaY;
X       bx = left;               by = ay;
X       cx = bx;                 cy = bottom - deltaY;
X       dx = ax;                 dy = cy;
X       tmpL  = board[x][y][level].conlev[WEST];
X       if ( tmpL == NOWHERE) {
X            putedge(ax,ay,dx,dy);
X            goto DrawSouth;
X            }
X       color = renderColor(x,y,level,x-1,y,tmpL);
X       if (tmpL != level && level == 1) {
X            by = by + YDIF*(tmpL - 1);
X            cy = cy - YDIF*(tmpL - 1);
X            }
X       showside(ax,ay,bx,by,cx,cy,dx,dy,color);
X
X       /**** Do the SOUTH side of this level next ****/
X       DrawSouth:
X       ax = left + deltaX;      ay = bottom - deltaY;
X       bx = ax;                 by = bottom;
X       cx = right - deltaX;     cy = by;
X       dx = cx;                 dy = ay;
X       tmpL  = board[x][y][level].conlev[SOUTH];
X       if ( tmpL == NOWHERE) {
X            putedge(ax,ay,dx,dy);
X            goto DrawEast;
X            }
X       color = renderColor(x,y,level,x,y+1,tmpL);
X       if (tmpL != level && level == 1) {
X            bx = bx + XDIF*(tmpL-1);
X            cx = cx - XDIF*(tmpL-1);
X            }
X       showside(ax,ay,bx,by,cx,cy,dx,dy,color);
X
X       /**** Do the EAST side of this level last ****/
X       DrawEast:
X       ax = right - deltaX;     ay = bottom - deltaY;
X       bx = right;              by = ay;
X       cx = bx;                 cy = top + deltaY;
X       dx = ax;                 dy = cy;
X       tmpL  = board[x][y][level].conlev[EAST];
X       if ( tmpL == NOWHERE) {
X            putedge(ax,ay,dx,dy);
X            goto DrawComplete;
X            }
X       color = renderColor(x,y,level,x+1,y,tmpL);
X       if (tmpL != level && level == 1) {
X            by = by - YDIF*(tmpL - 1);
X            cy = cy + YDIF*(tmpL - 1);
X            }
X       showside(ax,ay,bx,by,cx,cy,dx,dy,color);
X       DrawComplete:;
X       }
X   /* now copy temporary bitmap into window */
X
X   BltBitMapRastPort(&tmpBM,0L,0L, rp,(LONG)Bleft,(LONG)Btop,
X            (LONG)SquareXsize,(LONG)SquareYsize, (LONG)0x0c0);
X   }  /* end of render() */
X
X
X/* references() returns the number connections from a given square. */
Xint references(x, y, level)
Xint x, y, level;
X{ int i, refs;
X    refs = 0;
X    for (i=0; i < DIRECTIONS; i++)
X        if (board[x][y][level].conlev[i] != NOWHERE)
X            refs++;
X    return(refs);
X    }
X
X/* linkable() returns true if we can connect the two indicated squares. */
X/* NOTE: We don't allow connecting to the second square if it */
X/* is already part of the maze.  This test if the first if stmt.*/
X/* The second test if more subtle.  The problem being tested for is shown in */
X/* the following diagram.  This is an edge-on view of the board: */
X/*   a __    __ d   */
X/*       \  /       */
X/*         /        */
X/*        /         */
X/*   c __/  \__ b   */
X/* If c and d are connected, I can't connect a to b because the paths would */
X/* intersect.  The way the test is written, it will work regardless of whether */
X/* the new path is going up, down, or level. */
X
Xint linkable(x1,y1,level1,dir1, x2,y2, level2, dir2)
Xint x1,y1,level1,dir1, x2,y2,level2;
X{
X   int tmp;
X   if (references(x2,y2,level2)) return(0);
X   if (board[x1][y1][level2].conlev[dir1] == level1) return(0);
X   return(-1);
X   }
X
X/* Returns the other Direction, or NOWHERE if an invalid direction is passed. */
Xint otherDir(nd)
Xint nd;
X{ switch (nd) {
X    case NORTH : return(SOUTH); break;
X    case SOUTH : return(NORTH); break;
X    case EAST  : return(WEST) ; break;
X    case WEST  : return(EAST) ; break;
X    }
X  return(NOWHERE);
X  }
X
X
X/* makepathlist() returns the number of directions we can go from here w/o */
X/*  backtracking -- i.e., not counting the way we got here.  These */
X/*  "uncharted" routes are characterized by .compus==NOWHERE.  The list of */
X/*  directions is placed in pl[]. */
X
Xint makepathlist(x,y,z,pl)
Xint x, y, z, pl[];
X{   int di, le, paths;
X    paths = 0;
X    for (di=0; di<DIRECTIONS; di++) {
X        pl[paths] = di;
X        le = board[x][y][z].conlev[di];
X        if (le != NOWHERE)
X           switch (di) {
X              case NORTH   :  if (board[x][y-1][le].compass == NOWHERE)
X                                 paths++;
X                              break;
X              case SOUTH   :  if (board[x][y+1][le].compass == NOWHERE)
X                                 paths++;
X                              break;
X              case EAST    :  if (board[x+1][y][le].compass == NOWHERE)
X                                 paths++;
X                              break;
X              case WEST    :  if (board[x-1][y][le].compass == NOWHERE)
X                                 paths++;
X                              break;
X              case NOWHERE :  break;
X              }
X        }
X    return(paths);
X    }
X
Xint topscore;
X
X/* buildreturnmap() is a recursive routine which starts the end of a path on */
X/* our tree-structured maze and traverses up to an intersection or dead end. */
X/* When we hit a dead end, we just return, but when we hit an intersection, we */
X/* call buildreturnmap() again, once for each path going off from the */
X/* intersection, except for the one got there on.  We keep a score for how far */
X/* we are from the first square.  One point per square, plus 5 times the */
X/* number of paths leading off from each intersection.  We keep a topscore to */
X/* find out which square is farthest (in this modified sense) from our */
X/* starting square.  This helps to ensure that we get a reasonably difficult */
X/* maze to solve. */
X/*   We also record the direction to the end of the maze in each square.  This */
X/* information is used by the hint facility. */
X
Xbuildreturnmap(x,y,z,score)
Xint x, y, z, score;
X{   int pathlist[DIRECTIONS], paths, i, le;
X
X    while ( (paths = makepathlist(x,y,z,pathlist)) == 1) {
X          z = board[x][y][z].conlev[pathlist[0]];
X          switch (pathlist[0]) {
X            case NORTH : y--; break;
X            case SOUTH : y++; break;
X            case EAST  : x++; break;
X            case WEST  : x--; break;
X            }
X          board[x][y][z].compass = otherDir(pathlist[0]);
X          /* score++; */
X          }
X
X    if (paths == 0) {   /* We are at the end of a path... */
X        if (score >= topscore) {
X            topscore = score;
X            StartX = x;
X            StartY = y;
X            StartLevel = z;
X            }
X        return;
X        }
X
X    /* if we got here, we are not at the end of a path.   paths > 1 */
X    score = score + paths;
X
X    for (i=0; i<paths; i++) {
X        le = board[x][y][z].conlev[pathlist[i]];
X        switch (pathlist[i]) {
X           case NORTH   : board[x][y-1][le].compass = SOUTH;
X                          buildreturnmap(x,y-1,le,score);     break;
X
X           case SOUTH   : board[x][y+1][le].compass = NORTH;
X                          buildreturnmap(x,y+1,le,score);     break;
X
X           case EAST    : board[x+1][y][le].compass = WEST;
X                          buildreturnmap(x+1,y,le,score);     break;
X
X           case WEST    : board[x-1][y][le].compass = EAST;
X                          buildreturnmap(x-1,y,le,score);     break;
X           }
X        }
X    }
X
X#define MAXENDS 120
X#define FREEEND -1
X#define LASTEND -1
Xtypedef struct {
X        int x,y,z;    /* board coordinates. x=FREEEND means this one is free */
X        int prevdir;  /* The direction we went to get here. */
X                      /*    In picking what direction to go, we are biased */
X                      /*    toward this direction.  This gives paths */
X                      /*    with several straight sections -- keeps one path from */
X                      /*    knotting up one part of the board. */
X        int nextfree; /* next unused end, LASTEND means no more  */
X        } endtype;
X
Xendtype ends[MAXENDS];
Xint     firstfree;
Xint     MaxEnds = MAXENDS;
X
Xinitends()
X{   int i;
X
X    for (i=0; i<MaxEnds; i++) {
X        ends[i].x = -1;
X        ends[i].y = -1;
X        ends[i].z = -1;
X        ends[i].nextfree = i - 1;
X        }
X    firstfree = MaxEnds - 1;
X    /* NOTE that ends[0].nextfree == -1 == LASTEND.  If that define ever */
X    /* changes, we will have to include the statement: */
X    /* ends[0].nextfree = LASTEND; */
X    }
X
X/* IF you want to play around with the parameters that effect the way
X   boards are built, you will want to try different combinations of
X   "tries", "length", and global MaxEnds. */
X
Xint extendend(curend,tries,length)
Xint curend, tries, length;
X{
X    int x, y, level;
X    int nd,od, nx, ny, nl, i, moves, link;
X
X    moves = 0;
X
X    x     = ends[curend].x;
X    y     = ends[curend].y;
X    level = ends[curend].z;
X    nd    = ends[curend].prevdir;
X
X    /* try up to i times to add a random square */
X    for (i=0; i<tries && moves < length; i++) {
X        do {         /*  try not to go out of bounds */
X             nd = ((RangeRand(10L) < 4) ? (int)RangeRand((LONG)DIRECTIONS) : nd);
X             } while ((nd == NORTH && y == 1)           ||
X                      (nd == WEST  && x == 1)           ||
X                      (nd == SOUTH && y == BoardMaxY-1) ||
X                      (nd == EAST  && x == BoardMaxX-1)     );
X        /* Now that we've got a direction, see that we don't already go that way */
X        if (board[x][y][level].conlev[nd] != NOWHERE)
X            continue;
X        nx = x;  ny = y;
X        switch (nd) {                /* work out the new x and y */
X            case NORTH : ny = y - 1; break;
X            case SOUTH : ny = y + 1; break;
X            case EAST  : nx = x + 1; break;
X            case WEST  : nx = x - 1; break;
X            }
X        od = otherDir(nd);
X        nl = level;
X
X        /** get some level we can go onto from here **/
X        if (!(link=linkable(x, y, level, nd, nx, ny, nl, od))) {   /* stay on the same level if we can... */
X           if (level > MinLevel) {    /* can't stay on this level so go down */
X               nl = level - 1;
X               link = linkable(x, y, level, nd, nx, ny, nl, od); /* if we can't go down, go up */
X               }
X           if (!link && (level < MaxLevel - 1)) {
X               nl = level + 1;   /* can't go down or level, so try up */
X               link = linkable(x, y, level, nd, nx, ny, nl, od);
X               }
X           }
X
X        if (link) {
X            board[x ][y ][level].conlev[nd] = nl;
X            board[nx][ny][nl   ].conlev[od] = level;
X            render( x, y);
X            render(nx,ny);
X            moves++;
X            /* sometimes fork, putting our old coordinates in a free end slot. */
X            if (firstfree != LASTEND) {  /* make sure there IS a free end slot */
X                if (RangeRand(10L) < 4) {
X                   ends[firstfree].x = x;
X                   ends[firstfree].y = y;
X                   ends[firstfree].z = level;
X                   ends[firstfree].prevdir = nd;
X                   firstfree = ends[firstfree].nextfree;
X                   }
X                }
X            ends[curend].x = x     = nx;
X            ends[curend].y = y     = ny;
X            ends[curend].z = level = nl;
X            }
X        }
X    /* if we got this far and made no moves, we are probably on dead end and */
X    /* should put this ends[] on the free list. */
X    if (moves == 0) {
X          ends[curend].x = FREEEND;
X          ends[curend].nextfree = firstfree;
X          firstfree = curend;
X          }
X    return(moves);
X    }
Xint xties, xlength;
Xint makepath()
X{   int i, endsfound, totalsquares;
X
X    initends();   /* This sets the table of path ends to all zeros */
X
X    /*   ends[] is a list of the ends of paths which we can add more paths */
X    /*   onto.  Note that they don't really have to be an end; they can be */
X    /*   in the middle of a path as well.   Not all of them are in use as */
X    /*   an end all the time.  Some are in a linked list of "free" ends, */
X    /*   available for use if we want to add an end.  Free (unused) array */
X    /*   elements are marked by a .x == FREEEND.  Ends get taken out of active */
X    /*   service and put on the free list when the path generator "extendend()" */
X    /*   fails to extend the path from that end.  When no active ends remain, */
X    /*   maze generation terminates. */
X
X    /*  p.s.: I don't particularly care for the mazes that are generated by */
X    /*  this method, nor am I particularly fond of the method.  I would like */
X    /*  to hear of other strategies for maze generation. */
X
X
X    ends[firstfree].x = 1 + RangeRand((LONG)BoardMaxX - 1);
X    ends[firstfree].y = 1 + RangeRand((LONG)BoardMaxY - 1);
X    ends[firstfree].z = 0;
X    ends[firstfree].prevdir = RangeRand((LONG)DIRECTIONS);
X    firstfree = ends[firstfree].nextfree;
X
X    totalsquares = 0;
X    do {
X         endsfound = 0;
X         for (i=0; i< MaxEnds; i++) {
X             if (ends[i].x != FREEEND) {
X                    endsfound++;
X                    totalsquares += extendend(i,xties,xlength);
X                    }
X             }
X         } while (endsfound);
X    return( totalsquares );
X    }
X
Xpickends()
X{   int x, y, z, i;
X
X    /* Find then end of a path on the bottom level. */
X    do {
X        StartX = 1 + RangeRand( (LONG) BoardMaxX-1L );
X        StartY = 1 + RangeRand( (LONG) BoardMaxY-1L );
X        StartLevel =  MinLevel;
X        } while (references( StartX, StartY, StartLevel) != 1);
X
X    /* The reason for doing this 4 times is to make the ends as far apart as */
X    /* possible.  If our first choice is close to the top of the tree, it */
X    /* can't be very far away from every leaf node.  The way this works is: */
X    /*     1  Find a leaf node. */
X    /*     2  Find the leaf farthest from the one found in step 1. */
X    /*     3  Find the leaf farthest from the one found in step 2. ... */
X    /* Eventually you should end up with two good choices for the ends. */
X
X    for (i=0; i<4; i++) {
X        for (x=1; x<BoardMaxX; x++)
X            for (y=1; y<BoardMaxY; y++)
X                for (z=MinLevel; z<MaxLevel; z++)
X                    board[x][y][z].compass = NOWHERE;
X
X        EndX = StartX;   EndY = StartY;    EndLevel = StartLevel;
X        board[ EndX ][ EndY ][ EndLevel ].compass = SOLVED;
X        topscore = 0;
X        buildreturnmap(EndX, EndY, EndLevel, 0);
X        }
X
X    board[ StartX ][ StartY ][ StartLevel ].inpath = FIRSTPIECE;
X    board[ EndX   ][ EndY   ][ EndLevel   ].inpath = LASTPIECE;
X    CurX     = StartX;
X    CurY     = StartY;
X    CurLevel = StartLevel;
X    NewX     = CurX;
X    NewY     = CurY;
X    NewLevel = CurLevel;
X    render( StartX, StartY);
X    render( EndX,   EndY);
X    }
X
Xinit1( l )
Xint l;
X{
X  int i, x, y, level, dir;
X  static int Xsize[] = { 54, 16, 24, 34 }; /* Square widths  */
X  static int Xsqrs[] = { 10, 34, 22, 16 }; /* No. of squares */
X
X  static int Ysize[] = { 26, 10, 14, 18 }; /* Square heights */
X  static int Ysqrs[] = {  6, 16, 11,  9 }; /* No. of squares */
X
X     /* Reset the entire board, including a strip of squares around */
X     /* the edges that we never go into. */
X  for(x=0; x <= BOARDMAXX; x++)
X     for(y=0; y <= BOARDMAXY; y++)
X        for(level=0; level < MAXLEVELS; level++) {
X           board[x][y][level].inpath   =  NOTTRAVERSED;
X           board[x][y][level].compass  =  NOWHERE;
X           for(dir=0; dir < DIRECTIONS; dir++)
X              board[x][y][level].conlev[dir] =  NOWHERE;
X           }
X
X  SetAPen( rp, 0L);
X  SetBPen( rp, 0L);
X  RectFill( rp, 4L, 11L, (LONG)windowW-4, (LONG)windowH-2);
X
X  MaxLevel = l;   /* l==0 is a special-case first-time super-easy 1-level */
X                  /* maze.  It generates fast so we can get to the menus. */
X
X  BoardMaxX   = Xsqrs[ MaxLevel ] + 1;
X  SquareXsize = Xsize[ MaxLevel ];
X  BoardMaxY   = Ysqrs[ MaxLevel ] + 1;
X  SquareYsize = Ysize[ MaxLevel ];
X
X  if (MaxLevel == 0)
X     MaxLevel = 1;
X
X  makepath();
X
X  pickends();
X  setHint( (int)FALSE );
X  }
X
Xint autosolve()
X{   int newDir;
X    square *oldSq, *newSq;
X
X    while ( (newDir = board[CurX][CurY][CurLevel].compass) != SOLVED ) {
X          NewX = CurX;
X          NewY = CurY;
X          NewLevel = board[CurX][CurY][CurLevel].conlev[newDir];
X          switch (newDir) {
X              case NORTH : NewY--; break;
X              case SOUTH : NewY++; break;
X              case EAST  : NewX++; break;
X              case WEST  : NewX--; break;
X              }
X
X          oldSq = &board[ CurX ][ CurY ][ CurLevel];
X          newSq = &board[ NewX ][ NewY ][ NewLevel];
X
X          oldSq->inpath = TRAVERSED;
X
X          switch (newSq->inpath) {
X              case TRAVERSED  :
X              case FIRSTPIECE : /* We must have backed up to get here, so...*/
X                          oldSq->inpath = NOTTRAVERSED; break;
X              default         : ;
X              }
X
X          /* set the inpath flag of the new square in any case */
X          newSq->inpath = CURPIECE;
X
X          /* Also, just in case we backed up to the starting square */
X          /*   or from the ending square.... */
X          board[StartX][StartY][StartLevel].inpath = FIRSTPIECE;
X          board[EndX  ][EndY  ][EndLevel  ].inpath = LASTPIECE;
X
X          /* Now draw both squares */
X          render(CurX,CurY);
X          render(NewX,NewY);
X
X          /* Now new becomes current */
X          CurX = NewX;
X          CurY = NewY;
X          CurLevel = NewLevel;
X
X          }
X    }
X
X
X
Xint mousewatch()
X{   static int canmove = FALSE;
X    int x, y, newDir;
X
X    x = ((MouseX) -  4)/SquareXsize + 1;
X    y = ((MouseY) - 11)/SquareYsize + 1;
X
X    x = x * SIGN(MouseX);
X    y = y * SIGN(MouseY);
X
X    if (x == CurX && y == CurY) {
X        canmove = TRUE;
X        }
X
X    newDir = NOWHERE;
X    if (x == CurX) {
X         if (y == CurY + 1 && y < BoardMaxY)
X               newDir = SOUTH;
X            else if (y == CurY - 1 && y > 0)
X                      newDir = NORTH;
X         }
X      else
X         if (y == CurY) {
X               if (x == CurX + 1 && x < BoardMaxX)
X                     newDir = EAST;
X                  else if (x == CurX - 1 && x > 0)
X                           newDir = WEST;
X             }
X
X    if (newDir == NOWHERE ) {
X         canmove = FALSE;
X         return(NOWHERE);
X         }
X
X    NewLevel = board[CurX][CurY][CurLevel].conlev[newDir];
X
X    if (NewLevel == NOWHERE) {
X       canmove = FALSE;
X       return(NOWHERE);
X       }
X    NewX = x;
X    NewY = y;
X    return(newDir);
X    }
X
Xint trymove() /* returns TRUE if we won, FALSE if we didn't win. */
X{   int newDir;
X    square *oldSq, *newSq;
X
X    newDir = mousewatch();
X    if (newDir == NOWHERE)
X       return(board[CurX][CurY][CurLevel].compass == SOLVED);
X
X    oldSq = &board[ CurX ][ CurY ][ CurLevel];
X    newSq = &board[ NewX ][ NewY ][ NewLevel];
X
X    oldSq->inpath = TRAVERSED;
X    switch (newSq->inpath) {
X        case TRAVERSED  :
X        case FIRSTPIECE : /* We must have backed up to get here, so...*/
X                          oldSq->inpath = NOTTRAVERSED; break;
X        default         : ;
X        }
X
X    /* set the inpath flag of the new square in any case */
X    newSq->inpath = CURPIECE;
X
X    /* Also, just in case we backed up from the starting square */
X    /*   or the ending square.... */
X    board[StartX][StartY][StartLevel].inpath = FIRSTPIECE;
X    board[EndX  ][EndY  ][EndLevel  ].inpath = LASTPIECE;
X
X    /* Now draw both squares */
X    render(CurX,CurY);
X    render(NewX,NewY);
X
X    /* Now new becomes current */
X    CurX = NewX;
X    CurY = NewY;
X    CurLevel = NewLevel;
X
X    /* ?did we win? */
X
X    setHint((int)(newSq->compass == SOLVED));
X
X    if (newSq->compass == SOLVED) {
X          cycle( 3 );
X          return( (int)TRUE );
X          }
X    return( (int)FALSE);
X    }
X
XHandleMenu(menucode)
XUSHORT menucode;
X{
X    ModifyIDCMP( window, (ULONG) MIDCMP2 );
X
X    switch ( ITEMNUM( menucode) ) {
X        case 0 : about()   ;  break;
X        case 1 : init1( 1 );  break;
X        case 2 : init1( 2 );  break;
X        case 3 : init1( 3 );  break;
X        case 4 : autosolve(); break;
X        }
X
X    ModifyIDCMP( window, (ULONG) MIDCMP1 );
X    }
X
X
XEventLoop()
X{
X  struct IntuiMessage *mesg;
X  ULONG  class, code, mousemoved, closewindow, menupick;
X  USHORT menucode;
X
X  closewindow = FALSE;
X  ModifyIDCMP( window, (ULONG) MIDCMP1 );
X
X  do {
X       mousemoved = FALSE;
X       menupick   = FALSE;
X
X       Wait( (LONG) 1 << window -> UserPort -> mp_SigBit);
X
X       while ((mesg=(struct IntuiMessage *)GetMsg(window->UserPort))) {
X             class = mesg->Class;
X             code  = mesg->Code;
X             MouseX = mesg->MouseX;
X             MouseY = mesg->MouseY;
X             ReplyMsg(mesg);
X             if (class == MOUSEMOVE) mousemoved = TRUE;
X             if (class == CLOSEWINDOW) closewindow = TRUE;
X             if (class == MOUSEBUTTONS && code == SELECTDOWN)
X                setHint( (int) TRUE);
X             if (class == MENUPICK) {
X                menupick = TRUE;
X                menucode = code;
X                }
X             }
X       if (mousemoved) trymove();
X       if (menupick)   HandleMenu(menucode);
X       } while (closewindow == FALSE);
X  }
X
Xstruct TextFont *textfont = NULL;
X
Xopenstuff()
X{   ULONG Seconds, Micros;
X
X    IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L);
X    if (IntuitionBase == NULL) {closestuff(); exit(0);}
X
X    GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L);
X    if (GfxBase == NULL) {closestuff(); exit(0); }
X
X    /* My <functions.h> shows OpenFont() returns a *Font. */
X    /* I think that is an error! */
X
X    textfont = (struct TextFont *)OpenFont( &font );
X    if (textfont==NULL) { closestuff(); exit(0); }
X
X    if (( window=(struct Window *)OpenWindow(&nw))==NULL) {
X       closestuff();
X       exit(0);
X       }
X    if (SetFont(window->RPort,textfont)==0) { closestuff(); exit(0); }
X
X    SetWindowTitles(window,(UBYTE *)" TML's AmigaMaze     ver. 1.2 ",
X            (UBYTE *)"TML's AmigaMaze       First distributed on JUMPDISK.");
X
X    SetMenuStrip( window, &menu);
X
X    /*  This next bit is a cludge because I can't seem to get */
X    /*                 extern ULONG RangeSeed; */
X    /*      to work.  Anyone got any ideas? */
X    /*  LATER: It turns out that the RangeSeed is not public */
X    /*      in the Manx sources.  Hope they fix this someday. */
X    CurrentTime(&Seconds,&Micros);
X    Micros = Micros & (ULONG) 0x0fff;
X    for (Seconds=0; Seconds < Micros; Seconds++)
X         RangeRand(4L);
X    }
X
X
Xclosestuff()
X{   int i;
X    for(i=0; i<2; i++) {
X       if (tmpBM.Planes[i])
X            FreeRaster(tmpBM.Planes[i],tmpBMxy,tmpBMxy);
X       }
X    if (window) {
X        ClearMenuStrip( window );
X        CloseWindow(window);
X        }
X    if (textfont) CloseFont(textfont);
X    if (GfxBase) CloseLibrary(GfxBase);
X    if (IntuitionBase) CloseLibrary(IntuitionBase);
X    }
X
Xmain(/*argc,argv*/)
X/* int argc; */
X/* char *argv[]; */
X{   UWORD areabuffer[250], areabuffer2[250];
X    struct TmpRas   tmpras,   tmprasB;
X    struct AreaInfo areainfo, areainfo2;
X    PLANEPTR plane,planeB;
X    int i;
X
X    /* if (argc > 1) */
X    /*     xties = atoi(argv[1]); */
X    /* if (xties < 1 || xties > 100) */
X        xties = 30;
X
X    /* if (argc > 2) */
X    /*     xlength = atoi(argv[2]); */
X    /* if (xlength < 1 || xlength > 100) */
X        xlength = 9;
X
X    /* if (argc > 3) */
X    /*     MaxEnds = atoi(argv[3]); */
X    /* if (MaxEnds < 2 || MaxEnds > MAXENDS) */
X        MaxEnds = MAXENDS;
X
X    MaxLevel = 1;
X    MinLevel = 0;
X    openstuff();
X    InitBitMap( &tmpBM, 2L, tmpBMxy, tmpBMxy );
X    for (i=0; i<2; i++) {
X         if ((tmpBM.Planes[i] = (PLANEPTR)AllocRaster(tmpBMxy,tmpBMxy))==NULL) {
X             closestuff();
X             exit(0);
X             }
X         }
X    rp = window->RPort;
X    if ((plane = AllocRaster(windowW,windowH))==NULL) {
X        closestuff();
X        exit(0);
X        }
X    if ((planeB = AllocRaster(tmpBMxy,tmpBMxy))==NULL) {
X        FreeRaster(plane, windowW,windowH);
X        closestuff();
X        exit(0);
X        }
X    InitArea(&areainfo, areabuffer, 90L);
X    InitArea(&areainfo2,areabuffer2,90L);
X
X    InitTmpRas(&tmpras, plane, RASSIZE( windowW, windowH));
X    InitTmpRas(&tmprasB,planeB,RASSIZE( tmpBMxy, tmpBMxy));
X
X    rp->AreaInfo    = &areainfo;
X    rp->TmpRas      = &tmpras;
X
X    InitRastPort( tmpRP );
X    if (SetFont(tmpRP,textfont)==0) { closestuff(); exit(0); }
X    tmpRP->BitMap = &tmpBM;
X    tmpRP->AreaInfo = &areainfo2;
X    tmpRP->TmpRas   = &tmprasB;
X
X    init1(0); /* Zero is a special case.  Super simple fast easy maze
X                 so the user can get to the menus w/o waiting so long. */
X    ModifyIDCMP( window, (ULONG) MIDCMP2 );
X    about();
X    EventLoop();
X    FreeRaster(plane, windowW, windowH);
X    FreeRaster(planeB,tmpBMxy, tmpBMxy);
X    closestuff();
X    }
X
X/* Save some code space by stubbing _wb_parse() and _cli_parse(). */
Xvoid _wb_parse()
X{ }
X
Xvoid _cli_parse()
X{ }
X
SHAR_EOF
echo "extracting stdhead.c"
sed 's/^X//' << \SHAR_EOF > stdhead.c
X#include <exec/types.h>
X#include <intuition/intuition.h>
X#include <functions.h>
X#include <graphics/gfxmacros.h>
X#include <graphics/view.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
SHAR_EOF
echo "extracting makefile"
sed 's/^X//' << \SHAR_EOF > makefile
Xstdhead.t: stdhead.c
X    cc  +Hstdhead.t +m stdhead.c
X
Xabout.o: about.c stdhead.t
X    cc -n +Istdhead.t  about.c
X
Xmaze.o: maze.c  stdhead.t
X    cc -n  +Istdhead.t  maze.c
X
Xmaze: maze.o about.o
X     ln -g maze.o about.o  -lc
X
X# maze.l: maze.c about.c
X#      lint >maze.l -iSYS1:include/ -zero -si2 SYS9:manx.c maze.c about.c
X
SHAR_EOF
echo "End of archive 1 (of 1)"
# if you want to concatenate archives, remove anything after this line
exit