扫雷
来源:互联网 发布:大连民族大学网络教学 编辑:程序博客网 时间:2024/05/22 08:04
从发表问题到今天10月28日,这几天在超级课程表上认真回复我的童鞋只有 小短腿 一个人,所以我尽最大的努力试着写了一个C语言版本的扫雷,本来没准备写的,因为以前第一次写类似的程序是编写贪吃蛇,用了三个月时间(大部分时间都在调试BUG),那时候没想过先写过程,再码代码,而是自以为是的认为可以凭借自己的小脑核一下子全部写出代码的,自此留下心理阴影。。。
现在学过java后,理解了面向对象编程,又知道了大型工程都是分块的团队合作完的之后,总之,现在不会上来就码代码,而是分析代码运行过程,看看能不能分成几块,就像蚂蚁搬家一样,既然我没办法一下子写完,就只能一块块写完,只要每一块都没问题,最后调试就相对简单了。
在10月26日看到回复后,用了两天的课间时间思考整个程序的运行过程,并用了三页的纸画流程图(估摸着只有自己能看懂,第一张最简单,第二张有大致分类,第三张比较详细),最后今天用了一个下午的时间用代码实现功能。里面的随机函数是网上找的,不常用就没记住函数名,知道到哪里去找就可以。
大致分为四部分
1图形部分
2扫雷部分
3随机位置生成部分
4接收输入部分
使用方法及简介在最下面
#include<stdio.h>
#include<stdlib.h>#include <time.h>
#define X 10+1
#define Y 10+1
int storage[X][Y]={0}; //位置显示存储
/* 显示 数字表达
雷 * 9
初始 + -2
无雷 0-8 0-8
被标记 @ -1
*/
int mine[X][Y]={0}; //雷位置存储
/*
有雷 无雷
1 0
*/
int mark=0,markNum=0;
/*
mark记录可标记数量
markNum记录已标记数量
*/
int suiJiShu(int max)//产生1到max的随机数
{
if(max<=0)
return 1;
return rand()%max+1;
}
void suiji()// 随机生成雷的位置并保存到mine数组
{
int i,j;
int sum;
int N=X*Y*0.20;
//使雷的总数达到总位置数的 20% 左右
//(测试时这个数量的图像看上去比较养眼)
int k=0;
int b=1;
int small;//找 X 和 Y 中最小的
if(X>Y)
{
small=X-1;
}
else
{
small=Y-1;
}
while(1)
{
int a;
a=suiJiShu(small);
mine[a][b]=1;
b++;
if(b==Y)
{
b=1;
}
k++;
if(N==k)
{
break;
}
}
}
void show()// test 成功
{
int i,j;
for(i=0;i<20;i++)
printf("\n");
for(i=0;i<X;i++)
{
for(j=0;j<Y;j++)
{
if(0==i||0==j)
{
if(0==i)
{
if(j==0)
{
printf(" ");
}
else
{
printf("%-3d",j);
}
}
if(0==j)
{
if(i==0)
{
}
else
{
printf("%-3d",i);
}
}
}
else
{
//判断
int n;
n=storage[i][j];
switch(n)
{
case -2:printf("+ ");break;
case -1:printf("@ ");break;
case 9:printf("* ");break;
default:printf("%-3d",n);
}
}
}
printf("\n");
}
}
/*
1 2 3
1 (1,2)
2 (2,2)
3
*/
int flag[X][Y]={0};//可以理解为标志位,避免重复搜索同一个地方
int sweep(int x,int y)//深度搜索旁边有雷就停并显示雷的数量
{
if(flag[x][y]==1)
{
return 0;
}
if(1==mine[x][y])
{
int i;
for(i=0;i<20;i++)
printf("\n");
printf("Game over! \n 你踩到雷了!\n");
return 4;
}
int M=0;//假设周围为 0 个雷,每遇到一个就加一
int i;
int situationX[9]={0};
int situationY[9]={0};
int si=0;
for(i=1;i<=8;i++)
{
int a=0,b=0;
switch(i)
{
case 1:
if(0==(x-1))//表示上边是边界 ,什么都不做
{
continue ;
}
else
{
a=x-1;
b=y;
}
break;
case 2:
//右上
if((x-1)==0||(y+1)==Y)//表示是边界 ,什么都不做
{
continue ;
}
else
{
a=x-1;
b=y+1;
}
break;
case 3:
//右
if((y+1)==Y)//表示是边界 ,什么都不做
{
continue ;
}
else
{
a=x;
b=y+1;
}
break;
case 4:
//右下
if(X==(x+1)||(y+1)==Y)//表示是边界 ,什么都不做
{
continue ;
}
else
{
a=x+1;
b=y+1;
}
break;
case 5:
if(X==(x+1))
{
continue;
}
else
{
a=x+1;
b=y;
}
break;
case 6:
//左下
if(X==(x+1)||(y-1)==0)//表示是边界 ,什么都不做
{
continue ;
}
else
{
a=x+1;
b=y-1;
}
break;
case 7:
//左
if((y-1)==0)//表示是边界 ,什么都不做
{
continue ;
}
else
{
a=x;
b=y-1;
}
break;
case 8:
//左上
if(0==(x-1)||(y-1)==0)//表示是边界 ,什么都不做
{
continue ;
}
else
{
a=x-1;
b=y-1;
}
break;
}
if(1==mine[a][b])//是雷
{
M++;
}
else
{
si++;
situationX[si]=a;
situationY[si]=b;
}
}
storage[x][y]=M;
if(M!=0)
return 0;
flag[x][y]=1;
while(si)
{
sweep(situationX[si],situationY[si]); //递归循环本函数
si--;
}
flag[x][y]=0;
return 0;
}
int receive() //test 成功 接收位置和命令
{
int x,y,operate;
while(1)
{
scanf("%d%d%d",&x,&y,&operate);
int x1=0,y1=0,ope=0;
if(x<1||x>X-1)
{
x1=1;
printf("\n x 坐标数值<1~%d> ",X-1);
}
if(y<1||y>Y-1)
{
y1=1;
printf(" y 坐标数值<1~%d> ",Y-1);
}
if(operate<1||operate>3)
{
ope=1;
printf("操作命令数值<1~3> ");
}
if(0!=(x1+y1+ope))
{
printf("出错,请重新输入:\n");
}
else
{
break;
}
}
//printf("input yes:%d %d %d\n\n",x,y,operate);
//int x,y,operate;
switch(operate)
{
case 1:
//printf("在x=%d,y=%d位置扫雷\n",x,y);
//条件 位置应是初始状态
if(-2==storage[x][y])
{
int numOfSweep=0;
//printf("jin ru sweep\n");//------------------------调试时的剩余代码
numOfSweep=sweep(x,y);
//printf("sweep han shu jie shu\n");//--------------调试时的剩余代码
if(4==numOfSweep)
{
return 4;
//点到炸弹
}
else
{
//正常
}
}
else
{
printf("需要扫雷的位置不是初始状态\n");
}
break;
case 2:
//printf("判断x=%d,y=%d位置为空,就标记\n",x,y); //调试时的剩余代码
//加一条 如果标记数等于0就不允许再添加
if(-2==storage[x][y])
{
if(markNum==mark)
{
printf("禁止将标记数量超过雷的总数\n");
break;
}
else
{
markNum++;
storage[x][y]=-1;
}
}
break;
case 3:
//printf("判断x=%d,y=%d位置被标记,就取消\n",x,y);
if(-1==storage[x][y])
{
markNum--;
storage[x][y]=-2;
}
break;
default:printf("no possible! 不可能到这里滴... ^_^\n");
}
return 0;
}
int main()
{
srand((unsigned)time( NULL ));// 以时间为种子,运行一次即可 yes
suiji();//生成随机雷位置,并存储到 mine[X][Y] 中 yes
int i,j;
//for 循环找到所有雷数量 yes
//初始化显示存储
for(i=1;i<X;i++)
{
for(j=1;j<Y;j++)
{
if(1==mine[i][j])
{
mark+=1;
}
storage[i][j]=-2;
}
}
/*
mark记录可标记数量 (雷的总数 )
markNum记录已标记数量 (标记数量)
*/
int end=0;
while(1)
{
//检查是否所有的雷是否都被正确标记 yes
int n=0;
for(i=1;i<X;i++)
{
for(j=1;j<Y;j++)
{
if(1==mine[i][j]&&-1==storage[i][j])//(与雷位置一一对应 )
{
n++;
}
}
}
if(n==mark)
{
break;
}
else
{
show();//显示图像 yes
end=receive();//接收数据输入并执行
if(4==end)//正常返回 0 返回 4 表示 触到雷
{
return 0;
}
}
}
//显示所有雷的位置,并将其他全部清空为加号。 yes
for(i=1;i<X;i++)
{
for(j=1;j<Y;j++)
{
if(1==mine[i][j])
{
storage[i][j]=9;
}
else
{
storage[i][j]=-2;
}
}
}
show();
//输出祝贺语句 yes
printf("祝贺你成功了!\n");
return 0;
}
/*
storage[X][Y]={0}; //位置显示存储
显示 数字表达
雷 * 9
初始 + -2
无雷 0-8 0-8
被标记 @ -1
*/
/*
使用方法,和linux中的shell命令行操作一致,或者说和Windows中的cmd差不太多,
界面初始状态下显示为
输入的只有三个数,用空格隔开
比如:2 4 1
代表的含义是
在第2行第4列执行操作1
一共10行10列,可自定义
1操作是扫雷
2操作是标记
3操作是取消标记
输入错误会有简单提示
踩到也会说出来的
没版权,没限制,自由复制,自由学习>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
*/
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 扫雷
- 脑洞大开 90后卖飞机的小女孩又众筹帆船
- 【国内首家VR虚拟现实主题公园】免费预约体验!
- 1672: [Usaco2005 Dec]Cleaning Shifts 清理牛棚 DP + 线段树 / SPFA
- 输出满足1+2+3...+n<8888的最大正整数.(作业)
- 14.34
- 扫雷
- Linux之shell基础
- 进程间的通讯方式_信号量
- mac 安装docker
- 国考将至 手机管家提醒:“包过关”你别信
- IP虽好仍需孵化平台助力 QQ浏览器提速优质内容接入
- codevs1160-蛇形矩阵(螺旋矩阵)
- 够快才畅快vivo X6跨界首发全球最强Hi-Fi芯片 或同时发布耳机
- 基础知识总结:基本数据类型