C++實(shí)現(xiàn)掃雷經(jīng)典小游戲
用C++復(fù)現(xiàn)經(jīng)典掃雷,供大家參考,具體內(nèi)容如下
主要是dfs實(shí)現(xiàn)打開(kāi)一片的操作,數(shù)字帶有顏色,很真實(shí)。
windows掃雷中鼠標(biāo)左右鍵同時(shí)按也實(shí)現(xiàn)了,即試探。
先上圖,詳見(jiàn)下面代碼:

代碼中有詳細(xì)注釋?zhuān)幾g無(wú)任何錯(cuò)誤警告。
Ps.有bug請(qǐng)?jiān)u論指出,謝謝啦~
另外我覺(jué)得代碼比較臃腫,有什么可以?xún)?yōu)化的也請(qǐng)?zhí)岢鰚
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<conio.h>
#include<windows.h>
#include<cstdlib>
#include<ctime>
using namespace std;
#define MAXN 35
#define MIDX 10
#define MIDY 40
#define CG 25
#define CK 80
int G,K,Lnum,Wnum;//G為地圖高,K為地圖,Lnum為地圖中的雷數(shù),Wnum為剩余的小旗數(shù)
int nx,ny;//現(xiàn)在光標(biāo)所在的位置
bool QR=0,Lose=0,is_flag_true[MAXN][MAXN];//QR為確認(rèn)模式是否打開(kāi),Lose為是否輸,第三個(gè)是這個(gè)位置上的旗是否放對(duì)
char map[MAXN][MAXN],tmap[MAXN][MAXN];//第一個(gè)是只有雷和空地的地圖,第二個(gè)是玩家能看到的地圖
int map1[MAXN][MAXN],mapc[MAXN][MAXN];//map1為數(shù)字的地圖,其中0代表空地,-1為雷,1-8為周?chē)椎膫€(gè)數(shù)
//mapc為當(dāng)前格子的顏色
int col[10]={240,249,242,252,241,244,243,240,248};//col[i]表示windows掃雷中i的顏色,col[0]為空格的顏色
int d[10][4]={{0},{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};//8個(gè)方向
bool ZB;//作弊是否打開(kāi)
/*各種函數(shù)*/
void color(int);//顏色
void gto(int,int);//光標(biāo)位置
void make();//制作隨機(jī)地圖
void print();//打印地圖等
bool check(int,int);//判斷坐標(biāo)是否合法
bool is_win();//判斷是否贏
bool is_lose();//是否輸
void dfs(int,int);//用深搜來(lái)打開(kāi)方塊
void st(int,int);//試探,即windows掃雷中的左右鍵同時(shí)按
void flag(int,int);//小旗
void bj(int,int);//標(biāo)記
void swt();//確認(rèn)模式
void again();//重新開(kāi)始
void zb();//作弊模式
void mainmain();//主函數(shù)
void print_real_map();//打印最終的地圖
void begin();//各種操作
int main()
{
mainmain();
}
void color(int a){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a);}
void gto(int x,int y)
{
COORD pos;pos.X=y;pos.Y=x;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void make()
{
for(int i=1;i<=G;i++)
for(int j=1;j<=K;j++)
map[i][j]='#';//初始化
for(int i=1;i<=Lnum;i++)
{
int x=rand()%G+1,y=rand()%K+1;
while(map[x][y]=='O')
x=rand()%G+1,y=rand()%K+1;
map[x][y]='O';
}//隨機(jī)放雷
for(int i=1;i<=G;i++)
for(int j=1;j<=K;j++)
{
if(map[i][j]=='O')map1[i][j]=-1,mapc[i][j]=240;//如果是雷
else
{
for(int k=1;k<=8;k++)
if(map[i+d[k][0]][j+d[k][1]]=='O')
map1[i][j]++;//計(jì)算周?chē)椎膫€(gè)數(shù)
mapc[i][j]=col[map1[i][j]];//根據(jù)格子上的數(shù)設(shè)置顏色
}
}
for(int i=1;i<=G;i++)
for(int j=1;j<=K;j++)
if(mapc[i][j]==0)//空地
mapc[i][j]=240;
}
void print()
{
system("cls");
gto(0,MIDY-4); color(233); printf("掃雷");
color(240);
gto(1,MIDY);
for(int i=2;i<=G+1;i++)
{
gto(i,0);
for(int j=1;j<=K;j++)
printf("#"),tmap[i-1][j]='#';//初始化玩家所看到的地圖
}
gto(2,0);
nx=2,ny=0;
color(15);
printf("@");
color(15);
gto(2,2*K+5);printf("-----規(guī)則-----");
gto(3,2*K+5);printf("wasd:選擇位置");
gto(4,2*K+5);printf("空格:打開(kāi)");
gto(5,2*K+5);printf("1鍵:試探周?chē)?個(gè)方塊,如果其中有雷則不會(huì)打開(kāi),無(wú)");
gto(6,2*K+5);printf(" 雷或旗幟標(biāo)對(duì)了則會(huì)將周?chē)鸁o(wú)雷的位置打開(kāi),");
gto(7,2*K+5);printf(" 如果試探時(shí)周?chē)袠?biāo)錯(cuò)的旗幟,則會(huì)游戲失敗");
gto(8,2*K+5);printf(" 必須額外確認(rèn)一次,以便查看周?chē)辉囂降膮^(qū)域");
gto(9,2*K+5);printf("2鍵:放置/取消小旗(F)");
gto(10,2*K+5);printf("3鍵:放置/取消標(biāo)記(?)");
gto(11,2*K+5);printf("4鍵:打開(kāi)/關(guān)閉確認(rèn)模式,即每次操作需再按一次確認(rèn)");
gto(12,2*K+5);printf("5鍵:打開(kāi)/關(guān)閉作弊模式,即顯示原本地圖");
gto(13,2*K+5);printf("0鍵:重新開(kāi)始");//打印規(guī)則
gto(G+4,0);printf("-----操作提示-----\n");
printf("請(qǐng)選擇方塊進(jìn)行操作");
gto(1,2*K+10);color(12);printf("剩余小旗數(shù):%d",Wnum=Lnum);
}
bool check(int x,int y){return y>=0&&y<K&&x>=2&&x<G+2;}
//因?yàn)榈貓D是從2行0列開(kāi)始打的,而地圖是從1行1列開(kāi)始存的,所以gto(x,y)走到的是map[x-1][y+1]
bool is_win()
{
int cnt=0;
for(int i=1;i<=G;i++)
for(int j=1;j<=K;j++)
if(map[i][j]=='#'&&map1[i][j]==-1)
cnt++;
if(cnt==Lnum) return 1;
//所有沒(méi)被打開(kāi)的方塊都是雷=>勝利
for(int i=1;i<=G;i++)
for(int j=1;j<=K;j++)
if((tmap[i][j]!='F'&&map1[i][j]==-1)||(tmap[i][j]=='F'&&map1[i][j]!=-1))
return 0;
return 1;
//所有雷都標(biāo)有旗
}
bool is_lose(){return Lose;}
void dfs(int x,int y)
{
if(map1[x-1][y+1]>0)//只要邊界全部是數(shù)字就return
{
gto(x,y),color(mapc[x-1][y+1]),printf("%d",map1[x-1][y+1]);
tmap[x-1][y+1]=map1[x-1][y+1]+'0';
return;
}
gto(x,y);color(255);
tmap[x-1][y+1]=' ';
printf(" ");//因?yàn)橄旅媾袛嗔死?,上面判斷了?shù)字,這里就一定是空地
for(int i=1;i<=8;i++)
{
int xx=x+d[i][0]-1,yy=y+d[i][1]+1;//這里的xx和yy是在map中的,而不是gto中的
if(check(xx+1,yy-1)&&tmap[xx][yy]=='#'&&map1[xx][yy]!=-1)//所以check和dfs的參數(shù)要變化
dfs(xx+1,yy-1);
}
}
void st(int x,int y)
{
for(int i=1;i<=8;i++)
{
int xx=x+d[i][0],yy=y+d[i][1];
if(check(xx,yy))
{
gto(xx,yy);
if(tmap[xx-1][yy+1]!='#')
color(mapc[xx-1][yy+1]-128);//減去128使周?chē)?個(gè)格子的背景顏色變?yōu)榛疑?
else
color(112);//這里特判一下'#',應(yīng)該可以不用
printf("%c",tmap[xx-1][yy+1]);
}
}
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
//試探必須額外確認(rèn)一次,規(guī)則上有說(shuō)
char c=getch();
if(c=='1')
{
for(int i=1;i<=8;i++)
{
int xx=x+d[i][0],yy=y+d[i][1];
if(check(xx,yy))
if(tmap[xx-1][yy+1]=='F'&&map1[xx-1][yy+1]!=-1)//試探時(shí)有格子的小旗標(biāo)錯(cuò)了=>失敗
{
Lose=1;
return;
}
}
for(int i=1;i<=8;i++)
{
int xx=x+d[i][0],yy=y+d[i][1];
if(check(xx,yy))
if(map1[xx-1][yy+1]==-1&&tmap[xx-1][yy+1]!='F')//試探是有格子為雷=>取消打開(kāi)
return;
}
for(int i=1;i<=8;i++)
{
int xx=x+d[i][0],yy=y+d[i][1];
if(check(xx,yy)&&tmap[xx-1][yy+1]=='#')//打開(kāi)周?chē)?個(gè)格子
dfs(xx,yy);
}
}
}
void flag(int x,int y)
{
x-=1,y+=1;
if(tmap[x][y]=='F')//原本為小旗=>取消小旗
{
tmap[x][y]='#';mapc[x][y]=240;
gto(x+1,y-1),color(240),printf("#");
Wnum++;//更新小旗數(shù)
}
else//否則就放置小旗
{
is_flag_true[x][y]=map1[x][y]==-1;//判斷小旗是否放對(duì)
tmap[x][y]='F';mapc[x][y]=253;
gto(x+1,y-1),color(253),printf("F");
Wnum--;//更新小旗數(shù)
}
gto(1,2*K+10);color(12);printf("剩余小旗數(shù): ");
gto(1,2*K+22);printf("%d",Wnum);//更新小旗數(shù)
}
void bj(int x,int y)//和放小旗差不多,只是不用更新is_flag_true
{
x-=1,y+=1;
if(tmap[x][y]=='?')
{
gto(x+1,y-1),color(240),printf("#");
tmap[x][y]='#';mapc[x][y]=240;
}
else
{
if(tmap[x][y]=='F')//如果原本這個(gè)位置上是小旗,而你把它變?yōu)榱藰?biāo)記,就要更新小旗數(shù)
{
Wnum++;
gto(1,2*K+10);color(12);printf("剩余小旗數(shù): ");
gto(1,2*K+22);printf("%d",Wnum);
}
gto(x+1,y-1),color(240),printf("?");
tmap[x][y]='?';mapc[x][y]=240;
}
}
void swt(){QR=!QR;}
void zb()
{
if(ZB)//如果本來(lái)作弊打開(kāi)了就把作弊地圖清除
{
for(int i=1;i<=G;i++)
{
gto(i+1,K+2);
for(int j=1;j<=K;j++)
color(15),printf(" ");
}
ZB=0;
}
else//否則打印作弊地圖
{
for(int i=1;i<=G;i++)
{
gto(i+1,K+2);
for(int j=1;j<=K;j++)
{
color(mapc[i][j]);
if(map1[i][j]==-1) printf("O");
else if(map1[i][j]>0) printf("%d",map1[i][j]);
else printf(" ");
}
}
ZB=1;
}
}
void again()
{
G=K=Lnum=nx=ny=Lose=ZB=0;
QR=0;
memset(is_flag_true,0,sizeof(is_flag_true));
memset(map,0,sizeof(map));
memset(tmap,0,sizeof(tmap));
memset(map1,0,sizeof(map1));
memset(mapc,0,sizeof(mapc));
color(15);
system("cls");//初始化
mainmain();
}
void begin()//各種操作
{
char c=getch();
gto(G+5,0),color(15),printf("請(qǐng)選擇方塊進(jìn)行操作");
color(240);
if(c=='w'&&check(nx-1,ny))
{
gto(nx,ny);
if(tmap[nx-1][ny+1]!='#'||tmap[nx-1][ny+1]==' ')
color(mapc[nx-1][ny+1]);
printf("%c",tmap[nx-1][ny+1]);
gto(nx-=1,ny);color(15);printf("@");
}
else if(c=='s'&&check(nx+1,ny))
{
gto(nx,ny);if(tmap[nx-1][ny+1]!='#'||tmap[nx-1][ny+1]==' ')color(mapc[nx-1][ny+1]);printf("%c",tmap[nx-1][ny+1]);
gto(nx+=1,ny);color(15);printf("@");
}
else if(c=='a'&&check(nx,ny-1))
{
gto(nx,ny);if(tmap[nx-1][ny+1]!='#'||tmap[nx-1][ny+1]==' ')color(mapc[nx-1][ny+1]);printf("%c",tmap[nx-1][ny+1]);
gto(nx,ny-=1);color(15);printf("@");
}
else if(c=='d'&&check(nx,ny+1))
{
gto(nx,ny);if(tmap[nx-1][ny+1]!='#'||tmap[nx-1][ny+1]==' ')color(mapc[nx-1][ny+1]);printf("%c",tmap[nx-1][ny+1]);
gto(nx,ny+=1);color(15);printf("@");
}
//上下左右移動(dòng)
else
{
if(c==' '&&(!(tmap[nx-1][ny+1]<='9'&&tmap[nx-1][ny+1]>='0'))&&tmap[nx-1][ny+1]!='F')
{
mapc[nx-1][ny+1]=col[map1[nx-1][ny+1]];//如果本來(lái)放了標(biāo)記,mapc[nx-1][ny+1]的顏色為黑色,在打開(kāi)時(shí)里面的顏色卻不一定是黑色
if(QR)
{
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
if(getch()==' ')
{
if(map1[nx-1][ny+1]==-1) {Lose=1;return;}
dfs(nx,ny);
}
}
else
{
if(map1[nx-1][ny+1]==-1) {Lose=1;return;}
dfs(nx,ny);
}
}
else if(c=='1')
{
if(QR)
{
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
if(getch()=='1') st(nx,ny);
}
else st(nx,ny);
for(int i=1;i<=8;i++)
{
int xx=nx+d[i][0],yy=ny+d[i][1];
if(check(xx,yy))
{
gto(xx,yy);
if(tmap[xx-1][yy+1]!='#') color(mapc[xx-1][yy+1]);
else color(240);
printf("%c",tmap[xx-1][yy+1]);
}
}
}
else if(c=='2'&&(tmap[nx-1][ny+1]>'9'||tmap[nx-1][ny+1]<'1'))
{
if(QR)
{
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
if(getch()=='2') flag(nx,ny);
}
else flag(nx,ny);
}
else if(c=='3'&&(tmap[nx-1][ny+1]>'9'||tmap[nx-1][ny+1]<'1'))
{
if(QR)
{
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
if(getch()=='3') bj(nx,ny);
}
else bj(nx,ny);
}
else if(c=='4')
{
if(QR)
{
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
if(getch()=='4') swt();
}
else swt();
}
else if(c=='5')
{
if(QR)
{
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
if(getch()=='5') zb();
}
else zb();
}
else if(c=='0')
{
if(QR)
{
gto(G+5,0),color(15),printf("請(qǐng)確認(rèn) ");
if(getch()=='0') again();
}
else again();
}
}
}
void mainmain()
{
system("mode con cols=120 lines=35");//設(shè)置窗口大小
srand((unsigned)time(NULL));
int mode;
printf("1.初級(jí)\n2.中級(jí)\n3.高級(jí)\n4.自定義\n");
scanf("%d",&mode);if(mode>4) mode=4;
if(mode==1) G=9,K=9,Lnum=10;
else if(mode==2) G=16,K=16,Lnum=40;
else if(mode==3) G=16,K=30,Lnum=99;//三種等級(jí)的參數(shù)
else
{
printf("請(qǐng)輸入雷區(qū)高度:");scanf("%d",&G);
printf("請(qǐng)輸入雷區(qū)寬度:");scanf("%d",&K);
printf("請(qǐng)輸入雷個(gè)數(shù)(建議不超過(guò)總大小的三分之一):");scanf("%d",&Lnum);
if(G>24) G=24;if(K>30) K=30;
if(G<9) G=9;if(K<9) K=9;
if(Lnum<10) Lnum=10;if(Lnum>G*K*9/10) Lnum=G*K*9/10;
//控制參數(shù)的范圍,最后一個(gè)if是雷的數(shù)量不超過(guò)地圖大小的9/10
}
make();
print();
while(1)
{
begin();
bool f1=is_win(),f2=is_lose();
if(f1||f2)
{
gto(0,0);
if(f1)
color(202),gto(0,0),printf("你 贏 了!!是否重來(lái)?(y/n)");
if(f2)
color(137),gto(0,0),printf("你 輸 了!!是否重來(lái)?(y/n)");//輸贏
print_real_map();
char c=getch();
if(c=='y'||c=='Y') again();
else
{
color(15);
system("cls");
gto(MIDX,MIDY-5);
printf("歡迎下次再來(lái)");
return;
}
}
}
}
void print_real_map()
{
color(240);
for(int i=1;i<=G;i++)
{
gto(i+1,0);
for(int j=1;j<=K;j++)
{
if(tmap[i][j]=='F'&&is_flag_true[i][j]==0)//如果旗標(biāo)錯(cuò)了顯示紅色的X
color(252),printf("X");
else if(map1[i][j]==-1)//雷為黑色O
color(240),printf("O");
else if(map1[i][j]==0)//空
color(240),printf(" ");
else//數(shù)字
color(mapc[i][j]),printf("%d",map1[i][j]);
}
}
}
更多精彩游戲小代碼,請(qǐng)點(diǎn)擊《游戲?qū)n}》閱讀
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
帶你了解C語(yǔ)言的數(shù)據(jù)的存儲(chǔ)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的數(shù)據(jù)的存儲(chǔ),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來(lái)幫助2021-08-08
詳細(xì)解析C語(yǔ)言中的開(kāi)方實(shí)現(xiàn)
這篇文章主要介紹了詳細(xì)解析C語(yǔ)言中的開(kāi)方實(shí)現(xiàn),包括一道要求精度的整數(shù)開(kāi)方的題目,需要的朋友可以參考下2015-08-08
C++實(shí)現(xiàn)LeetCode(557.翻轉(zhuǎn)字符串中的單詞之三)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(557.翻轉(zhuǎn)字符串中的單詞之三),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
如何在C++中通過(guò)模板去除強(qiáng)制轉(zhuǎn)換
本文講解的是如何在C++中通過(guò)模板去除強(qiáng)制轉(zhuǎn)換,在編程工作中應(yīng)盡量少使用強(qiáng)制類(lèi)型轉(zhuǎn)換,模板有助于我們實(shí)現(xiàn)這一目的,需要的朋友可以參考下2015-07-07

