扫雷游戏(c语言)

1分析

我们需要写三个部分,分别是game.h game.c 扫雷.c三个文件,其中game.c实现扫雷函数的实行,而扫雷.c则是宏观的具体框架,game.h则是我们声明函数的地方

2game.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
void InitBoard (char board[ROWS][COLS],int rows,int cols,char set);//这个字符set可以实现show初始化'0'mine初始化*
void DisplayBoar(char board[ROWS][COLS], int row, int col);//打印函数
void SetMine(char board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col);
void expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int *win);
//展开一片的前提
//1该坐标不是雷
//2该坐标周围不是雷
//扩展功能实现
//1展开一片
//2标记雷
//3显示剩余雷的个数

ROW表示行COL表示列

InitBoard表示初始化游戏,我们使用的是二维数组,DisplayBoard是玩家选择坐标,SetMine是埋雷,FindMine是找雷,expand是扩展功能实现当周围8个格子都没有雷的时候我们可以直接展开。后续还可以完善标记雷的功能。

3game.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;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		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 <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行数
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
void SetMine(char mine[ROWS][COLS], int row, int col)
{
	//假设布置10个雷
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row+1;//1~9
		int y = rand() % col+1;//1~9
		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
			{
				expand(mine, show, x, y, &win);
				system("cls");//清屏(看需要)
				DisplayBoard(show, ROW, COL);
				//统计坐标周围有几个雷
				int n=get_mine_count(mine,x,y);
				show[x][y] = n+'0';//此处我们要输入的是字符n n+'0'就是我们对应的字符
				DisplayBoard(show, ROW, COL);
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == (row * col - EASY_COUNT))
	{
		//system("cls");//看需要是否想清屏
		printf("小石,恭喜你,排雷成功了\n");
		DisplayBoard(mine, ROW, COL);
	}
}
void expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int*win)
{
	if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		int count = get_mine_count(mine, x, y);
		if (count == 0)
		{
			show[x][y] = ' ';
			int i = 0;
			for (i = x - 1; i < x + 1; i++)
			{
				int j = 0;
					for (j = y - 1; j <= y + 1; j++)
					{
						if (show[i][j] == '*')
						{
							expand(mine, show, i, j, win);
						}
					}
			}
		}
		else
		{
			show[x][y] = count + '0';
		}
		(* win)++;
	}
}

值得注意的是expand的win我们需要取地址,只有这样才能修改win的值,不然就会出现我们已经成功通关,但是游戏还是没有结束的情况。

关于随机设置雷的问题,我们其实在五子棋游戏中就有讲到,需要用到srand((unsigned int)time(NULLL))利用时间戳来得到随机值,头文件是#include<stdlib.h> #include<time.h>

初始化部分,我们首先需要两个二维数组,我们设置了两个define的常量一个是11 一个是9 

这样做的原因是防止溢出,两个二维数组,一个是mine[][]也就是雷的数组,一个是show[][]也就是展示的数组,我们在初始化数组的时候,我们把雷的数组全部初始化为字符‘0’,把show[][]数组初始化*,这个时候为了方便初始化,所以我们在最后还新增了一个接受量,利用这个接受量就避免的写两个循环分别初始化这两个数组。

打印函数,我们打印了横坐标和纵坐标的标号,然后我们使用一个循环嵌套打印数组。

设置雷函数,我们使用rand随机数设置雷的数量,然后我们雷的值赋值成1,然后把值赋值给我们的mine[][]数组

找雷函数,首先为了防止我们排查过已经排查过的坐标,我们需要一个检查功能,如果不等于*那么就说明已经被排查过了,如果等于*说明还没有排查,然后我们需要实现一个显示周围8个格子雷的数量的功能,为了实现这个功能我们加入了get_mine_count函数,特别需要注意的是,我们使用都是字符,所以我们加和之后需要减去的是8*'0'才能得到对应的int值,int值变成对应的字符值也很简单只需要加上'0'就可以了

此时游戏已经可以初步玩了,但是如果是这样玩一把的失败率太高,时间也太久,所以我们还需要

一个expand函数用来展开,当周围没有雷的时候,直接自动排除,为了写出expand函数,我们需要使用递归,而且为了不出现排雷成功但是游戏还没结束的情况,我们需要使用&取地址符,只有这样我们的win++的值才会作用到比较的win上。

此时基本功能和函数都已经完善,可以正常的游戏啦!

3扫雷.c

最后是扫雷.c 其实我们在写代码的时候最先写的是扫雷.c 完善菜单和选择模块,然后我们才开始去思考需要什么函数,函数该如何实现

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
	printf("******************\n");
	printf("****  1.play  ****\n");
	printf("****  0.exit  ****\n");
	printf("******************\n");
}
void game()
{
	//1存放布置好的雷的信息,存放排查出的雷的信息,我们需要两个二维数组
	//排查坐标的时候,为了防止坐标越界,我们给数组的行和列都增加2
	//mine雷 show 默认希望show数组都是* 默认希望mine数组都是字符0
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//打印棋盘
	DisplayBoard(show, ROW, COL);
	SetMine(mine, ROW, COL);
	//DisplayBoard(mine, ROW, COL);//这是游戏外挂,如果你注销该注释,即可拥有游戏外挂
	//排雷
	FindMine(mine,show,ROW,COL);


}
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");
		}
	} while (input);
}
int main(void)
{
	test();
	return 0;
}


    

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值