文章目錄
- 游戲介紹
- 代碼實作
- game.c
- Initboard()
- Displayboard()
- Mentmine()
- Finemine()
- Inspcoor()
- GetMinecont()
- Openboard()
- ISwin()
- Onemine()
- test.c
- game.h
- 總結
游戲介紹
掃雷是一款大眾類的益智小游戲,于1992年發行,游戲目標是在最短的時間內根據點擊格子出現的數字找出所有非雷格子,同時避免踩雷,踩到一個雷即全盤皆輸

由于代碼量比較多,我們采用多檔案的方式來模擬實作掃雷方便后期修改維護,并將每個功能都封裝成一個函式實作,
首先我們得先創建兩個源檔案和一個頭檔案
- test.c ------------------整體邏輯框架
- game.c----------------游戲程序實作
- game.h----------------存放函式宣告
代碼實作
game.c
先創建兩個二維陣列用來模擬掃雷的棋盤,創建陣列的時候我們要注意,如果想在9*9的棋盤上進行掃雷游戲的話,為了防止在邊上排雷的時候越界訪問,我們創建真實陣列的時候行和列就應該比列印出來的行列多兩行

#define ROW 9 //列印的行
#define COL 9 //列印的列
#define ROWS ROW+2 //真實的行
#define COLS COL+2 //真實的列
mine陣列用來雷的資訊,show陣列用來展示給玩家看的資訊
//儲存雷的棋盤
char mine[ROWS][COLS];
//展示的棋盤
char show[ROWS][COLS];
游戲開始先初始化棋盤,為了美觀,我將mine的棋盤初始化成空格,show棋盤初始化為’*’,
//初始化棋盤
Initboard(mine, ROWS, COLS, ' ');
Initboard(show, ROWS, COLS, '*');
代碼如下
Initboard()
//初始化棋盤
void Initboard(char board[ROWS][COLS], int rows, int cols, char ret)
{
//遍歷陣列初始化棋盤
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = ret;
}
}
}
初始化棋盤后,我們需要將用于展示的棋盤列印出以下的形狀,為了方便確認坐標,我加上了橫豎序號,

以下是列印棋盤的函式
//列印棋盤
Displayboard(show, ROW, COL);
Displayboard()
//列印棋盤
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i <= col; i++)
{
if (i == 0)
printf(" ");
else
{
printf(" %d ", i);//列印坐標列號
}
}
printf("\n");
for (i = 0; i <= col; i++)
{
if (0 == i)
{
printf(" ");
}
else
{
printf("--- ");
}
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);//列印坐標行號
for (j = 1; j <= col; j++)
{
printf("|");
printf(" %c ", board[i][j]);
}
printf("|");
printf("\n");
if (i <row)
{
printf(" ");
for (j = 1; j <=row; j++)
{
printf("|");
printf("---");
}
printf("|");
printf("\n");
}
}
for (i = 0; i <= col; i++)
{
if (0 == i)
{
printf(" ");
}
else
{
printf("--- ");
}
}
printf("\n");
}
開始布置雷,先定義一個宏表示雷的個數,然后我們在mine棋盤里面布置雷,這里我們用字符’1’來代表雷,這里需要注意的是,為了防止少雷的情況,我們傳參傳的是用于展示的行和列,
#define EASY_COUNT 10//雷
//布置雷
Mentmine(mine, ROW, COL, EASY_COUNT);
Mentmine()
布置雷的程序是隨機的,所以我們用了rand這個庫函式來實作生成亂數,不過rand這個庫函式有個弊端,它生成的數并不是完全隨機的,所以在此之前,我們需要在前面利用srand使用系統時間作為rand亂數的種子,
srand((unsigned int)time(NULL));//利用系統時間作為亂數的種子
//布置雷
void Mentmine(char board[ROWS][COLS], int row, int col, int count)
{
while (count)
{
int x = rand() % row + 1;//生成1-row的坐標
int y = rand() % col + 1;//生成1-row的坐標
if (board[x][y] == ' ')
{
board[x][y] = '1';
count--;
}
}
}
Finemine()
雷布置完后,就開始排雷了,由于技術有限,這里我就用坐標來代替滑鼠操作,排雷的程序是個回圈,直到排雷成功或者踩雷才會退出回圈,在每次輸入坐標的時候都要判斷坐標是否合法,坐標合法的情況下才能進入掃雷的程序,
//排雷
Finemine(mine, show, ROW, COL);
//排雷
void Finemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int flag = 1;
while (1)
{
char ch = 0;
int x = 0;
int y = 0;
printf("請輸入要排查的坐標:");
scanf("%d%d", &x, &y);
while (ch != '\n')//清空快取區
{
ch = getchar();
}
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (Inspcoor(show, x, y))//檢查坐標是否已經排過雷的函式,
{
printf("當前坐標已經排過雷,請重新輸入!!!\n");
continue;
}
if (mine[x][y] == '1')
{
system("cls");
printf("非常抱歉,你踩到雷了\n");
Displayboard(mine, ROW, COL);//列印雷的資訊
break;
}
else
{
int count = GetMinecont(mine, x, y);//統計坐標周圍八個坐標有幾個雷
if (count != 0)
{
show[x][y] = count + '0';//存放周圍有多少個雷的字符
}
else
{
show[x][y] = ' ';
Openboard(mine, show, x, y);//沒踩到雷則進行展開操作
}
system("cls");
Displayboard(show, ROW, COL);
if (Iswin(show, row, col) == EASY_COUNT)//判斷輸贏
{
system("cls");
printf("恭喜你,排雷成功!!\n");
Displayboard(mine, ROW, COL);//排雷成功后,把雷的布置列印在螢屏上
break;
}
}
}
else
{
printf("坐標不合法,請重新輸入!!!\n");
}
}
}
上面我們看到,在排雷的程序中我們是需要檢查輸入的坐標有沒有被排過雷,這個比較簡單,只需要判斷那個坐標對應的是不是字符’*'就可以,
Inspcoor()
//檢查輸入的坐標是否排過雷,
Inspcoor(show, x, y);
//檢查坐標是否已經排過雷
//回傳1則排過
//回傳0則沒有排過
int Inspcoor(char show [ROWS][COLS], int x, int y)
{
if (show[x][y] != '*')
{
return 1;
}
return 0;
}
GetMinecont()
在掃雷的程序中,我們需要知道這個坐標周圍的八個當中有幾個雷,或者沒有雷,先定義一個計數器,然后遍歷mine陣列的周圍八個坐標,看有沒有雷,如果有計數器自增一次,最后回傳計數器的個數,回傳的個數加上字符’0’就能得到對應的字符數字,
//統計坐標周圍八個坐標有幾個雷
int GetMinecont(char board[ROWS][COLS], int x, int y)
{
int count = 0;//計數器
if (board[x - 1][y - 1] == '1')
count++;
if (board[x - 1][y] == '1')
count++;
if (board[x - 1][y + 1]=='1')
count++;
if (board[x][y - 1]=='1')
count++;
if (board[x][y + 1]=='1')
count++;
if (board[x + 1][y - 1]=='1')
count++;
if (board[x + 1][y]=='1')
count++;
if (board[x + 1][y + 1]=='1')
count++;
return count;
}
int count = GetMinecont(mine, x, y);//統計坐標周圍八個坐標有幾個雷
if (count != 0)
{
show[x][y] = count + '0';//存放周圍有多少個雷的字符
}
else
{
show[x][y] = ' ';
Openboard(mine, show, x, y);//沒踩到雷則進行展開操作
}
如果回傳的數是0,就代表當前坐標周圍沒有雷,則進行我們的遞回展開操作
Openboard()
Openboard(mine, show, x, y);//沒踩到雷則進行展開操作
//展開操作
void Openboard(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if (GetMinecont(mine, x, y)==0)//判斷周圍是否有雷
{
show[x][y] = ' ';//把當前坐標設為空格
//遍歷當前坐標周圍八個位置
if (x > 0 && x <= ROW && y - 1 > 0 && y - 1 <= COL && show[x][y-1] == '*')
{
Openboard(mine, show, x, y - 1);
}
if (x - 1 > 0 && x - 1 <= ROW && y > 0 && y <= COL && show[x-1][y] == '*')
{
Openboard(mine, show, x-1, y);
}
if (x - 1 > 0 && x - 1 <= ROW && y + 1 > 0 && y + 1 <= COL && show[x-1][y + 1] == '*')
{
Openboard(mine, show, x - 1, y + 1);
}
if (x > 0 && x <= ROW && y - 1 > 0 && y - 1 <= COL && show[x][y - 1] == '*')
{
Openboard(mine, show, x, y - 1);
}
if (x > 0 && x <= ROW && y + 1 > 0 && y + 1 <= COL && show[x][y + 1] == '*')
{
Openboard(mine, show, x, y + 1);
}
if (x + 1 > 0 && x + 1 <= ROW && y - 1 > 0 && y - 1 <= COL && show[x+1][y - 1] == '*')
{
Openboard(mine, show, x+1, y - 1);
}
if (x + 1 > 0 && x + 1 <= ROW && y > 0 && y <= COL && show[x+1][y] == '*')
{
Openboard(mine, show, x+1, y);
}
if (x+1 > 0 && x+1 <= ROW && y + 1 > 0 && y+1 <= COL &&show[x+1][y+1] == '*')
{
Openboard(mine, show, x + 1, y+1);
}
}
else//周圍有雷的情況下//遞回的出口
{
show[x][y] = GetMinecont(mine, x, y) + '0';//存放周圍有多少個雷的字符
}
}
最后就是判斷游戲贏的條件
ISwin()
遍歷當前的棋盤,如果回傳的’*'號個數等于雷數,說明全部非雷區已經排完,則獲得勝利,跳出游戲回圈
if (Iswin(show, row, col) == EASY_COUNT)//判斷輸贏
{
system("cls");
printf("恭喜你,排雷成功!!\n");
Displayboard(mine, ROW, COL);//排雷成功后,把雷的布置列印在螢屏上
break;
}
//判斷輸贏
int Iswin(char show[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show[i][j] == '*')
{
count++;
}
}
}
return count;
}
另外,為了有游戲體驗感,防止出現玩家在第一次排雷的時候就被炸死的情況,所以設計了一個防止第一次被炸死的函式
Onemine()
//防止第一次踩到雷
Onemine(mine,show, ROW, COL);
//防止第一次踩到雷
void Onemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
char ch = 0;
int x = 0;
int y = 0;
while (1)
{
printf("請輸入要排查的坐標:>");
scanf("%d%d", &x, &y);
while (ch != '\n')//清空快取區
{
ch = getchar();
}
if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷坐標合法性
{
if (mine[x][y] == '1')
{
mine[x][y] = ' ';//補救第一次踩到雷
Mentmine(mine, row, col, 1);//呼叫布置雷的函式重新布置一個
int count = GetMinecont(mine, x, y);//統計坐標周圍八個坐標有幾個雷
if (count != 0)
{
show[x][y] = count + '0';//存放周圍有多少個雷的字符
}
else
{
show[x][y] = ' ';
}
system("cls");
Displayboard(show, ROW, COL);
break;//跳出回圈
}
else//沒踩到雷的情況下
{
int count = GetMinecont(mine, x, y);//統計坐標周圍八個坐標有幾個雷
if (count != 0)
{
show[x][y] = count + '0';//存放周圍有多少個雷的字符
}
else
{
show[x][y] = ' ';
Openboard(mine, show, x, y);//沒踩到雷則進行展開操作
}
system("cls");
Displayboard(show, ROW, COL);
break;//跳出回圈
}
}
else
{
printf("坐標不合法,請重新輸入\n");
}
}
}
最后講到這里就把我們整個游戲的邏輯給講完了,把這些邏輯整合起來就是整個游戲框架,
test.c
#include"game.h"
void game()
{
//儲存雷的棋盤
char mine[ROWS][COLS];
//展示的棋盤
char show[ROWS][COLS];
//初始化棋盤
Initboard(mine, ROWS, COLS, ' ');
Initboard(show, ROWS, COLS, '*');
//列印棋盤
Displayboard(show, ROW, COL);
//布置雷
Mentmine(mine, ROW, COL, EASY_COUNT);
//Displayboard(mine, ROW, COL);//查看布置好雷的布局
//Displayboard(mine, ROW, COL);//查看第一次踩到雷的布局
Onemine(mine,show, ROW, COL);//防止第一次踩到雷
//Displayboard(mine, ROW, COL);//查看第一次踩到雷后,雷布置去哪的布局
//排雷
Finemine(mine, show, ROW, COL);
system("pause");
}
void menu()
{
printf("**************************\n");
printf("**** 1.play ****\n");
printf("**** 0.exit ****\n");
printf("**************************\n");
}
int main()
{
char ch = 0;
int input = 0;
srand((unsigned int)time(NULL));//利用系統時間作為亂數的種子
do
{
menu();//選單
printf("請選擇:>");
scanf("%d", &input);
while (ch != '\n')//清空快取區
{
ch = getchar();
}
switch (input)
{
case 1:
system("cls");
game();
system("cls");
break;
case 0:
printf("退出游戲\n");
break;
default :
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
}
別忘了函式是需要宣告的哦,我把函式宣告都放在了自己創建的頭檔案當中,所以在使用函式的時候需要參考頭檔案,參考自己創建的頭檔案用""參考,
#include"game.h"
game.h
#include<stdio.h>
#include<stdlib.h>//rand srand
#include<time.h>//time
#define ROW 9 //列印的行
#define COL 9 //列印的列
#define ROWS ROW+2 //真實的行
#define COLS COL+2 //真實的列
#define EASY_COUNT 10//雷
//宣告函式
//初始化
void Initboard(char board[ROWS][COLS], int rows, int cols, char ret);
//列印
void Displayboard(char board[ROWS][COLS], int row, int col);
//布置雷
void Mentmine(char board[ROWS][COLS], int row, int col,int count);
//防止第一次踩到雷
void Onemine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);
//排雷
void Finemine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);
總結
在此記錄一個小白的成長程序,有什么寫的不好的地方歡迎指出,有什么問題也可以私信問我,源代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/253013.html
標籤:其他
上一篇:C語言實作掃雷小游戲
下一篇:如何用C語言實作簡單的掃雷游戲
