用C語言完成:掃雷。


上一篇我們介紹了三子棋游戲小程序,

那這一篇我來介紹另一個簡單的游戲小程序——掃雷。

相信大家都玩過windows下的掃雷游戲,對其的規則也比較了解,

這里我們就不對規則做過多贅述了。

首先菜單和主函數的編寫和上一篇三子棋中的內容一致,

這里我們直接給出代碼:

void menu()
{
    printf("*********  Welcom  to  Mines  *********\n");
    printf("***************************************\n");
    printf("*      1.play             0.exit      *\n");
    printf("***************************************\n");
}

int main()
{
    int choice;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("Input your choice:");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            game();
            break;
        case 0:
            break;
        default:
            printf(" Input error!Please try again.\n");
            break;
        }
    } while (choice);
    return 0;
}

下面展示我的代碼寫出的菜單和主函數:

一樣,我們先定義一個game()函數,而后慢慢填充其中的內容。

和三子棋不同的是,這里需要創建兩個數組,其中一個是雷區數組,另一個是需要輸出在屏幕上的顯示數組。

為了便於區分兩個數組,雷區數組我用mines表示,顯示數組我用show_area來表示。

但這一步我們先跳過,先來完成初始化數組的功能函數。

這次我選擇使用memset()函數來進行初始化操作。

在init函數中,我們需要將雷區數組全部賦成“0”,“0”表示沒雷。

將顯示數組全部初始化為“.”,“.”表示未探索區域。

由於是掃雷程序,那么在雷區中一定要有雷才行,所以我們用上一篇提到的rand()來隨機生成坐標指向雷區數組的元素,

並將其賦值為“1”,“1”表示有雷。

代碼如下:

void init_mines(char mine[ROWS][COLS],char show[ROWS][COLS],int rows,int cols,int row,int col)
{
    int i, x, y;
    memset(mine, '0', rows*cols*sizeof(char));
    memset(show, '.', rows*cols*sizeof(char));
    for (i = 0; i < MINES; i++)
    {
        while (1)
        {
            x = rand() % row + 1;
            y = rand() % col + 1;
            if (mine[x][y] == '0')
            {
                mine[x][y] = '1';
                break;
            }
        }
    }
}

當用戶完成每次掃雷操作后,一定要打印出當前的狀況,這時就需要一個顯示功能函數display()。

代碼如下:

void display(char mine[ROWS][COLS],int row,int col)
{
    int i, j;
    for (i = 1; i <= row; i++)
    {
        printf("%4d", i);
    }
    printf("\n");
    for (i = 1; i <= col; i++)
    {
        printf("%2d", i);
        for (j = 1; j <= col; j++)
        {
            printf(" %c  ", mine[i][j]);
        }
        printf("\n");
    }
}

為了用戶體驗,我們在打印出的雷區上方和左方加上了行數、列數,方便用戶觀察坐標。

下面展示用我的代碼打印出的雷區數組,和初始化后的顯示數組:

這時我們就需要利用掃雷規則來編寫完成checkwin()函數,以判斷是否勝利。

這里我們首先判斷其是不是雷,

如果不是雷,我們再編寫一個checkmine()函數,用來遍歷其周圍雷的個數,並將個數填入顯示數組中對應的元素中。

如果是雷,則返回一個值“*”,“*”表示被炸死。

最后判斷是否勝利。

我們先定義一個count變量,用來記錄未探索區域的個數,

如果未探索區域的個數和初始化時隨機生成的雷的個數相等,則表示雷排完了,

返回一個值“w”,“w”表示勝利。

代碼如下:

int checkwin(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col,int x,int y)
{
    int count = 0;
    if (mine[x][y] == '0')
        show[x][y] = checkmine(mine, show, x, y);
    else return '*';
    for (x = 1; x <= row; x++)
    {
        for (y = 1; y <= col; y++)
        {
            if (show[x][y] == '.')
                count++;
        }
    }
    if (count == MINES)
        return 'w';
    return 0;
}

接着我們給出上面提到的,用來遍歷該坐標周圍雷數的checkmine()函數。

static char checkmine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
    int m, n;
    char mine_count = '0';
    for (m = x - 1; m <= x + 1 ; m++)
    {
        for (n = y - 1; n <= y + 1; n++)
        {
            if (mine[m][n] == '1')
                mine_count++;
        }
    }
    return mine_count;
}

由於該代碼只在該源文件中使用,所以我在其類型前加上了static。

 

這時我們就完成了掃雷各個功能函數的編寫,接着根據我們平時玩游戲的思路將上述函數引入game()中即可完成簡單掃雷的編寫。

game()函數的代碼如下:

void game() { char mines[ROWS][COLS], show_area[ROWS][COLS], ret; int x, y; init_mines(mines, show_area, ROWS, COLS, ROW, COL); display(show_area, ROW, COL); while (1) { printf("Input x and y(like x y):"); scanf("%d %d", &x, &y); if (x >= 1 && x <= ROW && y >= 1 && y <= COL) { ret = checkwin(mines, show_area, ROW, COL, x, y); if (ret == 'w') { display(mines, ROW, COL); printf("Congratulations!You win!\n"); break; } else if (ret == '*') { display(mines, ROW, COL); printf("You lose!Good luck next time!\n"); break; } else { display(show_area, ROW, COL); printf("\n"); } } else printf("Input error!Please try again.\n"); } }

和三子棋一樣,我這里定義數組時也運用了宏定義。

下面展示除勝利外的幾種情況:

1、在(1,2)周圍有1個雷。

2、被炸死。

最后放上我自己寫出的代碼:

代碼分為三部分,

第一部分是頭文件:

#ifndef __MINES_H__
#define __MINES_H__ #include<stdio.h> #include<time.h> #include<stdlib.h> #include<string.h> #define COLS 12 #define ROWS 12 #define COL 10 #define ROW 10 #define MINES 10 void init_mines(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols, int row, int col); void display(char mine[ROWS][COLS], int row, int col); int checkwin(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y); #endif//__MINES_H__

第二部分是源文件的函數部分:

#include"mines.h" void init_mines(char mine[ROWS][COLS],char show[ROWS][COLS],int rows,int cols,int row,int col) { int i, x, y; memset(mine, '0', rows*cols*sizeof(char)); memset(show, '.', rows*cols*sizeof(char)); for (i = 0; i < MINES; i++) { while (1) { x = rand() % row + 1; y = rand() % col + 1; if (mine[x][y] == '0') { mine[x][y] = '1'; break; } } } } void display(char mine[ROWS][COLS],int row,int col) { int i, j; for (i = 1; i <= row; i++) { printf("%4d", i); } printf("\n"); for (i = 1; i <= col; i++) { printf("%2d", i); for (j = 1; j <= col; j++) { printf(" %c ", mine[i][j]); } printf("\n"); } } static char checkmine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { int m, n; char mine_count = '0'; for (m = x - 1; m <= x + 1 ; m++) { for (n = y - 1; n <= y + 1; n++) { if (mine[m][n] == '1') mine_count++; } } return mine_count; } int checkwin(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col,int x,int y) { int count = 0; if (mine[x][y] == '0') show[x][y] = checkmine(mine, show, x, y); else return '*'; for (x = 1; x <= row; x++) { for (y = 1; y <= col; y++) { if (show[x][y] == '.') count++; } } if (count == MINES) return 'w'; return 0; }

這部分內容,我並沒有完成關鍵的2點。 1、為了用戶體驗,在第一次用戶執行掃雷操作時,不會被炸死。

2、當用戶輸入的坐標周圍沒雷時,可以實現無雷區的展開。

第三部分是源文件的游戲測試部分:

#include"mines.h" void menu() { printf("********* Welcom to Mines *********\n"); printf("***************************************\n"); printf("* 1.play 0.exit *\n"); printf("***************************************\n"); } void game() { char mines[ROWS][COLS], show_area[ROWS][COLS], ret; int x, y; init_mines(mines, show_area, ROWS, COLS, ROW, COL); display(mines, ROW, COL); display(show_area, ROW, COL); while (1) { printf("Input x and y(like x y):"); scanf("%d %d", &x, &y); if (x >= 1 && x <= ROW && y >= 1 && y <= COL) { ret = checkwin(mines, show_area, ROW, COL, x, y); if (ret == 'w') { display(mines, ROW, COL); printf("Congratulations!You win!\n"); break; } else if (ret == '*') { display(mines, ROW, COL); printf("You lose!Good luck next time!\n"); break; } else { display(show_area, ROW, COL); printf("\n"); } } else printf("Input error!Please try again.\n"); } } int main() { int choice; srand((unsigned int)time(NULL)); do { menu(); printf("Input your choice:"); scanf("%d", &choice); switch (choice) { case 1: game(); break; case 0: break; default: printf(" Input error!Please try again.\n"); break; } } while (choice); return 0; }

希望各位能對我的代碼提出意見和建議,並能指導我完成第二部分鍾我未完成的兩點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM