OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [services/] [gfx/] [mw/] [v2_0/] [src/] [demos/] [nanox/] [landmine.c] - Blame information for rev 365

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
/*
2
 * Landmine, the game.
3
 * Written for mini-X by David I. Bell.
4
 */
5
 
6
#include <stdio.h>
7
#include <stdarg.h>
8
#include <stdlib.h>
9
#if UNIX | DOS_DJGPP
10
#include <fcntl.h>
11
#include <unistd.h>
12
#include <time.h>
13
#endif
14
#define MWINCLUDECOLORS
15
#include "nano-X.h"
16
 
17
 
18
#define MINSIZE         3               /* minimum size of board */
19
#define MAXSIZE         30              /* maximum size of board */
20
#define SIZE            15              /* default size of playing board */
21
#define MINEPERCENT     15              /* default percentage of mines */
22
#define SAVEFILE        "landmine.save" /* default save file name */
23
#define MAGIC           649351261       /* magic number in save files */
24
#define MAXPARAMS       1000            /* maximum different game parameters */
25
 
26
#define FULLSIZE        (MAXSIZE + 2)   /* board size including borders */
27
 
28
#ifdef __ECOS
29
/* 240x320 screen values*/
30
#define BOARDGAP        2               /* millimeter gap around board */
31
#define RIGHTGAP        2               /* mm gap between board, right side */
32
#define BUTTONGAP       5               /* mm gap between buttons */
33
#define STATUSGAP       10              /* mm gap between buttons and status */
34
 
35
#define BUTTONWIDTH     80              /* width of buttons (pixels) */
36
#define BUTTONHEIGHT    25              /* height of buttons (pixels) */
37
#define RIGHTSIDE       90              /* pixels to guarantee for right side */
38
#define BOARDBORDER     2               /* border size around board */
39
#else
40
#define BOARDGAP        10              /* millimeter gap around board */
41
#define RIGHTGAP        15              /* mm gap between board, right side */
42
#define BUTTONGAP       20              /* mm gap between buttons */
43
#define STATUSGAP       35              /* mm gap between buttons and status */
44
 
45
#define BUTTONWIDTH     80              /* width of buttons (pixels) */
46
#define BUTTONHEIGHT    25              /* height of buttons (pixels) */
47
#define RIGHTSIDE       150             /* pixels to guarantee for right side */
48
#define BOARDBORDER     2               /* border size around board */
49
#endif
50
 
51
/*
52
 * Print the number of steps taken.
53
 * This is used twice, and is a macro to guarantee that
54
 * the two printouts match.
55
 */
56
#define PRINTSTEPS      printline(2, "Steps: %3d\n", steps)
57
 
58
 
59
/*
60
 * Typedefs local to this program.
61
 */
62
typedef unsigned short  CELL;   /* cell value */
63
typedef int             POS;    /* cell position */
64
 
65
 
66
/*
67
 * For defining bitmaps easily.
68
 */
69
#define X       ((unsigned) 1)
70
#define _       ((unsigned) 0)
71
 
72
#define BITS(a,b,c,d,e,f,g,h,i) \
73
        (((((((((a*2+b)*2+c)*2+d)*2+e)*2+f)*2+g)*2+h)*2+i) << 7)
74
 
75
 
76
static  GR_BITMAP       twolegs_fg[] = {        /* two legs foreground */
77
        BITS(_,_,_,_,_,_,_,_,_),
78
        BITS(_,_,_,X,X,X,_,_,_),
79
        BITS(_,_,_,X,X,X,_,_,_),
80
        BITS(_,_,_,X,X,X,_,_,_),
81
        BITS(_,_,_,_,X,_,_,_,_),
82
        BITS(_,_,X,X,X,X,X,_,_),
83
        BITS(_,X,_,X,_,X,_,X,_),
84
        BITS(_,X,_,X,X,X,_,X,_),
85
        BITS(_,_,_,X,_,X,_,_,_),
86
        BITS(_,_,_,X,_,X,_,_,_),
87
        BITS(_,_,X,X,_,X,X,_,_),
88
        BITS(_,_,_,_,_,_,_,_,_)
89
};
90
 
91
static  GR_BITMAP       twolegs_bg[] = {        /* two legs background */
92
        BITS(_,_,X,X,X,X,X,_,_),
93
        BITS(_,_,X,X,X,X,X,_,_),
94
        BITS(_,_,X,X,X,X,X,_,_),
95
        BITS(_,_,X,X,X,X,X,_,_),
96
        BITS(_,X,X,X,X,X,X,X,_),
97
        BITS(X,X,X,X,X,X,X,X,X),
98
        BITS(X,X,X,X,_,X,X,X,X),
99
        BITS(X,X,X,X,X,X,X,X,X),
100
        BITS(X,X,X,X,X,X,X,X,X),
101
        BITS(_,X,X,X,X,X,X,X,_),
102
        BITS(_,X,X,X,X,X,X,X,_),
103
        BITS(_,X,X,X,X,X,X,X,_)
104
};
105
 
106
 
107
static  GR_BITMAP       oneleg_fg[] = {         /* one leg foreground */
108
        BITS(_,_,_,_,_,_,_,_,_),
109
        BITS(_,_,_,X,X,X,_,_,_),
110
        BITS(_,_,_,X,X,X,_,_,_),
111
        BITS(_,_,_,X,X,X,_,_,_),
112
        BITS(_,_,_,_,X,_,_,_,_),
113
        BITS(_,_,X,X,X,X,X,_,_),
114
        BITS(_,X,_,X,_,X,_,X,_),
115
        BITS(_,_,_,X,X,X,_,X,_),
116
        BITS(_,_,_,_,_,X,_,_,_),
117
        BITS(_,_,_,_,_,X,_,_,_),
118
        BITS(_,_,_,_,_,X,X,_,_),
119
        BITS(_,_,_,_,_,_,_,_,_),
120
};
121
 
122
 
123
static  GR_BITMAP       oneleg_bg[] = {         /* one leg background */
124
        BITS(_,_,X,X,X,X,X,_,_),
125
        BITS(_,_,X,X,X,X,X,_,_),
126
        BITS(_,_,X,X,X,X,X,_,_),
127
        BITS(_,_,X,X,X,X,X,_,_),
128
        BITS(_,X,X,X,X,X,X,X,_),
129
        BITS(X,X,X,X,X,X,X,X,X),
130
        BITS(X,X,X,X,_,X,X,X,X),
131
        BITS(X,X,X,X,X,X,X,X,X),
132
        BITS(_,_,X,X,X,X,X,X,X),
133
        BITS(_,_,_,_,X,X,X,X,_),
134
        BITS(_,_,_,_,X,X,X,X,_),
135
        BITS(_,_,_,_,X,X,X,X,_)
136
};
137
 
138
 
139
static  GR_BITMAP       noleg_fg[] = {          /* no legs foreground */
140
        BITS(_,_,_,_,_,_,_,_,_),
141
        BITS(_,_,_,X,X,X,_,_,_),
142
        BITS(_,_,_,X,X,X,_,_,_),
143
        BITS(_,_,_,X,X,X,_,_,_),
144
        BITS(_,_,_,_,X,_,_,_,_),
145
        BITS(_,_,X,X,X,X,X,_,_),
146
        BITS(_,X,_,X,_,X,_,X,_),
147
        BITS(_,_,_,X,X,X,_,_,_),
148
        BITS(_,_,_,_,_,_,_,_,_),
149
        BITS(_,_,_,_,_,_,_,_,_),
150
        BITS(_,_,_,_,_,_,_,_,_),
151
        BITS(_,_,_,_,_,_,_,_,_),
152
};
153
 
154
 
155
static  GR_BITMAP       noleg_bg[] = {          /* no legs background */
156
        BITS(_,_,X,X,X,X,X,_,_),
157
        BITS(_,_,X,X,X,X,X,_,_),
158
        BITS(_,_,X,X,X,X,X,_,_),
159
        BITS(_,_,X,X,X,X,X,_,_),
160
        BITS(_,X,X,X,X,X,X,X,_),
161
        BITS(X,X,X,X,X,X,X,X,X),
162
        BITS(X,X,X,X,_,X,X,X,X),
163
        BITS(X,X,X,X,X,X,X,X,X),
164
        BITS(_,_,X,X,X,X,X,_,_),
165
        BITS(_,_,_,_,_,_,_,_,_),
166
        BITS(_,_,_,_,_,_,_,_,_),
167
        BITS(_,_,_,_,_,_,_,_,_)
168
};
169
 
170
 
171
/*
172
 * Components of a cell.
173
 */
174
#define F_EMPTY         ' '             /* default value for empty square */
175
#define F_REMEMBER      '*'             /* character to remember mine */
176
#define F_WRONG         'X'             /* character to remember wrong guess */
177
#define F_DISPLAY       0xff            /* character to be displayed here */
178
#define F_MINE          0x100           /* TRUE if a mine is here */
179
#define F_EDGE          0x200           /* TRUE if this is edge of the world */
180
#define F_OLD           0x400           /* TRUE if been at this square before */
181
#define F_REACH         0x800           /* TRUE if can reach this square */
182
#define F_FLAGS         0xff00          /* all flags */
183
 
184
 
185
/*
186
 * The status of the game.
187
 * This structure is read and written from the save file.
188
 */
189
static  struct status {                 /* status of games */
190
        long    s_magic;                /* magic number */
191
        short   s_playing;              /* TRUE if playing a game */
192
        short   s_size;                 /* current size of board */
193
        short   s_mines;                /* current number of mines on board */
194
        short   s_legs;                 /* number of legs left */
195
        short   s_steps;                /* number of steps taken this game */
196
        short   s_index;                /* current game parameter index */
197
        short   s_sizeparam[MAXPARAMS]; /* table of size parameters */
198
        short   s_mineparam[MAXPARAMS]; /* table of mine parameters */
199
        long    s_games0[MAXPARAMS];    /* games finished with no legs */
200
        long    s_games1[MAXPARAMS];    /* games finished with one leg */
201
        long    s_games2[MAXPARAMS];    /* games finished with two legs */
202
        long    s_steps0[MAXPARAMS];    /* steps taken in no leg games */
203
        long    s_steps1[MAXPARAMS];    /* steps taken in one leg games */
204
        long    s_steps2[MAXPARAMS];    /* steps taken in two leg games */
205
        CELL    s_board[FULLSIZE*FULLSIZE];     /* board layout */
206
} st;
207
 
208
 
209
/*
210
 * Definitions to make structure references easy.
211
 */
212
#define magic           st.s_magic
213
#define playing         st.s_playing
214
#define size            st.s_size
215
#define mines           st.s_mines
216
#define legs            st.s_legs
217
#define steps           st.s_steps
218
#define index           st.s_index
219
#define sizeparam       st.s_sizeparam
220
#define mineparam       st.s_mineparam
221
#define games0          st.s_games0
222
#define games1          st.s_games1
223
#define games2          st.s_games2
224
#define steps0          st.s_steps0
225
#define steps1          st.s_steps1
226
#define steps2          st.s_steps2
227
#define board           st.s_board
228
 
229
 
230
#define boardpos(row, col)      (((row) * FULLSIZE) + (col))
231
#define ismine(cell)            ((cell) & F_MINE)
232
#define isedge(cell)            ((cell) & F_EDGE)
233
#define isold(cell)             ((cell) & F_OLD)
234
#define isseen(cell)            (((cell) & F_DISPLAY) == F_REMEMBER)
235
#define isknown(cell)           (((cell) & F_DISPLAY) != F_EMPTY)
236
#define displaychar(cell)       ((cell) & F_DISPLAY)
237
#define badsquare(n)            (((n) <= 0) || ((n) > size))
238
 
239
 
240
/*
241
 * Offsets for accessing adjacent cells.
242
 */
243
static  POS     steptable[8] = {
244
        FULLSIZE, -FULLSIZE, 1, -1, FULLSIZE-1,
245
        FULLSIZE+1, -FULLSIZE-1, -FULLSIZE+1
246
};
247
 
248
 
249
static  GR_WINDOW_ID    mainwid;        /* main window id */
250
static  GR_WINDOW_ID    boardwid;       /* board window id */
251
static  GR_WINDOW_ID    statwid;        /* status display window id */
252
static  GR_WINDOW_ID    quitwid;        /* window id for quit button */
253
static  GR_WINDOW_ID    savewid;        /* window id for save button */
254
static  GR_WINDOW_ID    newgamewid;     /* window id for new game button */
255
 
256
static  GR_GC_ID        boardgc;        /* graphics context for board */
257
static  GR_GC_ID        cleargc;        /* GC for clearing cell of board */
258
static  GR_GC_ID        redgc;          /* GC for drawing red */
259
static  GR_GC_ID        greengc;        /* GC for drawing green */
260
static  GR_GC_ID        blackgc;        /* GC for drawing black */
261
static  GR_GC_ID        delaygc;        /* GC for delaying */
262
static  GR_GC_ID        statgc;         /* GC for status window */
263
static  GR_GC_ID        buttongc;       /* GC for drawing buttons */
264
static  GR_GC_ID        xorgc;          /* GC for inverting things */
265
 
266
static  GR_SIZE         xp;             /* pixels for x direction per square */
267
static  GR_SIZE         yp;             /* pixels for y direction per square */
268
static  GR_SIZE         statwidth;      /* width of window drawing text in */
269
static  GR_SIZE         statheight;     /* height of window drawing text in */
270
static  GR_SIZE         charheight;     /* height of characters */
271
static  GR_COORD        charxpos;       /* current X position for characters */
272
static  GR_COORD        charypos;       /* current Y position for characters */
273
 
274
static  GR_SCREEN_INFO  si;             /* window information */
275
static  GR_FONT_INFO    fi;             /* font information */
276
 
277
static  GR_SIZE         COLS, ROWS;
278
 
279
static  char    *savefile;              /* filename for saving game */
280
 
281
 
282
/*
283
 * Procedures.
284
 */
285
static  void    printline(GR_COORD, char *, ...);
286
static  void    newline();
287
static  void    delay();
288
static  void    dokey();
289
static  void    handleevent();
290
static  void    doexposure();
291
static  void    dobutton();
292
static  void    drawbomb();
293
static  void    drawstatus();
294
static  void    drawbutton();
295
static  void    drawboard();
296
static  void    drawcell();
297
static  void    cellcenter();
298
static  void    clearcell();
299
static  void    newgame();
300
static  void    movetopos();
301
static  void    setcursor();
302
static  void    togglecell();
303
static  void    gameover();
304
static  void    readgame();
305
static  void    findindex();
306
static  POS     findcell();
307
static  GR_BOOL checkpath();
308
static  GR_BOOL writegame();
309
 
310
int
311
main(argc,argv)
312
        int argc;
313
        char **argv;
314
{
315
        GR_COORD        x;
316
        GR_COORD        y;
317
        GR_SIZE         width;
318
        GR_SIZE         height;
319
        GR_COORD        rightx;         /* x coordinate for right half stuff */
320
        GR_BOOL         setsize;        /* TRUE if size of board is set */
321
        GR_BOOL         setmines;       /* TRUE if number of mines is set */
322
        GR_SIZE         newsize = 10;   /* desired size of board */
323
        GR_COUNT        newmines = 25;  /* desired number of mines */
324
        GR_WM_PROPERTIES props;
325
 
326
        setmines = GR_FALSE;
327
        setsize = GR_FALSE;
328
 
329
        argc--;
330
        argv++;
331
        while ((argc > 0) && (**argv == '-')) {
332
                switch (argv[0][1]) {
333
                        case 'm':
334
                                if (argc <= 0) {
335
                                        fprintf(stderr, "Missing mine count\n");
336
                                        exit(1);
337
                                }
338
                                argc--;
339
                                argv++;
340
                                newmines = atoi(*argv);
341
                                setmines = GR_TRUE;
342
                                break;
343
 
344
                        case 's':
345
                                if (argc <= 0) {
346
                                        fprintf(stderr, "Missing size\n");
347
                                        exit(1);
348
                                }
349
                                argc--;
350
                                argv++;
351
                                newsize = atoi(*argv);
352
                                setsize = GR_TRUE;
353
                                break;
354
 
355
                        default:
356
                                fprintf(stderr, "Unknown option \"-%c\"\n",
357
                                        argv[0][1]);
358
                                exit(1);
359
                }
360
                argc--;
361
                argv++;
362
        }
363
        if (argc > 0)
364
                savefile = *argv;
365
 
366
        srand(time(0));
367
 
368
        readgame(savefile);
369
 
370
        if (setsize) {
371
                if ((newsize < MINSIZE) || (newsize > MAXSIZE)) {
372
                        fprintf(stderr, "Illegal board size\n");
373
                        exit(1);
374
                }
375
                if (newsize != size) {
376
                        if (steps && playing) {
377
                                fprintf(stderr,
378
                                        "Cannot change size while game is in progress\n");
379
                                exit(1);
380
                        }
381
                        playing = GR_FALSE;
382
                        size = newsize;
383
                        if (!playing)
384
                                mines = (size * size * MINEPERCENT) / 100;
385
                }
386
        }
387
 
388
        if (setmines) {
389
                if ((newmines <= 0) || ((newmines > (size * size) / 2))) {
390
                        fprintf(stderr, "Illegal number of mines\n");
391
                        exit(1);
392
                }
393
                if (newmines != mines) {
394
                        if (steps && playing) {
395
                                fprintf(stderr,
396
                                        "Cannot change mines while game is in progress\n");
397
                                exit(1);
398
                        }
399
                        playing = GR_FALSE;
400
                        mines = newmines;
401
                }
402
        }
403
 
404
        findindex();
405
 
406
        /*
407
         * Parameters of the game have been verified.
408
         * Now open the graphics and play the game.
409
         */
410
 
411
        if (GrOpen() < 0) {
412
                fprintf(stderr, "Cannot open graphics\n");
413
                exit(1);
414
        }
415
 
416
        GrReqShmCmds(655360); /* Test by Morten Rolland for shm support */
417
 
418
        GrGetScreenInfo(&si);
419
        GrGetFontInfo(0, &fi);
420
        charheight = fi.height;
421
 
422
        /*
423
         * Create the main window which will contain all the others.
424
         */
425
#if 0
426
COLS = si.cols - 40;
427
#else
428
COLS = si.cols;
429
#endif
430
ROWS = si.rows - 80;
431
        mainwid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, COLS, ROWS,
432
                0, BLACK, WHITE);
433
 
434
        /* set title */
435
        props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS;
436
        props.props = GR_WM_PROPS_APPFRAME | GR_WM_PROPS_CAPTION;
437
        props.title = "Land Mine";
438
        GrSetWMProperties(mainwid, &props);
439
 
440
        /*
441
         * Create the board window which lies at the left side.
442
         * Make the board square, and as large as possible while still
443
         * leaving room to the right side for statistics and buttons.
444
         */
445
        width = COLS - RIGHTSIDE - (si.xdpcm * RIGHTGAP / 10) - BOARDBORDER * 2;
446
        height = (((long) width) * si.ydpcm) / si.xdpcm;
447
        if (height > ROWS /* - y * 2*/) {
448
                height = ROWS - BOARDBORDER * 2;
449
                width = (((long) height) * si.xdpcm) / si.ydpcm;
450
        }
451
        xp = width / size;
452
        yp = height / size;
453
 
454
        width = xp * size - 1;
455
        height = yp * size - 1;
456
        x = BOARDBORDER;
457
        y = (ROWS - height) / 2;
458
 
459
        rightx = x + width + (si.xdpcm * RIGHTGAP / 10);
460
        boardwid = GrNewWindow(mainwid, x, y, width, height, BOARDBORDER,
461
                BLUE, WHITE);
462
        /*
463
         * Create the buttons.
464
         */
465
        x = rightx;
466
        y = (si.ydpcm * BOARDGAP / 10);
467
        quitwid = GrNewWindow(mainwid, x, y, BUTTONWIDTH, BUTTONHEIGHT,
468
                1, RED, WHITE);
469
 
470
        y += (si.ydpcm * BUTTONGAP / 10);
471
        savewid = GrNewWindow(mainwid, x, y, BUTTONWIDTH, BUTTONHEIGHT,
472
                1, GREEN, WHITE);
473
 
474
        y += (si.ydpcm * BUTTONGAP / 10);
475
        newgamewid = GrNewWindow(mainwid, x, y, BUTTONWIDTH, BUTTONHEIGHT,
476
                1, GREEN, WHITE);
477
 
478
        /*
479
         * Create the statistics window.
480
         */
481
        x = rightx;
482
        y += (si.ydpcm * STATUSGAP / 10);
483
        width = COLS - x;
484
        height = ROWS - y;
485
        statwid = GrNewWindow(mainwid, x, y, width, height, 0,
486
                0, 0);
487
        statwidth = width;
488
        statheight = height;
489
 
490
        /*
491
         * Create the GC for drawing the board.
492
         */
493
        boardgc = GrNewGC();
494
        cleargc = GrNewGC();
495
        delaygc = GrNewGC();
496
        redgc = GrNewGC();
497
        greengc = GrNewGC();
498
        statgc = GrNewGC();
499
        blackgc = GrNewGC();
500
        buttongc = GrNewGC();
501
        xorgc = GrNewGC();
502
        GrSetGCBackground(boardgc, BLUE);
503
        GrSetGCForeground(cleargc, BLUE);
504
        GrSetGCForeground(redgc, RED);
505
        GrSetGCForeground(greengc, GREEN);
506
        GrSetGCForeground(statgc, GRAY);
507
        GrSetGCForeground(delaygc, BLACK);
508
        GrSetGCForeground(blackgc, BLACK);
509
        GrSetGCMode(delaygc, GR_MODE_XOR);
510
        GrSetGCMode(xorgc, GR_MODE_XOR);
511
        GrSetGCUseBackground(boardgc, GR_FALSE);
512
        GrSetGCUseBackground(buttongc, GR_FALSE);
513
 
514
        GrSelectEvents(mainwid, GR_EVENT_MASK_CLOSE_REQ);
515
 
516
        GrSelectEvents(boardwid, GR_EVENT_MASK_EXPOSURE |
517
                GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_KEY_DOWN);
518
 
519
        GrSelectEvents(statwid, GR_EVENT_MASK_EXPOSURE);
520
 
521
        GrSelectEvents(quitwid, GR_EVENT_MASK_EXPOSURE |
522
                GR_EVENT_MASK_BUTTON_DOWN);
523
 
524
        GrSelectEvents(newgamewid, GR_EVENT_MASK_EXPOSURE |
525
                GR_EVENT_MASK_BUTTON_DOWN);
526
 
527
        GrSelectEvents(savewid, GR_EVENT_MASK_EXPOSURE |
528
                GR_EVENT_MASK_BUTTON_DOWN);
529
 
530
        setcursor();
531
 
532
        GrMapWindow(mainwid);
533
        GrMapWindow(boardwid);
534
        GrMapWindow(statwid);
535
        GrMapWindow(quitwid);
536
        GrMapWindow(savewid);
537
        GrMapWindow(newgamewid);
538
 
539
        if (!playing)
540
                newgame();
541
 
542
        while (GR_TRUE) {
543
                GR_EVENT event;
544
 
545
                GrGetNextEvent(&event);
546
                handleevent(&event);
547
        }
548
}
549
 
550
 
551
/*
552
 * Read the next event and handle it.
553
 */
554
static void
555
handleevent(GR_EVENT *ep)
556
{
557
        switch (ep->type) {
558
                case GR_EVENT_TYPE_BUTTON_DOWN:
559
                        dobutton(&ep->button);
560
                        break;
561
 
562
                case GR_EVENT_TYPE_EXPOSURE:
563
                        doexposure(&ep->exposure);
564
                        break;
565
 
566
                case GR_EVENT_TYPE_KEY_DOWN:
567
                        dokey(&ep->keystroke);
568
                        break;
569
 
570
                case GR_EVENT_TYPE_CLOSE_REQ:
571
                        GrClose();
572
                        exit(0);
573
        }
574
}
575
 
576
 
577
/*
578
 * Handle exposure events.
579
 */
580
static void
581
doexposure(ep)
582
        GR_EVENT_EXPOSURE       *ep;
583
{
584
        if (ep->wid == boardwid) {
585
                drawboard();
586
                return;
587
        }
588
 
589
        if (ep->wid == statwid) {
590
                drawstatus();
591
                return;
592
        }
593
 
594
        if (ep->wid == quitwid) {
595
                drawbutton(quitwid, "QUIT");
596
                return;
597
        }
598
 
599
        if (ep->wid == savewid) {
600
                drawbutton(savewid, "SAVE GAME");
601
                return;
602
        }
603
 
604
        if (ep->wid == newgamewid) {
605
                drawbutton(newgamewid, "NEW GAME");
606
                return;
607
        }
608
}
609
 
610
 
611
/*
612
 * Here when we get a button down event.
613
 */
614
static void
615
dobutton(bp)
616
        GR_EVENT_BUTTON         *bp;
617
{
618
        if (bp->wid == boardwid) {
619
                movetopos(findcell(bp->x, bp->y));
620
                return;
621
        }
622
 
623
        if (bp->wid == quitwid) {
624
                GrFillRect(quitwid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT);
625
                GrFlush();
626
                if (savefile)
627
                        writegame(savefile);
628
                GrClose();
629
                exit(0);
630
        }
631
 
632
        if (bp->wid == savewid) {
633
                GrFillRect(savewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT);
634
                GrFlush();
635
                if (savefile == NULL)
636
                        savefile = SAVEFILE;
637
                if (writegame(savefile))
638
                        write(1, "\007", 1);
639
                else
640
                        delay();
641
                GrFillRect(savewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT);
642
        }
643
 
644
        if (bp->wid == newgamewid) {
645
                GrFillRect(newgamewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT);
646
                GrFlush();
647
                /*if (playing)
648
                        write(1, "\007", 1);
649
                else {*/
650
                        newgame();
651
                        delay();
652
                /*}*/
653
                GrFillRect(newgamewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT);
654
        }
655
}
656
 
657
 
658
/*
659
 * Here when we get a keypress in a window.
660
 */
661
static void
662
dokey(kp)
663
        GR_EVENT_KEYSTROKE      *kp;
664
{
665
        if ((kp->wid != boardwid) || !playing)
666
                return;
667
 
668
        switch (kp->ch) {
669
                case ' ':                       /* remember or forget mine */
670
                        togglecell(findcell(kp->x, kp->y));
671
                        break;
672
        }
673
}
674
 
675
 
676
/*
677
 * Redraw the board.
678
 */
679
static void
680
drawboard()
681
{
682
        GR_COORD        row;
683
        GR_COORD        col;
684
 
685
        for (row = 1; row < size; row++) {
686
                GrLine(boardwid, boardgc, 0, row * yp - 1, size * xp - 1,
687
                        row * yp - 1);
688
                GrLine(boardwid, boardgc, row * xp - 1, 0,
689
                        row * xp - 1, size * yp - 1);
690
        }
691
        for (row = 0; row < FULLSIZE; row++) {
692
                for (col = 0; col < FULLSIZE; col++) {
693
                        drawcell(boardpos(row, col));
694
                }
695
        }
696
}
697
 
698
 
699
/*
700
 * Draw a cell on the board.
701
 */
702
static void
703
drawcell(pos)
704
        POS             pos;            /* position to be drawn */
705
{
706
        GR_COORD        x;
707
        GR_COORD        y;
708
        GR_SIZE         chwidth;
709
        GR_SIZE         chheight;
710
        GR_SIZE         chbase;
711
        CELL            cell;
712
        GR_CHAR         ch;
713
 
714
        cell = board[pos];
715
        if (!isknown(cell))
716
                return;
717
 
718
        ch = displaychar(cell);
719
        if (ch == F_WRONG) {
720
                drawbomb(pos, greengc, GR_FALSE);
721
                return;
722
        }
723
 
724
        if (isold(cell)) {
725
                clearcell(pos);
726
                cellcenter(pos, &x, &y);
727
                GrGetGCTextSize(boardgc, &ch, 1, GR_TFASCII, &chwidth,
728
                        &chheight, &chbase);
729
                GrText(boardwid, boardgc, x - chwidth / 2 + 1,
730
                        y + chheight / 2, &ch, 1, GR_TFBOTTOM);
731
                return;
732
        }
733
 
734
        drawbomb(pos, redgc, GR_FALSE);
735
}
736
 
737
 
738
/*
739
 * Clear a particular cell.
740
 */
741
static void
742
clearcell(pos)
743
        POS             pos;            /* position to be cleared */
744
{
745
        GR_COORD        row;
746
        GR_COORD        col;
747
 
748
        row = pos / FULLSIZE;
749
        col = pos % FULLSIZE;
750
        GrFillRect(boardwid, cleargc, col * xp - xp, row * yp - yp,
751
                xp - 1, yp - 1);
752
}
753
 
754
 
755
/*
756
 * Draw a bomb in a window using the specified GC.
757
 * The bomb is animated and the terminal is beeped if necessary.
758
 */
759
static void
760
drawbomb(pos, gc, animate)
761
        POS             pos;            /* position to draw bomb at */
762
        GR_GC_ID        gc;             /* GC for drawing (red or green) */
763
        GR_BOOL         animate;        /* TRUE to animate the bomb */
764
{
765
        GR_COORD        x;
766
        GR_COORD        y;
767
        GR_COUNT        count;
768
 
769
        if (animate)
770
                write(1, "\007", 1);
771
 
772
        cellcenter(pos, &x, &y);
773
 
774
        count = (animate ? 8 : 1);
775
        for (;;) {
776
                GrFillEllipse(boardwid, gc, x, y, xp / 2 - 3, yp / 2 - 3);
777
                if (--count == 0)
778
                        return;
779
                delay();
780
                clearcell(pos);
781
                delay();
782
        }
783
}
784
 
785
 
786
/*
787
 * Draw a button which has a specified label string centered in it.
788
 */
789
static void
790
drawbutton(window, label)
791
        GR_WINDOW_ID    window;
792
        char            *label;
793
{
794
        GR_SIZE         width;
795
        GR_SIZE         height;
796
        GR_SIZE         base;
797
 
798
        GrGetGCTextSize(buttongc, label, strlen(label), GR_TFASCII, &width,
799
                &height, &base);
800
        GrText(window, buttongc, (BUTTONWIDTH - width) / 2,
801
                (BUTTONHEIGHT - height) / 2 + height - 1,
802
                label, -1, GR_TFBOTTOM);
803
}
804
 
805
 
806
/*
807
 * Set the cursor as appropriate.
808
 * The cursor changes depending on the number of legs left.
809
 */
810
static void
811
setcursor()
812
{
813
        GR_BITMAP       *fgbits;        /* bitmap for foreground */
814
        GR_BITMAP       *bgbits;        /* bitmap for background */
815
 
816
        switch (legs) {
817
                case 0:
818
                        fgbits = noleg_fg;
819
                        bgbits = noleg_bg;
820
                        break;
821
                case 1:
822
                        fgbits = oneleg_fg;
823
                        bgbits = oneleg_bg;
824
                        break;
825
                default:
826
                        fgbits = twolegs_fg;
827
                        bgbits = twolegs_bg;
828
                        break;
829
        }
830
        GrSetCursor(boardwid, 9, 12, 4, 6, WHITE, BLACK, fgbits, bgbits);
831
}
832
 
833
 
834
/*
835
 * Delay for a while so that something can be seen.
836
 * This is done by drawing a large rectangle over the window using a mode
837
 * of XOR with the value of 0, (which does nothing except waste time).
838
 */
839
static void
840
delay()
841
{
842
        GR_COUNT        i;
843
 
844
        for (i = 0; i < 1; i++) {
845
                GrFillRect(boardwid, delaygc, 0, 0, xp * size - 1,
846
                        yp * size - 1);
847
                GrFlush();
848
        }
849
}
850
 
851
 
852
/*
853
 * Calculate the coordinates of the center of a cell on the board.
854
 * The coordinates are relative to the origin of the board window.
855
 */
856
static void
857
cellcenter(pos, retx, rety)
858
        POS             pos;            /* position to find center of */
859
        GR_COORD        *retx;          /* returned X coordinate */
860
        GR_COORD        *rety;          /* returned Y coordinate */
861
{
862
        *retx = (pos % FULLSIZE) * xp - 1 - xp / 2;
863
        *rety = (pos / FULLSIZE) * yp - 1 - yp / 2;
864
}
865
 
866
 
867
/*
868
 * Draw the status information in the status window.
869
 */
870
static void
871
drawstatus()
872
{
873
        long    score;
874
        long    allsteps;
875
        long    games;
876
 
877
        score = 0;
878
        games = games0[index];
879
        allsteps = steps0[index];
880
        score += games1[index];
881
        games += games1[index];
882
        allsteps += steps1[index];
883
        score += games2[index] * 2;
884
        games += games2[index];
885
        allsteps += steps2[index];
886
 
887
        printline(0, "Size:   %2d\n", size);
888
        printline(1, "Mines: %3d\n", mines);
889
        PRINTSTEPS;
890
        printline(3, "Legs:    %d\n", legs);
891
 
892
        printline(5, "Won games:  %3d\n", games2[index]);
893
        printline(6, "1-leg games:%3d\n", games1[index]);
894
        printline(7, "Lost games: %3d\n", games0[index]);
895
 
896
        if (games) {
897
                printline(9, "Legs/game: %3d.%03d\n", score / games,
898
                        ((score * 1000) / games) % 1000);
899
 
900
                printline(10, "Steps/game:%3d.%03d\n", allsteps / games,
901
                        ((allsteps * 1000) / games) % 1000);
902
        }
903
}
904
 
905
 
906
/*
907
 * Printf routine for windows, which can print at particular lines.
908
 * A negative line number means continue printing at the previous location.
909
 * Assumes the status window for output.
910
 */
911
static void printline(GR_COORD row, char * fmt, ...)
912
{
913
        va_list         ap;
914
        GR_COUNT        cc;
915
        GR_SIZE         width;
916
        char            *cp;
917
        char            buf[256];
918
 
919
        va_start(ap, fmt);
920
        vsprintf(buf, fmt, ap);
921
        va_end(ap);
922
 
923
        if (row >= 0) {
924
                charxpos = 0;
925
                charypos = charheight * row + charheight - 1;
926
        }
927
 
928
        cp = buf;
929
        for (;;) {
930
                cc = 0;
931
                width = 0;
932
                while (*cp >= ' ') {
933
                        width += fi.widths[(int)*cp++];
934
                        cc++;
935
                }
936
                if (width) {
937
                        GrText(statwid, statgc, charxpos, charypos,
938
                                cp - cc, cc, GR_TFBOTTOM);
939
                        charxpos += width;
940
                }
941
 
942
                switch (*cp++) {
943
                        case '\0':
944
                                return;
945
                        case '\n':
946
                                newline();
947
                                break;
948
                        case '\r':
949
                                charxpos = 0;
950
                                break;
951
                }
952
        }
953
}
954
 
955
 
956
/*
957
 * Clear the remainder of the line and move to the next line.
958
 * This assumes output is in the status window.
959
 */
960
static void
961
newline()
962
{
963
        GrFillRect(statwid, blackgc, charxpos, charypos - charheight + 1,
964
                statwidth - charxpos, charheight);
965
        charxpos = 0;
966
        charypos += charheight;
967
}
968
 
969
 
970
/*
971
 * Translate a board window coordinate into a cell position.
972
 * If the coordinate is outside of the window, or exactly on one
973
 * of the interior lines, then a coordinate of 0 is returned.
974
 */
975
static POS
976
findcell(x, y)
977
        GR_COORD        x;
978
        GR_COORD        y;
979
{
980
        GR_COORD        row;
981
        GR_COORD        col;
982
 
983
        if (((x % xp) == 0) || ((y % yp) == 0))
984
                return 0;
985
        row = (y / yp) + 1;
986
        col = (x / xp) + 1;
987
        if ((row <= 0) || (row > size) || (col <= 0) || (col > size))
988
                return 0;
989
        return boardpos(row, col);
990
}
991
 
992
 
993
/*
994
 * Initialize the board for playing
995
 */
996
static void
997
newgame()
998
{
999
        GR_COORD        row;
1000
        GR_COORD        col;
1001
        GR_COUNT        count;
1002
        CELL            cell;
1003
        POS             pos;
1004
 
1005
        for (row = 0; row < FULLSIZE; row++) {
1006
                for (col = 0; col < FULLSIZE; col++) {
1007
                        cell = F_EMPTY;
1008
                        if (badsquare(row) || badsquare(col))
1009
                                cell |= F_EDGE;
1010
                        board[boardpos(row, col)] = cell;
1011
                }
1012
        }
1013
 
1014
        playing = GR_TRUE;
1015
        count = 0;
1016
        legs = 2;
1017
        steps = 0;
1018
        drawstatus();
1019
        setcursor();
1020
 
1021
        while (count < mines) {
1022
                do {
1023
                        row = (rand() / 16) % (size * size + 1);
1024
                } while (row == (size * size));
1025
 
1026
                col = (row % size) + 1;
1027
                row = (row / size) + 1;
1028
                pos = boardpos(row, col);
1029
 
1030
                if ((pos == boardpos(1,1)) || (pos == boardpos(1,2)) ||
1031
                        (pos == boardpos(2,1)) || (pos == boardpos(2,2)) ||
1032
                        (pos == boardpos(size,size)))
1033
                                continue;
1034
 
1035
                if (!ismine(board[pos]) && checkpath(pos))
1036
                        count++;
1037
        }
1038
 
1039
        board[boardpos(1,1)] = (F_OLD | '0');
1040
 
1041
        GrClearWindow(boardwid, GR_TRUE);
1042
}
1043
 
1044
 
1045
/*
1046
 * Check to see if there is still a path from the top left corner to the
1047
 * bottom right corner, if a new mine is placed at the indicated position.
1048
 * Returns GR_TRUE if mine was successfully placed.
1049
 */
1050
static GR_BOOL
1051
checkpath(pos)
1052
        POS             pos;            /* position to place mine at */
1053
{
1054
        CELL            *bp;            /* current board position */
1055
        CELL            *endbp;         /* ending position */
1056
        POS             endpos;         /* ending position */
1057
        GR_COUNT        count;          /* number of neighbors */
1058
        GR_COUNT        i;              /* loop counter */
1059
        GR_BOOL         more;           /* GR_TRUE if new square reached */
1060
 
1061
        /*
1062
         * Begin by assuming there is a mine at the specified location,
1063
         * and then count neighbors.  If there are less than two other
1064
         * mines or edge squares, then there must still be a path.
1065
         */
1066
        board[pos] |= F_MINE;
1067
 
1068
        count = 0;
1069
 
1070
        for (i = 7; i >= 0; i--) {
1071
                if (board[pos + steptable[i]] & (F_MINE | F_EDGE))
1072
                count++;
1073
        }
1074
 
1075
        if (count < 2)
1076
                return GR_TRUE;
1077
 
1078
        /*
1079
         * Two or more neighbors, so we must do the full check.
1080
         * First clear the reach flag, except for the top left corner.
1081
         */
1082
        endpos = boardpos(size, size);
1083
        bp = &board[endpos];
1084
        endbp = bp;
1085
        while (bp != board)
1086
                *bp-- &= ~F_REACH;
1087
        board[boardpos(1,1)] |= F_REACH;
1088
 
1089
        /*
1090
         * Now loop looking for new squares next to already reached squares.
1091
         * Stop when no more changes are found, or when the lower right
1092
         * corner is reached.
1093
         */
1094
        do {
1095
                more = GR_FALSE;
1096
                for (bp = &board[boardpos(1,1)]; bp != endbp; bp++) {
1097
                        if (*bp & F_REACH) {
1098
                                for (i = 7; i >= 0; i--) {
1099
                                        if ((bp[steptable[i]] & (F_MINE | F_REACH | F_EDGE)) == 0) {
1100
                                                bp[steptable[i]] |= F_REACH;
1101
                                                more = GR_TRUE;
1102
                                        }
1103
                                }
1104
                        }
1105
                }
1106
 
1107
                if (board[endpos] & F_REACH)
1108
                        return GR_TRUE;
1109
        } while (more);
1110
 
1111
        /*
1112
         * Cannot reach the lower right corner, so remove the mine and fail.
1113
         */
1114
        board[pos] &= ~F_MINE;
1115
 
1116
        return GR_FALSE;
1117
}
1118
 
1119
 
1120
/*
1121
 * Move to a particular position and see if we hit a mine.
1122
 * If not, then count the number of mines adjacent to us so it can be seen.
1123
 * If we are stepping onto a location where we remembered a mine is at,
1124
 * then don't do it.  Moving is only allowed to old locations, or to
1125
 * locations adjacent to old ones.
1126
 */
1127
static void
1128
movetopos(newpos)
1129
        POS             newpos;         /* position to move to */
1130
{
1131
        POS             fixpos;         /* position to fix up */
1132
        CELL            cell;           /* current cell */
1133
        GR_COUNT        count;          /* count of cells */
1134
        GR_COUNT        i;              /* index for neighbors */
1135
 
1136
        if ((newpos < 0) || (newpos >= (FULLSIZE * FULLSIZE)) || !playing)
1137
                return;
1138
 
1139
        cell = board[newpos];
1140
 
1141
        if (isedge(cell) || (isseen(cell)) || isold(cell))
1142
                return;
1143
 
1144
        count = isold(cell);
1145
        for (i = 0; i < 8; i++)
1146
                if (isold(board[newpos + steptable[i]]))
1147
                        count++;
1148
 
1149
        if (count <= 0)
1150
                return;
1151
 
1152
        cell = (cell & F_FLAGS) | F_OLD;
1153
        steps++;
1154
 
1155
        PRINTSTEPS;
1156
 
1157
        if (ismine(cell)) {             /* we hit a mine */
1158
                legs--;
1159
                board[newpos] = (F_REMEMBER | F_MINE);
1160
                cell = (F_EMPTY | F_OLD);
1161
                board[newpos] = cell;
1162
                drawbomb(newpos, redgc, GR_TRUE);
1163
                clearcell(newpos);
1164
                setcursor();
1165
                for (i = 0; i < 8; i++) {
1166
                        fixpos = newpos + steptable[i];
1167
                        if (isold(board[fixpos])) {
1168
                                board[fixpos]--;
1169
                                drawcell(fixpos);
1170
                        }
1171
                }
1172
                drawstatus();
1173
        }
1174
 
1175
        count = 0;
1176
        for (i = 0; i < 8; i++)
1177
                if (ismine(board[newpos + steptable[i]]))
1178
                        count++;
1179
        board[newpos] = cell | (count + '0');
1180
 
1181
        drawcell(newpos);
1182
 
1183
        if ((legs <= 0) || (newpos == boardpos(size,size)))
1184
                gameover();
1185
}
1186
 
1187
 
1188
/*
1189
 * Remember or forget the location of a mine.
1190
 * This is for informational purposes only and does not affect anything.
1191
 */
1192
static void
1193
togglecell(pos)
1194
        POS     pos;            /* position to toggle */
1195
{
1196
        CELL    cell;
1197
 
1198
        if ((pos <= 0) || !playing)
1199
                return;
1200
 
1201
        cell = board[pos];
1202
        if (isknown(cell)) {
1203
                if (!isseen(cell))
1204
                        return;
1205
                board[pos] = (board[pos] & F_FLAGS) | F_EMPTY;
1206
                clearcell(pos);
1207
                return;
1208
        }
1209
 
1210
        board[pos] = (board[pos] & F_FLAGS) | F_REMEMBER;
1211
        drawcell(pos);
1212
}
1213
 
1214
 
1215
/*
1216
 * Here when the game is over.
1217
 * Show where the mines are, and give the results.
1218
 */
1219
static void
1220
gameover()
1221
{
1222
        POS     pos;
1223
        CELL    cell;
1224
 
1225
        playing = GR_FALSE;
1226
        switch (legs) {
1227
                case 0:
1228
                        games0[index]++;
1229
                        steps0[index] += steps;
1230
                        break;
1231
                case 1:
1232
                        games1[index]++;
1233
                        steps1[index] += steps;
1234
                        break;
1235
                case 2:
1236
                        games2[index]++;
1237
                        steps2[index] += steps;
1238
                        break;
1239
        }
1240
 
1241
        for (pos = 0; pos < (FULLSIZE * FULLSIZE); pos++) {
1242
                cell = board[pos];
1243
                if (isseen(cell))
1244
                        cell = (cell & F_FLAGS) | F_WRONG;
1245
                if (ismine(cell))
1246
                        cell = (cell & F_FLAGS) | F_REMEMBER;
1247
                board[pos] = cell;
1248
        }
1249
 
1250
        drawboard();
1251
        drawstatus();
1252
}
1253
 
1254
 
1255
/*
1256
 * Search the game parameter table for the current board size and
1257
 * number of mines, and set the index for those parameters so that
1258
 * the statistics can be accessed.  Allocates a new index if necessary.
1259
 */
1260
static void
1261
findindex()
1262
{
1263
        for (index = 0; index < MAXPARAMS; index++) {
1264
                if ((sizeparam[index] == size) && (mineparam[index] == mines))
1265
                        return;
1266
        }
1267
        for (index = 0; index < MAXPARAMS; index++) {
1268
                if (sizeparam[index] == 0) {
1269
                        sizeparam[index] = size;
1270
                        mineparam[index] = mines;
1271
                        return;
1272
                }
1273
        }
1274
        fprintf(stderr, "Too many parameters in save file\n");
1275
        exit(1);
1276
}
1277
 
1278
 
1279
/*
1280
 * Read in a saved game if available, otherwise start from scratch.
1281
 * Exits if an error is encountered.
1282
 */
1283
static void
1284
readgame(name)
1285
        char    *name;          /* filename */
1286
{
1287
        int     fd;
1288
 
1289
        fd = -1;
1290
        if (name)
1291
                fd = open(name, 0);
1292
 
1293
        if (fd < 0) {
1294
                magic = MAGIC;
1295
                size = SIZE;
1296
                mines = (size * size * MINEPERCENT) / 100;
1297
                playing = GR_FALSE;
1298
                return;
1299
        }
1300
 
1301
        if (read(fd, &st, sizeof(st)) != sizeof(st))
1302
                magic = 0;
1303
        close(fd);
1304
 
1305
        if ((magic != MAGIC) || (size > MAXSIZE)) {
1306
                fprintf(stderr, "Save file format is incorrect\n");
1307
                exit(1);
1308
        }
1309
}
1310
 
1311
 
1312
/*
1313
 * Write the current game to a file.
1314
 * Returns nonzero on an error.
1315
 */
1316
static GR_BOOL
1317
writegame(name)
1318
        char    *name;          /* filename */
1319
{
1320
        int     fd;
1321
 
1322
        if (name == NULL)
1323
                return GR_TRUE;
1324
 
1325
        fd = creat(name, 0666);
1326
        if (fd < 0)
1327
                return GR_TRUE;
1328
 
1329
        if (write(fd, &st, sizeof(st)) != sizeof(st)) {
1330
                close(fd);
1331
                return GR_TRUE;
1332
        }
1333
        close(fd);
1334
        return GR_FALSE;
1335
}
1336
 
1337
/* END CODE */

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.