This is MazeView.m in view mode; [Download] [Up]
#import "MazeView.h" #import <stdlib.h> #import <sys/time.h> #import <dpsclient/psops.h> #import <dpsclient/dpsNeXT.h> #import <appkit/Control.h> #import <appkit/nextstd.h> #import <appkit/graphics.h> #import <appkit/Cursor.h> #define FAT 10 extern long random(); extern srandom(int seed); extern void NXBeep(void); extern void PSflushgraphics(void); struct mazecell { BOOL wall, floor, already; }; struct place { short x,y; }; int horiz, vert; struct mazecell *theMaze; int solutionLen, numAllocated, tickie, lowTouch; struct place *theSolution; int spacing, tickPeriod; void drawSolution(int lowlimit) { int k, numOps; BOOL dash; short *data, boundingBox[4]; char *ops; lowlimit--; if (lowlimit < 0) lowlimit = 0; boundingBox[0] = 0; boundingBox[1] = 0; boundingBox[2] = horiz * spacing; boundingBox[3] = vert * spacing; data = malloc((solutionLen - lowlimit + 1) * 2 * sizeof(short)); ops = malloc((solutionLen - lowlimit + 1) * sizeof(char)); data[0] = theSolution[lowlimit].x * spacing; data[1] = (vert - 1 - theSolution[lowlimit].y) * spacing; ops[0] = dps_moveto; numOps = 1; for (k=lowlimit; k<solutionLen; k++) { data[numOps * 2] = theSolution[k].x * spacing; data[numOps * 2 + 1] = (vert - 1 - theSolution[k].y) * spacing; ops[numOps++] = dps_lineto; } DPSDoUserPath(data, numOps * 2, dps_short, ops, numOps, boundingBox, dps_ustroke); free(data); free(ops); } BOOL findSolution(struct place where) { theMaze[where.x + where.y * horiz].already = YES; if (solutionLen < lowTouch) lowTouch = solutionLen; theSolution[solutionLen++] = where; if (++tickie == tickPeriod) { PSsetgray(NX_WHITE); drawSolution(lowTouch); PSflushgraphics(); PSsetgray(NX_BLACK); drawSolution(lowTouch); NXPing(); tickie = 0; lowTouch = 1000000000; } if (solutionLen == numAllocated) { numAllocated += 1000; theSolution = realloc(theSolution, numAllocated * sizeof(struct place)); } if (((where.x == (horiz - 1)) && (where.y == (vert - 1))) || ((theMaze[where.x + where.y * horiz].wall == NO) && (theMaze[(where.x + 1) + where.y * horiz].already == NO) && (findSolution((struct place){where.x + 1, where.y}))) || ((theMaze[where.x + where.y * horiz].floor == NO) && (theMaze[where.x + (where.y + 1) * horiz].already == NO) && (findSolution((struct place){where.x, where.y + 1}))) || ((where.x > 0) && (theMaze[(where.x - 1) + where.y * horiz].wall == NO) && (theMaze[(where.x - 1) + where.y * horiz].already == NO) && (findSolution((struct place){where.x - 1, where.y}))) || ((where.y > 0) && (theMaze[where.x + (where.y - 1) * horiz].floor == NO) && (theMaze[where.x + (where.y - 1) * horiz].already == NO) && (findSolution((struct place){where.x, where.y - 1})))) return YES; else { solutionLen--; return NO; } } void drawSelfGlue(DPSTimedEntry te, double now, void *me) { DPSRemoveTimedEntry(te); [(id)me lockFocus]; [(id)me drawSelf:NULL :0]; [(id)me unlockFocus]; [[(id)me window] flushWindow]; } @implementation MazeView - setRanFactor:anObject { ranFactor = anObject; return self; } + newFrame:(const NXRect *) frameRect { self = [super newFrame:frameRect]; horiz = vert = spacing = 8; theMaze = NULL; theSolution = NULL; tickPeriod = 100; [self newMaze:self]; return self; } - changeSpacing:sender { int oldSpacing; oldSpacing = spacing; spacing = [sender intValue]; horiz = (horiz * oldSpacing) / spacing; vert = (vert * oldSpacing) / spacing; if (horiz < 2) horiz = 2; if (vert < 2) vert = 2; [[self window] sizeWindow:horiz * spacing + FAT :vert * spacing + FAT]; [self newMaze:self]; return self; } - changeTickPeriod:sender { tickPeriod = [sender intValue]; } - drawFloors { int j, k, numInGroup, numOps; BOOL dash; short *data, boundingBox[4]; char *ops; PSmoveto(0, vert * spacing + 1); PSrlineto(horiz * spacing, 0); PSstroke(); boundingBox[0] = bounds.origin.x; boundingBox[2] = bounds.size.width; boundingBox[3] = 1; data = malloc((horiz + 1) * 2 * sizeof(short)); ops = malloc((horiz + 1) * sizeof(char)); for (k=0; k<vert; k++) /* floors */ { data[0] = 0; data[1] = k * spacing + 1; boundingBox[1] = k * spacing + 1; ops[0] = dps_moveto; numOps = 1; j=0; dash = theMaze[(vert - 1 - k) * horiz + j].floor; do { dash = !dash; numInGroup = 0; while ((j<horiz) && (theMaze[(vert - 1 - k) * horiz + j].floor == dash)) {j++; numInGroup++;} data[numOps * 2] = spacing * numInGroup; data[numOps * 2 + 1] = 0; ops[numOps++] = dash ? dps_rlineto : dps_rmoveto; } while (j<horiz); DPSDoUserPath(data, numOps * 2, dps_short, ops, numOps, boundingBox, dps_ustroke); PSflushgraphics(); } free(data); free(ops); } - drawWalls { int j, k, numInGroup, numOps; BOOL dash; short *data, boundingBox[4]; char *ops; PSmoveto(0, 1); PSlineto(0, vert * spacing); PSstroke(); boundingBox[1] = bounds.origin.y; boundingBox[2] = 1; boundingBox[3] = bounds.size.height; data = malloc((vert + 1) * 2 * sizeof(short)); ops = malloc((vert + 1) * sizeof(char)); for (k=0; k<horiz; k++) /* walls */ { boundingBox[0] = (k + 1) * spacing; data[0] = (k + 1) * spacing; data[1] = 1; ops[0] = dps_moveto; numOps = 1; j=vert-1; dash = theMaze[j * horiz + k].wall; do { dash = !dash; numInGroup = 0; while ((j>=0) && (theMaze[j * horiz + k].wall == dash)) {j--; numInGroup++;} data[numOps * 2] = 0; data[numOps * 2 + 1] = spacing * numInGroup; ops[numOps++] = dash ? dps_rlineto : dps_rmoveto; } while (j>=0); DPSDoUserPath(data, numOps * 2, dps_short, ops, numOps, boundingBox, dps_ustroke); PSflushgraphics(); } free(data); free(ops); } - drawMaze { [self drawFloors]; [self drawWalls]; } - drawSelf:(const NXRect *)rects :(int)rectCount { if (theMaze == NULL) return; if (bounds.size.width != horiz * spacing + 2) return; if (bounds.size.height != vert * spacing + 2) return; if (rects != NULL) { DPSAddTimedEntry(0.0, &drawSelfGlue, (void *)self, 1); return self; } PSgsave(); PSsetgray(NX_LTGRAY); PSsetlinewidth(0.15); PSrectfill(0, 0, bounds.size.width, bounds.size.height); PStranslate(0, 1); PSsetgray(NX_DKGRAY); [self drawMaze]; if (spacing > 4) { PStranslate(1, -1); PSsetgray(NX_WHITE); [self drawMaze]; } PSgrestore(); return self; } - generateNewMaze { struct timeval theTime; int width, row, column, temp, *J, *T, factor; struct mazecell *currentCell; if (ranFactor) factor = [ranFactor intValue]; else factor = 800000000; if (theMaze != NULL) free(theMaze); if (theSolution != NULL) free(theSolution); theSolution = NULL; theMaze = malloc(horiz * vert * sizeof(struct mazecell)); currentCell = theMaze; width = horiz + 1; J = malloc(width * sizeof(int)); T = malloc(width * sizeof(int)); row = vert; gettimeofday(&theTime, NULL); srandom(theTime.tv_sec + theTime.tv_usec); J[0] = column = 1; for(temp=width; --temp; J[temp] = T[temp] = temp); while (1) /* until break */ { column--; if (column == 0) { column = width - 1; if (row == 0) break; row--; } temp = J[column - 1]; if ((column-temp) && ((factor < random()) || ((row == 0) && (column == T[column])))) { T[temp] = T[column]; J[T[temp]] = temp; T[column] = column - 1; J[T[column]] = column; currentCell->wall = NO; } else currentCell->wall = YES; temp = J[column]; if ((row == 0) || ((column-temp) && ((factor < random()) || ((row == 0) && (column == T[column]))))) { T[temp] = T[column]; J[T[temp]] = temp; T[column] = column; J[T[column]] = column; currentCell->floor = YES; } else currentCell->floor = NO; currentCell->already = NO; currentCell++; } } - newMaze:sender { [NXWait push]; [self generateNewMaze]; [[self window] display]; [NXWait pop]; return self; } - solve:sender { int j, k; [self lockFocus]; if (theSolution != NULL) { free(theSolution); [self drawSelf:NULL :0]; } if (spacing > 4) { PStranslate(spacing / 2 + 1, spacing / 2 + 1); PSsetlinewidth(spacing - 4); } else if (spacing == 3) { PStranslate(2, 3); PSsetlinewidth(2.0); } else { PStranslate(spacing / 2, spacing / 2 + 2); PSsetlinewidth(0.15); } PSsetlinecap(2); PSsetlinejoin(0); numAllocated = 1000; solutionLen = 0; theSolution = malloc(numAllocated * sizeof(struct place)); tickie = 0; lowTouch = 1000000000; findSolution((struct place){0,0}); for (j=0; j<horiz; j++) for (k=0; k<vert; k++) theMaze[j + k * horiz].already = NO; PSsetgray(NX_WHITE); drawSolution(0); PSflushgraphics(); [self unlockFocus]; } - windowWillResize:sender toSize:(NXSize *)frameSize; { NXRect startRect, tempRect, resultRect; int tempHoriz, tempVert; startRect.size = *frameSize; [Window getContentRect:&tempRect forFrameRect:&startRect style:[sender style]]; tempHoriz = (tempRect.size.width - FAT) / spacing; tempVert = (tempRect.size.height - FAT) / spacing; if (tempHoriz < 2) tempHoriz = 2; if (tempVert < 2) tempVert = 2; tempRect.size.width = tempHoriz * spacing + FAT; tempRect.size.height = tempVert * spacing + FAT; [Window getFrameRect:&resultRect forContentRect:&tempRect style:[sender style]]; *frameSize = resultRect.size; } - windowDidResize:sender { NXRect startRect, tempRect; int tempHoriz, tempVert; [[self window] getFrame:&startRect]; [Window getContentRect:&tempRect forFrameRect:&startRect style:[[self window] style]]; horiz = (tempRect.size.width - FAT) / spacing; vert = (tempRect.size.height - FAT) / spacing; [self generateNewMaze]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.