本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
为了复习C语言的语法嘛,就简单的写了一下扫雷这样一个小游戏,完全在命令行窗口运行。思路也比较简单,采用数组来模拟棋盘。一个用来模拟地雷的分布的数组。一个用来打印玩家开始看到的数组。在选择坐标后展开周围的地方。判断未展开的格子数与地雷数是否相等。结束游戏。
简单的初始界面
简单的一个初始界面,用来选择开始游戏和退出。也可以在这里在后续加上难度选择等等功能。
void ShowMenu()
{
printf("*********************************\n");
printf("*********************************\n");
printf("**********输入1 开始游戏*********\n");
printf("**********输入0 退出游戏*********\n");
printf("*********************************\n");
printf("*********************************\n");
printf("\n");
printf("\n");
printf("\n");
printf(" 请输入:\n");
}
制作棋盘和布雷
棋盘采用二维数组来构成,为了保证游戏可以重复开始,在每次开始时都要对数组进行初始化,然后随机布“雷”。为了方便在接下来扫描展开位置周围是否有“雷”。我们将数组全部初始化为0,将“雷”标记为1。这样就可以布置好地图。
void InitMap()
{
int count = 0;
for (int i = 0; i <= ROW; i++)// 初始化地图
for (int j = 0; j <= COLUMN; j++)
{
map[i][j] = 0;
show_map[i][j] = '*';
}
while (count != BANG_NUMBER) //埋雷
{
int x = rand() % ROW + 1;
int y = rand() % COLUMN + 1;
if (map[x][y] != 1)
{
map[x][y] = 1;
++count;
}
}
}
void Show_BangMap()
{
system("CLS");
printf("*********************************\n");
printf("*********************************\n");
printf("\n");
printf(" "); //打印 行列数
for (int i = 1; i <= ROW; i++)
printf(" %d ", i);
printf("\n");
for (int i = 1; i <= ROW; i++) // 打印地图
{
printf(" %d ", i);
for (int j = 1; j <= COLUMN; j++)
printf(" %c ", show_map[i][j]);
printf("\n");
}
}
“雷”的判断与展开
在判断目标周围是否有雷时,将周围所有值相加,如果结果是0,则周围没有雷,将“ ”(空格)返回给该点。否则将“雷”数返回。 在展开时,采用递归的方式,如果改点周围没有“雷“,且周围的点还未展开时,递归展开这个位置就好。一般而言。一个数的周围会有8个位置,所以需要做8次判断。但是在边缘时,会产生数字越界的警告,因此在定义数组时,将数组的范围加大一圈。我们需要一个10x10的地图时,定义一个12x12的数组,在初始化时,将所有元素赋0。但在埋”雷“时,限制范围为10x10。
int GetBangNum(int x, int y) //判断雷数
{
//将周围的所有格子的数加起来来判断是否有雷
return map[x - 1][y - 1] + map[x][y - 1] + map[x + 1][y - 1] + map[x - 1][y] + map[x + 1][y] + map[x - 1][y + 1] + map[x][y + 1] + map[x + 1][y + 1];
}
void OpenMap(int x, int y) //判断展开
{
if (GetBangNum(x,y) == 0)
{
show_map[x][y] = ' ';
if (x - 1 > 0 && y - 1 > 0 && show_map[x - 1][y - 1] == '*')
OpenMap(x - 1, y - 1);
if (x - 1 > 0 && show_map[x - 1][y] == '*')
OpenMap(x - 1, y);
if (y - 1 > 0 && show_map[x][y - 1] == '*')
OpenMap(x, y - 1);
if (x + 1 < ROW && y + 1 < COLUMN && show_map[x + 1][y + 1] == '*')
OpenMap(x + 1, y + 1);
if (y + 1 < COLUMN && show_map[x][y + 1] == '*')
OpenMap(x, y + 1);
if (x + 1 < ROW && show_map[x + 1][y] == '*')
OpenMap(x + 1, y);
if (x - 1 > 0 && y + 1 < COLUMN && show_map[x - 1][y + 1] == '*')
OpenMap(x - 1, y + 1);
if (x + 1 < ROW && y - 1 > 0 && show_map[x + 1][y - 1])
OpenMap(x + 1, y - 1);
}
else
show_map[x][y] = GetBangNum(x, y) + 48;
判断游戏结束
判断游戏结束很简单,只需要判断在地图中的“*”是否与我们开始埋下的“雷”元素是否相等。如果相等说明目前地图中只有是“雷”的元素还没有展开,则游戏结束。
int IsFull() // 判断游戏是否结束
{
int count = 0;
for(int i =1;i<=ROW;i++)
for (int j = 1; j <= COLUMN; j++)
if (show_map[i][j] == '*')
++count;
if (count == BANG_NUMBER)
return TRUE;
else
return FALSE;
}
执行游戏
接下来就没有什么问题了,将写好的函数合理调用,当键入一个坐标时,判断相应元素属性,然后按部就班调用函数。最后在用关键词switch来模拟一个游戏菜单的选择即可。
void Playing()
{
InitMap();
Show_BangMap();
int x, y;
while (TRUE)
{
printf("输入坐标:\n");
scanf_s("%d%d",&x,&y);
if (x > 0 && y > 0 && x <= ROW && y <= COLUMN)
{
if (map[x][y] == 1) //踩雷
{
for (int i = 1; i <= ROW; i++)
for (int j = 1; j <= COLUMN; j++)
if (show_map[i][j] == '*')
show_map[i][j] = '!';
Show_BangMap();
printf("\n");
printf("失败!!游戏结束!!");
break;
}
else //没有踩雷
{
if (GetBangNum(x, y) == 0)
OpenMap(x, y);
else
show_map[x][y] = GetBangNum(x, y) + 48;
Show_BangMap();
}
if (IsFull() == TRUE) //判断胜利
{
for (int i = 1; i <= ROW; i++)
for (int j = 1; j <= COLUMN; j++)
if (show_map[i][j] == '*')
show_map[i][j] = '!';
void Show_BangMap();
printf("游戏胜利!!!");
break;
}
}
else
printf("输入有误");
}
}
void test()
{
ShowMenu();
int a;
while (TRUE)
{
scanf_s("%d", &a);
switch (a)
{
case 1:
Playing();
break;
case 2:
printf("游戏结束!");
return;
default:
printf("输入有误");
}
}
}