#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void menu(int *map_x, int *map_y); //主菜单
char **make_map(int map_x, int map_y); //生成地图
char **make_mine_map(int mine_x, int mine_y, int mine_num); //生成地雷地图
void print_all_map(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y); //打印地图
int begin_game(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int mine_num); //开始游戏
int open_place(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y); //打开玩家选择的位置
void expand(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y); //通过递归方式实现扫雷的扩展功能,游戏最重要的部分
int check_mine(char **mine_map, int mine_x, int mine_y, int x, int y); //检测一个位置周围8格以内的地雷数
int check_win(char **map, int mine_x, int mine_y, int mine_num); //检测是否赢得游戏
void win(char **map, int map_x, int map_y); //赢得游戏,打印所有地雷所在位置
void win(char **map, int map_x, int map_y)
{
int i, j;
for(i = 0; i < map_x; i++)
{
for(j = 0; j < map_y; j++)
{
if(map[i][j] == '+')
{
map[i][j] = '@';
}
printf("%c ", map[i][j]);
}
putchar('\n');
}
}
int check_win(char **map, int mine_x, int mine_y, int mine_num)
{
int i, j;
int num = 0;
for(i = 1; i < mine_x; i++)
{
for(j = 1; j < mine_y; j++)
{
if(map[i][j] == '+')
{
num++;
}
}
}
if(num == mine_num)
{
printf("恭喜你赢了\n");
return 1;
}
return 0;
}
int check_mine(char **mine_map, int mine_x, int mine_y, int x, int y)
{
int num = 0;
//判断该位置周围8格的地雷数
if(x - 1 > 0 && mine_map[x - 1][y] == '@')
{
num++;
}
if(x + 1 < mine_x && mine_map[x + 1][y] == '@')
{
num++;
}
if(y - 1 > 0 && mine_map[x][y - 1] == '@')
{
num++;
}
if(y + 1 < mine_y && mine_map[x][y + 1] == '@')
{
num++;
}
if(x - 1 > 0 && y - 1 > 0 && mine_map[x - 1][y - 1] == '@')
{
num++;
}
if(x - 1 > 0 && y + 1 < mine_y && mine_map[x - 1][y + 1] == '@')
{
num++;
}
if(x + 1 < mine_x && y + 1 < mine_x && mine_map[x + 1][y + 1] == '@')
{
num++;
}
if(x + 1 < mine_x && y - 1 > 0 && mine_map[x + 1][y - 1] == '@')
{
num++;
}
return num;
}
void expand(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y)
{
int num;
if(!(num = check_mine(mine_map, mine_x, mine_y, x, y))) //判断这个位置的周围8格是否有地雷,如果有将该位置设置为地雷数,并停止对该位置后续的展开
{
map[x][y] = ' ';
//向该位置的8个方向进行展开
if(x - 1 > 0 && map[x - 1][y] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x - 1, y);
}
if(x + 1 < mine_x && map[x + 1][y] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x + 1, y);
}
if(y - 1 > 0 && map[x][y - 1] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x, y - 1);
}
if(y + 1 < mine_y && map[x][y + 1] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x, y + 1);
}
if(x - 1 > 0 && y - 1 > 0 && map[x - 1][y - 1] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x - 1, y - 1);
}
if(x - 1 > 0 && y + 1 < mine_y && map[x - 1][y + 1] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x - 1, y + 1);
}
if(x + 1 < mine_x && y + 1 < mine_y && map[x + 1][y + 1] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x + 1, y + 1);
}
if(x + 1 < mine_x && y - 1 > 0 && map[x + 1][y - 1] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x + 1, y - 1);
}
}
else
{
map[x][y] = num + 48;
}
}
int open_place(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y)
{
if(mine_map[x][y] == '@')
{
printf("游戏结束!\n");
return 0;
}
else if(mine_map[x][y] == '+')
{
expand(map, map_x, map_y, mine_map, mine_x, mine_y, x, y); //如果玩家选中的位置没有踩雷,就需要展它周围的空位置
return 1;
}
return 1;
}
int begin_game(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int mine_num)
{
char x = ' ', y = ' ';
char choose;
static int num = 0;
do
{
printf("总地雷数:%d 当前地雷数:%d\n", mine_num, mine_num - num);
printf("请输入行和列(qq退出游戏):");
scanf("%c %c", &x, &y);
getchar();
if(x == 'q' && y == 'q')
{
exit(0);
}
}
while(x < '0' || y < '0' || x > (char)(map_x - 2 + 48) || y > (char)(map_y - 2 + 48));
do
{
printf("1.打开:2.标记:3.取消标记:4.重新选择\n");
printf("请选择你要执行的命令:");
choose = getchar();
getchar();
}
while(choose != '1' && choose != '2' && choose != '3');
switch(choose)
{
case '1':
{
return open_place(map, map_x, map_y, mine_map, mine_x, mine_y, (int)x - 48, (int)y - 48); //因为我们的x和y设置的是字符型,要将他强制转换成int型,方便open_place函数定位
}
case '2':
{
num++;
map[(int)x - 48][(int)y - 48] = '^';
break;
}
case '3':
{
num--;
map[(int)x - 48][(int)y - 48] = '+';
break;
}
case '4':
{
break;
}
}
}
void print_all_map(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y)
{
int i, j;
for(i = 0; i < map_x; i++)
{
for(j = 0; j < map_y; j++)
{
printf("%c ", map[i][j]);
}
putchar('\n');
}
/*for(i = 0; i < mine_x; i++)
{
for(j = 0; j < mine_y; j++)
{
printf("%c ", mine_map[i][j]);
}
putchar('\n');
}*/
}
char **make_mine_map(int mine_x, int mine_y, int mine_num)
{
char **mine_map;
int i, j;
int x, y;
int num = 0;
mine_map = (char **)malloc(sizeof(char *) * mine_x);
for(i = 0; i < mine_x; i++)
{
mine_map[i] = (char *)malloc(sizeof(char) * mine_y);
}
srand(time(NULL));
for(i = 0; i < mine_x; i++)
{
for(j = 0; j < mine_y; j++)
{
mine_map[i][j] = '+';
}
}
while(num < mine_num)
{
do
{
x = rand()%(mine_x - 1) + 1;
y = rand()%(mine_y - 1) + 1;
}
while(mine_map[x][y] != '+');
mine_map[x][y] = '@';
num++;
}
return mine_map;
}
char **make_map(int map_x, int map_y)
{
char **map;
int i, j, k = 1;
map = (char **)malloc(sizeof(char *) * map_x);
for(i = 0; i < map_x; i++)
{
map[i] = (char *)malloc(sizeof(char) * map_y);
}
for(i = 0; i < map_x - 1; i++)
{
map[i][0] = i + 48;
}
for(j = 0; j < map_y - 1; j++)
{
map[0][j] = j + 48;
}
for(i = 1; i < map_x - 1; i++)
{
for(j = 1; j < map_y - 1; j++)
{
map[i][j] = '+';
}
}
return map;
}
void menu(int *map_x, int *map_y)
{
char choose;
do
{
printf("********************1.开始游戏*******************\n");
printf("********************2.退出游戏*******************\n");
printf("请选择:");
choose = getchar();
getchar();
}
while(choose != '1' && choose != '2');
if(choose == '1')
{
do
{
printf("1.初级:2.中级:3.高级:4.自定义");
printf("请选择:");
choose = getchar();
getchar();
}
while(choose != '1' && choose != '2' && choose != '3' && choose != '4');
switch(choose)
{
case '1':
{
*map_x = 12;
*map_y = 12;
break;
}
case '2':
{
*map_x = 22;
*map_y = 22;
break;
}
case '3':
{
*map_x = 42;
*map_y = 42;
break;
}
case '4':
{
do
{
printf("请输入行:");
scanf("%d", map_x);
getchar();
}
while(*map_x <= 0 || *map_x > 100);
do
{
printf("请输入列:");
scanf("%d", map_y);
getchar();
}
while(*map_y <= 0 || *map_y > 100);
*map_x += 2;
*map_y += 2;
}
}
}
else exit(0);
}
int main(void)
{
int map_x, map_y;
menu(&map_x, &map_y);
char **map; //设置一个二级指针来接受返回的动态二维数组
map = make_map(map_x, map_y); //为了使得行列可以自定义,用动态申请二维数组的方法
char **mine_map; //同样的方法设置一个地雷地图的二级指针
int mine_x = map_x - 1; //设置地雷地图的行列
int mine_y = map_y - 1;
int mine_num = mine_x + mine_y - 4; //设置地雷数
mine_map = make_mine_map(mine_x, mine_y, mine_num); //动态申请一个二维数组
do
{
print_all_map(map, map_x, map_y, mine_map, mine_x, mine_y); //打印地图
if(check_win(map, mine_x, mine_y, mine_num)) //玩家每走一步就检测是否赢得比赛
{
win(map, map_x, map_y);
break;
}
}
while(begin_game(map, map_x, map_y, mine_map, mine_x, mine_y, mine_num)); //begin_game该游戏的主要函数
return 0;
}