扫雷C语言实现

头文件部分: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);

游戏主体函数部分:

涉及主要逻辑

  1. 设置雷->排查雷(被雷炸死/非雷全被命中胜利)
  2. 统计九宫格雷数利用ASCII码运算,而没用循环判断
  3. 主动标记雷的位置
  4. 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;
}

若存在不足,敬请提出!

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值