Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!ncar!ames!oliveb!sun!swap!page From: page%swap@Sun.COM (Bob Page) Newsgroups: comp.sources.amiga Subject: v89i119: maze - build and solve mazes Message-ID: <103740@sun.Eng.Sun.COM> Date: 9 May 89 00:02:22 GMT Sender: news@sun.Eng.Sun.COM Lines: 1420 Approved: page@sun.com 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 X#include X#include X#include X#include X#include 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 X#include X#include X#include X#include 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= 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 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; xinpath = 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 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 X#include X#include X#include X#include X#include X#include 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