先上代码(main函数在测试.c)
头文件 游戏.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//显示的行列
#define HANG 9
#define LIE 9
//真实的行列
#define HANG_JIA HANG + 2
#define LIE_JIA LIE + 2
//雷数
#define LEI_SHU 5
//菜单
void cai_dan(void);
//扫雷
void sao_lei(void);
//初始化
void chu_shi_hua(char shu_zu[HANG_JIA][LIE_JIA], int hang_jia, int lie_jia, char zi_fu);
//显示
void xian_shi(char shu_zu[HANG_JIA][LIE_JIA], int hang, int lie);
//布雷
void bu_lei(char an[HANG_JIA][LIE_JIA], int hang, int lie);
//排雷
void pai_lei(char ming[HANG_JIA][LIE_JIA], char an[HANG_JIA][LIE_JIA], int hang, int lie);
//探雷
void tan_lei(char ming[HANG_JIA][LIE_JIA], char an[HANG_JIA][LIE_JIA], int x, int y, int hang, int lie, int* z);
//周围雷的个数
int zhou_wei(char an[HANG_JIA][LIE_JIA], int x, int y);
源文件 游戏.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "游戏.h"
void cai_dan()
{
printf("\n");
printf(" 输入1开始游戏\n");
printf(" 输入0退出游戏\n");
printf("\n");
}
void sao_lei()
{
//两个棋盘,一明一暗
char ming[HANG_JIA][LIE_JIA] = { 0 };
char an[HANG_JIA][LIE_JIA] = { 0 };
chu_shi_hua(ming, HANG_JIA, LIE_JIA, '*');
chu_shi_hua(an, HANG_JIA, LIE_JIA, '0');
xian_shi(ming, HANG, LIE);
//xian_shi(an, HANG, LIE);
bu_lei(an, HANG, LIE);
//xian_shi(an, HANG, LIE);
pai_lei(ming, an, HANG, LIE);
}
//初始化
void chu_shi_hua(char shu_zu[HANG_JIA][LIE_JIA], int hang_jia, int lie_jia, char zi_fu)
{
int i = 0;
int j = 0;
for (i = 0; i < hang_jia; i++)
{
for (j = 0; j < lie_jia; j++)
{
shu_zu[i][j] = zi_fu;
}
}
}
//显示
void xian_shi(char shu_zu[HANG_JIA][LIE_JIA], int hang, int lie)
{
int i = 0;
int j = 0;
//行号
for (j = 0; j <= lie; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= hang; i++)
{
//列号
printf("%d ", i);
for (j = 1; j <= lie; j++)
{
printf("%c ", shu_zu[i][j]);
}
printf("\n");
}
}
//布雷
void bu_lei(char an[HANG_JIA][LIE_JIA], int hang, int lie)
{
int lei_shu = LEI_SHU;
while (lei_shu)
{
int x = rand() % hang + 1;
int y = rand() % lie + 1;
if (an[x][y] == '0')
{
an[x][y] = '1';
lei_shu--;
}
}
}
//排雷
void pai_lei(char ming[HANG_JIA][LIE_JIA], char an[HANG_JIA][LIE_JIA], int hang, int lie)
{
int x = 0;
int y = 0;
//成功排雷的个数z
int z = 0;
while (1)
{
printf("请输入需排查的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= hang && y >= 1 && y <= lie)
{
if (ming[x][y] == '*')
{
if (an[x][y] == '0')
{
tan_lei(ming, an, x, y, hang, lie, &z);
xian_shi(ming, HANG, LIE);
printf("扫除成功\n");
}
else
{
printf("不幸踩雷,扫雷失败\n");
xian_shi(an, HANG, LIE);
break;
}
}
else
{
printf("坐标已排查过,请换一个坐标\n");
}
}
else
{
printf("坐标错误,请重新输入\n");
}
if (z == HANG * LIE - LEI_SHU)
{
printf("所有雷均已扫除!\n");
break;
}
}
}
//探雷
void tan_lei(char ming[HANG_JIA][LIE_JIA], char an[HANG_JIA][LIE_JIA], int x, int y, int hang, int lie, int* z)
{
while (1)
{
if (x >= 1 && x <= hang && y >= 1 && y <= lie && ming[x][y] == '*' && an[x][y] == '0')
{
*z = *z + 1;
if (zhou_wei(an, x, y) == 0)
{
ming[x][y] = ' ';
tan_lei(ming, an, x - 1, y - 1, hang, lie, z);
tan_lei(ming, an, x - 1, y, hang, lie, z);
tan_lei(ming, an, x - 1, y + 1, hang, lie, z);
tan_lei(ming, an, x, y - 1, hang, lie, z);
tan_lei(ming, an, x, y + 1, hang, lie, z);
tan_lei(ming, an, x + 1, y - 1, hang, lie, z);
tan_lei(ming, an, x + 1, y, hang, lie, z);
tan_lei(ming, an, x + 1, y + 1, hang, lie, z);
}
else
{
//数字加'0' = 对应的数字字符
ming[x][y] = zhou_wei(an, x, y) + '0';
}
}
break;
}
}
//周围雷的个数
int zhou_wei(char an[HANG_JIA][LIE_JIA], int x, int y)
{
int i = 0;
if (an[x - 1][y - 1] == '1')
i++;
if (an[x - 1][y] == '1')
i++;
if (an[x - 1][y + 1] == '1')
i++;
if (an[x][y - 1] == '1')
i++;
if (an[x][y + 1] == '1')
i++;
if (an[x + 1][y - 1] == '1')
i++;
if (an[x + 1][y] == '1')
i++;
if (an[x + 1][y + 1] == '1')
i++;
return i;
}
源文件 测试.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "游戏.h"
int main()
{
srand((unsigned int)time(NULL));
while (1)
{
cai_dan();
int i = 0;
printf("请选择:");
scanf("%d", &i);
if (i == 1)
{
sao_lei();
}
else if (i == 0)
{
printf("退出游戏成功\n");
break;
}
else
{
printf("输入错误,请重新输入\n");
}
}
return 0;
}
运行截图
思路
三个文件,一个头文件,两个源文件,自定义头文件里放各种C语言自带的头文件(套娃)和自定义函数的声明。测试.c的源文件里就放了个main,游戏.c放各种自定义函数。
1、开始菜单,很简单,直接打印就行了。
2、设置棋盘,为了之后计算周围雷的个数的时候数组不越界,数组设置的时候要大一圈。之后初始化,打印数组。
3、布雷,使用随机数随机布雷,注意对应数组下标。
4、排雷,根据输入坐标的不同,可以分为超出棋盘、已排查、踩雷、未踩雷几种情况,用if语句对应判断即可。
5、探雷,我是通过直接枚举周围8个数组元素,然后递归实现的,递归的时候要注意探查过的坐标就不要再探查了,不然会死递归。
好了,大概就这些。
总结 (・ ᴗ ・)
代码实现的效果已经和真实的扫雷非常接近了,但不足的地方还是有的,就是第一步可能会踩雷,而实际扫雷游戏中是不会的,日后可以改进。(但愿)