这段时间事情比较忙,好不容易抽出些时间再找点游戏练练手,这里献丑了。 我在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