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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [mw/] [src/] [demos/] [nanox/] [landmine.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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