为了后续的函数说明,我在这里现将头文件以及函数定义打印如下:
#pragma once
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
//ROW表示行数,SOW表示列数,NUMBER表示雷数,三组数据分别表示三种难度
#define ROW 9
#define SOW 9
#define ROWS ROW + 2
#define SOWS SOW + 2
#define NUMBER 10
//#define ROW 16
//#define SOW 16
//#define ROWS ROW + 2
//#define SOWS SOW + 2
//#define NUMBER 40
//
//#define ROW 16
//#define SOW 30
//#define ROWS ROW + 2
//#define SOWS SOW + 2
//#define NUMBER 99
//初始化棋盘
void InitBorad(char borad[ROWS][SOWS], int row, int sow, char set);
//打印棋盘
void print_borad(char borad[ROWS][SOWS], int row, int sow);
//设置雷
void SetMine(char borad1[ROWS][SOWS], int row, int sow);
//排雷
void FindMine(char borad1[ROWS][SOWS], char borad2[ROWS][SOWS], int row, int sow);
//统计周围雷个数
int GetBorad1Count(char borad1[ROWS][SOWS],int x, int y);
扫雷游戏的功能要求:
一、
首先,我们需要一个界面,来供玩家进行选择。这里,我选择定义一个meun函数,函数功能简单仅用于打印出 选项,具体的选择,我采用Switch函数,通过识别玩家输入的数字来判断选择,简单的选择仅给出了1、开始游戏与2、退出游戏。具体的代码如下:
void meun1() {
printf("***********************\n");
printf("**** ****\n");
printf("**** 1.进行游戏 ****\n");
printf("**** 2.离开游戏 ****\n");
printf("**** ****\n");
printf("***********************\n");
}
二、
其次,以上,我们仅做出了简单的定义以及简单的界面设置,想要完成一个扫雷游戏,这样是远远不够的。分析,一个扫雷游戏,会有,扫雷,排雷,统计雷等几个基础功能。
1.扫雷
首先,由于C语言的程序限制,我们只能选择用某一个数字或者符号对雷进行描述与封装。进过短暂的思考 ,我选择使用数字1来表示雷,在打开之前,用*号进行封装,并且没有雷的地方就用0表示 。思考,按照我们对于扫雷的了解,扫雷是一个类似于N宫格的设计,所以我们使用二维数字即可表示。接下来,继续思考我上面所说的,用1表示雷*号进行遮盖,一个为整形,一个为字符型,所以我们考虑使用两个数组,但是在打印棋盘的时候,我们会发现,如果,一个为整形,一个为字符型,我们需要设计两个函数,为了减小麻烦,我们思考后,考虑使用字符型数组,将1用‘1’表示,将0用‘0’表示。这样我们就进行了一个棋盘的初始化定义,再以函数对棋盘进行打印。
具体的代码如下:
棋盘初始化:
void InitBorad(char borad[ROWS][SOWS], int rows, int sows, char set){
int i = 0,j = 0;
for (i = 0; i < rows; i++) {
for (j = 0; j < sows; j++) {
borad[i][j] = set;
}
}
}
棋盘打印:
void print_borad(char borad[ROWS][SOWS], int row, int sow){
int i = 0;
int j = 0;
printf(" ");
for (j = 1; j <= sow; j++) {
printf(" %d", j);
}
printf("\n");
printf("-------------------\n");
for (i = 1; i <= row; i++) {
printf("%d", i);
printf("|");
for (j = 1; j <= sow; j++) {
printf("%c ", borad[i][j]);
}
printf("\n");
}
}
2.
在棋盘定义以后,考虑在棋盘中随机插入雷。这里考虑在二维中,行列是可以以坐标的形势表示,这里我们只需要找到两个随机的行列坐标,xy。为了得到两个随机的行列值,使用rand()函数,随机得到两个值,使用rand函数,必须用srand()与time函数。我们在得到坐标以后,将该点的值赋值为‘1’,即为雷。
具体代码如下:
void SetMine(char borad1[ROWS][SOWS], int row, int sow) {
int count = NUMBER;
int x = 0;
int y = 0;
while (count) {
x = rand() % row + 1;
y = rand() % sow + 1;
if (borad1[x][x] != '1') {
borad1[x][y] = '1';
count--;
}
}
}
3.
接下来考虑排雷工作的进行。排雷无非就是两个选项,输入的坐标点的值是表示雷或者不是雷。如果该点事雷,则直接弹出“踩雷了,游戏结束的提示”,并且,回到选择的界面,让玩家选择是否继续进行游戏;如果该点不是雷,则,弹出下一个界面,并且在该点上标明周围八个位置的雷的数量(该功能在下一个介绍上说明),再进行下一个点坐标的输入,如此往复。特别说明,当排雷完成后需要结束游戏,这时候需要一个特别的判断功能,我们只需要判断剩余的点的数量即可。
具体代码如下:
void FindMine(char borad1[ROWS][SOWS], char borad2[ROWS][SOWS], int row, int sow) {
int x = 0;
int y = 0;
int win = 0;
while (win<row*sow-NUMBER) {
printf("请输入要排查的坐标:");
scanf_s("%d %d", &x, &y);
if (x>=1 && x <= row && y>=1 &&y <= sow) {
if (borad1[x][y] == '1') {
printf("踩雷了,游戏结束!\n");
print_borad(borad1, ROW, SOW);
break;
}
else {
int count = GetBorad1Count(borad1, x, y);
borad2[x][y] = count + '0';
print_borad(borad2, ROW, SOW);
win++;
}
}
else {
printf("输入的坐标越界,x,y在1~9以内!请重新输入!\n");
}
}
if (win == row * sow - NUMBER) {
printf("恭喜你排雷完成!\n");
print_borad(borad1, ROW, SOW);
}
}
4.
排雷后的雷数统计,让人疑惑。怎样实现这个功能呢?其实还是很简单的,我们需要理清楚该坐标作为点与坐标之间的关系,这里我不做详细说明,大家可以自己看一下。当我们理清楚这些点之间的关系以后,将这些点的进行字符到数字之间的转换(‘1’-‘0’),装换以后将8个点的数字进行求和,求和以后赋予最初点。特别的说明,当点在边界时,我们这个时候统计则会越界,如此,越界后该点的值是不确定的,所以,在一开始,我们的二维数组定义是多了两行两列的,且赋值为‘0’,这样就避免了越界后产生的不确定性,已经程序的危险性。
具体代码如下:
int GetBorad1Count(char borad1[ROWS][SOWS], int x, int y) {
int i = 0, j = 0;
int count = 0;
for ( i = -1; i <= 1; i++) {
for (j = -1; j <= 1; j++) {
count = (borad1[x + i][y + j] - '0');
}
}
return count;
}
三、
最后,写一个函数对游戏功能进行实现,该函数采用循环以及switch来进行,操作也是相当的简单。
具体如下:
void game() {
char borad1[ROWS][SOWS];//存放雷的信息
char borad2[ROWS][SOWS];//存放周围雷的数量
//初始化棋盘
InitBorad(borad1, ROWS, SOWS, '0');
InitBorad(borad2, ROWS, SOWS, '*');
//打印棋盘
print_borad(borad2, ROW, SOW);
//设置雷
SetMine(borad1, ROW, SOW);
print_borad(borad1, ROW, SOW);
//排雷
FindMine(borad1, borad2, ROW, SOW);
}
void test() {
srand((unsigned int)time(NULL));
int input = 0;
do {
meun1();
scanf_s("%d", &input);
switch (input) {
case 1:
game();
break;
case 2:
printf("已退出游戏!\n");
break;
default :
printf("非法输入,请重新选择!\n");
break;
}
} while (input == 1);
}
int main() {
test();
return 0;
}
到此我们写完了一个简单的扫雷游戏!因为是使用vscod进行编译,并且包含了多个源文件,所以以上代码如需使用,还需你自己酌情修改,现将完整代码如下展示:
#pragma once
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
//ROW表示行数,SOW表示列数,NUMBER表示雷数,后缀(1,2,3)分别表示三种难度
#define ROW 9
#define SOW 9
#define ROWS ROW + 2
#define SOWS SOW + 2
#define NUMBER 10
//#define ROW 16
//#define SOW 16
//#define ROWS ROW + 2
//#define SOWS SOW + 2
//#define NUMBER 40
//
//#define ROW 16
//#define SOW 30
//#define ROWS ROW + 2
//#define SOWS SOW + 2
//#define NUMBER 99
//初始化棋盘
void InitBorad(char borad[ROWS][SOWS], int row, int sow, char set);
//打印棋盘
void print_borad(char borad[ROWS][SOWS], int row, int sow);
//设置雷
void SetMine(char borad1[ROWS][SOWS], int row, int sow);
//排雷
void FindMine(char borad1[ROWS][SOWS], char borad2[ROWS][SOWS], int row, int sow);
//统计周围雷个数
int GetBorad1Count(char borad1[ROWS][SOWS],int x, int y);
//初始化棋盘
void InitBorad(char borad[ROWS][SOWS], int rows, int sows, char set){
int i = 0,j = 0;
for (i = 0; i < rows; i++) {
for (j = 0; j < sows; j++) {
borad[i][j] = set;
}
}
}
//打印棋盘
void print_borad(char borad[ROWS][SOWS], int row, int sow){
int i = 0;
int j = 0;
printf(" ");
for (j = 1; j <= sow; j++) {
printf(" %d", j);
}
printf("\n");
printf("-------------------\n");
for (i = 1; i <= row; i++) {
printf("%d", i);
printf("|");
for (j = 1; j <= sow; j++) {
printf("%c ", borad[i][j]);
}
printf("\n");
}
}
//设置雷
void SetMine(char borad1[ROWS][SOWS], int row, int sow) {
int count = NUMBER;
int x = 0;
int y = 0;
while (count) {
x = rand() % row + 1;
y = rand() % sow + 1;
if (borad1[x][x] != '1') {
borad1[x][y] = '1';
count--;
}
}
}
//排查周围雷个数
int GetBorad1Count(char borad1[ROWS][SOWS], int x, int y) {
int i = 0, j = 0;
int count = 0;
for ( i = -1; i <= 1; i++) {
for (j = -1; j <= 1; j++) {
count = (borad1[x + i][y + j] - '0');
}
}
return count;
}
//排雷
void FindMine(char borad1[ROWS][SOWS], char borad2[ROWS][SOWS], int row, int sow) {
int x = 0;
int y = 0;
int win = 0;
while (win<row*sow-NUMBER) {
printf("请输入要排查的坐标:");
scanf_s("%d %d", &x, &y);
if (x>=1 && x <= row && y>=1 &&y <= sow) {
if (borad1[x][y] == '1') {
printf("踩雷了,游戏结束!\n");
print_borad(borad1, ROW, SOW);
break;
}
else {
int count = GetBorad1Count(borad1, x, y);
borad2[x][y] = count + '0';
print_borad(borad2, ROW, SOW);
win++;
}
}
else {
printf("输入的坐标越界,x,y在1~9以内!请重新输入!\n");
}
}
if (win == row * sow - NUMBER) {
printf("恭喜你排雷完成!\n");
print_borad(borad1, ROW, SOW);
}
}
void meun1() {
printf("**********************\n");
printf("**** ****\n");
printf("**** 1.进行游戏 ****\n");
printf("**** 2.离开游戏 ****\n");
printf("**** ****\n");
printf("**********************\n");
}
//难度选项
void meun2() {
printf("**********************\n");
printf("***1.初级(10个雷)***\n");
printf("***2.中级(40个雷)***\n");
printf("***3.高级(99个雷)***\n");
printf("**********************\n");
}
//棋盘安排
void game() {
char borad1[ROWS][SOWS];//存放雷的信息
char borad2[ROWS][SOWS];//存放周围雷的数量
//初始化棋盘
InitBorad(borad1, ROWS, SOWS, '0');
InitBorad(borad2, ROWS, SOWS, '*');
//打印棋盘
print_borad(borad2, ROW, SOW);
//设置雷
SetMine(borad1, ROW, SOW);
print_borad(borad1, ROW, SOW);
//排雷
FindMine(borad1, borad2, ROW, SOW);
}
void test() {
srand((unsigned int)time(NULL));
int input = 0;
do {
meun1();
scanf_s("%d", &input);
switch (input) {
case 1:
game();
break;
case 2:
printf("已退出游戏!\n");
break;
default :
printf("非法输入,请重新选择!\n");
break;
}
} while (input == 1);
}
int main() {
test();
return 0;
}