头文件部分:game.h
- 设置雷的总数
- 准备使用两个二维数组char型
- 大数组设置冗余行列,替代越界判断,布置信息字符0/1表示地雷位置
- 小数组显示隐藏符号及地雷数
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
//游戏地图大小
#define ROW 9
#define COL 9
//增加冗余行列,省去实际ROW*COL大小下的越界处理
#define ROWS ROW+2
#define COLS COL+2
#define BOMBNUM 10//地雷数量
void initialshow(char show[ROW][COL], int row, int col);//初始化显示扫雷图
void initialinform(char inform[ROWS][COLS], int rows, int cols, int row, int col);//初始化信息扫雷图
void displayinform(char inform[ROWS][COLS], int row, int col);//打印信息图
void display( char show[ROW][COL], int rows, int cols, int row, int col);//打印扫雷图
int judge(char inform[ROWS][COLS], int x, int y);//判断地雷及九宫格内地雷数
void Flag(char show[ROW][COL], int row, int col);//主动标记/取消标记地雷位置
//从排雷位置开始展开连续的九宫格内地雷数为0的空地区域
void zerofind(char inform[ROWS][COLS], char show[ROW][COL], int row, int col,int x,int y);
//游戏主体逻辑
void game(char inform[ROWS][COLS], char show[ROW][COL], int rows, int cols, int row, int col);
游戏主体函数部分:
涉及主要逻辑
- 设置雷->排查雷(被雷炸死/非雷全被命中胜利)
- 统计九宫格雷数利用ASCII码运算,而没用循环判断
- 主动标记雷的位置
- 0处延展 递归判断(设置状态数组避免重复访问)递归条件1. 此处不是雷2.周围没有雷3.第一次访问)
#include "game.h"
//全局变量
char Ybomb = '1';//有地雷
char Nbomb = '0';//无地雷
char mystery = '*';//扫雷样式
char bomb = '!';//标记有地雷
int visit[ROWS][COLS] = { 0 };//访问判断数组,避免九宫格递归判断死循环
int notfind = ROW * COL - BOMBNUM;//还未发现的安全区
void initialshow(char show[ROW][COL], int row, int col) {
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++) {
show[i][j] = mystery;
}
}
}
void initialinform(char inform[ROWS][COLS], int rows, int cols, int row, int col) {
int i = 0, j = 0;
int num = 0;//已设置雷数
//ROWS*COLS范围内初始化雷数='0'
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
inform[i][j] = Nbomb;
}
}
//生成随机数设置雷位置-ROW*COL范围对应inform下标1-9
while (num < BOMBNUM) {
i = rand() % row + 1;
j = rand() % col + 1;
if (inform[i][j] == Nbomb) {
num++;
inform[i][j] = Ybomb;
}
}
}
void displayinform(char inform[ROWS][COLS], int row, int col) {
int i = 0, j = 0;
for (i = 0; i <= row; i++) {
printf(" %d ", i);
}
printf("\n");
for (i = 0; i <= row; i++) {
printf("---");
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf(" %d|", i);
for (j = 1; j <= col; j++) {
printf(" %c ", inform[i][j]);
}
printf("\n\n");
}
}
void display(char show[ROW][COL], int rows, int cols, int row, int col) {
int i = 0, j = 0;
//打印列号
for (i = 0; i <= row; i++) {
printf(" %d ", i);
}
printf("\n\n");
for (i = 0; i < row; i++)
{
//打印行号
printf(" %d ", i + 1);
for (j = 0; j < col; j++) {
printf(" %c ", show[i][j]);
}
printf("\n\n");
}
}
int judge(char inform[ROWS][COLS], int x, int y) {
int num = 0;
//判地雷
if (inform[x][y] == Ybomb) {
return -1;
}
else {//统计九宫格内雷数-正整数,以(x,y)为(0,0)
num = inform[x - 1][y - 1]//(-1,-1)
+ inform[x - 1][y]//(-1,0)
+ inform[x - 1][y + 1]//(-1,1)
+ inform[x][y - 1]//(0,-1)
+ inform[x][y + 1]//(0,1)
+ inform[x + 1][y - 1]//(1,-1)
+ inform[x + 1][y]//(1,0)
+ inform[x + 1][y + 1]//(1,1)
- 8 * '0';//基于ASCII码计算
//show[x - 1][y - 1] = '0' + num;
return num;
}
return 0;
}
void Flag(char show[ROW][COL], int row, int col) {
int x = 0, y = 0;
int sign = 1;
do {
printf("请输入你想标记/取消标记的可能地雷坐标:行 列\n");
scanf("%d %d", &x, &y);
if (x<1 || y<1 || x>row || y>col) {
printf("该位置不存在,请重新选择位置!\n");
}
//判断是否排过
else if (show[x - 1][y - 1] != mystery && show[x - 1][y - 1] != bomb) {
printf("该位置已经排查过,请重新选择位置!\n");
}
else {
sign = 0;
if (show[x - 1][y - 1] == bomb) {
show[x - 1][y - 1] = mystery;
}
else {
show[x - 1][y - 1] = bomb;
}
}
} while (sign);
}
void zerofind(char inform[ROWS][COLS], char show[ROW][COL], int row, int col, int x, int y) {
int value = -1;
if (x >= 1 && y >= 1 && x <= row && y <= col && visit[x][y] == 0) {
value = judge(inform, x, y);
visit[x][y] = 1;
if (value == 0) { //九宫格内地雷数为0
show[x - 1][y - 1] = '0';
notfind--;
//递归判断相邻四个位置
//上
zerofind(inform, show, row, col, x - 1, y);
//下
zerofind(inform, show, row, col, x + 1, y);
//左
zerofind(inform, show, row, col, x, y - 1);
//右
zerofind(inform, show, row, col, x, y + 1);
}
}
}
void game(char inform[ROWS][COLS], char show[ROW][COL], int rows, int cols, int row, int col) {
int i = 0;
int j = 0;
int flag = 0;//有无标记请求
int judgedeath = 0;//0-contiune;1-fail
//初始化信息地图
initialinform(inform, rows, cols, row, col);
//初始化显示地图
initialshow(show, row, col);
//开始扫雷
displayinform(inform, row, col);
display(show, rows, cols, row, col);
while (notfind) {
printf("是否需要标记或取消标记位置:1-yes,其他数-no\n");
scanf("%d", &flag);
if (flag == 1) {
Flag(show, row, col);
display(show, rows, cols, row, col);
}
printf("请输入要排查的位置:行 列\n");
scanf("%d %d", &i, &j);
//判断合法性
if (i<1 || j<1 || i>row || j>col) {
printf("该位置不存在,请重新选择位置!\n");
continue;
}
//判断是否排过
else if (show[i - 1][j - 1] != mystery) {
if (show[i - 1][j - 1] == bomb) {
printf("该位置已标记,需要先取消标记!\n");
}
printf("该位置已经排查过,请重新选择位置!\n");
continue;
}
//基于合法位置进行处理
//1.判断此处是否有雷,并对show作相应修改
judgedeath = judge(inform, i, j);
//打印地图
if (judgedeath < 0) {
printf("地雷分布如下:\n");
displayinform(inform, row, col);
printf("很遗憾你碰到了地雷,失败!\n");
break;
}
else {
show[i - 1][j - 1] = '0' + judgedeath;
if (judgedeath != 0) {//避免zerofind多次减
notfind--;//发现一处空地
}
if (!notfind) {
displayinform(inform, row, col);
printf("恭喜你发现了所有的雷,游戏胜利!\n");
}
else {
//若链接0在扩展开
zerofind(inform, show, row, col, i, j);
display(show, rows, cols, row, col);
}
}
}
}
main:
#include "game.h"
void menu() {
printf("$$$$$$$$$$$$$$$$$$$$$$\n");
printf("$$$$ 欢迎来到扫雷 $$$$\n");
printf("$$$ 1.游戏 2.退出 $$$\n");
printf("$$$$$$$$$$$$$$$$$$$$$$\n");
}
int main() {
srand((unsigned int)time(NULL));
int select = 0;
int tag = 1;//1表示游戏继续进行,0表示结束游戏,2表示输入不合法
char information[ROWS][COLS] = { 0 };//设置为字符型,统计九宫格内雷数利用ASCII码,主要方便mapshow的打印
char mapshow[ROW][COL] = { 0 };
while (tag != 0) {
if (tag != 2) {
menu();
}
printf("输入选择(1或2)->");
scanf("%d", &select);
//判断如何进行
switch (select)
{
case 1:
{
tag = 1;
game(information,mapshow,ROWS,COLS,ROW,COL);
//进行游戏
break;
}
case 2:
{
tag = 0;
printf("游戏即将退出\n");
break;
}
default:
{
tag = 2;
printf("输入选择不合法,请重新输入\n");
break;
}
}
}
return 0;
}
若存在不足,敬请提出!