Listing 3
/* * puzzle.c: This QNX Windows program creates a * moving tile puzzle, with 15 numbered tiles in a * 4 X 4 enclosure. * * It is reproduced here by permission of Quantum * Software Systems, Ltd of Kanata, Canada. */ #include <stdio.h> #include <windows.h> #define RECT_HEIGHT 250 #define RECT_WIDTH 360 #define PANE_BORDER 140 #define PANE_HEIGHT ((rows)*RECT_HEIGHT + 120) #define PANE_WIDTH ((rows)*RECT_WIDTH + 120) #define CASE(str) (((str)[0] << 8) (str)[1]) EVENT_MSG msg; int rows = 4, max_num; int b[20][20], old[20][20]; int mv; main() { int go = YES, wid, pid; /* connect to QWindows */ if ( !GraphicsOpen (NULL)) exit ( -1 ); SetName("Puzzle", NULL); /* Optional */ pid = PictureOpen ( "pict", NULL, NULL, LIGHT_GRAY, NULL, NULL, NULL ); PictureHighlightOptions( NULL, 'N', 0, 0 ); init(); display(); wid = WindowOpen ("Puzzle", PANE_HEIGHT, PANE_WIDTH, "MT480-r;s", NULL, NULL, pid); /* * Put control button in top frame. */ WindowBarCurrent( TOP, NULL ); SetButton( NULL, WHITE, NULL ); DrawAt( 300, 120 ); AttachDialog("Options", NULL, "Scramble;Size@(Easy03;The Famous 4 x 404;Hard 05;Very Hard06;You've got to be Kidding 10)^R", NULL, "MD", NULL, NULL); DrawButton( "Options", NULL, "Ns;D", "op"); Draw(); WindowBarCurrent( NULL, NULL ); load_icon( "/windows/apps/puzzle" ); DrawStart(NULL, 0); while ( go ) { GetEvent ( 0, &msg, sizeof(msg)); switch ( Event ( &msg ) ) { case QUIT: WindowClose( 0, NULL ); go = NO; break; case TERMINATED: go = NO; break; case CLICK: if (msg.hdr.code == 'S') { /* game piece selected */ move(atoi(msg.hdr.key) - 1); mv++; win (); } break; case DIALOG: switch(CASE(msg.hdr.key)) { case '03': case '04': case '05': case '06': case '07': case '10': rows = atoi(msg.hdr.key); case 'Sc': new_game(); break; } } } GraphicsClose(); exit (0); } init() { int i, j, r, loop; max_num = rows*rows; for (i = 0; i < rows; i++) for (j = 0; j < rows; j++) { b[i][j] = ( i * rows + j); old[i][j] = -1; } i = j = rows - 1; srand(get_ticks()); r = rand() % 200 + 500; for (loop = 0; loop < 5000; ++loop) { switch (rand() % 4) { case 0: if (i != 0) { b[i][j] = b[i - 1][j]; b[i - 1][j] = max_num; --i; } break; case 1: if (i != rows - 1) { b[i][j] = b[i + 1][j]; b[i + 1][j] = max_num; i++; } break; case 2: if (j != 0) { b[i][j] = b[i][j - 1]; b[i][j - 1] = max_num; --j; } break; case 3: if (j != rows - 1) { b[i] [j] = b[i] [j + 1]; b[i] [j + 1] = max_num; j++; } break; } } } display() { int i, j; for (i = 0; i < rows; i++) if (memcmp(b[i], old[i], rows)) { for (j = 0; j < rows; j++) if (b[i][j] != max_num) draw_number(i, j, b[i][j] + 1); memcpy(old[i], b[i], rows); } } draw_number( row, col, number) int row, col, number; { char tbuf[4]; tsprintf(tbuf, "%2d", number); SetColor ( "T", BLACK ); DrawAt (PANE_BORDER + (row*RECT_HEIGHT) + CHARH/2, PANE_BORDER + (col*RECT_WIDTH )); DrawText( tbuf, 0, 0, 0, "Sem", tbuf); Draw (); } move_number( row, col, number) int row, col, number; { char buffer[7]; tsprintf(buffer, "%2d", number); ShiftTo( buffer, PANE_BORDER + (row*RECT_HEIGHT) + CHARH/2, PANE_BORDER + (col*RECT_WIDTH )); } move(m) int m; { int i1, j1, i, j, i2, j2, c; i1 = j1 = -1; for (i = 0; i1 == -1 && i < rows; i++) for (j = 0; j < rows; j++) if (b[i][j] == m) { i1 = i; j1 = j; break; } if (i1 != -1) { i2 = j2 = -1; for (i = 0; i < rows; i++) if (b[i][j1] == max_num) { i2 = i; j2 = j1; break; } if (i2 == -1) for (j = 0; j < rows; j++) if (b[i1][j] == max_num) { i2 = i1; j2 = j; break; } if (i2 == -1) return; } else return; /* Hold picture for smoother updates */ PictureHold(); if (i1 == i2) if (j1 < j2) for (j = j2 - 1; j >= j1; --j) { b[i1][j + 1] = b[i1][j]; move_number(i1, j+1, b[i1][j]+1); } else for (j = j2; j < j1; j++) { b[i1][j = b[i1][j + 1]; move_number(i1, j, b[i1][j+1]+1); } else if (i1 < i2) for (i = i2 - 1; i >= i1; --i) { b[i + 1][j1] = b[i][j1]; move_number(i+1, j1, b[i][j1]+1); } else for (i = i2; i < i1; i++) { b[i][j1] = b[i + 1][j1]; move_number(i, j1, b[i+1][j1]+1); } b[i1][j1] = max_num; /* update current picture */ PictureContinue(); } win() { int c = 0, i, j; char buf[50]; for (i = 0; i < rows; i++) for (j = 0; j < rows; j++) if (b[i][j] < c) return( 0 ); else c = (int) b[i][j]; tsprintf(buf, "You got it in %d moves!", mv); Notice( NULL, "You Win", NULL, "W", buf); return( 1 ); } new_game() { RECT_AREA area; WindowInfo(NULL,&area,NULL,NULL,NULL,NULL); /* erase all elements in the picture */ WindowHold(); Erase( ALL ); area.height = PANE_HEIGHT; area.width = PANE_WIDTH; init(); display(); mv = 0; WindowChange( &area, NULL, KEEP, NULL, "!" ); WindowContinue(); }