一、基本思路
代码由三部分组成:game.h(头文件以及声明函数)、test.c(主函数以及调用game.c中的函数实现扫雷)、game.c(定义扫雷的4个函数)。
要实现扫雷的功能,game.c中应包含以下功能:①初始化棋盘;②打印棋盘;③布置雷;④排查雷及判断输赢;
在test.c中,首先要打印一个菜单供玩家选择,其次玩家在选择后要实现玩游戏或退出游戏。
二、test.c
在编写主函数时,我们想先在屏幕上输出一个菜单,玩家在看到后可以供玩家选择,写一个menu()函数,主函数调用打印菜单。menu函数:
void menu()
{
printf("########################\n");
printf("###### 1.进入游戏 ######\n");
printf("###### 0.退出游戏 ######\n");
printf("########################\n");
}
在打印完菜单后由玩家选择,do while循环实现,内嵌switch。输入1,玩家进入游戏,调用game()函数,game()函数中有4个其他函数,实现扫雷的功能;输入0,退出循环,玩家退出游戏;输入其他数字,提示有误,重新输入。主函数(针对第二行srand()放在后面解释):
int main()
{
srand((unsigned int)time(NULL));
int n;
do {
menu();
printf("请玩家选择:> ");
scanf("%d", &n);
switch (n) {
case 1:
game();
break;
case 0:
printf("玩家退出游戏");
break;
default:
printf("玩家选择有误,请重新选择\n");
break;
}
} while (n);
}
game()函数设计思路:
可以将棋面想象成一个二维数组,放雷的为一个棋面,排查雷信息的为一个棋面,所以先定义两个二维数组,针对二维数组的行与列以及雷的个数,将其定义为常变量,方便对棋面以及游戏难易程度进行改动。在game()中调用了4个函数,先调用InitalBoard()函数初始化棋面,将布置雷的棋面,字符型二维数组赋值为'0';将雷的信息,字符型二维数组赋值为'*';再调用PrintfBoard()函数,打印雷的信息的棋面;再调用SetMine()函数,在布置雷的棋面上设置相应个数的雷;最后调用LookMine()函数,在打印雷信息的棋面上计算对应坐标周围雷的个数,并判断输赢。
void game()
{
char a[ROWS][COLS];
char b[ROWS][COLS];
//初始化棋面
InitalBoard(a, ROWS, COLS, '0');
InitalBoard(b, ROWS, COLS, '*');
//打印棋面
//PrintfBoard(a, ROW, COL); //打印布置好雷的棋面
PrintfBoard(b, ROW, COL); //打印雷的信息
//布置雷
SetMine(a, ROW, COL);
//PrintfBoard(a, ROW, COL); //打印布置好雷的棋面
//排查雷信息
LookMine(a, b, ROW, COL);
}
三、game.c
在game.c中主要是定义了InitalBoard()、PrintfBoard()、SetMine()、LookMine() 4个函数。
InitalBoard()函数:
将棋面想象成二维数组,布置雷的棋面初始化为'0',显示雷信息的棋面初始化为'*',需要注意的是,在排查雷信息时,对于边界处的坐标,在统计时容易数组出界,所以我们初始化的棋面是在打印棋面上增大了一圈,例如:玩游戏的界面是9×9的,但是在初始化的时候是11×11,布置雷是在9×9棋面上,排查雷是在11×11棋面上,打印雷的信息是9×9的棋面。
void InitalBoard(char a[ROWS][COLS], int rows, int cols, char b)
{
int i, j;
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++)
a[i][j] = b;
}
}
PrintfBoard()函数:
打印出初始化的雷信息棋面,元素全为'*',且打印出了每行每列的数字。
void PrintfBoard(char a[ROWS][COLS], int row, int col)
{
printf("------ 棋面 ------\n");
int i, j;
for (j = 0; j <= col; j++) {
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++) {
printf("%d ", i);
for (j = 1; j <= col; j++) {
printf("%c ", a[i][j]);
}
printf("\n");
}
}
SetMine()函数:
放置Mine个雷,范围为第一个二维数组中第1行到第ROW行,第1列到第COL列,如何在二维数组中随机产生雷?先创建rand()函数可以产生随机值,而在主函数中使用srand((unsigned int)time(NULL))可以保证每次进入游戏产生的随机值不同,为了使产生的随机值在二维数组范围内,可以使用rand()%row+1,产生1到row1之间的数。while循环判断雷的个数是否达到给定个数,在while循环中使用if语句判断是否重复放置雷。
void SetMine(char a[ROWS][COLS], int row, int col)
{
int i, j;
int count = 0;
while (count < Mine) {
i = rand() % row + 1; //产生1到row的随机数
j = rand() % col + 1; //产生1到col的随机数
if (a[i][j] == '0') {
a[i][j] = '1';
count++;
}
}
}
LookMine()函数:
布置好雷后,在第一个二维数组中输入坐标,当输入坐标有误时,会要求玩家重新输入坐标。若刚好开中雷,则游戏结束;若没开中雷,则统计其周围一圈8个元素雷的个数,若有雷,则变量count加1,最终将count变量转为字符,填入对应坐标的第二个数组。当统计雷的信息的元素等于二维数组(行×列-雷的个数)时,游戏结束,玩家取得胜利。
void LookMine(char a[ROWS][COLS], char b[ROWS][COLS], int row, int col)
{
int x, y;
int count = 0;
int k = 0;
while (k < (row * col) - Mine)
{
printf("请输入坐标,用空格隔开:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (a[x][y] == '1')
{
printf("很遗憾你开中了雷,游戏结束\n");
PrintfBoard(a, ROW, COL);
break;
}
else
{
int i, j;
for (i = x - 1; i <= x + 1; i++) {
for (j = y - 1; j <= y + 1; j++) {
if (a[i][j] == '1')
count++;
}
}
b[x][y] = count + '0';
count = 0;
k++;
PrintfBoard(b, ROW, COL); //打印雷的信息
}
}
else
printf("输入坐标有误,需重新输入");
}
if (k == (row * col) - Mine)
printf("恭喜你,游戏成功!!!\n");
}
四、game.h
game.h中主要放需要用到的头文件以及game.c中4个函数的声明,c语言的标志头文件#include<stdio.h>,调用rand()函数用到头文件#include<stdlib.h>,在主函数srand()函数中调用time()函数,用到头文件#include<time.h>,定义棋盘行数、列数以及雷的个数为常变量,用到头文件#define
#pragma once
#include<stdio.h>
#include <stdlib.h>;
#include <time.h>;
#define COL 9
#define ROW 9
#define COLS COL+1
#define ROWS ROW+1
#define Mine 10
//初始化棋盘函数声明
void InitalBoard(char a[ROWS][COLS], int rows, int cols, char b);
//打印棋盘函数声明
void PrintfBoard(char a[ROWS][COLS], int row, int col);
//布置雷函数声明
void SetMine(char a[ROWS][COLS], int row, int col);
//排查雷信息函数
void LookMine(char a[ROWS][COLS], char b[ROWS][COLS], int row, int col);
五、完整代码
game.h:
#pragma once
#include<stdio.h>
#include <stdlib.h>;
#include <time.h>;
#define COL 9
#define ROW 9
#define COLS COL+1
#define ROWS ROW+1
#define Mine 10
//初始化棋盘函数声明
void InitalBoard(char a[ROWS][COLS], int rows, int cols, char b);
//打印棋盘函数声明
void PrintfBoard(char a[ROWS][COLS], int row, int col);
//布置雷函数声明
void SetMine(char a[ROWS][COLS], int row, int col);
//排查雷信息函数
void LookMine(char a[ROWS][COLS], char b[ROWS][COLS], int row, int col);
test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("########################\n");
printf("###### 1.进入游戏 ######\n");
printf("###### 0.退出游戏 ######\n");
printf("########################\n");
}
void game()
{
char a[ROWS][COLS];
char b[ROWS][COLS];
//初始化棋面
InitalBoard(a, ROWS, COLS, '0');
InitalBoard(b, ROWS, COLS, '*');
//打印棋面
//PrintfBoard(a, ROW, COL); //打印布置好雷的棋面
PrintfBoard(b, ROW, COL); //打印雷的信息
//布置雷
SetMine(a, ROW, COL);
//PrintfBoard(a, ROW, COL); //打印布置好雷的棋面
//排查雷信息
LookMine(a, b, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int n;
do {
menu();
printf("请玩家选择:> ");
scanf("%d", &n);
switch (n) {
case 1:
game();
break;
case 0:
printf("玩家退出游戏");
break;
default:
printf("玩家选择有误,请重新选择\n");
break;
}
} while (n);
}
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘函数定义
void InitalBoard(char a[ROWS][COLS], int rows, int cols, char b)
{
int i, j;
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++)
a[i][j] = b;
}
}
//打印棋盘函数定义
void PrintfBoard(char a[ROWS][COLS], int row, int col)
{
printf("------ 棋面 ------\n");
int i, j;
for (j = 0; j <= col; j++) {
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++) {
printf("%d ", i);
for (j = 1; j <= col; j++) {
printf("%c ", a[i][j]);
}
printf("\n");
}
}
//放雷函数定义
void SetMine(char a[ROWS][COLS], int row, int col)
{
int i, j;
int count = 0;
while (count < Mine) {
i = rand() % row + 1; //产生1到row的随机数
j = rand() % col + 1; //产生1到col的随机数
if (a[i][j] == '0') {
a[i][j] = '1';
count++;
}
}
}
//排查雷信息函数定义
void LookMine(char a[ROWS][COLS], char b[ROWS][COLS], int row, int col)
{
int x, y;
int count = 0;
int k = 0;
while (k < (row * col) - Mine)
{
printf("请输入坐标,用空格隔开:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (a[x][y] == '1')
{
printf("很遗憾你开中了雷,游戏结束\n");
PrintfBoard(a, ROW, COL);
break;
}
else
{
int i, j;
for (i = x - 1; i <= x + 1; i++) {
for (j = y - 1; j <= y + 1; j++) {
if (a[i][j] == '1')
count++;
}
}
b[x][y] = count + '0';
count = 0;
k++;
PrintfBoard(b, ROW, COL); //打印雷的信息
}
}
else
printf("输入坐标有误,需重新输入");
}
if (k == (row * col) - Mine)
printf("恭喜你,游戏成功!!!\n");
}