C语言实现扫雷

欢迎来到程序员的快乐!

目录

一、游戏规则

二、编程准备和分析

三、game.h

1、头文件的包含

2、#define 的作用是定义的标识符常量

3、函数的声明

四、游戏菜单界面打印

 五、游戏逻辑函数

六、游戏相关函数的实现

七、游戏测试

八、game.c和text.c


一、游戏规则

哈喽,童年的你扫雷时真的了解游戏的规则吗?

在一块网格中,埋有若干颗雷。游戏开始后选择一块区域,若该网格为雷则失败,反之,显示这块区域周围8个网格中埋雷的个数。我们根据这个提示继续排雷直至胜利!

二、编程准备和分析

1、准备:

 Text.c:测试游戏逻辑。

game.c:游戏相关函数的实现。

game.h:头文的包含、函数的声明、符号声明。

2、分析:

实现一个9*9的简易扫雷游戏,创建两个字符数组,

char mine[][]埋雷:存放布置雷的信息。

雷的个数(固定)我们设定为10,每次游戏开始后随机在棋盘上生成,雷用字符‘1’表示,非雷用字符‘0’表示。

注意:这里的‘1’和‘0’是char类型的!

char show[][]排雷:存放排查雷的信息。

打印出来的棋盘用“*”表示,用坐标选择网格区域,若是雷游戏结束,若不是雷,则显示这个网格周围8个区域相加的雷的个数。想到这里有的小伙伴可能会出现疑问,当我们排到棋盘的边缘时该怎么办呢?我们可以这样解决,创建数组的时候,我们多创建成11*11并初始化,在9*9的范围内布雷,保证雷不会出界,打印的时候只打印出9*9,。

三、game.h

小游戏的所有头文件引用,符号的定义和函数的声明 

#pragma once
//头文件的包含
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

//符号的定义
#define minenum 10
#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

//函数的声明

//初始化数组
void initboard(char board[ROWS][COLS],int rows,int cols,char set);
//打印棋盘
void printfboard(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);

头文件的包含

#include <stdio.h>      /* printf, scanf, puts, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */

#define 的作用是定义的标识符常量

minenum>代表布雷的个数。

ROW 9*9棋盘的行号。

COL 9*9棋盘的列号。

ROWS 11*11棋盘的行号.

COL S 11*11棋盘的列号.

函数的声明

初始化数组的函数

打印棋盘的函数

布置雷的函数

排雷的函数

四、游戏菜单界面打印

1、自己动手写一个menu()函数实现菜单界面的打印。

//打印菜单
void menu()
{
	printf("|------------Mine*Clearance --------|\n");
	printf("|***********  1.开始游戏  **********|\n");
	printf("|***********  0.退出游戏  **********|\n");
	printf("|-----------------------------------|\n");
}

2、在主函数中使用do...while循环语句和switch多分支,实现选择不同选项出现不同的效果,我们暂时输出一句话来显示不同的效果。input是我们定义的一个变量,并把它当做循环和分支的条件表达式,当input = 1时开始游戏,input = 0 时退出游戏并且退出循环,input= 其它值时打印出一句错误提醒! 

int main()
{
	int input;
		do
		{

			menu();
			printf("请选择选项:>");
			scanf("%d",&input);
			switch (input)
			{
			case 0:
				printf("退出游戏\n");
				break;
			case 1:
				printf("开始游戏\n");
				break;
			default:
				printf("选项错误,请重新输入:>\n");
			}
		} while (input);


	return 0;
}

效果截图:

 五、游戏逻辑函数

当我们在菜单界面选择1时,单单输出一句话肯定是不行的,所以我们要调用一个game()函数,来实现开始游戏后展现出的游戏效果。

//游戏逻辑
void game()
{
	//创建字符数组存储数据
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	
	//数组初始化
	initboard(mine,ROWS,COLS,'0');
	initboard(show, ROWS, COLS, '*');
	
	//打印棋盘
	printfboard(show, ROW, COL);

	//布置雷
	setmine(mine, ROW, COL);
	printfboard(mine, ROW, COL);	
	//排雷
	findmine(mine,show,ROW,COL);

}

1、创建两个11*11的字符数组,mine数组用来布雷,在游戏的过程中是隐藏的,show数组是我们直接操作的。

2、用来数组初始化的函数,四个参数分别为:数组、行、列、字符。

mine数组初始化成字符‘0’,show数组初始化成'*'。

3、打印棋盘、把初始化后的show数组打印。

4、布雷,在mine中操作,在9*9的范围内随机布雷,这里涉及到一个rand()函数,在下面会有详细介绍。

5、排雷:游戏过程中可能出现的情况:我们输入一个合法坐标后,

排到雷->游戏失败。

不是雷->在棋盘上返回一个信息提示玩家周围有几个雷。

排到只剩下雷,游戏胜利。

六、游戏相关函数的实现

1initboard()函数,形参set的作用是接收传来的‘0’和‘*’,达到两个数组分别初始化的效果!

void initboard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i<rows; i++)
	{
		for (j = 0;j<cols; j++)
		{
		   board[i][j] = set;
		}
	}
}

2、printfboard()函数,虽然我们创建的是11*11的数组,但是我们只打印出9*9的棋盘,棋盘行号和列号的打印是为了玩家方便坐标的输入!

//打印棋盘
void printfboard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("------------扫雷游戏------------\n");
	for (i = 0; i<=row;i++)
	{
		//打印列号
		printf("%d ",i);
	}
	printf("\n");
	for ( i = 1;i<=row;i++)
	{
		//打印行号
		printf("%d ",i);
		for (j = 1;j<=col;j++)
		{
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}
	printf("------------扫雷游戏------------\n");
}

 3、setmine()函数,在mine[][]数组中随机布雷
  

//布置雷
void setmine(char board[ROWS][COLS], int row, int col)
{
	int count = minenum;//记录雷的个数
	
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

rand()函数: 生成随机数,介于0和 RAND_MAX(32767)之间的随机整数。

我们输入的坐标是要在9*9棋盘的范围内的,所以布置雷的坐标也一定要符合条件,

rand() % row的范围是0到8,所以rand()% row +1这个表达式是满足条件的!

count记录雷的个数,每次布好一颗雷后自减。当count=0时跳出循环。


 4、 findmine()函数,排查雷,输入一个坐标判断是否合法,如果合法,判断是不是雷,

是雷:游戏结束!

不是雷:返回一个信息告诉玩家这个区域周围一共有几颗雷,存储信息到show数组

在9*9的网格中排查到只剩下10个网格的时候游戏胜利

//排雷
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-minenum)
	{
		printf("请输入一个坐标:>");
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x > 0 && x <=row && y>0 && y <=col)
		{
			//判断是不是雷
			if (mine[x][y] == '1')
			{
				printf("有炸弹,游戏结束!\n");
				//游戏结束,打印结果
				printfboard(mine,row,col);
				break;

			}
			else
			{
				//不是雷,返回一个信息告诉玩家这个区域周围一共有几颗雷,存储信息到show数组
				int count = get_mine_count(mine,x,y);
				show[x][y] = count + '0';
				printfboard(show, row, col);
				win++;
			}
		}
		else
		{
			printf("坐标错误!\n");
		}
	}
	if (win >= row * col - minenum)
	{
		printf("排雷成功,游戏胜利!\n");
		printfboard(mine,row,col);
	}
}

int count = get_mine_count(mine,x,y);
				show[x][y] = count + '0';

get_mine_count(mine,x,y)函数的作用是计算我们输入做标的周围有几颗雷,返回值返回到show[][]中。但是返回的是一个int 类型,而show是一个字符数组,所以这时我们可以让count + '0'转换成一个字符存到数组中去。

5、 findmine()函数中调用了一个get_mine_count(mine,x,y)函数,在不是雷的情况下给玩家返回一个提示周围有几颗雷的信息。

 

int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
	return 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] +
		mine[x - 1][y + 1] - 8 * '0';
}

七、游戏测试

游戏失败:

 游戏成功,这里为了方便,把布雷的个数改成80,提前打印mine[][]数组查看,测试游戏成功的情况:

八、game.c和text.c

game.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;
	int j = 0;
	for (i = 0; i<rows; i++)
	{
		for (j = 0;j<cols; j++)
		{
		   board[i][j] = set;
		}
	}
}

//打印棋盘
void printfboard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("------------扫雷游戏------------\n");
	for (i = 0; i<=row;i++)
	{
		//打印列号
		printf("%d ",i);
	}
	printf("\n");
	for ( i = 1;i<=row;i++)
	{
		//打印行号
		printf("%d ",i);
		for (j = 1;j<=col;j++)
		{
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}
	printf("------------扫雷游戏------------\n");
}

//布置雷
void setmine(char board[ROWS][COLS], int row, int col)
{
	int count = minenum;//记录雷的个数
	
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % row + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
	return 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] +
		mine[x - 1][y + 1] - 8 * '0';
}

//排雷
void findmine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
	//接收坐标
	//判断坐标是否合法
	//合法坐标进行检测
	//是雷:游戏结束
	//不是雷:返回一个信息告诉玩家这个区域周围一共有几颗雷,存储信息到show数组
	//在9*9的网格中排查到只剩下10个网格的时候游戏胜利
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row*col-minenum)
	{
		printf("请输入一个坐标:>");
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x > 0 && x <=row && y>0 && y <=col)
		{
			//判断是不是雷
			if (mine[x][y] == '1')
			{
				printf("有炸弹,游戏结束!\n");
				//游戏结束,打印结果
				printfboard(mine,row,col);
				break;

			}
			else
			{
				//不是雷,返回一个信息告诉玩家这个区域周围一共有几颗雷,存储信息到show数组
				int count = get_mine_count(mine,x,y);
				show[x][y] = count + '0';
				printfboard(show, row, col);
				win++;
			}
		}
		else
		{
			printf("坐标错误!\n");
		}
	}
	if (win >= row * col - minenum)
	{
		printf("排雷成功,游戏胜利!\n");
		printfboard(mine,row,col);
	}
}

text.c

#define _CRT_SECURE_NO_WARNINGS 1
//测试游戏的逻辑
#include "game.h"

//打印菜单
void menu()
{
	printf("|------------Mine*Clearance --------|\n");
	printf("|***********  1.开始游戏  **********|\n");
	printf("|***********  0.退出游戏  **********|\n");
	printf("|-----------------------------------|\n");
}
//游戏逻辑
void game()
{
	//创建字符数组存储数据
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	
	//数组初始化
	initboard(mine,ROWS,COLS,'0');
	initboard(show, ROWS, COLS, '*');
	
	//打印棋盘
	printfboard(show, ROW, COL);

	//布置雷
	setmine(mine, ROW, COL);
	/*printfboard(mine, ROW, COL);	*/
	//排雷
	findmine(mine,show,ROW,COL);

}

int main()
{
	srand((unsigned int)time(NULL));
	int input;
		do
		{

			menu();
			printf("请选择选项:>");
			scanf("%d",&input);
			switch (input)
			{
			case 0:
				printf("退出游戏\n");
				break;
			case 1:
				game();
				break;
			default:
				printf("选项错误,请重新输入:>\n");
			}
		} while (input);


	return 0;
}

嘻嘻,今天的你快乐了吗!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值