编写一个扫雷游戏,我们首先要清楚游戏规则:
扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。游戏主区域由很多个方格组成。使用鼠标左键随机点击一个方格,方格即被打开并显示出方格中的数字;方格中数字则表示其周围的8个方格隐藏了几颗雷;如果点开的格子为空白格,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有空白格,则会引发连锁反应;在你认为有雷的格子上,点击右键即可标记雷;如果一个已打开格子周围所有的雷已经正确标出,则可以在此格上同时点击鼠标左右键打开其周围剩余的无雷格。
转化为c语言的东西就是我们用一个字节表示其各种状态,第八位可以表示显示初始化的标识,第七位表示显示雷的标识,第六位表示设置地雷,第五位表示显示数字,剩下的四位就表示身边的地雷数字,为了防止改变比特位的时候把状态也改变了,我们就用到了位与“&”以及位或“|”,而非逻辑与“&&”与逻辑或“|”,通俗点说就是,1与任何值&的结果都是1,0与任何值|的结果都是0。
代码:
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<windows.h>
#include<time.h>
#define INIT_VIEW 0X80 //1000 0000 @
#define MINE_VIEW 0X40 //0100 0000 #//地雷标记
#define MAKE_MINE 0X20 //0010 0000 //地雷
#define MAKE_NUM 0X10 //0001 0000 0 1 2 3雷的个数
#define CLEAR_INIT 0X7F //0111 1111 清除初始化
#define CLEAR_MINE 0XBF //1011 1111 清除雷的显示
#define VIEW_NUM 0X0F //0000 1111 显示数字
#define ROWSIZE 15 //游戏区域
#define COLSIZE 15
#define MINESIZE 64 //雷的个数
typedef unsigned char Grid[ROWSIZE+2][COLSIZE+2];
//行和列多2,方便计算不是累的方格周围的雷数
void Init_ar(Grid ar,int row,int col)
{
assert(ar !=nullptr);
for(int r=1;r<=row;++r)
{
for(int c=1;c<=col;++c)
{
ar[r][c]|=INIT_VIEW;//初始化显示
}
}
int num=0;
srand((unsigned)time(NULL)); //设置时间种子,以至于每次执行程序的时候地雷的位置不一样
while(num<MINESIZE) //随机设置地雷
{
int r=rand()%ROWSIZE+1;
int c=rand()%COLSIZE+1;
if(!(ar[r][c]&MAKE_MINE))//如果这个队列不是地雷的话,就设置为雷,直到整个地图有64个雷
{
ar[r][c]|=MAKE_MINE;
++num;
}
}
}
void testprint(Grid ar,int row,int col)
{
printf(" ");
for(int j=1;j<=col;++j)
{
printf("%2d",j);
}
printf("\n");
for(int i=1;i<=row;++i)
{
printf("%2d",i);
for(int j=1;j<=col;++j)
{
if(ar[i][j]&MAKE_MINE)
{
printf("%2c",'#');
}
else
{
printf("%2c",'@');
}
}printf("\n");
}printf("\n");
}
void testprint2(Grid ar,int row,int col)
{
printf(" ");
for(int j=1;j<=col;++j)
{
printf("%2d",j);
}
printf("\n");
for(int i=1;i<=row;++i)
{
printf("%2d",i);
for(int j=1;j<=col;++j)
{
if(ar[i][j]&MAKE_NUM)
{
printf("%2d",ar[i][j]&VIEW_NUM);
}
else if(ar[i][j]&MAKE_MINE)
{
printf("%2c",'#');
}
else
{
printf("%2c",'@');
}
}printf("\n");
}printf("\n");
}
void setminenum(Grid ar,int row,int col)//计算不是雷的方格周围的雷数
{
assert(ar !=nullptr);
for(int r=1;r<=row;++r)
{
for(int c=1;c<=col;++c)
{
if(!(ar[r][c]&MAKE_MINE))//如果这个点不是雷
{
unsigned char num=0;
for(int i=r-1;i<=r+1;++i)//判断每个点的三行三列
{
for(int j=c-1;j<=c+1;++j)
{
//如果是雷
if(ar[i][j]&MAKE_MINE)
{
num+=1;
}
}
}
ar[r][c]|=MAKE_NUM;//数字状态
ar[r][c]|=(0x0f&num);//周围有几个雷
}
}
}
}
void show_ar(Grid ar,int row,int col)
{
//system("cls");
printf(" ");
for(int j=1;j<=col;++j)
{
printf("%2d",j);
}
printf("\n");
for(int i=1;i<=row;++i)
{
printf("%2d",i);
for(int j=1;j<=col;++j)
{
if(ar[i][j]&INIT_VIEW) //初始化显示
{
printf("%2c",'@');
}
else if(ar[i][j]&MINE_VIEW)//雷的显示
{
printf("%2c",'#');
}
else{ //显示数字
printf("%2d",ar[i][j]&VIEW_NUM);
}
}
printf("\n");
}printf("\n");
}
int main()
{
Grid ar={0};
Init_ar(ar,ROWSIZE,COLSIZE);
//testprint(ar,ROWSIZE,COLSIZE);
setminenum(ar,ROWSIZE,COLSIZE);
//testprint2(ar,ROWSIZE,COLSIZE);
int num=0,tag=0;
int r,c;
char ch;
while(tag!=0||num<MINE_VIEW)
{
printf("%d\n",tag);//测试用,设置标记错误的雷的个数,不是雷,标记成雷+1,取消标记-1
/* for(r=1;r<=ROWSIZE;++r)
{
for(c=1;c<=COLSIZE;++c)
{
//Sleep(200);
ch='#';
*/
show_ar(ar,ROWSIZE,COLSIZE);
printf("输入行列\n");
scanf("%d %d %c",&r,&c,&ch);
if(r>=1&&r<=ROWSIZE&&c>=1&&c<=COLSIZE)
{ if(ch=='0')
{
if(ar[r][c]&MAKE_MINE)//将雷标记成不是雷
{
printf("雷炸了\n");
break;
}
else
{
if(ar[r][c]&MINE_VIEW)//0100 0000如果是雷的视图
{
ar[r][c]&=CLEAR_MINE;//1011 1111清除雷的标记
//ar[r][c]|=INIT_VIEW;//1000 0000初始化显示
tag=tag-1;
}
ar[r][c]&=CLEAR_INIT;//0111 1111清除初始化
}
}
else if(ch=='#')
{
if(ar[r][c]&MAKE_MINE)//是地雷
{
num=num+1;
}
else{tag=tag+1;}
ar[r][c]&=CLEAR_INIT;//清除初始化
ar[r][c]|=MINE_VIEW;//雷视图
//tag=tag+1;
//printf("tag=%d",tag);
//if(tag>64)
//{
//printf("标记雷的个数等于64,但是还没有寻找完成\n");
// break;
//}
}
else if(ch=='@')
{
if(ar[r][c]&MAKE_MINE)//是地雷
{
num=num-1;
}
else
{
if(ar[r][c]&MINE_VIEW)//0100 0000如果是雷的视图
{
tag=tag-1;
}
}
ar[r][c]&=CLEAR_MINE;//1011 1111清除雷的标记
ar[r][c]|=INIT_VIEW;//1000 0000初始化显示
}
}
else{printf("输入错误\n");}
} /* }
}*/
if(num>=MINESIZE)
{
printf("胜利\n");
}
if(tag>64)
{
printf("超出最大雷个数,没有找到所有雷,失败\n");
}
return 0;
}
//问题:标记完雷,直接标记不是雷,无法操作//已实现
结果:
0
1 2 3 4 5 6 7 8 9101112131415
1 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
2 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
3 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
4 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
5 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
6 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
7 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
8 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
9 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
10 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
11 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
12 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
13 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
14 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
15 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
输入行列
1 1 #
0
1 2 3 4 5 6 7 8 9101112131415
1 # @ @ @ @ @ @ @ @ @ @ @ @ @ @
2 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
3 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
4 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
5 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
6 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
7 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
8 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
9 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
10 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
11 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
12 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
13 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
14 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
15 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
输入行列
1 1 @
0
1 2 3 4 5 6 7 8 9101112131415
1 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
2 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
3 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
4 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
5 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
6 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
7 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
8 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
9 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
10 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
11 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
12 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
13 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
14 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
15 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
输入行列
1 1 0
雷炸了