c語言實現(xiàn)含遞歸清場版掃雷游戲
一,設(shè)計思路
想必大家都玩過掃雷

?這便是一個標準的掃雷,換做代碼實現(xiàn),我們需要考慮以下幾點:
1.棋盤的設(shè)計與初始化
2.在棋盤中放入雷
3.統(tǒng)計雷數(shù)
4.如何實現(xiàn)“一片”的效果
5.輸贏的判斷
接下來我們進行具體操作。


二.實現(xiàn)方式
1.菜單的打印
對任意一個游戲,菜單是必不可少的,也是最簡單的部分,直接上代碼
void menu()
{
printf("------------------掃雷------------------\n");
printf("---------------1.開始游戲---------------\n");
printf("---------------0.退出游戲---------------\n");
}
int main()
{
srand((unsigned int)time(NULL));
int a = 0;
do
{
menu();
scanf("%d", &a);
if (a == 0)
{
break;
}
game();
} while (a);
return 0;
}
其中srand是為了求隨機值,用來布置雷
2.game函數(shù)
主菜單完后進入game函數(shù),在game函數(shù)里我們就要開始主要的游戲部分,如棋盤初始化與打印等,當然這些步驟都依靠函數(shù)完成,game函數(shù)只相當于集合了一系列的游戲模塊
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
initeboard(mine, ROWS, COLS, '0');
initeboard(show, ROWS, COLS, '*');//初始棋盤
displayboard(show, ROW, COL);//打印棋盤
mine_make(mine, ROW, COL);//設(shè)置雷
//displayboard(mine, ROW, COL);
find_mine(mine, show, ROWS, COLS);//排查雷
}
3.棋盤的初始化與打印
可以看到,我在game函數(shù)里初始了兩個棋盤,為什么要兩個呢?
其實,一個是為了放置了雷,一個為了展示給玩家,為什么不用一個呢,我們要在放雷處用'1',表示不放雷處用‘0',這樣計算一個坐標周圍雷的數(shù)量就會更簡單,接下來看一段代碼:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 10 #define COL 10 #define ROWS ROW+2 #define COLS COL+2
這里我們看到定義了一個ROWS和COLS這又是為何呢?
回歸棋盤

?掃雷時當你確認一個點時,它會對此點周圍的八個點進行排查看是否有淚,當坐標位于紅線處時沒有無法判斷八個,因此有了ROWS與COLS,這時,有人就會問了:那埋雷的地方用ROW COL就可以了,還不用擔心雷跑到外邊我們加的框,想法很好,但我們有兩個棋盤,必須對應(yīng),而且也不存在跑出雷的情況,往下分析你就會知道
void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盤初始化,此處用了個節(jié)省步驟的方法,不用兩個棋盤依次初始化
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = s;
}
}
}
void displayboard(char board[ROWS][COLS], int row, int col)//棋盤打印
{
int i = 0;
int j = 0;
printf(" ");//與行中打印的0%d對應(yīng)
for (j = 0; j <=col; j++)
{
printf(" %d ", j);
}
printf("\n");
printf("-");
for (j = 1; j <= col + 1; j++)
{
printf("---");
printf("|");
}
printf("\n");//列對應(yīng)打印完成
for (i = 1; i <= row; i++)
{
if (i <= 9)
{
printf(" 0%d ", i);
}
else
printf(" %d ", i);
printf("|");
for (j = 1; j <= col; j++)
{
printf(" %c ", board[i][j]);
printf("|");
}
printf("\n");
printf("-");
for (j = 1; j <= col+1; j++)
{
printf("---");
printf("|");
}
printf("\n");//行對應(yīng)嵌套在內(nèi)部 打印的數(shù)前加0是為了讓當行數(shù)大于9時能夠?qū)?yīng) 如09與10
}
}
棋盤的打印做了行列對應(yīng),所以可能有點不明顯

?4.雷的放置,雷的個數(shù)
雷的放置很簡單,在棋盤‘0',處放置就行,因為我們對隨機數(shù)的算式使隨機數(shù)只會出現(xiàn)在0-9沒有跑出的情況
mine_make(char mine[ROWS][COLS], int row, int col)//設(shè)置雷
{
int count = 10;
while (count)
{
int x = rand() % 10;
int y = rand() % 10;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
雷的個數(shù)就需要一定考慮了:
首先,我們需要把周圍八個位置是否有雷,有多少個雷判斷出來,這時我們設(shè)計‘0' ‘1'類型就排上用場了,但是注意,這是字符,不是數(shù)字

?一張表 讓我們知道如何轉(zhuǎn)型
當然返回的數(shù)字記得轉(zhuǎn)成字符類型
int get_mine(char mine[ROWS][COLS], int i, int j)//得到一個坐標附近雷的個數(shù)
{
return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
mine[i][j - 1] + mine[i][j + 1] +
mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此處我們的數(shù)字其實是字符,用此方法可以轉(zhuǎn)為數(shù)字整形
}
5.遞歸實現(xiàn)一片效果
當不為雷是會展開附近一片不為雷,提高游戲效率
void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實現(xiàn)一大片
{
show[x][y] = ' ';//先讓輸入金的坐標處變?yōu)榭崭?,因為已?jīng)判定過雷所以可以直接轉(zhuǎn)空格
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++)//嵌套for循環(huán)表示輸入坐標包括自生及周圍八個
{
if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現(xiàn)負坐標,避免有雷,避免輸入重復
{
ret = get_mine(mine, i, j);//判斷ret是0或非0,并得出周圍雷數(shù)
if (!ret)//如果ret=0,!ret便是非0;為真
{
spread(show, mine, i, j);//遞歸
}
if (ret)//ret!=0時為真,便打印數(shù)
{
show[i][j] = ret + '0';//使數(shù)字轉(zhuǎn)成對應(yīng)字符
}
}
}
}
}
效果展示:

?6.排查雷
負責判斷是否被炸死及游戲勝利
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
printf("請輸入坐標\n");
int i = 0;
int j = 0;
int win = 0;
while (row*col-10)//因為是十個雷,所以是—10,因為下總數(shù)減10就贏了,所以可以以此跳出循環(huán),當然要是雷部位10,定一個變量就行,此處就不改了
{
scanf("%d %d", &i, &j);
if (mine[i][j] == '1')
{
printf("你掛了\n");
displayboard(mine, ROW, COL);
break;
}
else
{
show[i][j] = get_mine(mine, i, j)+'0';
spread(show,mine, i, j);
displayboard(show, ROW, COL);
win++;
}
}
if (win ==row * col - 10)
{
printf("恭喜你,成功了\n");
displayboard(mine, ROW, COL);
}
}
具體注釋都在代碼里了
正常情況把打印雷盤注釋就行,就可以正常游戲了

?三.完整代碼
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2
void menu()
{
printf("------------------掃雷------------------\n");
printf("---------------1.開始游戲---------------\n");
printf("---------------0.退出游戲---------------\n");
}
void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盤初始化,此處用了個節(jié)省步驟的方法,不用兩個棋盤依次初始化
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = s;
}
}
}
void displayboard(char board[ROWS][COLS], int row, int col)//棋盤打印
{
int i = 0;
int j = 0;
printf(" ");//與行中打印的0%d對應(yīng)
for (j = 0; j <=col; j++)
{
printf(" %d ", j);
}
printf("\n");
printf("-");
for (j = 1; j <= col + 1; j++)
{
printf("---");
printf("|");
}
printf("\n");//列對應(yīng)打印完成
for (i = 1; i <= row; i++)
{
if (i <= 9)
{
printf(" 0%d ", i);
}
else
printf(" %d ", i);
printf("|");
for (j = 1; j <= col; j++)
{
printf(" %c ", board[i][j]);
printf("|");
}
printf("\n");
printf("-");
for (j = 1; j <= col+1; j++)
{
printf("---");
printf("|");
}
printf("\n");//行對應(yīng)嵌套在內(nèi)部 打印的數(shù)前加0是為了讓當行數(shù)大于9時能夠?qū)?yīng) 如09與10
}
}
mine_make(char mine[ROWS][COLS], int row, int col)//設(shè)置雷
{
int count = 10;
while (count)
{
int x = rand() % 10;
int y = rand() % 10;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
int get_mine(char mine[ROWS][COLS], int i, int j)//得到一個坐標附近雷的個數(shù)
{
return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
mine[i][j - 1] + mine[i][j + 1] +
mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此處我們的數(shù)字其實是字符,用此方法可以轉(zhuǎn)為數(shù)字整形
}
void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實現(xiàn)一大片
{
show[x][y] = ' ';//先讓輸入金的坐標處變?yōu)榭崭?,因為已?jīng)判定過雷所以可以直接轉(zhuǎn)空格
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++)//嵌套for循環(huán)表示輸入坐標包括自生及周圍八個
{
if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現(xiàn)負坐標,避免有雷,避免輸入重復
{
ret = get_mine(mine, i, j);//判斷ret是0或非0,并得出周圍雷數(shù)
if (!ret)//如果ret=0,!ret便是非0;為真
{
spread(show, mine, i, j);//遞歸
}
if (ret)//ret!=0時為真,便打印數(shù)
{
show[i][j] = ret + '0';//使數(shù)字轉(zhuǎn)成對應(yīng)字符
}
}
}
}
}
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
printf("請輸入坐標\n");
int i = 0;
int j = 0;
int win = 0;
while (row*col-10)//因為是十個雷,所以是—10,因為下總數(shù)減10就贏了,所以可以以此跳出循環(huán),當然要是雷部位10,定一個變量就行,此處就不改了
{
scanf("%d %d", &i, &j);
if (mine[i][j] == '1')
{
printf("你掛了\n");
displayboard(mine, ROW, COL);
break;
}
else
{
show[i][j] = get_mine(mine, i, j)+'0';
spread(show,mine, i, j);
displayboard(show, ROW, COL);
win++;
}
}
if (win ==row * col - 10)
{
printf("恭喜你,成功了\n");
displayboard(mine, ROW, COL);
}
}
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
initeboard(mine, ROWS, COLS, '0');
initeboard(show, ROWS, COLS, '*');//初始棋盤
displayboard(show, ROW, COL);//打印棋盤
mine_make(mine, ROW, COL);//設(shè)置雷
displayboard(mine, ROW, COL);
find_mine(mine, show, ROWS, COLS);//排查雷
}
int main()
{
srand((unsigned int)time(NULL));
int a = 0;
do
{
menu();
scanf("%d", &a);
if (a == 0)
{
break;
}
game();
} while (a);
return 0;
}

總結(jié)
到此這篇關(guān)于c語言實現(xiàn)含遞歸清場版掃雷游戲的文章就介紹到這了,更多相關(guān)c語言實現(xiàn)掃雷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用C語言舉例講解數(shù)據(jù)結(jié)構(gòu)中的算法復雜度結(jié)與順序表
這篇文章主要介紹了講解數(shù)據(jù)結(jié)構(gòu)中的算法復雜度結(jié)與順序表的C語言版示例,包括對時間復雜度和空間復雜度等概念的簡單講解,需要的朋友可以參考下2016-02-02
C++實現(xiàn)LeetCode(141.單鏈表中的環(huán))
這篇文章主要介紹了C++實現(xiàn)LeetCode(141.單鏈表中的環(huán)),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07
嵌入式C實戰(zhàn)項目開發(fā)技巧:對一個有規(guī)律的數(shù)組表進行位移操作的方法
今天小編就為大家分享一篇關(guān)于嵌入式C實戰(zhàn)項目開發(fā)技巧:對一個有規(guī)律的數(shù)組表進行位移操作的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12
c++中vector<int>和vector<int*>的用法及區(qū)別
這篇文章主要介紹了c++中vector<int>和vector<int*>的用法及區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2013-10-10

