C語(yǔ)言小游戲之掃雷完整版
一.游戲介紹
看到這張圖片,相信很多小伙伴都非常熟悉,很多小伙伴都玩過(guò)掃雷這個(gè)小游戲,掃雷是一款益智類游戲,在放松娛樂(lè)的同時(shí)可以鍛煉各位小伙伴的智商。

游戲規(guī)則:如上圖,玩家需要在不被炸死的前提下找出圖中雷的位置,若能找出所有雷,則游戲勝利,若不幸踩到雷則被炸死。
注:先介紹程序?qū)崿F(xiàn)的主要功能,后文會(huì)有完整代碼
二.游戲步驟及實(shí)現(xiàn)的功能
(一) 游戲步驟
程序開(kāi)始執(zhí)行時(shí)玩家需要選擇是否開(kāi)始游戲,輸入1則游戲開(kāi)始,輸入0則退出游戲

show地圖出現(xiàn)后玩家開(kāi)始選擇進(jìn)行選擇,輸入1則開(kāi)始選擇區(qū)域,輸入2則可以標(biāo)記自己認(rèn)為是雷的區(qū)域,輸入3則可以取消原先被標(biāo)記的區(qū)域

當(dāng)所有非雷區(qū)域全部被排出來(lái)后則游戲勝利
//遍歷show地圖,以便判斷最后的勝利
int?Travel(char?show[ROWS][COLS],?int?row,?int?col)
{
?int?i?=?0;
?int?j?=?0;
?int?win?=?0;
?for?(i?=?1;?i?<=?row;?i++)
?{
??for?(j?=?1;?j?<=?col;?j++)
??{
???if?(show[i][j]?==?'*'?||?show[i][j]?==?'!')
???{
????win++;
???}
??}
?}
?return?win;
}
以下為效果圖:

(二)實(shí)現(xiàn)的功能
初始化雷盤(pán) 打印雷盤(pán) 隨機(jī)布置雷 玩家開(kāi)始排雷 防止玩家第一次被雷炸死. 統(tǒng)計(jì)所選位置周圍八個(gè)位置中雷的個(gè)數(shù) 遞歸拓展已選位置周圍的區(qū)域 標(biāo)記雷及取消標(biāo)記
1.初始化雷盤(pán)
初始化雷盤(pán)時(shí)需要構(gòu)造兩個(gè)二維數(shù)組,一個(gè)數(shù)組(mine數(shù)組)里面是存放雷的,用于實(shí)現(xiàn)各種功能,另一個(gè)數(shù)組(show數(shù)組)是給玩家操作時(shí)看的,看不到雷的具體位置。
由于需要統(tǒng)計(jì)每個(gè)位置周圍八個(gè)區(qū)域中雷的個(gè)數(shù),在統(tǒng)計(jì)最邊緣的位置時(shí)為了利于功能的實(shí)現(xiàn),在初始化雷盤(pán)時(shí)構(gòu)建的二維數(shù)組mine數(shù)組的行和列比show數(shù)組多兩行兩列。
//初始化雷盤(pán)
//主函數(shù)中函數(shù)的調(diào)用
//Initboard(mine,?ROWS,?COLS,'0');
//Initboard(show,?ROWS,?COLS,?'*');
void?Initboard(char?board[ROWS][COLS],?int?rows,?int?cols,char?set)
{
?int?i?=?0,?j?=?0;
?for?(i?=?0;?i??{
??for?(j?=?0;?j???{
???board[i][j]?=?set;
??}
?}
}
初始化雷盤(pán)時(shí),mine數(shù)組全部初始化為字符‘0’,show數(shù)組全部初始化為字符‘*’。
2.打印雷盤(pán)
玩家需要通過(guò)打印出的show數(shù)組雷盤(pán)進(jìn)行游戲,打印雷盤(pán)時(shí)將行號(hào)和列號(hào)全部打印出來(lái)有利于玩家進(jìn)行操作
搜索公眾號(hào):C語(yǔ)言中文社區(qū),關(guān)注免費(fèi)領(lǐng)取300G編程資料
void?DisplayBoard(char?board[ROWS][COLS],?int?row,?int?col)
{
?int?i?=?0,?j?=?0;
?//打印列號(hào)
?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");
?}
}
雷盤(pán)打印如下:

3.隨機(jī)布置雷
在show數(shù)組中,用字符‘0’表示無(wú)雷區(qū)域,用字符‘1’表示有雷區(qū)域,由于第一個(gè)步驟中已經(jīng)將show數(shù)組全部初始化為字符‘0’了,故只需使用srand和rand函數(shù)生成隨機(jī)數(shù),使得雷的分布為隨機(jī)位置。
//隨機(jī)布置雷
void?SetMine(char?board[ROWS][COLS],?int?row,?int?col)
{
?int?x?=?0,?y?=?0;
?int?count?=?EASY_COUNT;
?while?(count)
?{
??x?=?rand()?%?row+1;
??y?=?rand()?%?col+1;
??if?(board[x][y]?!=?'1')
??{
???board[x][y]?=?'1';
???count--;
??}
?}
}
4.玩家排雷
玩家根據(jù)show數(shù)組展示出的地圖開(kāi)始排雷,選擇自己認(rèn)為不是雷的區(qū)域
void?FindMine(char?mine[ROWS][COLS],?char?show[ROWS][COLS],?int?row,?int?col)
{
?int?ch?=?0;
?int?flag_count?=?0;
?int?win?=?0;
?int?fch?=?1;//用來(lái)標(biāo)記玩家是否為第一次排雷
?while?(1)
?{
??menu1();
??scanf("%d",?&ch);
??if?(ch?==?1)
??{
???int?x?=?0,?y?=?0;
???printf("請(qǐng)開(kāi)始排雷:>");
???scanf("%d%d",?&x,?&y);
???//判斷坐標(biāo)合法
???if?(x?<=?row?&&?x?>?0?&&?y?>?0?&&?y?<=?col)
???{
????//判斷玩家是否是第一次排雷
????if?(fch?==?1?&&?mine[x][y]?==?'1')
????{
????????//是第一次排雷
?????ChangePlace(mine,?row,?col,?x,?y);
?????fch++;
????}
????else?
????{
????????//判斷是否踩雷
?????if?(mine[x][y]?==?'1')
?????{
??????printf("游戲結(jié)束\n");
??????printf("恭喜你,踩到雷了\n");
??????DisplayBoard(mine,?row,?col);
??????break;
?????}
?????else
?????{
??????broad(mine,?show,?x,?y);
??????DisplayBoard(show,?row,?col);
?????}
?????fch++;
????}?
???}
???else
???{
????printf("輸入坐標(biāo)不合法,請(qǐng)重新輸入\n");
???}
??}
??else?if?(ch?==?2)
??{
???printf("請(qǐng)開(kāi)始標(biāo)記雷:>\n");
???//標(biāo)記雷的函數(shù)
???Flagmine(show,?row,?col,?flag_count);
???DisplayBoard(show,?row,?col);
??}
??else?if?(ch?==?3)
??{
???printf("請(qǐng)選擇要取消標(biāo)記的位置:>\n");
???//取消標(biāo)記的函數(shù)
???Cancelflag(show,?row,?col,?flag_count);
???DisplayBoard(show,?row,?col);
??}
??//遍歷show地圖(改進(jìn))
??win=Travel(show,?row,?col);
??if?(win?==?EASY_COUNT)
???break;
?}
?if?(win?==?EASY_COUNT)
?{
??printf("恭喜你,游戲勝利\n");
?}
}
5.防止玩家第一次被炸死
如果玩家第一次就踩雷,則提示玩家重新選擇,并將該位置的雷重新隨機(jī)布置。
//防止玩家第一次排雷被炸死
void?ChangePlace(char?mine[ROWS][COLS],?int?row,?int?col,?int?x,?int?y)
{
??x?=?rand()?%?row;
??y?=?rand()?%?col;
??mine[x][y]?=?'1';
??printf("第一次就踩雷了,重新選擇\n");
}

6.統(tǒng)計(jì)所選位置周圍八個(gè)位置中雷的個(gè)數(shù)
統(tǒng)計(jì)已選位置周圍八個(gè)位置中含有雷的個(gè)數(shù),并在該位置上數(shù)字的形式打印出來(lái)。
//計(jì)算坐標(biāo)周圍雷的個(gè)數(shù)
int?get_mine(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';
}
此處由于數(shù)組mine中存放的是字符’0’,而不是數(shù)字0,故當(dāng)統(tǒng)計(jì)完八個(gè)位置后需要減去字符’0’之后返回為數(shù)字。
7.遞歸拓展已選位置周圍的區(qū)域
以遞歸的方式拓展式排雷。
//拓展周圍不是雷的區(qū)域
void?broad(char?mine[ROWS][COLS],?char?show[ROWS][COLS],?int?x,?int?y)
{
?//判斷坐標(biāo)是否越界
?if?(x?==?0?||?y?==?0?||?x?==?ROWS?-?1?||?y?==?COLS?-?1)
??return;
?//判斷是否已經(jīng)被排除
?if?(show[x][y]?!=?'*')
?{
??return;
?}
?int?count?=?get_mine(mine,?x,?y);
?if?(count?>?0)
?{
??show[x][y]?=?count?+?'0';
??return;
?}
?//遞歸拓展地圖
?else?if?(count?==?0)
?{
??show[x][y]?=?'0';
??broad(mine,?show,?x?-?1,?y);
??broad(mine,?show,?x?-?1,?y?-?1);
??broad(mine,?show,?x,?y?-?1);
??broad(mine,?show,?x?+?1,?y?-?1);
??broad(mine,?show,?x?+?1,?y);
??broad(mine,?show,?x?+?1,?y?+?1);
??broad(mine,?show,?x,?y?+?1);
??broad(mine,?show,?x?-?1,?y?+?1);
?}
}
如果只能一個(gè)一個(gè)雷的排,將會(huì)使得此游戲無(wú)法進(jìn)行,故當(dāng)選擇一個(gè)位置a后對(duì)a周圍八個(gè)區(qū)域進(jìn)行排除,若其中一個(gè)位置b周圍八個(gè)位置仍沒(méi)有雷,就繼續(xù)對(duì)b周圍的八個(gè)位置進(jìn)行排雷,以此遞歸的方式不斷排除。
「效果如下:」

8.標(biāo)記雷及取消標(biāo)記
玩家可以通過(guò)輸入坐標(biāo)對(duì)自己覺(jué)得是雷的位置進(jìn)行標(biāo)記,標(biāo)記后為‘!’,如果覺(jué)得不是也可以取消標(biāo)記,取消標(biāo)記后恢復(fù)為‘*’。
//標(biāo)記雷
void?Flagmine(char?show[ROWS][COLS],?int?row,?int?col,int?flag_count)
{
?int?x?=?0,?y?=?0;
?//判斷標(biāo)記數(shù)與雷數(shù)是否相等
?if?(flag_count?==?EASY_COUNT)
?{
??printf("標(biāo)記的雷數(shù)和實(shí)際存在的雷數(shù)相等,無(wú)法再標(biāo)記\n");
??return;
?}
?printf("請(qǐng)輸入你要標(biāo)記位置的坐標(biāo):>\n");
?scanf("%d%d",?&x,?&y);
?//判斷坐標(biāo)是否合法
?if?(x?>?0?&&?x?<=?row?&&?y?>?0?&&?y?<=?col)
?{
??//判斷該坐標(biāo)是否仍未被排除
??if?(show[x][y]=='*')
??{
???show[x][y]?=?'!';
???flag_count++;
??}
??else?
??{
???printf("該位置不可能是雷,請(qǐng)重新輸入\n");
??}
?}
?else
?{
??printf("該坐標(biāo)不合法,請(qǐng)重新輸入:>\n");
?}
}
//取消標(biāo)記
void?Cancelflag(char?show[ROWS][COLS],?int?row,?int?col,?int?flag_count)
{
?int?x?=?0;
?int?y?=?0;
?scanf("%d%d",?&x,?&y);
?//判斷坐標(biāo)是否合法
?if?(x?>?0?&&?x?<=?row?&&?y?>?0?&&?y?<=?col)
?{
??//判斷該位置是否被標(biāo)記過(guò)
??if?(show[x][y]?==?'!')
??{
???show[x][y]?=?'*';
???flag_count--;
??}
??else
???printf("該位置未被標(biāo)記過(guò),無(wú)需取消標(biāo)記\n");
?}
?else
?{
??printf("該坐標(biāo)不合法,請(qǐng)重新輸入:>\n");
?}
}
圖中‘!’即為標(biāo)記區(qū)域

綜上,此程序基本實(shí)現(xiàn)了掃雷小游戲的功能,有一定的娛樂(lè)性,各位小伙伴感興趣的話可以玩一把。
「完整代碼」
阿里云盤(pán)鏈接:https://www.aliyundrive.com/s/FFcnypRbGoQ
原文鏈接:https://blog.csdn.net/weixin_56372949/article/details/121152803
