/* * 15 puzzle */ #include #include /* just for SIGBREAKF_CTRL_C */ #include #include extern struct IntuitionBase *IntuitionBase; extern struct GfxBase *GfxBase; #define NPZ 4 /* the square puzzle is NPZ x NPZ */ #define PZ_MT 0 /* the value of the "empty" tile */ char pz[NPZ][NPZ]; /* the puzzle array */ int mtr, mtc; /* location of the "empty" tile */ #define R0 11 /* origin row/col of upper left */ #define C0 4 #define RS (IMG_HT+1) /* row/col scaling factors (match images!!) */ #define CS (IMG_WID+3) #define IMG_WID 0x1f /* from the output of 'brush' */ #define IMG_HT 0xd struct Image img = { /* shared Image struct for all "tiles" */ 0,0, IMG_WID,IMG_HT, 1, NULL, 1,0, NULL }; /* the image data (in chip ram!) */ extern short id0[], id1[], id2[], id3[], id4[], id5[], id6[], id7[], id8[], id9[], id10[], id11[], id12[], id13[], id14[], id15[]; short *imgs[] = { /* array of pointers to the image data arrays */ id0, id1, id2, id3, id4, id5, id6, id7, id8, id9, id10, id11, id12, id13, id14, id15 }; #define W_WID 141 #define W_HT 68 struct NewWindow newin = { 100,50, W_WID,W_HT, 2,-1, MOUSEBUTTONS | CLOSEWINDOW | REFRESHWINDOW, WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG | SIMPLE_REFRESH, NULL, NULL, "Pz15", NULL, NULL, 0,0, 0,0, WBENCHSCREEN }; struct Window *win = NULL; struct RastPort *rp = NULL; /* Lattice likes prototypes: */ void putpiece(unsigned short, unsigned short, unsigned short); void refrow(unsigned short), refcol(unsigned short); short pzmove(unsigned short, unsigned short); void byewin(long); /* * Repaint a single tile. */ void putpiece(r, c, v) register unsigned short r, c, v; { img.ImageData = imgs[v]; DrawImage(rp, &img, (long) c*CS+C0, (long) r*RS+R0); } /* * Repaint a specified row. */ void refrow(r) register unsigned short r; { register unsigned short c; for ( c = 0; c < NPZ; c++ ) putpiece(r, c, (unsigned short)pz[r][c]); } /* * Repaint a specified column. */ void refcol(c) register unsigned short c; { register unsigned short r; for ( r = 0; r < NPZ; r++ ) putpiece(r, c, (unsigned short) pz[r][c]); } /* * Move the "empty" tile (MT) to the "moused" row and column. */ short pzmove(mr, mc) unsigned short mr, mc; { register unsigned short r, c; /* row/col counters */ register short ir, ic; /* row/col increments */ if ( mtr == mr ) /* Are we in the same row as MT? */ ir = 0; /* yes, row-inc is zero */ else ir = (mtr < mr) ? 1 : -1; /* yes, row-inc is +/-1 */ if ( mtc == mc ) /* Are we in the same col as MT? */ ic = 0; /* yes, col-inc is zero */ else ic = (mtc < mc) ? 1 : -1; /* yes, col-inc is +/-1 */ if ( ir == 0 && ic == 0 ) /* If in same row and col as MT... */ return 0; /* ... nothing to do */ if ( ir != 0 && ic != 0 ) /* If not in either row or col as MT... */ return -1; /* ... too much to do */ /* "double-loop", but really only r _or_ c gets changed */ for ( r = mtr, c = mtc; ; r += ir, c += ic ) { /* start at MT */ pz[r][c] = pz[r+ir][c+ic]; /* shift pieces towards MT */ if ( r == mr && c == mc ) /* until we hit the 'moused' position */ break; } pz[mr][mc] = PZ_MT; /* mark the new empty square */ mtr = mr; mtc = mc; if ( ir == 0 ) /* update the display */ refrow(mr); /* either change a row */ else refcol(mc); /* or a column */ return 1; /* say there was just enough to do */ } /* * Refresh the entire puzzle. */ void pzref() { register unsigned short r; for ( r = 0; r < NPZ; r++ ) refrow(r); } /* * Setup the puzzle array. */ void pzinit() { register unsigned short r, c, i; i = 0; for ( r = 0; r < NPZ; r++ ) for ( c = 0; c < NPZ; c++ ) pz[c][r] = i++; /* scramble a little */ } /* * Get mouse clicks and handle them. */ void dopuz() { register struct IntuiMessage *msg; register unsigned short r, c; unsigned long class; unsigned short code; long flags, ret; flags = (1L << win->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C; /* loop, get mouse clicks, call pzmove() with reduced coords */ for ( ; ; ) { ret = Wait ( flags ); while ( msg = (struct IntuiMessage *)GetMsg(win->UserPort) ) { class = msg->Class; code = msg->Code; r = (msg->MouseY - R0) / RS; c = (msg->MouseX - C0) / CS; ReplyMsg((struct Message *)msg); if ( class == MOUSEBUTTONS && code == SELECTDOWN ) { (void)pzmove(r, c); } else if ( class == REFRESHWINDOW ) { pzref(); } else if ( class == CLOSEWINDOW ) { return; } } if ( ret & SIGBREAKF_CTRL_C ) { return; } } } /* * Shut the window; put back the things we borrowed. */ void byewin(r) long r; { if ( win ) CloseWindow(win); if ( GfxBase ) CloseLibrary(GfxBase); if ( IntuitionBase ) CloseLibrary(IntuitionBase); _exit(r); } /* * Open some libraries and a window. */ void mkwin() { if ( (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L)) == NULL ) byewin(-100L); if ( (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) == NULL ) byewin(-101L); if ( (win = (struct Window *)OpenWindow(&newin)) == NULL ) byewin(-102L); rp = win->RPort; } /* * FINALLY, here's where it all starts. */ void _main() { mkwin(); /* open up our window */ pzinit(); /* initialize the puzzle */ pzref(); /* and show it */ dopuz(); /* play it, until we close or get a ^C */ byewin(0L); /* then close the window and exit */ }