目录
1.游戏规则
扫雷相信大家都玩过,但是我还是要大概说一下这个游戏的规则。以vs这个运行窗口玩的扫雷,肯定没有正规的软件小程序来的全面,希望大家见谅。就拿简单模式来讲,是一个9*9的方阵内,随机安排10个雷,然后通过对每一个位置的周围一圈的8个位置,判断是否有雷,并将他们的数量统计加起来放在中间的位置。通过不断地推断排雷最终把10个雷排出来。管你听没听懂,看就完啦。
2.游戏代码的框架
- game.h --- 游戏函数的声明定义
- test.c --- 游戏的测试
- game. c --- 游戏函数的实现
3.游戏函数的一一解析
1。对于一些宏定义,头文件
#include<stdlib.h>
#include<time.h>
这两个头文件是用来生成随机数所必须的。
EASY_COUNT 代表着雷的数量
因为9*9的数组,在边界线的上的数组元素,找他的一周的雷的数量是会出现数组越界的情况,所以需要将数组的行和列设置位11行。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define EASY_COUNT 10
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
2.初始化一个棋盘
初始化棋盘,我们需要初始化两个棋盘,一个给玩家看,一个不给,这样做可以更方便的。mine字符数组代表设置雷区的一个棋盘,show字符数组代表着给玩家展示的棋盘。
这样的一个函数,参数中给到字符数组board,行数列数,还有一个字符。通过for循环将整个数组的元素都赋值set,这个set不同的棋盘给不同的字符。
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
3.打印棋盘
如果直接打印这个9*9的数组的话,会让玩家很难找打要找的位置,所以我们可以给每行每列标上数字,这样可以方便玩家找到需要排雷的位置下标。如图所示的样子。
代码的实现。先打印一行扫雷标志。通过for循环打印第一行的数字提示1-9,然后换行,循环打印每一行的元素,但是在每一行的前面需要打印数字提示,所以打印元素的循环就需要嵌套在内部,因为这个数组的首元素下标是0,二我们给的提示是1,并且玩家输入的也是提示数字,所以for循环需要从下标1开始,循环打印每一个元素,这样就可以打印出一个完整的棋盘,最后也可以再打印扫雷提示的标志。
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("-------扫雷--------\n");
for (j = 0; j <= row; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= col; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("-------扫雷--------\n");
}
4.布置雷
布置雷的思想就是通过生成随机数,作为下标,原本的mine的棋盘是不给玩家展示的,所以可以用1代表有雷,刚开始此棋盘是将所有的位置都赋值0,生成得到的随机下标代表的位置是'0',就可以将其换成'1',直到将10个雷全部布下。
生的随机数%9的话他的余数就是0-8,用它加一就可以得到1-9也就是期盼的下标。通过一个while循环,count的值给到10,每次布置好一颗雷就将这个count减一,直到count等于0的时候,也就说明这个雷已经布置好了。
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
5.排雷
1.获得周围的雷的数量
排雷的函数首先需要一个函数来获得周围一圈雷的数量。
这里用一个int 类型的函数,将四周8个位置的元素的字符的ASCII值加起来减去8个'0'的ASCII值,得到的数就是这周围一圈的雷的数量。
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] +
mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] +
mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');
}
2.主体函数
给到一个整型变量win,while循环的条件是win<9*9-10,先进入循环,输入需要排查的坐标,首先坐标要合理也就是x >= 1 && x <= row &&y >= 1 && y <= col。然后判断show棋盘中的字符,show棋盘的初始化字符是'*',所以当棋盘中是这个字符时就是没有被排查过,然后判断这个字符,如果时'1'的话就是代表此处是雷,那么游戏就结束了,玩家就被炸死了。如果不是的话,那就需要用到上面的get_mine_count这个函数,获得周围一圈的雷的数量,并且将这个值赋给这个位置。最后如果都不是的话那就是输入的坐标错误,会提示输入错误,重新输入,然后再回到之前的while循环入口,不断进行这样的操作,直到while判断条件的值小于等于10,也就是所有的雷都被排除,也就获得了游戏的胜利。
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win < (row * col - EASY_COUNT))
{
printf("输入需要排查的坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row &&y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("该坐标已被排查过\n");
continue;
}
if (mine[x][y] == '1')
{
printf("简单模式都能被炸死,没用!!\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int n = get_mine_count(mine, x, y);
show[x][y] = n + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("输入错误,请重新输入\n");
}
}
if (win == (row * col) - EASY_COUNT)
{
printf("恭喜你,扫雷成功!!\n");
DisplayBoard(mine, ROW, COL);
}
}
4.函数主体
1.菜单函数
首先给到一个菜单函数,在之前的游戏中都有涉及,就不过多作解释了。
void menu()
{
printf("**********************\n");
printf("****** 1. paly *******\n");
printf("****** 0. exit *******\n");
printf("**********************\n");
}
2.游戏函数
游戏函数的话就是将之前的函数合理的放在一起,使得游戏能够进行。
代码如下,也很简单,看看就能明白,要注意的各个函数调用的顺序,不然容易出错。
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
DisplayBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL);
DisplayBoard(mine, ROW, COL);
FindMine(mine,show, COL, ROW);
}
3.test函数
test函数就是整个游戏运行的大体思路,将所有的函数相互配合,完成游戏。
首先就是srand函数,来获得随机数。运行后的界面是菜单函数的界面,所以需要输入一个值,后来用do-while语句,它的条件就是输入值为真。while语句内部用的是switch语句,选择0,1中的一个,要么是进行游戏,执行game函数,不然就是输入0退出游戏,当输入1后,并且完成了游戏可以继续此游戏,直到输入0时才会结束。当输入的值不是0也不是1时,就会提示输入错误,需要重新输入。
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
4.main函数
这就是函数主题,就没东西。
int main()
{
test();
return 0;
}
5.代码实现
1.game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define EASY_COUNT 10
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
2.game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("-------扫雷--------\n");
for (j = 0; j <= row; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= col; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("-------扫雷--------\n");
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
//获得周围一圈雷的数量
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] +
mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] +
mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');
}
//排雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win < (row * col - EASY_COUNT))
{
printf("输入需要排查的坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row &&y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("该坐标已被排查过\n");
continue;
}
if (mine[x][y] == '1')
{
printf("简单模式都能被炸死,没用!!\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int n = get_mine_count(mine, x, y);
show[x][y] = n + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("输入错误,请重新输入\n");
}
}
if (win == (row * col) - EASY_COUNT)
{
printf("恭喜你,扫雷成功!!\n");
DisplayBoard(mine, ROW, COL);
}
}
3.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("**********************\n");
printf("****** 1. paly *******\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, '*');
//打印棋盘
DisplayBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL);
DisplayBoard(mine, ROW, COL);
FindMine(mine,show, COL, ROW);
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
以上就是扫雷的全部解析啦。