C++实现扫雷经典小游戏
用C++复现经典扫雷,供大家参考,具体内容如下
主要是dfs实现打开一片的操作,数字带有颜色,很真实。
windows扫雷中鼠标左右键同时按也实现了,即试探。
先上图,详见下面代码:
代码中有详细注释,编译无任何错误警告。
Ps.有bug请评论指出,谢谢啦~
另外我觉得代码比较臃肿,有什么可以优化的也请提出~
#include#include #include #include #include #include #include usingnamespacestd; #defineMAXN35 #defineMIDX10 #defineMIDY40 #defineCG25 #defineCK80 intG,K,Lnum,Wnum;//G为地图高,K为地图,Lnum为地图中的雷数,Wnum为剩余的小旗数 intnx,ny;//现在光标所在的位置 boolQR=0,Lose=0,is_flag_true[MAXN][MAXN];//QR为确认模式是否打开,Lose为是否输,第三个是这个位置上的旗是否放对 charmap[MAXN][MAXN],tmap[MAXN][MAXN];//第一个是只有雷和空地的地图,第二个是玩家能看到的地图 intmap1[MAXN][MAXN],mapc[MAXN][MAXN];//map1为数字的地图,其中0代表空地,-1为雷,1-8为周围雷的个数 //mapc为当前格子的颜色 intcol[10]={240,249,242,252,241,244,243,240,248};//col[i]表示windows扫雷中i的颜色,col[0]为空格的颜色 intd[10][4]={{0},{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};//8个方向 boolZB;//作弊是否打开 /*各种函数*/ voidcolor(int);//颜色 voidgto(int,int);//光标位置 voidmake();//制作随机地图 voidprint();//打印地图等 boolcheck(int,int);//判断坐标是否合法 boolis_win();//判断是否赢 boolis_lose();//是否输 voiddfs(int,int);//用深搜来打开方块 voidst(int,int);//试探,即windows扫雷中的左右键同时按 voidflag(int,int);//小旗 voidbj(int,int);//标记 voidswt();//确认模式 voidagain();//重新开始 voidzb();//作弊模式 voidmainmain();//主函数 voidprint_real_map();//打印最终的地图 voidbegin();//各种操作 intmain() { mainmain(); } voidcolor(inta){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a);} voidgto(intx,inty) { COORDpos;pos.X=y;pos.Y=x; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos); } voidmake() { for(inti=1;i<=G;i++) for(intj=1;j<=K;j++) map[i][j]='#';//初始化 for(inti=1;i<=Lnum;i++) { intx=rand()%G+1,y=rand()%K+1; while(map[x][y]=='O') x=rand()%G+1,y=rand()%K+1; map[x][y]='O'; }//随机放雷 for(inti=1;i<=G;i++) for(intj=1;j<=K;j++) { if(map[i][j]=='O')map1[i][j]=-1,mapc[i][j]=240;//如果是雷 else { for(intk=1;k<=8;k++) if(map[i+d[k][0]][j+d[k][1]]=='O') map1[i][j]++;//计算周围雷的个数 mapc[i][j]=col[map1[i][j]];//根据格子上的数设置颜色 } } for(inti=1;i<=G;i++) for(intj=1;j<=K;j++) if(mapc[i][j]==0)//空地 mapc[i][j]=240; } voidprint() { system("cls"); gto(0,MIDY-4);color(233);printf("扫雷"); color(240); gto(1,MIDY); for(inti=2;i<=G+1;i++) { gto(i,0); for(intj=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("-----规则-----"); gto(3,2*K+5);printf("wasd:选择位置"); gto(4,2*K+5);printf("空格:打开"); gto(5,2*K+5);printf("1键:试探周围8个方块,如果其中有雷则不会打开,无"); gto(6,2*K+5);printf("雷或旗帜标对了则会将周围无雷的位置打开,"); gto(7,2*K+5);printf("如果试探时周围有标错的旗帜,则会游戏失败"); gto(8,2*K+5);printf("必须额外确认一次,以便查看周围被试探的区域"); gto(9,2*K+5);printf("2键:放置/取消小旗(F)"); gto(10,2*K+5);printf("3键:放置/取消标记(?)"); gto(11,2*K+5);printf("4键:打开/关闭确认模式,即每次操作需再按一次确认"); gto(12,2*K+5);printf("5键:打开/关闭作弊模式,即显示原本地图"); gto(13,2*K+5);printf("0键:重新开始");//打印规则 gto(G+4,0);printf("-----操作提示-----\n"); printf("请选择方块进行操作"); gto(1,2*K+10);color(12);printf("剩余小旗数:%d",Wnum=Lnum); } boolcheck(intx,inty){returny>=0&&y =2&&x 胜利 for(inti=1;i<=G;i++) for(intj=1;j<=K;j++) if((tmap[i][j]!='F'&&map1[i][j]==-1)||(tmap[i][j]=='F'&&map1[i][j]!=-1)) return0; return1; //所有雷都标有旗 } boolis_lose(){returnLose;} voiddfs(intx,inty) { if(map1[x-1][y+1]>0)//只要边界全部是数字就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("");//因为下面判断了雷,上面判断了数字,这里就一定是空地 for(inti=1;i<=8;i++) { intxx=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的参数要变化 dfs(xx+1,yy-1); } } voidst(intx,inty) { for(inti=1;i<=8;i++) { intxx=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使周围的8个格子的背景颜色变为灰色 else color(112);//这里特判一下'#',应该可以不用 printf("%c",tmap[xx-1][yy+1]); } } gto(G+5,0),color(15),printf("请确认"); //试探必须额外确认一次,规则上有说 charc=getch(); if(c=='1') { for(inti=1;i<=8;i++) { intxx=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)//试探时有格子的小旗标错了=>失败 { Lose=1; return; } } for(inti=1;i<=8;i++) { intxx=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')//试探是有格子为雷=>取消打开 return; } for(inti=1;i<=8;i++) { intxx=x+d[i][0],yy=y+d[i][1]; if(check(xx,yy)&&tmap[xx-1][yy+1]=='#')//打开周围8个格子 dfs(xx,yy); } } } voidflag(intx,inty) { 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++;//更新小旗数 } else//否则就放置小旗 { is_flag_true[x][y]=map1[x][y]==-1;//判断小旗是否放对 tmap[x][y]='F';mapc[x][y]=253; gto(x+1,y-1),color(253),printf("F"); Wnum--;//更新小旗数 } gto(1,2*K+10);color(12);printf("剩余小旗数:"); gto(1,2*K+22);printf("%d",Wnum);//更新小旗数 } voidbj(intx,inty)//和放小旗差不多,只是不用更新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')//如果原本这个位置上是小旗,而你把它变为了标记,就要更新小旗数 { Wnum++; gto(1,2*K+10);color(12);printf("剩余小旗数:"); gto(1,2*K+22);printf("%d",Wnum); } gto(x+1,y-1),color(240),printf("?"); tmap[x][y]='?';mapc[x][y]=240; } } voidswt(){QR=!QR;} voidzb() { if(ZB)//如果本来作弊打开了就把作弊地图清除 { for(inti=1;i<=G;i++) { gto(i+1,K+2); for(intj=1;j<=K;j++) color(15),printf(""); } ZB=0; } else//否则打印作弊地图 { for(inti=1;i<=G;i++) { gto(i+1,K+2); for(intj=1;j<=K;j++) { color(mapc[i][j]); if(map1[i][j]==-1)printf("O"); elseif(map1[i][j]>0)printf("%d",map1[i][j]); elseprintf(""); } } ZB=1; } } voidagain() { 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(); } voidbegin()//各种操作 { charc=getch(); gto(G+5,0),color(15),printf("请选择方块进行操作"); 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("@"); } elseif(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("@"); } elseif(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("@"); } elseif(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("@"); } //上下左右移动 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]];//如果本来放了标记,mapc[nx-1][ny+1]的颜色为黑色,在打开时里面的颜色却不一定是黑色 if(QR) { gto(G+5,0),color(15),printf("请确认"); 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); } } elseif(c=='1') { if(QR) { gto(G+5,0),color(15),printf("请确认"); if(getch()=='1')st(nx,ny); } elsest(nx,ny); for(inti=1;i<=8;i++) { intxx=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]); elsecolor(240); printf("%c",tmap[xx-1][yy+1]); } } } elseif(c=='2'&&(tmap[nx-1][ny+1]>'9'||tmap[nx-1][ny+1]<'1')) { if(QR) { gto(G+5,0),color(15),printf("请确认"); if(getch()=='2')flag(nx,ny); } elseflag(nx,ny); } elseif(c=='3'&&(tmap[nx-1][ny+1]>'9'||tmap[nx-1][ny+1]<'1')) { if(QR) { gto(G+5,0),color(15),printf("请确认"); if(getch()=='3')bj(nx,ny); } elsebj(nx,ny); } elseif(c=='4') { if(QR) { gto(G+5,0),color(15),printf("请确认"); if(getch()=='4')swt(); } elseswt(); } elseif(c=='5') { if(QR) { gto(G+5,0),color(15),printf("请确认"); if(getch()=='5')zb(); } elsezb(); } elseif(c=='0') { if(QR) { gto(G+5,0),color(15),printf("请确认"); if(getch()=='0')again(); } elseagain(); } } } voidmainmain() { system("modeconcols=120lines=35");//设置窗口大小 srand((unsigned)time(NULL)); intmode; printf("1.初级\n2.中级\n3.高级\n4.自定义\n"); scanf("%d",&mode);if(mode>4)mode=4; if(mode==1)G=9,K=9,Lnum=10; elseif(mode==2)G=16,K=16,Lnum=40; elseif(mode==3)G=16,K=30,Lnum=99;//三种等级的参数 else { printf("请输入雷区高度:");scanf("%d",&G); printf("请输入雷区宽度:");scanf("%d",&K); printf("请输入雷个数(建议不超过总大小的三分之一):");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; //控制参数的范围,最后一个if是雷的数量不超过地图大小的9/10 } make(); print(); while(1) { begin(); boolf1=is_win(),f2=is_lose(); if(f1||f2) { gto(0,0); if(f1) color(202),gto(0,0),printf("你赢了!!是否重来?(y/n)"); if(f2) color(137),gto(0,0),printf("你输了!!是否重来?(y/n)");//输赢 print_real_map(); charc=getch(); if(c=='y'||c=='Y')again(); else { color(15); system("cls"); gto(MIDX,MIDY-5); printf("欢迎下次再来"); return; } } } } voidprint_real_map() { color(240); for(inti=1;i<=G;i++) { gto(i+1,0); for(intj=1;j<=K;j++) { if(tmap[i][j]=='F'&&is_flag_true[i][j]==0)//如果旗标错了显示红色的X color(252),printf("X"); elseif(map1[i][j]==-1)//雷为黑色O color(240),printf("O"); elseif(map1[i][j]==0)//空 color(240),printf(""); else//数字 color(mapc[i][j]),printf("%d",map1[i][j]); } } }
更多精彩游戏小代码,请点击《游戏专题》阅读
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。