打開vs,新建兩個c++檔案,分別是test.c和game.c,再新建一個頭檔案game.h,
其中test.c實作主函式,game.h放函式的宣告和一些宏定義,game.h放函式的實作
讓我們開始吧!
先把原始碼拿出來供大家參考,詳細解釋在下面
test.c
#include"game.h"
void menu()
{
printf("************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("************************\n");
}
void game()
{
//創建棋盤對應的陣列
char mine[ROWS][COLS];//存放布置好的雷的資訊
char show[ROWS][COLS];//存放排查出的雷的資訊
//初始化棋盤
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//列印棋盤
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL, EASY_CONUT);
//DisplayBoard(mine, ROW, COL);
//排查雷
FineMine(mine, show, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("請選擇:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("選擇錯誤,請重新選擇!\n");
break;
}
} while (input);
return 0;
}
game.c
#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 mine[ROWS][COLS], int row, int col, int count)
{
while (count)
{
//1 - 9
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
//x,y坐標處沒有雷
mine[x][y] = '1';
count--;
}
}
}
//統計mine陣列的x,y周圍有幾個雷
int GetMine(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';
}
//排雷
void FineMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
int win = 0;
while (win<row*col - EASY_CONUT)
{
printf("請輸入要排查的坐標:>");
int x = 0;
int y = 0;
scanf("%d%d", &x, &y);
//1.坐標合法性
if (x >= 1 && x <= row&&y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, row, col);
break;
}
else
{
//2.該坐標是不是雷?不是雷,統計雷的個數
int count = GetMine(mine, x, y);
show[x][y] = count + '0';//存放數字字符
DisplayBoard(show, row, col);
win++;
}
}
else
{
printf("坐標非法,請重新輸入!\n");
}
}
if (win == row*col - EASY_CONUT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, row, col);
}
}
game.h
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define EASY_CONUT 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);
//mine - 存放雷的資訊
//count - 布置的雷的個數
void SetMine(char mine[ROWS][COLS],int row,int col,int count);
//排雷
void FineMine(char mine[ROWS][COLS],
char show[ROWS][COLS],
int row,
int col);
統計mine陣列的x,y周圍有幾個雷
int GetMine(char mine[ROWS][COLS], int x, int y);
-----------------------------------------
游戲玩一次不夠可以一直玩,所以首先我們要在主函式里面寫一個do-while回圈,使我們有個入口進入游戲,完整代碼如下
int input = 0;
do
{
menu();
printf("請選擇:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("選擇錯誤,請重新選擇!\n");
break;
}
} while (input);
這里我們將游戲選單封裝成一個menu函式,menu函式的代碼如下
void menu()
{
printf("************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("************************\n");
}
選擇1后我們可以進入游戲,定義一個game()函式,而最開始我們應該列印兩個掃雷棋盤,一個是全是*的游戲棋盤,是我們之后用來玩的,另一個是由字符0組成的棋盤,是方便我們觀察雷是否布置成功和雷是如何布置的,
這里遇到了一個問題,當我們在排棋盤邊界上的雷的時侯,例如排左上角第一個雷,只能掃描出周圍三個格子的情況,對于邊界外的情況其實是未知的,因此我們在邊上還需要一圈格子
我們以9×9的掃雷舉例,我們應該創建一個11×11的棋盤,我們初始化11×11的棋盤,但我們顯示在程式中是一個9×9的棋盤,這就完美地解決了上面的問題,當我們創建掃雷棋盤的時候,我們需要定義兩個字符二維陣列,一個用來玩,一個用來布置雷
用來玩的棋盤為show,布置雷的棋盤為mine
//創建棋盤對應的陣列
char mine[ROWS][COLS];//存放布置好的雷的資訊
char show[ROWS][COLS];//存放排查出的雷的資訊
為了方便以后改動棋盤的尺寸而不僅僅是玩9×9的掃雷,我們先在game.h里寫一下宏定義
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
回到game函式里,此時要初始化棋盤,為了方便之后的操作,我們把我們mine棋盤初始化為字符0,之后布置雷的時候把有雷的地方改成字符1
而show棋盤就是要玩的棋盤,我們玩的時候不知道雷的具體布置情況,所以我們把show棋盤初始化為字符*
具體代碼如下
//初始化棋盤
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
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;
}
}
}
初始化完成后我們可以先列印出掃雷棋盤看看,因此定義一個顯示棋盤的函式DisplayBoard(),注意我們列印的時候應該傳9進去而不是11.
具體代碼如下(為了方便看出棋盤坐標,我在以下的代碼加入了一個簡易的二維坐標系)
//列印棋盤
DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
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");
}
完成列印棋盤的函式后,我們可以編譯運行一下看看效果,效果如下圖

完成棋盤的列印后,我們開始布置雷,定義一個SetMine()函式,EASY_COUNT為我們設定的雷的個數,在頭檔案中定義
//布置雷
SetMine(mine, ROW, COL, EASY_CONUT);
函式代碼如下
void SetMine(char mine[ROWS][COLS], int row, int col, int count)
{
while (count)
{
//1 - 9
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
//x,y坐標處沒有雷
mine[x][y] = '1';
count--;
}
}
}
其中x,y是設定的布置的雷坐標,布置的雷是隨機布置,因此我們這里用了庫函式rand(),但它的回傳值是一個偽隨機值,不夠隨機,因此我們應在main()函式的最開頭加上這么一句,以實作真正的隨機,
srand((unsigned int)time(NULL));
在頭檔案中我們可以修改宏定義來調整布置的雷的引數,這里以布置10個雷為例,布置雷的時候我們還要進行一下判斷,該格子不是雷(字符0)才能布置雷,
設定一個while回圈,當成功布置一個雷,count--;
當雷布置完后,count=0,跳出回圈
隨機的布置完雷后我們可以再呼叫一下DisplayBoard函式來看看布置雷完后的效果
//布置雷
SetMine(mine, ROW, COL, EASY_CONUT);
DisplayBoard(mine, ROW, COL);

可以看到其中的1就是我們隨機布置的雷
布置完雷之后的下一步就要開始排雷了,這里我們再定義一個排雷函式FineMine函式
//排查雷
FineMine(mine, show, ROW, COL);
//排雷
void FineMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
int win = 0;
while (win<row*col - EASY_CONUT)
{
printf("請輸入要排查的坐標:>");
int x = 0;
int y = 0;
scanf("%d%d", &x, &y);
//1.坐標合法性
if (x >= 1 && x <= row&&y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, row, col);
break;
}
else
{
//2.該坐標是不是雷?不是雷,統計雷的個數
int count = GetMine(mine, x, y);
show[x][y] = count + '0';//存放數字字符
DisplayBoard(show, row, col);
win++;
}
}
else
{
printf("坐標非法,請重新輸入!\n");
}
}
if (win == row*col - EASY_CONUT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, row, col);
}
}
思路:輸入你認為不是雷的坐標,輸入坐標后,要進行判斷,
判斷該坐標的合法性(以9×9為例,判斷輸入的坐標范圍是否在9×9的范圍內),若坐標非法,則提示重新輸入,然后回圈,輸入,
若坐標合法,則判斷該坐標是否是雷,若是雷,則游戲結束,展示整個雷盤并跳出回圈,
若該坐標不是雷,則需要統計雷的個數,并將周圍雷的個數展示在該坐標上
這里再定義一個用來統計雷的函式GetMine()
//統計mine陣列的x,y周圍有幾個雷
int GetMine(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';
}
思路:在前面初始化棋盤和布置棋盤的時候,我們采用的方法是此坐標不是雷,則為字符0,此坐標是雷,則為字符1
這種方法的好處在于方便我們這一步的統計雷,我們可以計算坐標x,y周圍8個格子里的字符數字之和,然后減掉8×字符0,回傳的值便是該坐標周圍8個格子的藏雷數
但是這是棋盤是一個字符陣列,我們再把回傳的值加上字符0,便得到該值的數字字符,然后我們可以呼叫DisplayBoard函式來展示棋盤,每輸入一次坐標展示一次棋盤,形成一個回圈,
那么問題又來了,回圈什么時候停止呢,
我寫的這個掃雷程式,贏的規則是把棋盤上所有不是雷的坐標都以輸入的方式排查出來,換句話說,就是當你輸入的坐標個數等于布置的雷的個數,就說明排雷成功,
因此這里我們可以初始化一個變數win=0,每成功輸入一個非雷的坐標,win++,
而回圈的判斷條件便是win的值和(棋盤格子總數-布置的雷的個數)的值進行比較,當win<總數-雷的個數時,說明雷還沒排完,回圈繼續,
當最后一次完成排雷,兩值相等,排雷完畢,跳出回圈,進行一次兩個值的比較判斷(因為跳出回圈也有可能是被雷炸死,而被雷炸死時兩值不相等,所以有必要進行值的比較判斷),
若兩值相等,便顯示排雷成功,然后再呼叫DisplayBoard函式展示一下你成功排完雷的棋盤,
-----------------------------分割線-----------------------------
一切就緒后,我們再把game函式中的DisplayBoard(mine, ROW, COL)和注釋掉,如下:
void game()
{
//創建棋盤對應的陣列
char mine[ROWS][COLS];//存放布置好的雷的資訊
char show[ROWS][COLS];//存放排查出的雷的資訊
//初始化棋盤
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//列印棋盤
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL, EASY_CONUT);
//DisplayBoard(mine, ROW, COL);
//排查雷
FineMine(mine, show, ROW, COL);
}
這樣布置雷的棋盤就不會顯示出來了,我們就可以開始玩了
為了方便演示效果,我把雷的個數改成了80個
編譯運行結果如下

我們可以看到,81個格子中只有坐標(6,5)不是雷,這便是掃雷游戲啦!
新人創作,若有意見和建議可在評論區提出,有不明白的地方也可以私信我探討
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/253014.html
標籤:其他
上一篇:C語言模擬實作掃雷游戲(可展開)
下一篇:三子棋(井字棋)的實作
