扫雷

来源:互联网 发布:自动化设备编程软件 编辑:程序博客网 时间:2024/05/02 04:48
这段时间事情比较忙,好不容易抽出些时间再找点游戏练练手,这里献丑了。 我在Ubuntu 10.04下测试过,可以正常运行。代码用到了NCURSES库。编译的时候链一下ncurses库就可以了,如:cc -Wall -O2 -o mine mine.c -lncurses首先放出界面欣赏一下,眼晕的看看外面再继续 ==!:     代码: 代码  1 #include <stdio.h>  2 #include <stdlib.h>  3 #include <string.h>  4 #include <sys/types.h>  5 #include <sys/wait.h>  6 #include <sys/select.h>  7 #include <time.h>  8 #include <signal.h>  9 #include <unistd.h> 10 #include <ncurses.h> 11  12 /* 雷区的范围 */ 13 #define MINEAREA_WIDTH      9 14 #define MINEAREA_LENGTH     9 15 /* 雷的个数 */ 16 #define MINE_NUMBER         10 17  18 /* 19  * 将每个方块的状态分类: 20  * 1.初始状态 21  * 2.判定为雷(也就是通常的插旗) 22  * 3.排除(若周边有n个雷则显示为n,0则显示为空,用-1来表示雷) 23  */ 24 #define SQUARE_INIT         0 25 #define SQUARE_FLAG         1 26 #define SQUARE_CLEAN        2 27 #define SQUARE_ZERO         0 28 #define SQUARE_MINE         -1 29  30 /* 显示图形 */ 31 #define GRAPH_INIT          '.' 32 #define GRAPH_MINE          '@' 33 #define GRAPH_NULL          ' ' 34 #define GRAPH_FLAG          'F' 35  36 #define NEWLINE             addch('\n') 37 #define _W(y)               (y * 2 + 3) 38 #define _L(x)               (x * 3 + 1) 39 /* 设置光标 */ 40 #define SET_CURSOR(y, x)    mvchgat(_W(y), _L(x), 2, A_REVERSE, 0, NULL) 41 #define CLEAN_CURSOR(y, x)  mvchgat(_W(y), _L(x), 2, A_NORMAL,  0, NULL) 42  43 #define WPRINT_NUMBER(y, x, v)   \ 44     mvprintw(y, x, "%d", v) 45 #define WPRINT_CHAR(y, x, c)     \ 46     mvaddch(y, x, c) 47  48 /* 光标的位置 */ 49 int g_cur_y = 0; 50 int g_cur_x = 0; 51  52 struct square_t { 53     int type; 54     int mine; 55 }; 56  57 /* timer process function */ 58 int timer_p(); 59 void sig_refresh_time(int signum); 60  61 int init_mine(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]); 62 int check_yx(int y, int x); 63 int game_loop(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]); 64 int clean_zero_squares(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int cur_y, int cur_x); 65  66 /* window functions */ 67 int win_init(int width, int length, int mine_num); 68 int win_refresh(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int width, int length, int mines); 69 int win_refresh_remine_mines(int mines); 70 int win_refresh_secs(int secs); 71 int win_mv_cursor(int delta_y, int delta_x, int width, int length); 72 int win_destroy(); 73 int win_bang(); 74 int win_win(); 75 int win_game_over(); 76  77 int main() 78 { 79     int pid_timer; 80     int pid_main; 81  82     switch (pid_timer = fork()) { 83     case 0: 84         /* timer进程,用作计时器 */ 85         timer_p(); 86         _exit(0); 87     case -1: 88         perror("fork() error!"); 89         return -1; 90     default: 91         /* main process */ 92         break; 93     } 94  95     pid_main = getpid(); 96  97     /* SIGUSR1信号用来刷新显示时间 */ 98     if (signal(SIGUSR1, sig_refresh_time) == SIG_ERR) 99         return -1;100 101     struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH];102 103     if (init_mine(square) == -1) return -1;104 105     win_init(MINEAREA_WIDTH, MINEAREA_LENGTH, MINE_NUMBER);106 107     /* 主循环 */108     game_loop(square);109 110     win_game_over();111 112     /* 主进程结束前需要结束timer子进程 */113     kill(pid_timer, SIGKILL);114 115     int key = -1;116     do {117         key = getch();118     }119     while (key != 'y' && key != 'Y');120 121     wait(NULL);122     win_destroy();123 124     return 0;125 }126 127 /* 初始化雷区信息 */128 int init_mine(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH])129 {130     if (square == NULL)131         return -1;132 133     printf("waiting...\n");134 135     int n,m;136     for (n = 0; n < 9; ++n) {137         for (m = 0; m < 9; ++m) {138             square[n][m].type = 0;139             square[n][m].mine = 0;140         }141     }142 143     int i;144     int y, x;145 146     srandom((int)time(NULL));147 148     for (i = 0; i < MINE_NUMBER; ++i) {149         y = random() % MINEAREA_WIDTH;150         x = random() % MINEAREA_LENGTH;151 152         if (square[y][x].mine == SQUARE_MINE) {153             --i;154         }155         else {156             square[y][x].mine = SQUARE_MINE;157 158             if (check_yx(y-1, x  ) == 0 && square[y-1][x  ].mine != SQUARE_MINE)159                 ++square[y-1][x  ].mine;160 161             if (check_yx(y+1, x  ) == 0 && square[y+1][x  ].mine != SQUARE_MINE)162                 ++square[y+1][x  ].mine;163 164             if (check_yx(y  , x-1) == 0 && square[y  ][x-1].mine != SQUARE_MINE)165                 ++square[y  ][x-1].mine;166 167             if (check_yx(y  , x+1) == 0 && square[y  ][x+1].mine != SQUARE_MINE)168                 ++square[y  ][x+1].mine;169 170             if (check_yx(y-1, x-1) == 0 && square[y-1][x-1].mine != SQUARE_MINE)171                 ++square[y-1][x-1].mine;172 173             if (check_yx(y+1, x-1) == 0 && square[y+1][x-1].mine != SQUARE_MINE)174                 ++square[y+1][x-1].mine;175 176             if (check_yx(y-1, x+1) == 0 && square[y-1][x+1].mine != SQUARE_MINE)177                 ++square[y-1][x+1].mine;178 179             if (check_yx(y+1, x+1) == 0 && square[y+1][x+1].mine != SQUARE_MINE)180                 ++square[y+1][x+1].mine;181         }182     }183 184     return 0;185 }186 187 int check_yx(int y, int x)188 {189     if (y >= 0190         && y < MINEAREA_WIDTH191         && x >= 0192         && x < MINEAREA_LENGTH)193     {194         return 0;195     }196 197     return -1;198 }199 200 /* 主循环 */201 int game_loop(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH])202 {203     fd_set rfd;204     FD_ZERO(&rfd);205     FD_SET(0, &rfd);206 207     static int sweeped_mines = 0; /* 判定正确的雷数 */208 209     int ret;210     int input;211     int remain_mines = MINE_NUMBER;212 213     while (1) {214         if ((ret = select(1, &rfd, NULL, NULL, NULL)) <= 0) {215             //return -1;    //当程序被信号中断时select可能会返回-1216             continue;217         }218 219         switch (input = getch()) {220         /* w,s,a,d方向键 */221         case 'w':222         case 'W':223             win_mv_cursor(-1, 0, MINEAREA_WIDTH, MINEAREA_LENGTH);224             break;225         case 's':226         case 'S':227             win_mv_cursor(+1, 0, MINEAREA_WIDTH, MINEAREA_LENGTH);228             break;229         case 'a':230         case 'A':231             win_mv_cursor(0, -1, MINEAREA_WIDTH, MINEAREA_LENGTH);232             break;233         case 'd':234         case 'D':235             win_mv_cursor(0, +1, MINEAREA_WIDTH, MINEAREA_LENGTH);236             break;237 238         /* 插旗 */239         case 'j':240         case 'J':241             if (square[g_cur_y][g_cur_x].type == SQUARE_INIT) {242                 square[g_cur_y][g_cur_x].type = SQUARE_FLAG;243                 --remain_mines;244 245                 if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE)246                     ++sweeped_mines;247             }248             else if (square[g_cur_y][g_cur_x].type == SQUARE_FLAG) {249                 square[g_cur_y][g_cur_x].type = SQUARE_INIT;250                 ++remain_mines;251 252                 if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE)253                     --sweeped_mines;254             }255             else256                 break;257 258             if (sweeped_mines == MINE_NUMBER) {259                 win_win();260                 goto GAME_OVER;261             }262 263             win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);264             break;265 266         /* 打开方块 */267         case 'k':268         case 'K':269             if (square[g_cur_y][g_cur_x].type == SQUARE_CLEAN)270                 break;271             else if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE) {272                 win_bang();273 274                 int n, m;275                 for (n = 0; n < MINEAREA_WIDTH; ++n) {276                     for (m = 0; m < MINEAREA_LENGTH; ++m) {277                         square[n][m].type = SQUARE_CLEAN;278                     }279                 }280 281                 win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);282                 goto GAME_OVER;283             }284 285             square[g_cur_y][g_cur_x].type = SQUARE_CLEAN;286 287             if (square[g_cur_y][g_cur_x].mine == SQUARE_ZERO)288                 clean_zero_squares(square, g_cur_y, g_cur_x);289 290             win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);291             break;292 293         /* 退出 */294         case 'q':295         case 'Q':296             goto GAME_OVER;297 298         default:299             break;300         }301     }302 303 GAME_OVER:304     return 0;305 }306 307 /* 如果打开的方块下面是0,则自动打开所有周围为0的方块 */308 int clean_zero_squares(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int cur_y, int cur_x)309 {310     if (check_yx(cur_y - 1, cur_x) == 0311         && square[cur_y - 1][cur_x].mine == SQUARE_ZERO312         && square[cur_y - 1][cur_x].type != SQUARE_CLEAN)313     {314         square[cur_y - 1][cur_x].type = SQUARE_CLEAN;315         clean_zero_squares(square, cur_y - 1, cur_x);316     }317 318     if (check_yx(cur_y + 1, cur_x) == 0319         && square[cur_y + 1][cur_x].mine == SQUARE_ZERO320         && square[cur_y + 1][cur_x].type != SQUARE_CLEAN)321     {322         square[cur_y + 1][cur_x].type = SQUARE_CLEAN;323         clean_zero_squares(square, cur_y + 1, cur_x);324     }325 326     if (check_yx(cur_y, cur_x - 1) == 0327         && square[cur_y][cur_x - 1].mine == SQUARE_ZERO328         && square[cur_y][cur_x - 1].type != SQUARE_CLEAN)329     {330         square[cur_y][cur_x - 1].type = SQUARE_CLEAN;331         clean_zero_squares(square, cur_y, cur_x - 1);332     }333 334     if (check_yx(cur_y, cur_x + 1) == 0335         && square[cur_y][cur_x + 1].mine == SQUARE_ZERO336         && square[cur_y][cur_x + 1].type != SQUARE_CLEAN)337     {338         square[cur_y][cur_x + 1].type = SQUARE_CLEAN;339         clean_zero_squares(square, cur_y, cur_x + 1);340     }341 342     return 0;343 }344 345 /*****************************************************************************/346 /* 初始化显示界面 */347 int win_init(int width, int length, int mine_num)348 {349     initscr();350     raw();351     noecho();352     keypad(stdscr, TRUE);353     curs_set(0);354     refresh();355 356     win_refresh_remine_mines(MINE_NUMBER);357     win_refresh_secs(0);358 359     int frame_width  = width  * 2 + 1;360     int frame_length = length * 3 + 1;361     char *line = NULL;362     line = (char*)malloc((frame_length + 1) * sizeof(char));363     memset(line, '-', frame_length);364     *(line + frame_length) = '\0';365     mvprintw(2, 0, line);NEWLINE;366 367     int i, j;368     for (j = 0; j < frame_width - 2; ++j) {369         addch('|');370         for (i = 0; i < length * 2 + 1 - 2; ++i) {371             if (j % 2 == 0) {372                 if (i % 2 == 0) {373                     addch(GRAPH_INIT);addch(' ');374                 }375                 else {376                     addch('|');377                 }378             }379             else {380                 if (i % 2 == 0) {381                     addch('-');addch('-');382                 }383                 else {384                     addch('+');385                 }386             }387         }388         addch('|');NEWLINE;389     }390 391     printw(line);NEWLINE;392 393     /* set cursor position */394     SET_CURSOR(g_cur_y, g_cur_x);395 396     refresh();397     return 0;398 }399 400 /* 刷新显示界面 */401 int win_refresh(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int width, int length, int mines)402 {403     if (square == NULL)404         return -1;405 406     win_refresh_remine_mines(mines);407 408     int j, i;409     for (j = 0; j < width; ++j) {410         for (i = 0; i < length; ++i) {411             switch (square[j][i].type) {412             case SQUARE_INIT:413                 WPRINT_CHAR(_W(j), _L(i), GRAPH_INIT);414                 break;415             case SQUARE_FLAG:416                 WPRINT_CHAR(_W(j), _L(i), GRAPH_FLAG);417                 break;418             case SQUARE_CLEAN:419                 switch (square[j][i].mine) {420                 case SQUARE_MINE:421                     WPRINT_CHAR(_W(j), _L(i), GRAPH_MINE);422                     break;423                 case SQUARE_ZERO:424                     WPRINT_CHAR(_W(j), _L(i), GRAPH_NULL);425                     break;426                 default:427                     WPRINT_NUMBER(_W(j), _L(i), square[j][i].mine);428                     break;429                 }430                 break;431             default:432                 break;433             }434         }435     }436 437     refresh();438 439     return 0;440 }441 442 int win_refresh_remine_mines(int mines)443 {444     mvprintw(0, 0, "Mines: %d", mines);445     mvprintw(1, 0, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");446     refresh();447     return 0;448 }449 450 int win_refresh_secs(int secs)451 {452     mvprintw(0, 15, "Seconds: %d", secs);453     refresh();454     return 0;455 }456 457 458 int win_mv_cursor(int delta_y, int delta_x, int width, int length)459 {460     CLEAN_CURSOR(g_cur_y, g_cur_x);461 462     if (g_cur_y + delta_y < width && g_cur_y + delta_y >= 0)463         g_cur_y += delta_y;464 465     if (g_cur_x + delta_x < length && g_cur_x + delta_x >= 0)466         g_cur_x += delta_x;467 468     SET_CURSOR(g_cur_y, g_cur_x);469 470     refresh();471 472     return 0;473 }474 475 int win_destroy()476 {477     endwin();478 479     return 0;480 }481 482 int win_bang()483 {484     mvprintw(0, 0, "BANG!!!!");485     refresh();486     return 0;487 }488 489 int win_win()490 {491     mvprintw(0, 0, "WIN!!!!");492     refresh();493     return 0;494 }495 496 int win_game_over()497 {498     mvprintw(1, 0, "Game Over!");499     mvprintw(1, 0, "Press 'y' or 'Y' to end.");500     refresh();501     return 0;502 }503 504 /*****************************************************************************/505 int timer_p()506 {507     /* 每秒钟给主进程发一次信号 */508     do {509         sleep(1);510         kill(getppid(), SIGUSR1);511     }512     while (1);513 514     return 0;515 }516 517 void sig_refresh_time(int signum)518 {519     static int secs = 0;520     win_refresh_secs(++secs);521 }522 

原创粉丝点击