Linux下的字元介面掃雷遊戲

來源:互聯網
上載者:User
轉載請註明出處。http://www.cnblogs.com/dave_cn/  

這段時間事情比較忙,好不容易抽出些時間再找點遊戲練練手,這裡獻醜了。 

我在Ubuntu 10.04下測試過,可以正常運行。

代碼用到了NCURSES庫。編譯的時候鏈一下ncurses庫就可以了,如:cc -Wall -O2 -o mine mine.c -lncurses

 

首先放出介面欣賞一下,眼暈的看看外面再繼續 ==!:

   

 

 代碼:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/select.h>#include <time.h>#include <signal.h>#include <unistd.h>#include <ncurses.h>/* 雷區的範圍 */#define MINEAREA_WIDTH      9#define MINEAREA_LENGTH     9/* 雷的個數 */#define MINE_NUMBER         10/* * 將每個方塊的狀態分類: * 1.初始狀態 * 2.判定為雷(也就是通常的插旗) * 3.排除(若周邊有n個雷則顯示為n,0則顯示為空白,用-1來表示雷) */#define SQUARE_INIT         0#define SQUARE_FLAG         1#define SQUARE_CLEAN        2#define SQUARE_ZERO         0#define SQUARE_MINE         -1/* 顯示圖形 */#define GRAPH_INIT          '.'#define GRAPH_MINE          '@'#define GRAPH_NULL          ' '#define GRAPH_FLAG          'F'#define NEWLINE             addch('\n')#define _W(y)               (y * 2 + 3)#define _L(x)               (x * 3 + 1)/* 設定游標 */#define SET_CURSOR(y, x)    mvchgat(_W(y), _L(x), 2, A_REVERSE, 0, NULL)#define CLEAN_CURSOR(y, x)  mvchgat(_W(y), _L(x), 2, A_NORMAL,  0, NULL)#define WPRINT_NUMBER(y, x, v)   \    mvprintw(y, x, "%d", v)#define WPRINT_CHAR(y, x, c)     \    mvaddch(y, x, c)/* 游標的位置 */int g_cur_y = 0;int g_cur_x = 0;struct square_t {    int type;    int mine;};/* timer process function */int timer_p();void sig_refresh_time(int signum);int init_mine(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]);int check_yx(int y, int x);int game_loop(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]);int clean_zero_squares(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int cur_y, int cur_x);/* window functions */int win_init(int width, int length, int mine_num);int win_refresh(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int width, int length, int mines);int win_refresh_remine_mines(int mines);int win_refresh_secs(int secs);int win_mv_cursor(int delta_y, int delta_x, int width, int length);int win_destroy();int win_bang();int win_win();int win_game_over();int main(){    int pid_timer;    int pid_main;    switch (pid_timer = fork()) {    case 0:        /* timer進程,用作計時器 */        timer_p();        _exit(0);    case -1:        perror("fork() error!");        return -1;    default:        /* main process */        break;    }    pid_main = getpid();    /* SIGUSR1訊號用來重新整理顯示時間 */    if (signal(SIGUSR1, sig_refresh_time) == SIG_ERR)        return -1;    struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH];    if (init_mine(square) == -1) return -1;    win_init(MINEAREA_WIDTH, MINEAREA_LENGTH, MINE_NUMBER);    /* 主迴圈 */    game_loop(square);    win_game_over();    /* 主進程結束前需要結束timer子進程 */    kill(pid_timer, SIGKILL);    int key = -1;    do {        key = getch();    }    while (key != 'y' && key != 'Y');    wait(NULL);    win_destroy();    return 0;}/* 初始化雷區資訊 */int init_mine(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]){    if (square == NULL)        return -1;    printf("waiting...\n");    int n,m;    for (n = 0; n < 9; ++n) {        for (m = 0; m < 9; ++m) {            square[n][m].type = 0;            square[n][m].mine = 0;        }    }    int i;    int y, x;    srandom((int)time(NULL));    for (i = 0; i < MINE_NUMBER; ++i) {        y = random() % MINEAREA_WIDTH;        x = random() % MINEAREA_LENGTH;        if (square[y][x].mine == SQUARE_MINE) {            --i;        }        else {            square[y][x].mine = SQUARE_MINE;            if (check_yx(y-1, x  ) == 0 && square[y-1][x  ].mine != SQUARE_MINE)                ++square[y-1][x  ].mine;            if (check_yx(y+1, x  ) == 0 && square[y+1][x  ].mine != SQUARE_MINE)                ++square[y+1][x  ].mine;            if (check_yx(y  , x-1) == 0 && square[y  ][x-1].mine != SQUARE_MINE)                ++square[y  ][x-1].mine;            if (check_yx(y  , x+1) == 0 && square[y  ][x+1].mine != SQUARE_MINE)                ++square[y  ][x+1].mine;            if (check_yx(y-1, x-1) == 0 && square[y-1][x-1].mine != SQUARE_MINE)                ++square[y-1][x-1].mine;            if (check_yx(y+1, x-1) == 0 && square[y+1][x-1].mine != SQUARE_MINE)                ++square[y+1][x-1].mine;            if (check_yx(y-1, x+1) == 0 && square[y-1][x+1].mine != SQUARE_MINE)                ++square[y-1][x+1].mine;            if (check_yx(y+1, x+1) == 0 && square[y+1][x+1].mine != SQUARE_MINE)                ++square[y+1][x+1].mine;        }    }    return 0;}int check_yx(int y, int x){    if (y >= 0        && y < MINEAREA_WIDTH        && x >= 0        && x < MINEAREA_LENGTH)    {        return 0;    }    return -1;}/* 主迴圈 */int game_loop(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]){    fd_set rfd;    FD_ZERO(&rfd);    FD_SET(0, &rfd);    static int sweeped_mines = 0; /* 判定正確的雷數 */    int ret;    int input;    int remain_mines = MINE_NUMBER;    while (1) {        if ((ret = select(1, &rfd, NULL, NULL, NULL)) <= 0) {            //return -1;    //當程式被訊號中斷時select可能會返回-1            continue;        }        switch (input = getch()) {        /* w,s,a,d方向鍵 */        case 'w':        case 'W':            win_mv_cursor(-1, 0, MINEAREA_WIDTH, MINEAREA_LENGTH);            break;        case 's':        case 'S':            win_mv_cursor(+1, 0, MINEAREA_WIDTH, MINEAREA_LENGTH);            break;        case 'a':        case 'A':            win_mv_cursor(0, -1, MINEAREA_WIDTH, MINEAREA_LENGTH);            break;        case 'd':        case 'D':            win_mv_cursor(0, +1, MINEAREA_WIDTH, MINEAREA_LENGTH);            break;        /* 插旗 */        case 'j':        case 'J':            if (square[g_cur_y][g_cur_x].type == SQUARE_INIT) {                square[g_cur_y][g_cur_x].type = SQUARE_FLAG;                --remain_mines;                if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE)                    ++sweeped_mines;            }            else if (square[g_cur_y][g_cur_x].type == SQUARE_FLAG) {                square[g_cur_y][g_cur_x].type = SQUARE_INIT;                ++remain_mines;                if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE)                    --sweeped_mines;            }            else                break;            if (sweeped_mines == MINE_NUMBER) {                win_win();                goto GAME_OVER;            }            win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);            break;        /* 開啟方塊 */        case 'k':        case 'K':            if (square[g_cur_y][g_cur_x].type == SQUARE_CLEAN)                break;            else if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE) {                win_bang();                int n, m;                for (n = 0; n < MINEAREA_WIDTH; ++n) {                    for (m = 0; m < MINEAREA_LENGTH; ++m) {                        square[n][m].type = SQUARE_CLEAN;                    }                }                win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);                goto GAME_OVER;            }            square[g_cur_y][g_cur_x].type = SQUARE_CLEAN;            if (square[g_cur_y][g_cur_x].mine == SQUARE_ZERO)                clean_zero_squares(square, g_cur_y, g_cur_x);            win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);            break;        /* 退出 */        case 'q':        case 'Q':            goto GAME_OVER;        default:            break;        }    }GAME_OVER:    return 0;}/* 如果開啟的方塊下面是0,則自動開啟所有周圍為0的方塊 */int clean_zero_squares(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int cur_y, int cur_x){    if (check_yx(cur_y - 1, cur_x) == 0        && square[cur_y - 1][cur_x].mine == SQUARE_ZERO        && square[cur_y - 1][cur_x].type != SQUARE_CLEAN)    {        square[cur_y - 1][cur_x].type = SQUARE_CLEAN;        clean_zero_squares(square, cur_y - 1, cur_x);    }    if (check_yx(cur_y + 1, cur_x) == 0        && square[cur_y + 1][cur_x].mine == SQUARE_ZERO        && square[cur_y + 1][cur_x].type != SQUARE_CLEAN)    {        square[cur_y + 1][cur_x].type = SQUARE_CLEAN;        clean_zero_squares(square, cur_y + 1, cur_x);    }    if (check_yx(cur_y, cur_x - 1) == 0        && square[cur_y][cur_x - 1].mine == SQUARE_ZERO        && square[cur_y][cur_x - 1].type != SQUARE_CLEAN)    {        square[cur_y][cur_x - 1].type = SQUARE_CLEAN;        clean_zero_squares(square, cur_y, cur_x - 1);    }    if (check_yx(cur_y, cur_x + 1) == 0        && square[cur_y][cur_x + 1].mine == SQUARE_ZERO        && square[cur_y][cur_x + 1].type != SQUARE_CLEAN)    {        square[cur_y][cur_x + 1].type = SQUARE_CLEAN;        clean_zero_squares(square, cur_y, cur_x + 1);    }    return 0;}/*****************************************************************************//* 初始化顯示介面 */int win_init(int width, int length, int mine_num){    initscr();    raw();    noecho();    keypad(stdscr, TRUE);    curs_set(0);    refresh();    win_refresh_remine_mines(MINE_NUMBER);    win_refresh_secs(0);    int frame_width  = width  * 2 + 1;    int frame_length = length * 3 + 1;    char *line = NULL;    line = (char*)malloc((frame_length + 1) * sizeof(char));    memset(line, '-', frame_length);    *(line + frame_length) = '\0';    mvprintw(2, 0, line);NEWLINE;    int i, j;    for (j = 0; j < frame_width - 2; ++j) {        addch('|');        for (i = 0; i < length * 2 + 1 - 2; ++i) {            if (j % 2 == 0) {                if (i % 2 == 0) {                    addch(GRAPH_INIT);addch(' ');                }                else {                    addch('|');                }            }            else {                if (i % 2 == 0) {                    addch('-');addch('-');                }                else {                    addch('+');                }            }        }        addch('|');NEWLINE;    }    printw(line);NEWLINE;    /* set cursor position */    SET_CURSOR(g_cur_y, g_cur_x);    refresh();    return 0;}/* 重新整理顯示介面 */int win_refresh(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int width, int length, int mines){    if (square == NULL)        return -1;    win_refresh_remine_mines(mines);    int j, i;    for (j = 0; j < width; ++j) {        for (i = 0; i < length; ++i) {            switch (square[j][i].type) {            case SQUARE_INIT:                WPRINT_CHAR(_W(j), _L(i), GRAPH_INIT);                break;            case SQUARE_FLAG:                WPRINT_CHAR(_W(j), _L(i), GRAPH_FLAG);                break;            case SQUARE_CLEAN:                switch (square[j][i].mine) {                case SQUARE_MINE:                    WPRINT_CHAR(_W(j), _L(i), GRAPH_MINE);                    break;                case SQUARE_ZERO:                    WPRINT_CHAR(_W(j), _L(i), GRAPH_NULL);                    break;                default:                    WPRINT_NUMBER(_W(j), _L(i), square[j][i].mine);                    break;                }                break;            default:                break;            }        }    }    refresh();    return 0;}int win_refresh_remine_mines(int mines){    mvprintw(0, 0, "Mines: %d", mines);    mvprintw(1, 0, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");    refresh();    return 0;}int win_refresh_secs(int secs){    mvprintw(0, 15, "Seconds: %d", secs);    refresh();    return 0;}int win_mv_cursor(int delta_y, int delta_x, int width, int length){    CLEAN_CURSOR(g_cur_y, g_cur_x);    if (g_cur_y + delta_y < width && g_cur_y + delta_y >= 0)        g_cur_y += delta_y;    if (g_cur_x + delta_x < length && g_cur_x + delta_x >= 0)        g_cur_x += delta_x;    SET_CURSOR(g_cur_y, g_cur_x);    refresh();    return 0;}int win_destroy(){    endwin();    return 0;}int win_bang(){    mvprintw(0, 0, "BANG!!!!");    refresh();    return 0;}int win_win(){    mvprintw(0, 0, "WIN!!!!");    refresh();    return 0;}int win_game_over(){    mvprintw(1, 0, "Game Over!");    mvprintw(1, 0, "Press 'y' or 'Y' to end.");    refresh();    return 0;}/*****************************************************************************/int timer_p(){    /* 每秒鐘給主進程發一次訊號 */    do {        sleep(1);        kill(getppid(), SIGUSR1);    }    while (1);    return 0;}void sig_refresh_time(int signum){    static int secs = 0;    win_refresh_secs(++secs);}

 

這裡給出我自己編的一個可執行檔(ubuntu 10.4):

 /Files/dave_cn/mine.zip

 

-- END -- 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.