1 /* Copyright (c) 2000 Simon Wood <simon@mungewell.uklinux.net>
3 * This program is licensed under the same terms that Microwindows
4 * and Nano-X are licensed under. See the file LICENSE accompanying
13 #define MWINCLUDECOLORS
16 /* set up size of the grid */
17 #define WIDTH_IN_TILES 4
18 #define HEIGHT_IN_TILES 4
19 #define MAX_TILES (WIDTH_IN_TILES * HEIGHT_IN_TILES)
22 static int value[WIDTH_IN_TILES][HEIGHT_IN_TILES];
23 static int calc_width, calc_height;
24 static int tile_width = 40;
25 static int tile_height = 40;
28 static void * image_addr;
29 static int using_image = 1;
30 static GR_WINDOW_ID image; /* storage area for image */
33 static GR_WINDOW_ID master; /* id for whole window */
34 static GR_WINDOW_ID buttons; /* id for buttons */
35 static GR_WINDOW_ID tiles; /* id for play area */
36 static GR_GC_ID gc1; /* graphics context for text */
38 static int value[WIDTH_IN_TILES][HEIGHT_IN_TILES];
40 /* function prototypes */
41 static void HandleEvents();
42 static void RefreshWindow();
43 static void RandomiseTiles();
44 static void MoveTile();
45 static void DrawTile();
48 main(int argc,char **argv)
51 fprintf(stderr, "cannot open graphics\n");
58 image = GrNewWindow(GR_ROOT_WINDOW_ID, 300, 0, (WIDTH_IN_TILES * tile_width),
59 (HEIGHT_IN_TILES * tile_height), 4, BLACK, WHITE);
62 /* No image specified, use numered tiles */
65 /* need to find out image size.... */
66 image_addr = malloc(4 * (WIDTH_IN_TILES * tile_width) *
67 (HEIGHT_IN_TILES * tile_height) );
69 image = GrNewPixmap((WIDTH_IN_TILES * tile_width),
70 (HEIGHT_IN_TILES * tile_height), image_addr);
72 GrDrawImageFromFile(image, gc1, 0, 0,
73 GR_IMAGE_MAX_SIZE, GR_IMAGE_MAX_SIZE, argv[1], 0);
77 /* calculate size of tile area */
78 calc_width = 10 + (WIDTH_IN_TILES * tile_width);
79 calc_height = 15 + 35 + (HEIGHT_IN_TILES * tile_height);
81 /* enforce minimum size */
82 if (calc_width < 240) calc_width=240;
83 if (calc_height < 320) calc_height=320;
85 master = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, calc_width, calc_height, 1, RED, WHITE);
86 buttons = GrNewWindow((GR_WINDOW_ID) master, 5, 5, (calc_width - 5), 35, 1, RED, RED);
88 tiles = GrNewWindow((GR_WINDOW_ID) master, (calc_width/2) - (WIDTH_IN_TILES * tile_width /2),
89 45 + ((calc_height - 50)/2) - (HEIGHT_IN_TILES * tile_height /2),
90 (WIDTH_IN_TILES * tile_width), (HEIGHT_IN_TILES * tile_height), 1, RED, RED);
97 srandom((int) getpid());
101 GrSelectEvents(master, GR_EVENT_MASK_EXPOSURE|GR_EVENT_MASK_CLOSE_REQ);
102 GrSelectEvents(buttons, GR_EVENT_MASK_BUTTON_DOWN);
103 GrSelectEvents(tiles, GR_EVENT_MASK_BUTTON_DOWN);
110 GrGetNextEvent(&event);
111 HandleEvents(&event);
117 * Read the next event and handle it.
120 HandleEvents(GR_EVENT *ep)
123 case GR_EVENT_TYPE_BUTTON_DOWN:
124 if (ep->button.wid == buttons) {
125 if (ep->button.x < (calc_width/2)) {
140 if (ep->button.wid == tiles) {
141 /* Try to move selected tile */
142 MoveTile( (int)(ep->button.x / tile_width),
143 (int)(ep->button.y / tile_height) );
147 case GR_EVENT_TYPE_EXPOSURE:
150 case GR_EVENT_TYPE_CLOSE_REQ:
162 GrSetGCForeground(gc1, WHITE);
163 GrSetGCBackground(gc1, RED);
165 /* draw the buttons */
166 GrRect(buttons, gc1, 0, 0, (calc_width - 12)/2, 34);
167 GrRect(buttons, gc1, (calc_width - 8)/2, 0, (calc_width - 12)/2, 34);
169 #if 0 /* for when center align text works */
170 GrText(buttons, gc1, (calc_width - 10)/4, 22, "Again", 5, 0);
171 GrText(buttons, gc1, (calc_width - 10)*3/4, 22, "Quit", 4, 0);
173 GrText(buttons, gc1, 5, 22, "Again", 5, 0);
174 GrText(buttons, gc1, (calc_width / 2) + 5, 22, "Quit", 4, 0);
178 for (ypos=0; ypos< HEIGHT_IN_TILES; ypos++){
179 for (xpos=0; xpos< WIDTH_IN_TILES; xpos++){
180 DrawTile(xpos, ypos);
188 int count, xpos, ypos;
190 /* allocate all the numbers in order 1..MAX_TILES */
191 for (ypos=0; ypos< HEIGHT_IN_TILES; ypos++){
192 for (xpos=0; xpos< WIDTH_IN_TILES; xpos++){
193 value[xpos][ypos] = 1 + xpos + (WIDTH_IN_TILES * ypos);
197 /* position of 'hole' */
198 xpos = WIDTH_IN_TILES - 1;
199 ypos = HEIGHT_IN_TILES - 1;
201 /* randomly slide them around, ALL games can therefore solved - so no excusses!! */
202 for (count=0; count< MAX_TILES * 1000; count++){
203 switch(random() % 4) {
205 if (ypos < HEIGHT_IN_TILES - 1) {
206 value[xpos][ypos] = value[xpos][ypos+1];
208 value[xpos][ypos] = MAX_TILES;
213 value[xpos][ypos] = value[xpos - 1][ypos];
215 value[xpos][ypos] = MAX_TILES;
220 value[xpos][ypos] = value[xpos][ypos - 1];
222 value[xpos][ypos] = MAX_TILES;
226 if (xpos < WIDTH_IN_TILES - 1) {
227 value[xpos][ypos] = value[xpos + 1][ypos];
229 value[xpos][ypos] = MAX_TILES;
240 /* check all possible moves to see if there is the blank (N,E,S,W) */
241 if (ypos > 0 && value[xpos][ypos - 1] == MAX_TILES) {
242 value[xpos][ypos - 1] = value[xpos][ypos];
243 value[xpos][ypos] = MAX_TILES;
244 DrawTile(xpos, ypos - 1);
245 DrawTile(xpos, ypos);
248 if (xpos < (WIDTH_IN_TILES - 1) && value[xpos + 1][ypos] == MAX_TILES) {
249 value[xpos + 1][ypos] = value[xpos][ypos];
250 value[xpos][ypos] = MAX_TILES;
251 DrawTile(xpos + 1, ypos);
252 DrawTile(xpos, ypos);
255 if (ypos < (HEIGHT_IN_TILES - 1) && value[xpos][ypos + 1] == MAX_TILES) {
256 value[xpos][ypos + 1] = value[xpos][ypos];
257 value[xpos][ypos] = MAX_TILES;
258 DrawTile(xpos, ypos + 1);
259 DrawTile(xpos, ypos);
262 if (xpos > 0 && value[xpos - 1][ypos] == MAX_TILES) {
263 value[xpos - 1][ypos] = value[xpos][ypos];
264 value[xpos][ypos] = MAX_TILES;
265 DrawTile(xpos - 1, ypos);
266 DrawTile(xpos, ypos);
269 /* check for a winner */
270 if (value[WIDTH_IN_TILES - 1][HEIGHT_IN_TILES - 1] == MAX_TILES) {
272 for (ypos=0; ypos< HEIGHT_IN_TILES; ypos++){
273 for (xpos=0; xpos< WIDTH_IN_TILES; xpos++){
274 if (value[xpos][ypos] == winner + 1)
280 if (winner == MAX_TILES) {
281 /* Do winning screen */
282 int loop = MAX_TILES;
283 for(loop=0; loop < MAX_TILES; loop++) {
284 for(winner=0; winner < (MAX_TILES - loop) ; winner++) {
286 /* move tiles around */
287 xpos = winner % WIDTH_IN_TILES;
288 ypos = (int)(winner/WIDTH_IN_TILES);
289 value[xpos][ypos] = loop + winner + 1;
290 DrawTile(winner % WIDTH_IN_TILES, (int)(winner/WIDTH_IN_TILES));
293 for(winner=0; winner < 10000000 ; winner++);
297 GrSetGCForeground(gc1, WHITE);
298 GrSetGCBackground(gc1, RED);
299 GrText(tiles, gc1, ((WIDTH_IN_TILES * tile_width)/2) - 40, (HEIGHT_IN_TILES * tile_height)/2, "Well Done!!", -1, 0);
312 /* blank out old tile */
313 GrSetGCForeground(gc1, RED);
314 GrFillRect(tiles, gc1, (xpos* tile_width), (ypos*tile_height), tile_width, tile_height);
316 if (value[xpos][ypos] != MAX_TILES ) {
317 /* re-draw tile and number */
318 GrSetGCForeground(gc1, WHITE);
319 GrSetGCBackground(gc1, RED);
320 GrRect(tiles, gc1, (xpos*tile_width), (ypos*tile_height), tile_width, tile_height);
324 /* copy from image window */
325 GrCopyArea(tiles, gc1, 1 + (xpos*tile_width), 1 + (ypos*tile_height),
326 tile_width - 2, tile_height - 2, image,
327 1 + (((value[xpos][ypos] - 1) % WIDTH_IN_TILES) * tile_width),
328 1 + (((int)(value[xpos][ypos] - 1) / WIDTH_IN_TILES) * tile_height), 0);
331 /* label the tile with a number */
332 if (value[xpos][ypos] > 9)
333 text[0] = 48 + (int)(value[xpos][ypos]/10);
337 text[1] = 48 + value[xpos][ypos] % 10;
339 GrText(tiles, gc1, (xpos*tile_width) + (tile_width /2) - 5, (ypos*tile_height) + (tile_height/2) + 5, &text, -1, 0);