有幸在鵬哥的指導下寫出了掃雷游戲,相比于上一次的三子棋代碼,掃雷代碼更加考驗一個程式員對于陣列的靈活運用,也再一次激起了我對代碼的興趣和熱情
在講解掃雷代碼前,先來介紹一下掃雷是個什么游戲,在沒要用C語言寫出掃雷之前我其實連掃雷是什么都不知道,兒時玩掃雷的時候就是一通瞎點,然后砰!的一下炸,游戲就失敗了
掃雷的游戲界面是這樣的:

最左邊紅色的數字就是這個棋盤里面埋了99個雷,右邊紅色的數字代表的是玩家所進行的時間

運氣不好,點了兩下就死掉了
調節一下游戲難度
現在這就是一個10x10的一個邊框,里面含有10個雷的棋盤
這里先點擊一下,出現了一個1

這個1的意思就是指,以它為中心的八個格子中有一顆地雷在附近
(因為沒有找到合適的效果就重開了一把,大概就是這樣)

看!這個游戲已經失敗了,顯示出來的雷中在1的周圍只有1個地雷,數字1的意思就是在1周圍的8x8的格子周圍中只有一個雷(紅筆所標示的)
當將所有沒有雷的地方全部猜中,棋盤空間里的地方只剩下來雷的時候,就代表這個游玩玩家勝利

如圖所示,8個1里圍著一塊空間,那這個空間的就只能是雷,棋盤已經除了是雷的地方已經全部被占滿了,系統也提示了“you win!”的提示
那講到這,掃雷的大致游戲原理我們就已經差不多明白了,接下來就開始實作它
首先參考頭檔案,輸入主函式,自定義函式SAOLEI(我是學西班牙語的,英語菜的和屎一樣)
#include<stdio.h>
int main()
{
SAOLEI();
return 0;
}
在做這一款掃雷游戲前我們先要做出這個游戲的游戲選單,用do…while回圈和switch分支的寫法,來達到玩家玩完游戲后再玩一次和提供玩家選擇的選單效果(具體的可以看我上一篇博客中寫道的三子棋,這里簡要代過)
void menu()
{
printf("掃雷游戲\n");
printf("1,開始游戲\n");
printf("0,結束游戲\n");
}
void SAOLEI()
{
int inpunt = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請輸入數字");
scanf("%d", &inpunt);
switch (inpunt)
{
case 1:
Saolei_s();
break;
case 0:
printf("結束游戲\n");
break;
default:
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (inpunt);
}
測驗一下,大概的效果就是這樣

可以根據自己的需求來制定界面,接下來就在case1的選項中自定義函式Saolei_s()來開始制作游戲內容
游戲內容我們分成兩個步驟來進行說明:1,制作棋盤2,開始掃雷
我們這里來制作一個10x10的棋盤,但在這之前,我們先要搞清楚棋盤到底是一個什么樣子的結構,通過我一開始的掃雷游戲講解我們不難推出,掃雷這個游戲的棋盤組成是由兩個棋盤構成的,分別是玩家輸入的棋盤還有埋雷的棋盤


換一種理解方式的話,我們可以理解為:普通的笑臉是一個棋盤,而哭臉也是一個棋盤,我們把這兩個棋盤都設定為陣列,當輸入的坐標是哭臉的雷的時候,我們就把它反映在笑臉的這個棋盤上,轉成哭臉棋盤,就顯示了失敗的樣子
同時我們還要注意的是,這個格子雖然看上去只有10x10,但要注意我們每輸入一個坐標,就要顯示周圍的地雷數,如果就會顯示出周圍的地雷數,可如果我們輸入的邊框的坐標,就像這樣:

那這里計算的也是他附近8x8的坐標,可是由于是邊框位置的受限,它只計算了附近三個坐標的地雷數,實際上它計算的還是8個
因此我們不難推出,這個棋盤實際的模樣是這樣的:

一個9x9的棋盤,我們需要一個11x11的棋盤來作為內棋盤(用來放置地雷和計算周圍地雷數),還需要一個9x9的棋盤用來給玩家進行操作
首先再一次定義主函式
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
為了方便列印和更改數字,我們就將其提前定義,同理既然是在原萊的樹上進行擴大,我們也在原來的數字上加2即可
接下來在剛剛選單分支一中自定義函式Saolei_s
void Saolei_s()
{
printf("開始游戲\n");
//布置好棋盤
char board[ROWS][COLS] = { 0 };
//布置好棋盤
char show[ROWS][COLS] = { 0 };
boards(board, ROWS, COLS, '0');//初始化棋盤
boards(show, ROWS, COLS, '*');
//列印棋盤
//DLYs_board(board, ROW, COL);這一個是內置雷區,用來布置雷
DLYs(show, ROW, COL);//只需要列印中間的那一圈(9X9)
//布置地雷
BUZHILEI(board, ROW, COL);
/*DLYs(board, ROW, COL);*///列印確認一下是否已經布置完畢
//掃描地雷
POOMPOOMPOOM(board, show, ROW, COL);}
}
定義里面布滿地雷的棋盤(下面簡稱為雷盤,board)和玩家游玩的棋盤(接下來稱為玩盤,show),然后開始棋盤的初始化,我們將雷盤放滿0,玩盤放滿1
void boards(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;
}
}
}
為了不定義兩個函式這么浪費空間,我們在這個函式上多參考一個char來放置我們要給雷盤和玩盤放入的東西
接下來我們列印棋盤,自定義函式DLYs
這里要留意的是,我們引入的整形是row和col,因為雷出現的范圍只能是在9x9的格子內,如果出現在11x11的盤子上,則會出現誤導玩家的情況玩家的操作空間只能是在9x9中
我們這里操作的還是雷盤(board),注意后面跟著的是11x11
void BUZHILEI(char board[ROWS][COLS], int row, int col)
void DLYs(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
i從1開始,小于等于row/col,就把棋盤限制在了9x9中
列印出來看看效果

這樣看感覺目不接暇,很難第一眼就找出我想要的坐標,不如在列印這些棋盤前先列印出數字怎么樣
修改代碼
void DLYs(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 1; 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");
}
}
再來看看列印效果

測驗沒問題
接下來開始布置地雷,自定義函式BUZHILEI,,代入量和上面的一樣
設ZD等于地雷的數量Poom,Poom放入頭檔案中定義,方便修改
void BUZHILEI(char board[ROWS][COLS], int row, int col)
{
int ZD = Poom;
while (ZD)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';//這里只有一個等于!
ZD--;
}
}
}
引入時間戳和隨機值
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Poom 10
在定義x和y放入隨機值,設定回圈,回圈里面放入ZD,因為雷盤中布置的全是0,所以只要隨機值的坐標是0,就把雷放進去,然后ZD減去1,當ZD等于0的時候,回圈跳出,雷就布置完畢
列印出來看看效果

接下來開始定義函式掃雷,用于玩家操作
void POOMPOOMPOOM(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
//先輸入玩家的坐標
int x = 0;
int y = 0;
int win = 0;
while (win<row*col-Poom)
{
int count = 0;
printf("請輸入排查坐標:>");
scanf("%d%d", &x, &y);
//如果坐標存在
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x][y] == '1')//如果觸發雷
{
show[x][y] = '1';
printf("排查失敗,你觸發了地雷\n");
DLYs(show, ROW, COL);
DLYs(board, ROW, COL);
break;
}
else//如果沒有觸發雷
{
//計算輸入坐標周圍的地雷數
int count = get_mine(board, x, y);
show[x][y] = count + '0';
DLYs(show, ROW, COL);
win++;
}
}
else
{
printf("輸入坐標錯誤,請重新輸入\n");
}
}
if (win==row * col - Poom)
{
printf("恭喜你,排雷成功!\n");
DLYs(board, ROW, COL);
}
}
這個函式比較復雜,我們一步一步講
首先我們要把兩個棋盤都放入函式中,并且放入row和col
設定三個變數,分別是x和y來給玩家輸入坐標,設定win來做判斷條件
設定while回圈,如果win<row*col-poom,也就是說當win等于71的時候,我們就跳出回圈,row和col還有Poom都是我們設的數字,71就是除了雷之外玩家可以排除的坐標(總共坐標有81個)
玩家輸入的坐標有三種情況:輸入坐標無雷,輸入坐標有雷,輸入坐標錯誤
先定義輸入坐標有雷無雷的,設定條件,將x和y的范圍限制在1和row/col之間,然后如果輸入的坐標是雷盤的1,那就是觸發地雷,失敗
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x][y] == '1')//如果觸發雷
{
show[x][y] = '1';
printf("排查失敗,你觸發了地雷\n");
DLYs(show, ROW, COL);
DLYs(board, ROW, COL);
break;
}
若不是,則列印出來周圍的數字,定義變數count,將雷盤和xy放入自定義整形函式get_mine中
else//如果沒有觸發雷
{
//計算輸入坐標周圍的地雷數
int count = get_mine(board, x, y);
int get_mine(char board[ROWS][COLS], int x, int y)
{
return board[x - 1][y] + board[x - 1][y + 1] + board[x - 1][y - 1] +
board[x][y + 1] + board[x][y - 1] + board[x + 1][y]+
board[x + 1][y + 1] + board[x + 1][y - 1] - 8 * '0';//減去8個字符0
}
注意,函式內操作的是一個字符,根據阿斯克碼表,每一個字符對應的數字是不一樣的
字符0對應的是48,1對應的是49…所以,為了能回傳一個真確的數字,我們要減掉8個字符‘0’(因為旁白有8個格子),回傳的是一個雷數,但是這個數字是一個字符
因為我們要顯示出這個字符(根據掃雷玩法,我們要顯示出這個坐標上周圍的雷數),我們就要在玩盤上對應的坐標來列印出周圍的雷數,因此
else//如果沒有觸發雷
{
//計算輸入坐標周圍的地雷數
int count = get_mine(board, x, y);
show[x][y] = count + '0';
DLYs(show, ROW, COL);
win++;
}
當輸入一個坐標且不是雷的時候,win就加1,來推動玩家的游戲進度(回圈條件)
在回圈內,若是玩家輸入錯誤坐標(9x9的格子里不可能出現(10,10)的坐標,我們就給玩家提示)
else
{
printf("輸入坐標錯誤,請重新輸入\n");
}
最后,當玩家跳出回圈時,我們在函式內的回圈外下給玩家慶祝:游戲勝利
if (win==row * col - Poom)
{
printf("恭喜你,排雷成功!\n");
DLYs(board, ROW, COL);
}
這樣子,這個掃雷游戲就制作完畢,最后給大家分享一下源代碼
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Poom 10
void DLYs(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 1; 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");
}
}
int get_mine(char board[ROWS][COLS], int x, int y)
{
return board[x - 1][y] + board[x - 1][y + 1] + board[x - 1][y - 1] +
board[x][y + 1] + board[x][y - 1] + board[x + 1][y]+
board[x + 1][y + 1] + board[x + 1][y - 1] - 8 * '0';//減去8個字符0
}
void POOMPOOMPOOM(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
//先輸入玩家的坐標
int x = 0;
int y = 0;
int win = 0;
while (win<row*col-Poom)
{
int count = 0;
printf("請輸入排查坐標:>");
scanf("%d%d", &x, &y);
//如果坐標存在
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x][y] == '1')//如果觸發雷
{
show[x][y] = '1';
printf("排查失敗,你觸發了地雷\n");
DLYs(show, ROW, COL);
DLYs(board, ROW, COL);
break;
}
else//如果沒有觸發雷
{
//計算輸入坐標周圍的地雷數
int count = get_mine(board, x, y);
show[x][y] = count + '0';
DLYs(show, ROW, COL);
win++;
}
}
else
{
printf("輸入坐標錯誤,請重新輸入\n");
}
}
if (win==row * col - Poom)
{
printf("恭喜你,排雷成功!\n");
DLYs(board, ROW, COL);
}
}
void BUZHILEI(char board[ROWS][COLS], int row, int col)
{
int ZD = Poom;
while (ZD)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';//這里只有一個等于!
ZD--;
}
}
}
void boards(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;
}
}
}
void Saolei_s()
{
int PD = 0;
printf("開始游戲\n");
//布置好棋盤
char board[ROWS][COLS] = { 0 };
//布置好棋盤
char show[ROWS][COLS] = { 0 };
boards(board, ROWS, COLS, '0');//初始化棋盤
boards(show, ROWS, COLS, '*');
//列印棋盤
//DLYs_board(board, ROW, COL);這一個是內置雷區,用來布置雷
DLYs(show, ROW, COL);//只需要列印中間的那一圈(9X9),需要將整個11X11提取出來
//布置地雷
BUZHILEI(board, ROW, COL);
/*DLYs(board, ROW, COL);*///列印確認一下是否已經布置完畢
//掃描地雷
POOMPOOMPOOM(board, show, ROW, COL);
}
void menu()
{
printf("掃雷游戲\n");
printf("1,開始游戲\n");
printf("0,結束游戲\n");
}
void SAOLEI()
{
int inpunt = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請輸入數字");
scanf("%d", &inpunt);
switch (inpunt)
{
case 1:
Saolei_s();
break;
case 0:
printf("結束游戲\n");
break;
default:
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (inpunt);
}
int main()
{
SAOLEI();
return 0;
}
一個小小的掃雷,里面居然蘊含了如此豐富的知識和細節,flash player已在2020年12月不再支持,對于那個時候在網頁上的游戲制作者創作出簡陋的游戲可卻趣味十足,在這里,深深對他們表示敬意和對我童年快樂的感謝
希望有一天,我也能像他們一樣,寫出可以讓大家變得開心的程式
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/252039.html
標籤:其他
上一篇:Python語法基礎 三
下一篇:經典問題之約瑟夫問題_C語言實作
