C語(yǔ)言實(shí)現(xiàn)掃雷小游戲的全過程記錄
第一步思考要實(shí)現(xiàn)的功能
想必大家都知道掃雷這個(gè)小游戲,今天我們來(lái)用C語(yǔ)言實(shí)現(xiàn)一下,首先要掃雷,我們首先就需要有一個(gè)布置了雷的棋盤,然后開始掃雷,玩過掃雷的小伙伴都知道,如果選中的格子旁邊沒有雷,那么旁邊的格子就會(huì)自動(dòng)清空,大概的思路有了,現(xiàn)在我們開始實(shí)現(xiàn)。
第二步實(shí)現(xiàn)
初級(jí)版掃雷
首先創(chuàng)建棋盤的作用是用來(lái)存儲(chǔ)雷的信息,這時(shí)我們思考一下,一個(gè)棋盤到底夠不夠用?棋盤多大才合適?我們打印出來(lái)的棋盤肯定是不能出現(xiàn)雷的信息的,不然游戲就無(wú)法正常進(jìn)行了,但是我們雷的信息又需要棋盤存儲(chǔ),這樣一想,一個(gè)棋盤似乎做不到,那么我們就可以再創(chuàng)建一個(gè)棋盤以達(dá)到既能存儲(chǔ)雷的信息也能打印一個(gè)不含雷的棋盤,保證游戲的正常進(jìn)行。
char mineboard[ROWS][COLS] = { 0 };//存放雷的數(shù)組 char showboard[ROWS][COLS] = { 0 };//展示信息的數(shù)組
讀者可以思考一下為什么這里創(chuàng)建的是字符數(shù)組,現(xiàn)在棋盤有了,但是里面放了什么我們并不確定放了些什么,所有我們將它初始化一下
initboard(mineboard, ROWS, COLS, '0'); initboard(showboard, ROWS, COLS, '*');
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;//ret為要初始化字符 } } }
有些讀者看到ROWS和COLS可能就會(huì)疑惑了,下標(biāo)怎么是符號(hào),其實(shí)這是因?yàn)椴┲魍ㄟ^#define將這兩個(gè)符號(hào)定義成了兩個(gè)數(shù)字
#define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define MINE_NUM 10
這樣做的好處就是,當(dāng)需要修改棋盤的大小時(shí),只需要改變這一處即可,至于MINE_NUM為要布置的雷的個(gè)數(shù),暫時(shí)用不上,我們先繼續(xù)實(shí)現(xiàn),既然棋盤有了,也初始化了,那么我們先打印出來(lái)看一下,是不是和我們預(yù)想的一樣,我們封裝一個(gè)打印函數(shù)實(shí)現(xiàn)打印
void printboard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (i = 1; i <= row; i++) { if (1 == i) { for (j = 0; j <= col; j++) { printf(" %d", j); } printf("\n"); } for (j = 1; j <= col; j++) { if (1 == j) { printf(" %d", i); } printf(" %c", board[i][j]); } printf("\n"); } }
printboard(mineboard, ROW, COL);//調(diào)用函數(shù)打印雷的信息 printboard(showboard, ROW, COL);//調(diào)用函數(shù)打印展示的的信息
接下來(lái)我們布置雷,同樣封裝一個(gè)布雷函數(shù),但是布雷,總不能人為布置吧,不然雷都知道了就沒得完了,所以我們應(yīng)該讓電腦幫我們布雷,而且多次游戲的話,雷的位置肯定不能一樣,所以我們就需要一個(gè)庫(kù)函數(shù)來(lái)幫我們實(shí)現(xiàn)隨機(jī)布雷
srand((unsigned int)time(NULL));//生成隨機(jī)數(shù)的種子
void setmine(char board[ROWS][COLS], int mine_num, int row, int col) { while (mine_num) { int x = rand() % row + 1;//生成隨機(jī)數(shù) int y = rand() % col + 1;//生成隨機(jī)數(shù) if (board[x][y] == '0') { board[x][y] = '1'; mine_num--; } } }
setmine(mineboard, MINE_NUM, ROW, COL);//調(diào)用布雷函數(shù)布雷
我們可以看到我們傳遞參數(shù)的時(shí)候就用到了MINE_NUM雷的個(gè)數(shù)這個(gè)符號(hào)常量,因?yàn)槌A坎豢杀恍薷?,所以我們將它放在?shí)參的位置上而不是直接用它,布置好雷之后,我們調(diào)用打印函數(shù)將雷盤信息打印一下。
printboard(mineboard, ROW, COL);
確認(rèn)信息無(wú)誤后,我們接著實(shí)現(xiàn)游戲,同樣封裝成一個(gè)函數(shù)
void play(char mineboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int n = 0;//記錄已排除的格子 while (row * col - MINE_NUM - n) { printf("請(qǐng)輸入坐標(biāo),以空格隔開輸入>:"); scanf("%d %d", &x, &y); if (x > ROW || y > COL || x < 1 || y < 1) { printf("坐標(biāo)非法,請(qǐng)重新輸入\n"); continue; } if (mineboard[x][y] != '1') { int ret = find(mineboard, x, y); if (ret != 0) { showboard[x][y] = ret + '0'; //n++; } else { showboard[x][y] = ' '; //spread(showboard, mineboard, x, y); } n = Isblank(showboard, row, col);//檢查已經(jīng)有多少格子已經(jīng)排除 system("cls"); printboard(showboard, row, col); } else { break; } } if (row * col - MINE_NUM - n) { printf("很遺憾,你被炸死了\n"); } else { printf("恭喜你,掃雷成功\n"); } printboard(mineboard, row, col); }
play(mineboard, showboard, ROW, COL);//調(diào)用函數(shù),開始游戲
在開始游戲之前無(wú)疑我們要先要先將展示的棋盤和提示信息打印出來(lái),讓玩家看到,從而進(jìn)行游戲,所以我們?cè)陂_始游戲之前調(diào)用一下打印函數(shù)
printboard(showboard, ROW, COL);
接下來(lái)就是游戲的實(shí)現(xiàn)了,可以看到游戲函數(shù)中有很多函數(shù)的接口比如find,Isblank等這就是我們接下來(lái)要實(shí)現(xiàn)的功能函數(shù),開始游戲給與提示,讀入坐標(biāo),并對(duì)坐標(biāo)進(jìn)行判斷,是否合法,不合法則提示玩家重新輸入,如果合法,則判斷斷當(dāng)前坐標(biāo)是不是雷如果是則退出循環(huán),游戲結(jié)束,并給與提示,如果不是雷則判斷附近有沒有雷,沒有則置為空也就是空格,有雷則放入附近雷的信息,然后判斷是不是所有不是雷的空格都找到了,如果不是則繼續(xù)游戲,重復(fù)剛才的判斷,是則游戲結(jié)束,掃雷成功,排雷功能在上面代碼已經(jīng)實(shí)現(xiàn),接下來(lái)實(shí)現(xiàn)判斷功能,其實(shí)很簡(jiǎn)單,遍歷棋盤,看看是不是所有不是雷的元素都被找出來(lái)即可
查找輸入坐標(biāo)附近雷的信息
int find(char board[ROWS][COLS], int x, int y) { int i = 0; int j = 0; int count = 0; if (x > 0 && x < ROW && y > 0 && y < COL) { for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { if (board[i][j] == '1') count++; } } } return count; }
統(tǒng)計(jì)已排除的坐標(biāo)個(gè)數(shù)
int Isblank(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; int n = 0; for (i = 1; i <= row; i++) { for (j = 1; j <= col; j++) { if (board[i][j] != '*') { n++; } } } return n; }
返回值就是我們需要的已經(jīng)被排查的坐標(biāo)個(gè)數(shù)了,判斷一下總的坐標(biāo)個(gè)數(shù)和雷的個(gè)數(shù)加已排除的坐標(biāo)個(gè)數(shù)即可,所以我們將這個(gè)條件作為循環(huán)停止的條件,如play函數(shù)中的while即可。
因?yàn)橥顺鲅h(huán)的原因有兩個(gè),所以我們對(duì),退出的條件進(jìn)行一下判斷,用如下代碼即可
if (row * col - MINE_NUM - n) { printf("很遺憾,你被炸死了\n"); } else { printf("恭喜你,掃雷成功\n"); }
到此初級(jí)的簡(jiǎn)單掃雷游戲就實(shí)現(xiàn)了。
掃雷進(jìn)階—遞歸實(shí)現(xiàn)自動(dòng)清空
初級(jí)版本的掃雷游戲只能輸入一個(gè)坐標(biāo)判斷一次,完成掃雷無(wú)疑是巨大的挑戰(zhàn),甚至說完全憑運(yùn)氣,所以我們來(lái)實(shí)現(xiàn)一下自動(dòng)清空附近沒有一個(gè)雷的坐標(biāo),來(lái)降低游戲的難度,接下來(lái)我們來(lái)實(shí)現(xiàn)這個(gè)功能,細(xì)心的小伙伴們會(huì)發(fā)現(xiàn)我在play函數(shù)中我留了一個(gè)名為spread的函數(shù)接口,而這個(gè)接口就是我們調(diào)用自動(dòng)清空函數(shù)的入口,因?yàn)樯厦鏇]有實(shí)現(xiàn)這個(gè)函數(shù),所以我就將它注釋掉了,現(xiàn)在我們將它還原即可。
void spread(char showboard[ROWS][COLS], char mineboard[ROWS][COLS], int x, int y) { showboard[x][y] = ' '; int i = 0; int j = 0; int ret = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { if (i > 0 && i <= ROW && j > 0 && j <= COL && mineboard[i][j] != '1' && showboard[i][j] == '*') { ret = find(mineboard, i, j); if (!ret) { spread(showboard, mineboard, i, j); } if (ret) { showboard[i][j] = ret + '0'; } else if (showboard[i][j] == '*') { showboard[i][j] = ' '; } } } } }
到此我們的掃雷就很好的實(shí)現(xiàn)了。小伙伴們趕緊試試吧。
完整的源碼
頭文件
#pragma once #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define MINE_NUM 10 #include<stdio.h> #include<windows.h> #include<stdlib.h> #include<time.h> //打印菜單 void menu(); //提示 void playgame(); //初始化雷盤 void initboard(char board[ROWS][COLS], int rows, int cols, char ret); //打印雷盤 void printboard(char board[ROWS][COLS], int row, int col); //布置雷 void setmine(char board[ROWS][COLS], int mine_num, int row, int col); //掃雷 void play(char mineboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col);
函數(shù)定義的源文件
#define _CRT_SECURE_NO_WARNINGS #include"game.h" void menu() { printf("****************************\n"); printf("*** 1.play 0.exit ***\n"); printf("****************************\n"); } void playgame() { printf("游戲開始"); Sleep(650); system("cls"); } 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; } } } void printboard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (i = 1; i <= row; i++) { if (1 == i) { for (j = 0; j <= col; j++) { printf(" %d", j); } printf("\n"); } for (j = 1; j <= col; j++) { if (1 == j) { printf(" %d", i); } printf(" %c", board[i][j]); } printf("\n"); } } void setmine(char board[ROWS][COLS], int mine_num, int row, int col) { while (mine_num) { int x = rand() % row + 1;//生成隨機(jī)數(shù) int y = rand() % col + 1;//生成隨機(jī)數(shù) if (board[x][y] == '0') { board[x][y] = '1'; mine_num--; } } } int find(char board[ROWS][COLS], int x, int y) { int i = 0; int j = 0; int count = 0; if (x > 0 && x < ROW && y > 0 && y < COL) { for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { if (board[i][j] == '1') count++; } } } return count; } void spread(char showboard[ROWS][COLS], char mineboard[ROWS][COLS], int x, int y) { //if (x > 0 && x <= ROW && y > 0 && y <= COL) //{ showboard[x][y] = ' '; //*pn += 1; int i = 0; int j = 0; int ret = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { if (i > 0 && i <= ROW && j > 0 && j <= COL && mineboard[i][j] != '1' && showboard[i][j] == '*') { ret = find(mineboard, i, j); if (!ret) { spread(showboard, mineboard, i, j); } if (ret) { showboard[i][j] = ret + '0'; //*pn += 1; } else if (showboard[i][j] == '*') { showboard[i][j] = ' '; //*pn += 1; } } } } //} } int Isblank(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; int n = 0; for (i = 1; i <= row; i++) { for (j = 1; j <= col; j++) { if (board[i][j] != '*') { n++; } } } return n; } void play(char mineboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int n = 0;//記錄已排除的格子 while (row * col - MINE_NUM - n) { printf("請(qǐng)輸入坐標(biāo),以空格隔開輸入>:"); scanf("%d %d", &x, &y); if (x > ROW || y > COL || x < 1 || y < 1) { printf("坐標(biāo)非法,請(qǐng)重新輸入\n"); continue; } if (mineboard[x][y] != '1') { int ret = find(mineboard, x, y); if (ret != 0) { showboard[x][y] = ret + '0'; //n++; } else { //showboard[x][y] = ' '; spread(showboard, mineboard, x, y); } n = Isblank(showboard, row, col);//檢查已經(jīng)有多少格子已經(jīng)排除 system("cls"); printboard(showboard, row, col); } else { break; } } if (row * col - MINE_NUM - n) { printf("很遺憾,你被炸死了\n"); } else { printf("恭喜你,掃雷成功\n"); } printboard(mineboard, row, col); }
測(cè)試的源文件
#define _CRT_SECURE_NO_WARNINGS #include"game.h" void game() { playgame(); char mineboard[ROWS][COLS] = { 0 };//存放雷的數(shù)組 char showboard[ROWS][COLS] = { 0 };//展示信息的數(shù)組 initboard(mineboard, ROWS, COLS, '0'); //printboard(mineboard, ROW, COL); initboard(showboard, ROWS, COLS, '*'); printboard(showboard, ROW, COL); setmine(mineboard, MINE_NUM, ROW, COL); //printboard(mineboard, ROW, COL); play(mineboard, showboard, ROW, COL); } int main() { int Input = 0; do { srand((unsigned int)time(NULL));//隨機(jī)數(shù)的種子 menu(); printf("請(qǐng)選擇>:"); scanf("%d", &Input); switch (Input) { case 1:game(); break; case 0:printf("退出游戲\n"); break; default:printf("選擇錯(cuò)誤,請(qǐng)重新選擇\n"); break; } } while (Input); return 0; }
寫在最后的話
現(xiàn)在我們來(lái)解釋一下,之前留下的問題,為什么要用字符數(shù)組,因?yàn)樽址麛?shù)組的打印可以更多形式可以是#,*,!等等比數(shù)字無(wú)疑多出很多可能,而且字符也有數(shù)字可以表示,玩家看上去并無(wú)區(qū)別,棋盤為什么是11 * 11的呢,那是因?yàn)檫@樣輸入的下標(biāo)就可以直接當(dāng)作棋盤的下標(biāo)使用了,也可以防止遍歷的時(shí)候越界,這樣說小伙伴們可以理解嗎?
到此這篇關(guān)于C語(yǔ)言實(shí)現(xiàn)掃雷小游戲的文章就介紹到這了,更多相關(guān)C語(yǔ)言掃雷小游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MacOS下C++使用WebRTC注意事項(xiàng)及問題解決
這篇文章主要介紹了MacOS下C++使用WebRTC注意事項(xiàng),對(duì)于iOS/macOS平臺(tái),開啟openh264,去除test,使用一些命令可以輕松解決,下面小編給大家?guī)?lái)了問題及解決方法,需要的朋友可以參考下2022-09-09