//扫雷游戏实现
1. 设定一个二维数组,作为表示地雷的地图,0表示没地雷,1表示有雷
2. 设定另一个二维数组,作为给玩家看的地图,位置是否被翻开,翻开后显示周围地雷数。
3. 地图初始化(包含布置地雷的过程)。
4. 输入坐标,并对输入进行合理化检查。
5. 判断翻开位置(包括有雷游戏结束,没雷翻开,显示周围有雷数)。
代码如下
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ROW 9
#define COL 9
#define MINE_COUNT 10
char mine_map[ROW + 2][COL + 2];
char show_map[ROW + 2][COL + 2];
//ROW + 2 棋盘边框,内容从1--10存放。就不要考虑row和col输入溢出问题
int Menu(int i)//菜单函数,实现游戏开始或者直接退出结束游戏
{
printf("================\n");
printf("1. PLAY GAME!\n");
printf("2. EXIT GAME!\n");
printf("================\n");
printf("请输入您的选择:");
scanf("%d", &i);
return i;
}
void Init(char mine_map[ROW + 2][COL + 2],
char show_map[ROW + 2][COL + 2])
//初始化函数,把两个棋盘初始化为‘0’和‘*’
//
{
int mine_count = 0;
//memset()函数对一段连续的空间进行赋值操作
memset(mine_map, '0', (ROW + 2) * (COL + 2));
memset(show_map, '*', (ROW + 2) * (COL + 2));
//等效代码如下
//给mine_map初始化布雷
//int row, col;
//int mine_count;
//for(row = 0; row < ROW + 2; ++row)
//{
// for(col = 0; col < COL + 2; ++col)
// {
// mine_map[row][col] = '0';
// }
//}
2. show_map 初始化全为 ‘*’
//for(row = 0; row < ROW + 2; ++row)
//{
// for(col = 0; col < COL + 2; ++col)
// {
// show_map[row][col] = '*';
// }
//}
mine_count = MINE_COUNT;
while(mine_count > 0)
{
int row, col;
//开始布雷,随机给雷
row = rand() % ROW + 1;
col = rand() % COL + 1;
if(mine_map[row][col] == '1')
{
continue;
}
mine_map[row][col] = '1';
mine_count--;
}
}
void Displaymap(char map[ROW + 2][COL + 2])
//打印棋盘边框打印成1--9,内部空间9*9
{
int row, col;
printf(" ");
for(col = 1; col <= COL; col++)
{
printf("%d ", col);
}
printf("\n");
//第一行打印完了
//接下来打印上边框
for(col = 1; col <= COL; col++)
{
printf("___");
}
printf("\n");
//打印每一行,注意每一行前要带上行号
for(row = 1; row <= ROW; ++row)
{
printf(" %d|", row);
for(col = 1; col <= COL; ++col)
{
printf("%c ", map[row][col]);
}
printf("\n");
}
}
int UpdateShowmap(char mine_map[ROW + 2][COL + 2],
char show_map[ROW + 2][COL + 2], int row, int col)
{
//把当前位置替换为一个数字(数字表示这个位置周围八个格子有雷的个数)
int mine_count = 0;
mine_count = mine_map[row - 1][col - 1] - '0'
+ mine_map[row - 1][col] - '0'
+ mine_map[row - 1][col + 1] - '0'
+ mine_map[row][col - 1] - '0'
+ mine_map[row][col + 1] - '0'
+ mine_map[row + 1][col - 1] - '0'
+ mine_map[row + 1][col] - '0'
+ mine_map[row + 1][col + 1] - '0';
//show_map[row][col] = mine_count + '0';
return mine_count;
}
int show_not_open_count(char show_map[ROW + 2][COL + 2], int row, int col)
//计算棋盘上还没有打开的‘*’的个数
//判断当返回数 count = MINE_COUNT时 游戏结束,玩家胜
//ROW + 2, COL + 2 当row - 1时就不用考虑溢出的问题
{
int count = 0;
for(row = 1; row <= ROW; ++row)
{
for(col = 1; col <= COL; ++col)
{
if(show_map[row][col] == '*')
{
count++;
}
}
}
return count;
}
void Open_around_not_mine(char mine_map[ROW + 2][COL + 2],
char show_map[ROW + 2][COL + 2], int row, int col)
//判断打开的位置周八个格子的周围总共有多少雷数,并赋予该位置周围雷数显示
{
if(mine_map[row - 1][col - 1] == '0')
{
show_map[row - 1][col - 1] =
//计算show_map[row - 1][col - 1]周围的雷数
UpdateShowmap(mine_map, show_map, row - 1, col - 1) + '0';
}
if(mine_map[row - 1][col] == '0')
{
show_map[row - 1][col] =
UpdateShowmap(mine_map, show_map, row - 1, col) + '0';
}
if(mine_map[row - 1][col + 1] == '0')
{
show_map[row - 1][col + 1] =
UpdateShowmap(mine_map, show_map, row - 1, col + 1) + '0';
}
if(mine_map[row][col - 1] == '0')
{
show_map[row][col - 1] =
UpdateShowmap(mine_map, show_map, row, col - 1) + '0';
}
if(mine_map[row][col + 1] == '0')
{
show_map[row][col + 1] =
UpdateShowmap(mine_map, show_map, row, col + 1) + '0';
}
if(mine_map[row + 1][col - 1] == '0')
{
show_map[row + 1][col - 1] =
UpdateShowmap(mine_map, show_map, row + 1, col - 1) + '0';
}
if(mine_map[row + 1][col] == '0')
{
show_map[row + 1][col] =
UpdateShowmap(mine_map, show_map, row + 1, col) + '0';
}
if(mine_map[row + 1][col + 1] == '0')
{
show_map[row + 1][col + 1] =
UpdateShowmap(mine_map, show_map, row + 1, col + 1) + '0';
}
}
void Game()
{
//char mine_map[ROW + 2][COL + 2];
//char show_map[ROW + 2][COL + 2];
clock_t start_time, finish_time;
//clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位
double deadline;
Init(mine_map, show_map);
Displaymap(show_map);
start_time = clock();//记录开始时间
//clock() 函数,返回从开启这个程序进程程序中调用clock()
//函数时之间的CPU时钟计时单元(clock tick)数(挂钟时间),返回单位是毫秒
while(1)
{
int row = 0;
int col = 0;
int not_mine_count = 0;
int is_mine_count = 0;
printf("请输入您要翻开的位置[row, col]:");
scanf("%d %d", &row, &col);
//判断输入坐标的合法性
if(row < 1 || row > ROW ||col < 1 || col > COL)
{
printf("您输入的位置不合法,请重新输入!\n");
continue;
}
if(mine_map[row][col] == '1')
{
printf("您踩雷了,游戏结束! ");
finish_time = clock();//取结束时间
deadline = (double)(finish_time - start_time) / CLOCKS_PER_SEC;
//可以用常量CLOCKS_PER_SEC, 这个常量表示每一秒(per second)有多少个时钟计时单元
printf("用时 %f 秒\n", deadline);
Displaymap(mine_map);
break;
}
//计算翻开位置不是雷的数量
not_mine_count = UpdateShowmap(mine_map, show_map, row, col);
//赋予翻开位置周围的总共的雷数
show_map[row][col] = not_mine_count + '0';
//翻开输入位置周围的八个位置,并计算出这八个位置周围的雷数并显示
Open_around_not_mine(mine_map, show_map, row, col);
Displaymap(show_map);
is_mine_count = show_not_open_count(show_map, row, col);
//计算棋盘上剩余没翻开的格子的个数
if(is_mine_count == MINE_COUNT)
//玩家棋盘的*数等于 雷阵上的雷数时
{
printf("恭喜您,扫雷成功! ");
finish_time = clock();//取结束时间
deadline = (double)(finish_time - start_time) / CLOCKS_PER_SEC;
printf("用时 %f 秒\n", deadline);
Displaymap(show_map);
break;
}
}
}
int main()
{
int choice = 0;
srand((unsigned int)time(0));
while(1)
{
choice = Menu(choice);
if(choice == 1)
{
Game();
}
else
{
printf("GOOD BYE!\n");
break;
}
}
system("pause");
return 0;
}
运行结果演示: