目录
一、设计思路
用两个二维数组,一个表示底层的雷和空地周围雷的数量(字符),一个表示表层的状态(揭开了,未揭开,标记为雷)。遍历判断即可。
二、函数和宏
因为判断格子周围雷的数量时需要判断上下左右的格子,所以我们的底层格子需要比表层的格子大一圈(长度大2),但是为什么我的表层的格子也大了1呢?因为我不打算用下标为0的元素,第一排第一个格子用surface[1][1],表示显得更为直观。
#define ROW 8 //行
#define COL 20 //列
int surface[ROW + 1][COL + 1]; //表层状态
char under[ROW + 2][COL + 2]; //底层状态
int s; //雷的总数量
int menu(); //菜单
void init(); //初始化
void display(); //打印地图
void play(); //游戏
int detect(); //输赢检测
三、主函数
为了实现雷的随机生成,我用到了随机数函数,头文件要用到<stdlib.h>(rand和srand)还要用到time函数生成随机数种子<time.h>(time)。
int main()
{
srand((unsigned)time(NULL)); 设置随机数种子
int c = menu();
char i;
while (c)
{
while (1)
{
init();
while (1)
{
display();
play();
if (detect())//输或赢会返回1或-1,未结束会返回0
{
display();
break;
}
}
if (detect() == 1)
{
system("cls");
puts("恭喜你,获胜了!");
}
else if (detect() == -1)
{
puts("很遗憾,你输了。");
}
Sleep(1000);
system("pause");
system("cls");
puts("是否继续游戏(y/n)");
fflush(stdin);
scanf("%c", &i);
if (i == 'n')
break;
}
}
return 0;
}
四、自定义函数实现
1、menu(); //菜单
int menu()
{
puts("--------------------------");
puts(" *** 扫雷 *** ");
puts("--------------------------");
puts("--------1.开始游戏--------");
puts("--------0.退出游戏--------");
puts("--------------------------");
int choice = 0;
puts("请作出你的选择:");
scanf("%d", &choice);
return choice;
}
2、init(); //初始化
显然,想要打印出雷的图标只能用字符输出,所以底层的雷是以字符型储存的,那么我们的数字(表示周围的雷)也尽量用字符型储存(数字也不是不行,但输出时要判断有点麻烦)
void init() //传入的参数是为了让玩家输入的第一个位置不是雷
{
int i, j;
s = 0; //初始化雷的数量
for (i = 0; i < ROW + 2; i++)
for (j = 0; j < COL + 2; j++)
{
under[i][j] = ' ';
}
for (i = 1; i < ROW + 1; i++) //初始化表层的原因是不止一次
for (j = 1; j < COL + 1; j++)
{
surface[i][j] = 0;
}
for (i = 1; i < ROW + 1; i++)
for (j = 1; j < COL + 1; j++)
{
if (rand() % 10 > 5)
{
under[i][j] = '*';
s++;
}
}
int count;
for (i = 1; i < ROW + 1; i++)
for (j = 1; j < COL + 1; j++)
{
count = 0;
if (under[i][j] == ' ')
{
if (under[i + 1][j] == '*')
count++;
if (under[i][j + 1] == '*')
count++;
if (under[i - 1][j] == '*')
count++;
if (under[i][j - 1] == '*')
count++;
if (under[i + 1][j - 1] == '*')
count++;
if (under[i - 1][j + 1] == '*')
count++;
if (under[i + 1][j + 1] == '*')
count++;
if (under[i - 1][j - 1] == '*')
count++;
under[i][j] = '0' + count;
}
}
}
3、display(); //打印地图
底层直接用字符就是舒服。
void display()
{
int i, j;
for (i = 1; i <= ROW; i++)
{
for (j = 1; j <= COL; j++)
{
if (surface[i][j] == 0)
printf("%c", ' ');
else if (surface[i][j] == 1) //说明插了旗
printf("%c", 'R');
else
printf("%c", under[i][j]); //说明表层没了打印底层
printf("|");
}
puts("");
for (j = 1; j <= COL; j++)
{
printf("-");
printf("|");
}
puts("");
}
}
5、play(); //游戏
注意不要“出格”或重复扫。
void play()
{
char ch;
int x, y;
fflush(stdin);
puts("请问你是排雷(a)还是标记雷(d)(输入a/d)(排雷会清除标记)");
scanf("%[ad]c", &ch);
puts("请输入排雷或标记雷的坐标(例:1,2)");
while (scanf("%d,%d", &x, &y))
if (x > 0 && y > 0 && x < ROW + 1 && y < COL + 1)//不能超出范围
{
if (surface[x][y] != -1) //排除已揭开的雷
{
if (ch == 'a')
surface[x][y]--;
else
surface[x][y] = 1;
break;
}
else
puts("此位置已揭开");
}
else
puts("没有这个位置");
}
6、detect(); //输赢检测
检测时要注意标记错的地方要要“减分”,如果只是找是否全部雷被标记,那么我从头标到尾也会赢。
int detect()
{
int count = 0;
int i, j;
for (i = 1; i < ROW + 1; i++)
for (j = 0; j < COL + 1; j++)
{
if (under[i][j] == '*' && surface[i][j] == -1)
count++;
}
if (count)
return -1;
for (i = 1; i < ROW + 1; i++)
for (j = 0; j < COL + 1; j++)
{
if (under[i][j] == '*' && surface[i][j] == 1)
count++;
if (under[i][j] == ' ' && surface[i][j] == 1)
count--;
}
if (count == s) //全部被标记
return 1;
else
return 0;
}
五、全部代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define ROW 8 //行
#define COL 20 //列
int surface[ROW + 1][COL + 1]; //表层状态
char under[ROW + 2][COL + 2]; //底层状态
int s; //雷的数量
int menu(); //菜单
void init(); //初始化
void display(); //打印地图
void play(); //游戏
int detect(); //输赢检测
int main()
{
srand((unsigned)time(NULL)); 设置随机数种子
int c = menu();
char i;
while (c)
{
while (1)
{
init();
while (1)
{
display();
play();
if (detect())
{
display();
break;
}
}
if (detect() == 1)
{
system("cls");
puts("恭喜你,获胜了!");
}
else if (detect() == -1)
{
puts("很遗憾,你输了。");
}
Sleep(1000);
system("pause");
system("cls");
puts("是否继续游戏(y/n)");
fflush(stdin);
scanf("%c", &i);
if (i == 'n')
break;
}
}
return 0;
}
void init() //传入的参数是为了让玩家输入的第一个位置不是雷
{
int i, j;
s = 0; //初始化雷的数量
for (i = 0; i < ROW + 2; i++)
for (j = 0; j < COL + 2; j++)
{
under[i][j] = ' ';
}
for (i = 1; i < ROW + 1; i++) //初始化表层的原因是不止一次
for (j = 1; j < COL + 1; j++)
{
surface[i][j] = 0;
}
for (i = 1; i < ROW + 1; i++)
for (j = 1; j < COL + 1; j++)
{
if (rand() % 10 > 5)
{
under[i][j] = '*';
s++;
}
}
int count;
for (i = 1; i < ROW + 1; i++)
for (j = 1; j < COL + 1; j++)
{
count = 0;
if (under[i][j] == ' ')
{
if (under[i + 1][j] == '*')
count++;
if (under[i][j + 1] == '*')
count++;
if (under[i - 1][j] == '*')
count++;
if (under[i][j - 1] == '*')
count++;
if (under[i + 1][j - 1] == '*')
count++;
if (under[i - 1][j + 1] == '*')
count++;
if (under[i + 1][j + 1] == '*')
count++;
if (under[i - 1][j - 1] == '*')
count++;
under[i][j] = '0' + count;
}
}
}
void display()
{
int i, j;
for (i = 1; i <= ROW; i++)
{
for (j = 1; j <= COL; j++)
{
if (surface[i][j] == 0)
printf("%c", ' ');
else if (surface[i][j] == 1) //说明插了旗
printf("%c", 'R');
else
printf("%c", under[i][j]); //说明表层没了打印底层
printf("|");
}
puts("");
for (j = 1; j <= COL; j++)
{
printf("-");
printf("|");
}
puts("");
}
}
void play()
{
char ch;
int x, y;
fflush(stdin);
puts("请问你是排雷(a)还是标记雷(d)(输入a/d)(排雷会清除标记)");
scanf("%[ad]c", &ch);
puts("请输入排雷或标记雷的坐标(例:1,2)");
while (scanf("%d,%d", &x, &y))
if (x > 0 && y > 0 && x < ROW + 1 && y < COL + 1)//不能超出范围
{
if (surface[x][y] != -1) //排除已揭开的雷
{
if (ch == 'a')
surface[x][y]--;
else
surface[x][y] = 1;
break;
}
else
puts("此位置已揭开");
}
else
puts("没有这个位置");
}
int detect()
{
int count = 0;
int i, j;
for (i = 1; i < ROW + 1; i++)
for (j = 0; j < COL + 1; j++)
{
if (under[i][j] == '*' && surface[i][j] == -1)
count++;
}
if (count)
return -1;
for (i = 1; i < ROW + 1; i++)
for (j = 0; j < COL + 1; j++)
{
if (under[i][j] == '*' && surface[i][j] == 1)
count++;
if (under[i][j] == ' ' && surface[i][j] == 1)
count--;
}
if (count == s) //全部被标记
return 1;
else
return 0;
}
int menu()
{
puts("--------------------------");
puts(" *** 扫雷 *** ");
puts("--------------------------");
puts("--------1.开始游戏--------");
puts("--------0.退出游戏--------");
puts("--------------------------");
int choice = 0;
puts("请作出你的选择:");
scanf("%d", &choice);
return choice;
}