目录
一.文件
1.头文件
game.h
用于存放所有源文件需要用的标准库头文件和函数的声明。(便于查找和让代码更简洁)
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define COLS COL+2
#define ROWS ROW+2
#define ALLMINE 10
void InitBoard(char board[ROWS][COLS],int row,int col,char set);
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void SetMine(char board[ROWS][COLS], int row, int col);
void FineMine(char mine[ROWS][COLS],char board[ROWS][COLS], int row, int col);
ROW和COL为扫雷的行和列,也就是面积
ROWS和ROWS为行和列加2,加2是因为我们后面需要统计每个格子四周的8个格子一共含有的雷数,为了避免越界问题,特地+2,左右上下各加一行或者一列嘛。
ALLMINEE为所有的雷一共10个
InitBoard,DisplayBoard,SetMine,FineMine为后面需要用到的函数的声明
2.源文件
game.c
test.c
game.c用来写所有自定义函数的代码
test.c用来写游戏界面的执行入口和游戏函数执行顺序
如图:
二.游戏界面和执行(test.c)
注意:记得加上自定义头文件game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu() {
printf("********************************\n");
printf("******** 1.开始游戏 ********\n");
printf("******** 0.退出游戏 ********\n");
printf("********************************\n");
}
void game() {
int mine[ROWS][COLS];
int show[ROWS][COLS];
InitBoard(mine,ROWS,COLS,'0');//初始化地雷数组
InitBoard(show, ROWS, COLS,'*');//初始化显示的数组
DisplayBoard(show,ROW,COL);//显示当前的情况
/*DisplayBoard(mine, ROW, COL);*/
SetMine(mine,ROW,COL);//放置地雷,随机
/*DisplayBoard(mine, ROW, COL);*/
FineMine(mine,show, ROW, COL);//排雷
}
int main() {
menu();
int input = 0;
srand((unsigned int)time(NULL));//需要标准库头文件stdlib.h和time.h
do {
printf("请输入1或0:>\n");
scanf("%d", &input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
return 0;
}
解释:
1.游戏的进入与退出我们使用do while循环,先执行一遍再根据输入的数判断是否再次决定游戏的进入与退出
2.至于srand()函数,void srand(unsigned int seed);是他的原型,srand
函数用于设置随机数生成器的种子。这个种子值决定了 rand
函数(后面会讲到)生成的随机数序列(如果种子为固定值,则随机的数也是固定值)。通常在调用 rand
之前调用 srand
,并传入一个无符号整数作为种子值。这里我们使用时间作为种子,因为时间是一直在流逝的嘛,所以其总能够生成随机数。
3.game()函数也就是后面会讲的game.c。
效果如下图:
三.函数实现(void game部分,源文件game.c)
注意:记得加上自定义头文件game.h
1.定义雷二维数组和展示二维数组
2.初始化地雷数组
给每个格子都初始化为0
void InitBoard(char board[ROWS][COLS], int row, int col,char set){//InitBoard(mine,ROWS,COLS,'0');
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
board[i][j] = set;
}
}
}
3.初始化显示的数组
注意和初始化地雷数组的区别,这个传入的 实参为show,上面那个传入的是mine
给每个格子初始化为' * '
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[ROWS][COLS], int row, int col,char set){//InitBoard(show, ROWS, COLS,'*');
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
board[i][j] = set;
}
}
}
4.显示当前的情况
注意这里的row和col为ROW,COL,而不是ROWS,COLS,我们显示的话只显示9*9的面积就可以了
上面那两个初始化则就是ROWS,COLS,
void DisplayBoard(char board[ROWS][COLS], int row, int col) {//DisplayBoard(show,ROW,COL);
for (int i = 0; i <= row; i++) {
printf("%d ", i);//给列显示坐标
}
printf("\n");
for (int i = 1; i <= row; i++) {
printf("%d ", i);//给行显示坐标
for (int j = 1; j <= col; j++) {
printf("%c ", board[i][j]);
}
printf("\n");
}
}
效果如图:
5.随机放置地雷
void SetMine(char board[ROWS][COLS], int row, int col) {//SetMine(mine,ROW,COL);
int n = ALLMINE;//前面在头文件定义了ALLMINE为10,也就是雷的个数
while (n) {
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '1') {
continue;
}//避免了在同一个坐标放置雷
else {
board[x][y] = 1 + '0';
n--;//放好雷之后才n--
}
}
}
解释:
1.
rand
rand
函数用于生成一个伪随机数。该函数不需要参数,返回一个在 0
到 RAND_MAX
之间的整数(包括 0
和 RAND_MAX
)。RAND_MAX
是一个常量,定义在 <stdlib.h>
中,通常是 32767
,但这取决于具体的实现。
srand
srand
函数用于设置随机数生成器的种子。这个种子值决定了 rand
函数生成的随机数序列。通常在调用 rand
之前调用 srand
,并传入一个无符号整数作为种子值。
2.
int x = rand() % row + 1;
int y = rand() % col + 1;
因为row和col都是9,所以我们让这个随机数模上一个9,得到的数的范围一定是0~8,此时我们再让他+1,那他的范围就是1~9了,就符合我们的坐标条件了
6.排雷
代码如下:
void FineMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col) {;
//FineMine(mine,show, ROW, COL);
int x;
int y;//x,y为你要排查的坐标,输入
int count = 0;//你排查了的坐标的个数
while (1) {//一直循环排雷,直到排到雷,或者是成功通关就结束循环
printf("请输入你要排查的坐标:>");
scanf("%d", &x);
scanf("%d", &y);
if (mine[x][y] != '1') {
if (show[x][y] = '*') {//
dfs(mine, show, x, y);//深度优先遍历
DisplayBoard(show, ROW, COL);//每排查一个坐标就接着显示面板
count++;//排查了的坐标++
}
else
printf("该坐标已经被占用,请重新输入:>");//如果不为'*'意味着已经排查过这个坐标了
}
else {
printf("很不幸,你被炸死了\n");
DisplayBoard(mine, ROW, COL);//炸死后显示所有雷的位置
break;
}
if (count == row * col - ALLMINE+1) {
printf("恭喜你,成功通关了!\n");
break;
}
}
}
至于dfs()函数后面讲
效果如图:
ps:深度优先遍历数组
当然目的就是让其每输入一个坐标都有可能展开一片的操作,极大地减少了工作量。
写这个代码前建议大家刷一下力扣的这道题:
代码如下:
上面有注释
void dfs(char mine[ROWS][COLS], char show[ROWS][COLS], int a, int b) {
//dfs(mine, show, x, y);
int dx[8] = { -1,-1,-1,0,0,1,1,1 };//每个x都对应着其相同下标的y
int dy[8] = { -1,0,1,-1,1,-1,0,1 };//输入的x和y所在位置的周围八个位置
int count = 0;//用来记录(a,b)周围雷的个数
for (int i = 0; i < 8; i++) {
int r = a + dx[i];
int c = b + dy[i];//定位到xy周围的位置
if (r >= 1 &&r<=9&& c >= 1&&c<=9 && mine[r][c] =='1') {//r >= 1 &&r<=9&& c >= 1&&c<=9这一坨就是判断有没有越界
count++;//该位置是雷的话,就count++
}
}
if (count == 0) {//周围八个位置没有雷
show[a][b] = '0';
for (int i = 0; i < 8; i++) {//在这没有雷的位置扩散开来,直到找到其周围有雷的为止
int r = a + dx[i];
int c = b + dy[i];
if (r >= 1 && r <= 9 && c >= 1 && c <= 9 && show[r][c] == '*') {
//注意show[r][c] == '*'这个条件,不要遍历到重复的已经遍历过的
dfs(mine, show, r, c);//从这个坐标开始扩散
}
}
}
效果如图:
可以看到边界都显示有雷的!
四.结束
一键三连哦,感谢大家的阅读!