在编辑代码前,我们使用多文件的形式实现,创建三个文件
test.c: 扫雷游戏的测试
game.h :扫雷游戏功能函数的声明
game.c :扫雷游戏功能函数的定义
一、游戏菜单选择
1.首先进入游戏要有菜单作为信息提示(1.进入游戏/0.退出游戏),然后输入选择项并判断。而我们每次玩完游戏时,如果觉得不过瘾,想再来一局,我们希望能够再次出现菜单Menu进行选择,这是就需要使用do-while循环实现此需求。我们使用自定义text函数存放这些信息。
void Menu()
{
printf(" Menu \n");
printf("-------------\n");
printf("- 1.Play -\n");
printf("-------------\n");
printf("- 0.Exit -\n");
printf("-------------\n");
}
void test()
{
int input = 0;
printf("欢迎来到扫雷\n");
do
{
Menu();//打印菜单
printf("请输入>");
scanf("%d", &input);
switch (input)
{
case 1:
game();//进入游戏
break;
case 0:
break;
default:
printf("输入错误,请重新输入(1/0)\n");
}
} while (input);
}
int main()
{
srand((unsigned int)time(NULL));//产生随机数用以布置随机雷的坐标
test();
return 0;
}
二、创建扫雷棋盘
用两个二维数组实现:
Mine:存放雷和非雷的信息
Show:存放某坐标周围雷的个数
常见的扫雷游戏以9*9棋盘的形式实现,我们可以使用9行(ROW)9列(COL)的二维数组替代棋盘。
#define ROW 9
#define COL 9
在创建数组的数和列数时需要注意,当我们在数组中布置好雷的位置后,需要在某个位置排查周围雷的个数,如果这个位置在最外围,那么在排查雷的时候,会出现溢出的情况
为避免这种情况,可以创建11行(ROWS)11(COLS)的数组防止排查时溢出。
#define ROWS ROW+2
#define COLS COL+2
我们希望Show数组只用来展示周围雷的个数,初始值全为 '*’ ,所以我们将其初始化为char型数组,在Mine数组中我们定义‘1’表示是雷,‘0’表示非雷,所以我们干脆将其都定义为char,且大小相同,都为11(ROWS)*11(COLS)。
//使用两个字符数组实现两个棋盘
char Mine[ROWS][COLS] = { 0 };//存放显示雷和非雷的信息
char Show[ROWS][COLS] = { 0 };//存放显示非雷坐标周围雷的个数
三、打印棋盘
game.h中声明
void SweepMine(char Mine[ROWS][COLS], char Show[ROWS][COLS]);//打印棋盘
game.c中定义
void PrintBoard(char board[ROWS][COLS])
{
int i = 0;
int j = 0;
printf("--------扫雷--------\n");
for (int n = 0; n <= COL; n++)
{
printf("%d ", n);//打印列的坐标
}
printf("\n");
for (i = 1; i <= ROW; i++)
{
printf("%d ", i);//打印行的坐标
for (j = 1; j <= COL; j++)
{
printf("%c ", board[i][j]);//打印棋盘
}
printf("\n");
}
}
test.c中调用
//打印棋盘
PrintBoard(Mine);
四、初始化棋盘
game.h中声明
//棋盘初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);
game.c中定义
void InitBoard(char board[ROWS][COLS],int rows,int cols,char ret)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = ret;
}
}
}
test.c中调用
//棋盘初始化
InitBoard(Mine, ROWS, COLS, '0');
InitBoard(Show, ROWS, COLS, '*');
五、随机布置雷
1.随机产生10个不重复的雷的坐标,并放入Mine数组中。
game.h中声明:
void SetMine(char board[ROWS][COLS]);//产生随机10个雷,布置这10个雷
game.c中定义
void SetMine(char board[ROWS][COLS])
{
int count = 0;//随机雷个数
while (count != 10)
{
int x = rand() % ROW + 1;//产生随机数用以布置随机雷的坐标
int y = rand() % COL + 1;//横、纵坐标范围1~9
if (board[x][y] != '1')//保证产生10个不重复的随机雷,位置坐标不同
{
board[x][y] = '1';
count++;
}
}
}
六、排查雷
game.h中声明
void SweepMine(char Mine[ROWS][COLS], char Show[ROWS][COLS]);//排查雷
game.c中定义
void SweepMine(char Mine[ROWS][COLS], char Show[ROWS][COLS])
{
int x = 0;
int y = 0;
int k = 0;
int count = ROW*COL-10;//非雷的个数
while (k<count)//直到排查出所有的非雷,循环结束
{
scanf("%d %d", &x, &y);//输入坐标
if (x >= 1 && x <= ROW && y >= 1 && y<= COL)
{
if (Mine[x][y] == '1')
{
printf("很遗憾,你踩雷了\ngame over\n");
printf("下方为 雷 的位置图\n");
PrintBoard(Mine);
break;
}
else
{
k++;
Print(Show,Mine,x,y);//打印周围雷的个数
}
}
else
{
printf("输入错误,请重新输入x(1~9),y(1~9)\n");
}
}
if(k==count)//代表排查出了所有雷
printf("恭喜你,排查出所有雷\n");
}
未触雷显示周围雷的个数
打印周围雷个数的函数Print
game.c中Print函数的声明
Print(Show,Mine,x,y);
game.c中Print函数的定义
void Print(char Show[ROWS][COLS], char Mine[ROWS][COLS],int x,int y)
{
//周围雷的个数 整型整数+'0'变为字符型 字符型-'0'变为整型
int MineCount = Mine[x-1][y-1]
+ Mine[x-1][y]
+ Mine[x-1][y+1]
+ Mine[x][y-1] //这些坐标为周围的坐标,包括自身坐标
+ Mine[x][y] //因为此时输入坐标对应的数组元素为'0',
+ Mine[x][y+1] //所以加上自身的‘0’,并不会影响周围雷个数的计算
+ Mine[x+1][y-1]
+ Mine[x+1][y]
+ Mine[x+1][y+1]-9*'0';
Show[x][y] = MineCount + '0';
PrintBoard(Show);
}
七、完整代码
game.h
#pragma once
#include<stdio.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);
//打印棋盘
void PrintBoard(char board[ROWS][COLS]);
//产生随机10个雷,布置这10个雷
void SetMine(char board[ROWS][COLS]);
//排查雷
void SweepMine(char Mine[ROWS][COLS], char Show[ROWS][COLS]);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[ROWS][COLS],int rows,int cols,char ret)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = ret;
}
}
}
void PrintBoard(char board[ROWS][COLS])
{
int i = 0;
int j = 0;
printf("--------扫雷--------\n");
for (int n = 0; n <= COL; n++)
{
printf("%d ", n);
}
printf("\n");
for (i = 1; i <= ROW; i++)
{
printf("%d ", i);
for (j = 1; j <= COL; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void SetMine(char board[ROWS][COLS])
{
int count = 0;
while (count != 10)
{
int x = rand() % ROW + 1;
int y = rand() % COL + 1;
if (board[x][y] != '1')
{
board[x][y] = '1';
count++;
}
}
}
void Print(char Show[ROWS][COLS], char Mine[ROWS][COLS],int x,int y)
{
//周围雷的个数 整型整数-'0'变为字符型 字符型+'0'变为整型
int MineCount = Mine[x-1][y-1]
+ Mine[x-1][y]
+ Mine[x-1][y+1]
+ Mine[x][y-1]
+ Mine[x][y]
+ Mine[x][y+1]
+ Mine[x+1][y-1]
+ Mine[x+1][y]
+ Mine[x+1][y+1]-9*'0';
Show[x][y] = MineCount + '0';
PrintBoard(Show);
}
void SweepMine(char Mine[ROWS][COLS], char Show[ROWS][COLS])
{
int x = 0;
int y = 0;
int k = 0;
int count = ROW*COL-10;
while (k<count)
{
scanf("%d %d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y<= COL)
{
if (Mine[x][y] == '1')
{
printf("很遗憾,你踩雷了\ngame over\n");
printf("下方为 雷 的位置图\n");
PrintBoard(Mine);
break;
}
else
{
k++;
Print(Show,Mine,x,y);
}
}
else
{
printf("输入错误,请重新输入x(1~9),y(1~9)\n");
}
}
if(k==count)
printf("恭喜你,排查出所有雷\n");
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void Menu()
{
printf(" Menu \n");
printf("-------------\n");
printf("- 1.Play -\n");
printf("-------------\n");
printf("- 0.Exit -\n");
printf("-------------\n");
}
void game()
{
//使用两个字符数组实现两个棋盘
char Mine[ROWS][COLS] = { 0 };//存放显示雷和非雷的信息
char Show[ROWS][COLS] = { 0 };//存放显示非雷坐标周围雷的个数
//棋盘初始化
InitBoard(Mine, ROWS, COLS, '0');
InitBoard(Show, ROWS, COLS, '*');
//打印棋盘
PrintBoard(Mine);
//PrintBoard(Show);
//产生随机10个雷,布置这10个雷
SetMine(Mine);
//排查雷
SweepMine(Mine,Show);
}
void test()
{
int input = 0;
printf("欢迎来到扫雷\n");
do
{
Menu();//打印菜单
printf("请输入>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入错误,请重新输入(1/0)\n");
}
} while (input);
}
int main()
{
srand((unsigned int)time(NULL));
test();
return 0;
}