oracle 小游戏编程,C++实现扫雷经典小游戏

用C++复现经典扫雷,供大家参考,具体内容如下

主要是dfs实现打开一片的操作,数字带有颜色,很真实。

windows扫雷中鼠标左右键同时按也实现了,即试探。

先上图,详见下面代码:

f59f41cc102a008600c1cf5ef9414b73.gif

代码中有详细注释,编译无任何错误警告。

Ps.有bug请评论指出,谢谢啦~

另外我觉得代码比较臃肿,有什么可以优化的也请提出~

#include

#include

#include

#include

#include

#include

#include

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为地图中的雷数,Wnum为剩余的小旗数

int nx,ny;//现在光标所在的位置

bool QR=0,Lose=0,is_flag_true[MAXN][MAXN];//QR为确认模式是否打开,Lose为是否输,第三个是这个位置上的旗是否放对

char map[MAXN][MAXN],tmap[MAXN][MAXN];//第一个是只有雷和空地的地图,第二个是玩家能看到的地图

int map1[MAXN][MAXN],mapc[MAXN][MAXN];//map1为数字的地图,其中0代表空地,-1为雷,1-8为周围雷的个数

//mapc为当前格子的颜色

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个方向

bool ZB;//作弊是否打开

/*各种函数*/

void color(int);//颜色

void gto(int,int);//光标位置

void make();//制作随机地图

void print();//打印地图等

bool check(int,int);//判断坐标是否合法

bool is_win();//判断是否赢

bool is_lose();//是否输

void dfs(int,int);//用深搜来打开方块

void st(int,int);//试探,即windows扫雷中的左右键同时按

void flag(int,int);//小旗

void bj(int,int);//标记

void swt();//确认模式

void again();//重新开始

void zb();//作弊模式

void mainmain();//主函数

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';

}//随机放雷

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]++;//计算周围雷的个数

mapc[i][j]=col[map1[i][j]];//根据格子上的数设置颜色

}

}

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("-----规则-----");

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);

}

bool check(int x,int y){return y>=0&&y=2&&x

//因为地图是从2行0列开始打的,而地图是从1行1列开始存的,所以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;

//所有没被打开的方块都是雷=>胜利

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;

//所有雷都标有旗

}

bool is_lose(){return Lose;}

void dfs(int x,int y)

{

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(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的参数要变化

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使周围的8个格子的背景颜色变为灰色

else

color(112);//这里特判一下'#',应该可以不用

printf("%c",tmap[xx-1][yy+1]);

}

}

gto(G+5,0),color(15),printf("请确认 ");

//试探必须额外确认一次,规则上有说

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)//试探时有格子的小旗标错了=>失败

{

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')//试探是有格子为雷=>取消打开

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]=='#')//打开周围8个格子

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++;//更新小旗数

}

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);//更新小旗数

}

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')//如果原本这个位置上是小旗,而你把它变为了标记,就要更新小旗数

{

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;

}

}

void swt(){QR=!QR;}

void zb()

{

if(ZB)//如果本来作弊打开了就把作弊地图清除

{

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("请选择方块进行操作");

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("@");

}

//上下左右移动

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);

}

}

else if(c=='1')

{

if(QR)

{

gto(G+5,0),color(15),printf("请确认 ");

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]

{

if(QR)

{

gto(G+5,0),color(15),printf("请确认 ");

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]

{

if(QR)

{

gto(G+5,0),color(15),printf("请确认 ");

if(getch()=='3') bj(nx,ny);

}

else bj(nx,ny);

}

else if(c=='4')

{

if(QR)

{

gto(G+5,0),color(15),printf("请确认 ");

if(getch()=='4') swt();

}

else swt();

}

else if(c=='5')

{

if(QR)

{

gto(G+5,0),color(15),printf("请确认 ");

if(getch()=='5') zb();

}

else zb();

}

else if(c=='0')

{

if(QR)

{

gto(G+5,0),color(15),printf("请确认 ");

if(getch()=='0') again();

}

else again();

}

}

}

void mainmain()

{

system("mode con cols=120 lines=35");//设置窗口大小

srand((unsigned)time(NULL));

int mode;

printf("1.初级\n2.中级\n3.高级\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;//三种等级的参数

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();

bool f1=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();

char c=getch();

if(c=='y'||c=='Y') again();

else

{

color(15);

system("cls");

gto(MIDX,MIDY-5);

printf("欢迎下次再来");

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)//如果旗标错了显示红色的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//数字

color(mapc[i][j]),printf("%d",map1[i][j]);

}

}

}

更多精彩游戏小代码,请点击《游戏专题》阅读

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值