前言
本篇文章使用C語言實作簡單小游戲---掃雷,(文章最后有完整代碼鏈接)
想必大多數人都玩過或者了解過掃雷的游戲規則,但是在這里,我們在一起重溫一下掃雷的游戲規則,也更好的讓我們了解程式的實作目的,
掃雷:掃雷就是要把所有非地雷的格子揭開即勝利;踩到地雷格子就算失敗,游戲主區域由很多個方格組成,使用滑鼠左鍵隨機點擊一個方格,方格即被打開并顯示出方格中的數字;方格中數字則表示其周圍的8個方格隱藏了幾顆雷,

在了解游戲規則后,我們就用C語言來實作這個簡單小游戲,
這是我們解決資源管理器內所創建的檔案,下來我們就進入代碼內部,

一,游戲使用到的頭檔案和游戲宣告
1.頭檔案的包含
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
2.符號的宣告
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
3.函式的宣告
初始化棋盤
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);
二,游戲測驗
1. 主函式
和三子棋一樣,主函式仍然簡單,函式內部呼叫test()測驗函式,
int main()
{
test();
return 0;
}
2.test()函式
void test()
{
int input = 0;
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);
}
決議test()函式內部:
A. srand((unsigned int )time(NULL))
利用時間戳,形成亂數,主要目的是實作游戲中地雷的隨機埋放,
B.menu() 游戲選單
void menu()// 游戲選單
{
printf("********************\n");
printf("**** 1. play *****\n");
printf("**** 0. exit *****\n");
printf("********************\n");
}
創建選單,實作效果演示:

C:switch case 選擇陳述句:
使用此陳述句實作玩家的自主選擇,當輸入1時進行掃雷游戲,當輸入0時,退出游戲,顯示效果如下:

3.game()函式
game()函式是主要游戲實作函式,以下是game函式主要是實作邏輯圖和實作順序

這里先讓大家看一下完整代碼,實作順序如上所示:

下面主要進入我們的游戲實作邏輯當中......劃重點
三,游戲實作
1.創建棋盤
// 創建陣列
// 創建雷的陣列(mine) 顯示的陣列(show) 兩個陣列一樣規模 一樣型別
char mine[ROWS][COLS] = { 0 }; // 存放布置好的雷的資訊
char show[ROWS][COLS] = { 0 }; // 存放排查出的雷的資訊
在這里我們需要創建2個相同大小,相同型別的二維陣列,
問:我們為什么要創建2個相同的陣列呢?
答:是因為我們在玩掃雷的時候我們首先看到的是一個未知得棋盤,不知道哪里埋放著雷,如果我們觸碰到雷結束游戲后,我們需要給玩家呈現這局游戲所有點位的情況,這樣以便于玩家清楚所有雷都在那里,為什么死,因此我們需要兩個棋盤才能完成這項任務,
在這里我們創建了11X11大小的棋盤,但是只顯示9X9大小的棋盤也就是81個格子,打算埋放10顆雷,玩家可以在頭檔案自行更改雷的個數,
問:我們顯示9X9大小的棋盤,為什么創建11X11大小的棋盤?
答:這是因為掃雷游戲規則中,我們在排雷的程序中,會顯示周圍8個格子的雷的個數,如果創建一個9X9的格子,那當我們在邊角的時候,我們周圍的格子不夠8個,但是我們還要訪問周圍8個格子,這時候我們必然會造成陣列越界問題,具體情況如下圖所示,這時候我們如果創建11X11的棋盤,對11X11的棋盤都初始化為字符' 0 ', 我們只顯示內部的9X9的格子,我們依然不會影響游戲,并且也解決了陣列越界的問題,
如圖所示,我們假設要查找坐標為(9,9)格子周圍8個格子的雷的個數,如果我們還只是9X9的格子,我們圖中的紅色陰影區域就處于陣列的范圍之外,因為我們需要創建11X11的棋盤,就可以輕松化解這個問題,

2.初始化棋盤
// 初始化mine陣列為全'0'
InitBoard(mine,ROWS,COLS,'0');//初始化--->棋盤函式
// 初始化show陣列為全'*'
InitBoard(show,ROWS,COLS,'*');//初始化--->棋盤函式
和三子棋一樣,我們依然自定義函式InitBoard(),具體代碼如下:
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0, j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
在這里我們對第一塊mine棋盤全部初始化為字符 ' 0 ' (注意這里是字符0,不是數字0),我們對第二塊show棋盤全部初始化為字符' * ' ,最終玩家首先會看到一幅全是字符' * '的棋盤,這樣也符合游戲規則,
3.列印棋盤
自定義函式DisplayBoard(),具體代碼如下:
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;
//列號的列印
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");
}
}
這樣通過呼叫DisplayBoard()函式我們可以檢查一下,我們剛才所創建和初始化的棋盤是否符合我們的要求,我們列印棋盤演示如下:


我們發現,列印出來的棋盤也完全符合我們的要求,我們也只需要最終將show棋盤顯示給玩家即可,
4.布置雷
在這里我們自定義函式SetMine()函式,具體代碼如下:
// 布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
我們對此代碼進行分析:
A:如何實作隨機布雷?
答:我們創建rand函式,利用時間戳生成亂數,因為我們所創建的棋盤大小是9X9大小,我們我們只需要給生成的亂數模上row(col)即可得到0~row-1 ,因此我們再 +1 即可得到一個在0~row(col)的亂數,從而實作隨機布雷,

我們設定count個雷,如果我們埋下一顆雷,我們就count-1,同時我們將初始化的字符' 0 ' 變成字符' 1 ' , 只有我們識別到目標格子是字符 ' 0 ' 時才會埋雷,這也解決了在同一位置重復埋雷的問題,
假設我們隨機埋下10顆雷,演示一下棋盤:

我們發現,我們隨機埋下了10顆雷,并且也改成了字符' 1 '
5.排雷
自定義函式FindMine(),具體代碼如下所示:
// 排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int win = 0;
while (win<ROW*COL- EASY_COUNT) {
printf("請輸入要排查的坐標:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遺憾你被炸死了\n");
DisplayBoard(mine, row, col);
break;
}
else
{
//計算x,y坐標周圍有幾個雷
int n = get_mine_count(mine,x,y);
show[x][y] = n+'0'; // 數字+'0'可以轉換成對應的ASCII
DisplayBoard(show, row, col);
win++;
}
}
else
{
printf("輸入坐標非法,無法排雷,請重新輸入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, row,col);
}
}
其中呼叫了get_mine_count函式,其代碼如下:
static int get_mine_count(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~row(col)之間的數字,如果在此之外,我們將會提醒玩家“輸入坐標非法,無法排雷,請重新輸入”字樣,
當我們輸入正確的坐標時候,我們需要對這個坐標下所對應的字符進行判斷,如果是字符' 1 ' ,說明踩中雷,說明游戲結束,這時候我們將完整棋盤列印出來,玩家也可以了解本局游戲的情況,
如果是字符 ' 0 ' ,說明玩家沒有踩中雷,根據游戲規,我們需要顯示這個格子周圍8個格子中存在雷的個數,這時候我們呼叫了get_mine_count函式,我們先看一下統計周圍雷的個數的代碼:
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';
我們發現,此代碼將周圍8個格子的字符全部加了起來,我們知道如果是字符 ' 0 ' 和字符 ' 1 '所對應的ASCII碼值相差1,我們可以通過ASCII碼值來進行判斷,我們將周圍8個字符相加,然后再減去8個字符' 0 ' 的和,這樣,我們就可以得到周圍8個格子中有多少個字符 ' 1 ' 的格子,也就是雷的個數,
為了方便大家理解,我們假定有10個雷,我們將Mine棋盤和show棋盤都顯示,我們根據棋盤制定輸入,看是否可以得到我們想要的結果:

如果我們排除萬難,最終將81個格子排完,我們將會獲得勝利,具體判斷代碼如下:
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, row,col);
}
我們這里假定有80個雷,我們顯示一下:

至此,我們掃雷小游戲也寫完了,完整代碼我也放在我的Gitee倉庫,鏈接如下:
C語言: C語言代碼學習-練習 - Gitee.com

其中這3個對應資源管理器3個檔案

總結
本節內容主要用C語言實作了小游戲---> 掃雷,大家可以拷貝到編譯器里面玩一玩,如果大家覺得還不錯有識訓的話,點贊收藏走一波唄~
由于我的個人技術水平有限,各位大佬發現錯誤及時指出哦~
這里是 用C語言實作《三子棋 》 小游戲的鏈接,大家有興趣也可以看看哦:
[ C語言 ] 用C語言實作小游戲 ---- 三子棋 代碼 + 決議_小白又菜的博客-CSDN博客
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/357214.html
標籤:其他
上一篇:C語言實作初級掃雷
下一篇:論文筆記:Adaptive event detection for Representative Load Signature Extraction
