扫雷
1.在game.h中进行宏定义,头文件引入以及函数声明
2.在main.c中实现主函数
3.在game.c中实现功能函数
除了基本的功能外,还实现以下几个功能:
1.第一步不会炸
2.点到周围没有雷的区域会自动展开
3.可以做标记
4.显示当前雷数
5.显示已用时间
待拓展的功能:选关
需要定义两个二维数组,一个作为记录雷的位置,一个作为展示界面,除此之外,实际定义的数组应比展示出来的界面大一圈,这样便于统计雷数
埋雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int x = 0, y = 0;
int n = EASY_COUNT;
while (n--) {
x = rand() % row + 1;
y = rand() % col + 1;
if (board[x][y] == '0')
board[x][y] = '1';
else n++;
}
}
在棋盘内随机选取10个位置埋雷。
用到了rand()函数生成伪随机数,使用rand函数前应先调用srand()唤醒,并用时间做参数。
查看坐标周围雷数
int GetMineCount(char board[ROWS][COLS],Location loc)
{
int count = 0;
int i, j;
for (i = loc.x - 1; i <= loc.x + 1; i++) {
for (j = loc.y - 1; j <= loc.y + 1; j++) {
if (i == loc.x && loc.y == j) continue;
if (board[i][j] == '1')
count++;
}
}
return count;
}
排雷并且保证第一步不炸
int SweepMine(char Show[ROWS][COLS],char Mine[ROWS][COLS], int rows, int cols, Location loc,int *pfirst)
{
int ret = 0;
if (Show[loc.x][loc.y] != '*' || loc.x>ROW || loc.x<1 || loc.y>COL || loc.y<1) {
printf("\n 该坐标不可选\n");
return 0;
}
//如果是第一步
if ((*pfirst) == 1) {
(*pfirst) = 0;
//如果踩到雷
if (Mine[loc.x][loc.y] == '1') {
//那就进入循环,重新埋雷,直到这个坐标不是雷
do {
InitBoard(Mine, ROWS, COLS, '0');
SetMine(Mine, ROW, COL);
} while (Mine[loc.x][loc.y] == '1');
}
if (Mine[loc.x][loc.y] == '1') {
printf("\n 1为雷区,0为安全区\n");
PrintBoard(Mine, ROWS, COLS);
printf("\n 砰~!很遗憾,你输了\n");
return 2;
}
else {
ret = GetMineCount(Mine, loc);
if (ret == 0)
Expand(Show, Mine, rows - 2, cols - 2, loc);
else Show[loc.x][loc.y] = ret + '0';
PrintBoard(Show, ROWS, COLS);
}
return 1;
}
自动展开
void Expand(char show[ROWS][COLS], char mine[ROWS][COLS],int row, int col, Location loc)
{
int i, j;
int ret = 0;
Location coord = { -1,-1 };
if (show[loc.x][loc.y] != '*')
return;
if (GetMineCount(mine, loc) == 0) {
show[loc.x][loc.y] = '0';
//判断它周围8个位置是否为0
for (i = loc.x - 1; i <= loc.x + 1; i++) {
for (j = loc.y - 1; j <= loc.y + 1; j++) {
if (i == loc.x&&j == loc.y)continue;
if (i > row || i<1 || j>col || j < 1)
continue;
coord.x = i;
coord.y = j;
ret = GetMineCount(mine, coord);
if (ret == 0) {
Expand(show, mine, row, col, coord);
}
else show[i][j] = ret + '0';
}
}
}
}
如果点到雷数是0的位置,就递归,展开到坐标雷数不是0(第一个不是0的位置也显示出来)
第一步下的是(5,5),显示雷数1,然后第二步是(9,9),雷数是0自动展开,直到雷数不是0
做标记
int Label(char show[ROWS][COLS], int rows, int cols, Location loc,int *pflag)
{
if (loc.x>ROW || loc.x<1 || loc.y>COL || loc.y<1) {
printf("\n 该坐标不可选\n");
return 0;
}
if (show[loc.x][loc.y] == '*') {
show[loc.x][loc.y] = 'X';
(*pflag)++;
}
else if (show[loc.x][loc.y] == 'X') {
show[loc.x][loc.y] = '*';
(*pflag)--;
}
else {
printf("\n 该坐标不可选\n");
return 0;
}
PrintBoard(show, rows, cols);
return 1;
}
如果有标记就取消,如果没有标记就做标记
显示雷数
不知道大家是怎么做的,我设置的是做一个标记雷数就减一
显示时间
这个用clock()函数就能实现,具体是,定义三个变量
clock_t start, finish;
double time;
在刚刚进入游戏时,
start = clock();
clock函数返回开启这个进程到调用clock()函数的CPU时钟单元
结束时间也是这样,
finish = clock();
time = (double)(finish - start) / CLOCKS_PER_SEC;//宏表示一秒钟有多少时钟单元
每次展开一个坐标就显示一次雷数和时间
printf("\n 当前雷数:%d 已用时:%.0f s\n",EASY_COUNT-flag,time);
判断输赢
当玩家选中有雷坐标时就输了
判断获胜会麻烦一点
//查看当前显示格子数目
int CheckMine(char show[ROWS][COLS], char mine[ROWS][COLS], int rows, int cols)
{
int i, j;
int count = 0;
for (i = 1; i < rows - 1; i++) {
for (j = 1; j < cols - 1; j++) {
if (show[i][j] != '*' && mine[i][j] == '0')
count++;
}
}
return count;
}
函数名字起的比较糟糕,功能是返回当前显示出来格子的数目
当所有不是雷的格子都显示出来时,玩家就获胜了
运行效果
刚刚让舍友玩了一局,她说界面太花了。。。这个是最需要改进的,目前我也没办法。。。