今天再來給大家分享用C語言知識來實現一個簡單的掃雷遊戲過程。
掃雷這個遊戲的原理想必大家都是比較清楚的了,這裡再來向大家簡單的介紹一下。
下面是一個9*9的掃雷棋盤
我們首先隨機的在棋盤上點選一個位置,如果該位置被佈置了雷,那麼很遺憾你直接被炸死了,如果沒有雷,那麼他會在該位置顯示出他周圍八個位置雷的個數,如果該位置有一個雷,就顯示數位1,有兩個雷就顯示數位2,依次類推。玩家根據提示把全部的安全位置都找到後,就會獲得遊戲的勝利。這就是掃雷遊戲的簡單規則。
接下來介紹C語言的實現過程。
在上一篇中我們剛剛介紹過了三子棋遊戲的實現,我們就可以借鑑三子棋的遊戲框架,只需改變遊戲模組的內容即可。所以我們建立一個test.c檔案來寫主函數部分,再建立一個game.c檔案來實現遊戲部分內容,在建立一個game.h檔案來宣告函數。
首先我們還是先簡單來看一下主函數部分,用do while迴圈來實現。
程式碼如下:
int main()
{
int input = 0;
do
{
menu();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();//掃雷遊戲
break;
case 0:
printf("退出遊戲\n");
break;
default:
printf("選擇錯誤!\n");
break;
}
} while (input);
return 0;
}
先給一個選單,選擇1進入遊戲,選擇0退出遊戲,選擇其他值則重新輸入。
接下來來看選單部分,很簡單,只需要一個函數來實現簡單的列印功能即可。
程式碼如下:
void menu()
{
printf("**********************\n");
printf("**** 1. play ***\n");
printf("**** 0. exit ***\n");
printf("**********************\n");
}
寫完這個函數我們就可以將選單列印到螢幕上了。
好了,接下來我們來實現這個遊戲最重要的部分,遊戲函數部分。
這次我們就需要我們站在遊戲設計的角度來看待這個遊戲,怎樣才完成一個掃雷遊戲呢,簡單的來概括有以下兩步:①設定雷。 ②排雷。
首先作為設計者,我們應該給玩家在一組棋盤上提前埋好雷,很顯然在C語言中我們可以用一個特定的字元來表示雷,而安全的地方我們就可以用另一個字元來表示。寫到這裡接下來的步驟顯然已經很明顯了,我們需要建立一個二維陣列來存放雷的位置和安全區域的位置。今天我們這裡就來設計一個9*9的掃雷吧,所以我們需要設計一個9*9的二維陣列。
建立好了這個二維陣列,也就是我們的棋盤,接下來要做的就是初始化棋盤。寫到這裡我想提問大家一下,如果我們這建立一個二維陣列夠嗎?顯然是不夠的,因為我們建立的這個二維陣列是來存放雷的,難道我們給玩家的棋盤能夠是我們存放雷的這個棋盤嗎?這樣的話我們雷的位置不就全部暴露出來了嗎?所以我們需要建立兩個二維陣列,一個是我們用來存放雷的陣列,一個是用來展示給玩家的陣列,而我們倒時候只需要把雷的位置傳給展示給玩家的陣列即可。
初始化之前我想先請大家簡單的思考一下游戲過程,我們排雷的時候需要排查這個元素周圍八個元素的位置裡有沒有雷,而如果這個元素在中間的話,我們可以成功的找到他周圍的八個元素,那麼如果這個元素在這個陣列的邊緣處,那麼我們在排查的時候沒有八個位置排查的話就會出錯,所以我們實際上需要建立一個11*11的二維陣列來保證我們9*9陣列的每一個元素周圍都是有元素的,這樣才不會出錯。
同樣的我們可以參考三子棋時候的寫法,我們建立兩個全域性變數來存放我們需要展示的陣列行和列,在建立兩個全域性變數給前面的全域性變數加2來存放實際建立陣列的行和列,這樣就不會把程式碼寫死。
我們給埋雷的陣列全部初始化為’0’,展示的陣列全部初始化為’*’.
程式碼如下:
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
我們只需設定相應的實參就可以給陣列初始化不同的元素
陣列初始化完成之後,我們接下來應該考慮的是,我們所寫好的陣列是不是要給玩家看啊,給玩家看是不是就意味著我們要將陣列列印到螢幕上。所以我們還需要再寫一個列印函數來吧我們的陣列列印到螢幕上。
程式碼如下:
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----------------------------------\n");
//列號的列印
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
//每一行最前面的行號
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("----------------------------------\n");
}
這裡我們需要注意,我們建立陣列的時候建立的是11*11的陣列,是避免邊緣元素排查出錯。而展示給玩家的時候,我們需要展示9*9的棋盤給玩家看,所以展示陣列的時候我們接收的應該是展示的行和列9.我們還看到列印函數的程式碼中我們還對棋盤進行了修飾,上下列印了分割線,還在周圍列印了行和列的號。
棋盤初始化完之後,我們就需要給埋雷的棋盤上埋雷了。
埋雷的時候我們先要確定埋雷的數量,這裡我們也可以定義一個全域性變數來確定我們埋雷的個數。我們知道掃雷遊戲也是有難度的,這樣我們就可以根據我們埋雷的數量來劃分遊戲的難度,使遊戲更加靈活多變。接下來我們需要隨機生成一個位置去放置雷,生成的隨機值我們還是用rand函數來實現,以時間戳作為srand函數的起點,這樣我們就可以得到這個隨機值了。我們還要注意,這個隨機值的座標在我們初始化的11*11棋盤中的範圍應該是1-9.
程式碼如下:
void SetMine(char board[ROWS][COLS], int row, int col)
{
//1. 隨機找座標佈置雷
//佈置多少個雷 - 10
int count = EASY_COUNT;
while (count)
{
//佈置成功一個雷,count--
//1. 生產隨機的座標
int x = rand() % row + 1;//1-9
int y = rand() % col + 1;//1-9
//2. 佈置
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
我們看到用一個簡單的while就可以實現埋雷的過程,這裡我們用字元’1’,代表雷。
寫到這裡可以看一下我們棋盤的效果了,我們可以將埋雷棋盤和展示棋盤用列印函數列印出來看一下。
如下圖:
上面是我們展示的棋盤,下面是我們埋雷的棋盤。
雷埋好之後就剩下最後一個掃雷的步驟了,接下來我們就來實現掃雷的程式碼。
掃雷的過程是這樣的,首先玩家要輸入一個座標。
接下來第一步我們要先判斷他輸入的這個座標是不是雷,如果他直接輸入一個雷的座標,那麼我們就需要需要提示他被炸死了,需要重新開始一把遊戲。
如果他輸入的座標不是雷,那麼我們接下來就要統計這個座標周圍的雷的個數。這個步驟我們放在一個函數中進行,接下來我們來介紹這個函數的功能。
統計一個座標周圍雷的個數,一般思維就是挨個檢查,這樣當然是可以的,但是有點麻煩,這裡向大家介紹一種非常巧妙的方法。我們知道,我們設定為安全的位置是字元’0’,有雷的位置是’1’, **我們只需把他周圍的八個元素加起來不就得到雷的個數了嗎?**但是我們需要注意,這裡的’1’和’0’是字元,不是數位,他們對應的ASCII碼值分別是48和49,所以我們計算的時候應該用加起來的數再減去字元’0’,然後把這個結果作為返回值返回過去,這樣我們就可以輕鬆得到周圍雷的個數了。
程式碼如下:
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0';
}
我們就可以通過以上程式碼實現當輸入座標不是雷的時候用來標記該座標周圍雷的個數。
那麼標記之後,我們是不是還得判斷遊戲是否勝利了啊,這裡我們可以檢測玩家排除安全區域的個數,棋盤上棋子的總個數我們是知道的,就是9*9=81,雷的個數也是已知的。所以我們用總數目減去雷的位置數目就是安全區域的數目。接下來我們可以檢測排除的安全區域個數是否檢測完畢,如果檢查完畢,則判斷玩家遊戲勝利。
程式碼如下:
void FindMine(char mine[ROWS][COLS],
char show[ROWS][COLS],
int row,
int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判斷x,y座標處是否是雷
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, row, col);
break;
}
else
{
//如果x,y座標不是雷,就統計周圍有幾個雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("座標非法\n");
}
}
if (win == ROW*COL - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, row, col);
}
}
以上就是實現掃雷遊戲的全部步驟。當然這裡我們只是設計了一個簡易的掃雷遊戲,還有許多地方可以繼續優化的,如果大家有興趣,下去之後還可以自己再完善一下這段程式碼。希望我的這篇文章能給大家帶來幫助。
最後將這個遊戲的完整程式碼留給大家。
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("**********************\n");
printf("**** 1. play ***\n");
printf("**** 0. exit ***\n");
printf("**********************\n");
}
void game()
{
//真正掃雷的過程
//建立2個陣列
//存放佈置好的雷
char mine[ROWS][COLS] = { 0 };//'0'
//存放排查出來的雷的資訊
char show[ROWS][COLS] = { 0 };//'*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
DisplayBoard(show, ROW, COL);
//佈置好的雷的資訊不應該輕易列印
//DisplayBoard(mine, ROW, COL);
//1. 佈置雷
SetMine(mine, ROW, COL);
//2. 掃雷
FindMine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
//time_t -- 整形
srand((unsigned int)time(NULL));//設定亂數的生成起點的
do
{
menu();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();//掃雷遊戲
break;
case 0:
printf("退出遊戲\n");
break;
default:
printf("選擇錯誤!\n");
break;
}
} while (input);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----------------------------------\n");
//列號的列印
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
//每一行最前面的行號
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("----------------------------------\n");
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
//1. 隨機找座標佈置雷
//佈置多少個雷 - 10
int count = EASY_COUNT;
while (count)
{
//佈置成功一個雷,count--
//1. 生產隨機的座標
int x = rand() % row + 1;//1-9
int y = rand() % col + 1;//1-9
//2. 佈置
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0';
}
//
//掃雷遊戲是怎麼結束的?
//1. 炸死了
//2. 正常排查了所有不是雷的位置
//
void FindMine(char mine[ROWS][COLS],
char show[ROWS][COLS],
int row,
int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判斷x,y座標處是否是雷
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, row, col);
break;
}
else
{
//如果x,y座標不是雷,就統計周圍有幾個雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("座標非法\n");
}
}
if (win == ROW*COL - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, row, col);
}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define EASY_COUNT 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//列印棋盤
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void SetMine(char mine[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//一定的程式設計邏輯+
//陣列-二維陣列
//函數 - 組合在一起 - 功能
//迴圈-變數