C语言扫雷(可展开)

C语言实现经典扫雷小游戏,利用递归实现棋盘展开


前言

 本篇文章,主要写一下<C语言程序实现扫雷小游戏>,会从一开始的结构思路出发,细分小步,一步一步将扫雷实现。

 


一、结构思路

参考与电脑上的扫雷小游戏,发现需要一下几步:1.需要一个棋盘 2.棋盘里面有提前布置好的雷 3.玩家走一步后,会显示出来周围一圈雷的个数 4.如果周围没有雷,将进行展开,直到有雷的地方停下,显示雷的个数 5.将雷排完,游戏结束。

为了书写方便这里使用3个文件,头文件:game.h  测试文件:test.c  游戏文件:game.c


 

二、具体步骤

1.在main()函数中调用test()函数

代码如下:

int main()
{

test();

return 0;
}

2.test()函数的实现

在test()函数中要实现 1.打印菜单 2.使用do...while循环使游戏不会停下来  3.调用游戏函数 

 游戏要进行至少一次,使用do....while循环刚刚好,然后Switch..case 语句进行选择,选择1.开始游戏,0.退出游戏  其他情况用 default 来解决

menu()函数来实现菜单的打印

srand((unsigned  int)time(NULL))随机数生成器,为下面的放置雷做准备

menu()函数:

test()函数:

 代码如下:

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");
			break;
				
		}
	} while (input);
}

 3.game()函数

在game()中来实现游戏的核心部分。 

1.创建两个数组 

1.创建两个数组,一个将雷的信息展示给玩家,另一个放置雷,但是需要注意的是两个数组的行和列并不相等,例如:我们将10颗雷,放在9*9的棋盘里面,因为检测周围雷的信息的时候是所下坐标周围的一圈,那么如果在棋盘边缘就不好检测,所以我们存放雷的信息的数组中需要在原来的基础上加上一圈,也就是11*11的一个数组,这样无论下到哪里所检测的都是周围一圈的信息。

为了方便更改,在头文件game.h中进行定义

#define ROW 3//mina数组的行
#define COL 3//mina数组的列
#define ROWS ROW+2//show数组的行
#define COLS COL+2//show数组的列

代码如下:

//创建两个数组
    char mina[ROWS][COLS] = { 0 };
    char show[ROWS][COLS] = { 0 };

2.对两个数组进行初始化

 初始化数组时,show数组是展示给玩家的,初始化成“*”,mina数组是我们放置雷所用的初始化成“0”,因为要将两个数组都初始化,初始化的内容不一样,但只要将“*”“0”,放到字符str中就完美解决了!

//将mina初始化为‘0’,将show初始化为‘*’
    Initializ(mina, ROWS, COLS, '0');
    Initializ(show, ROWS, COLS, '*');

//对两个数组进行初始化
void Initializ(char board[ROWS][COLS], int rows, int cols, char str)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < rows; i++)

    {
        for (j = 0; j < cols; j++)
        {
            board[i][j] = str;
        }
    }
}


3.打印数组 

为了方便进行扫雷,打印出行号列号和分割行

效果图:

//打印棋盘
void Disprint(char board[ROWS][COLS], int row, int col)
{
    int i = 0;
    int j = 0;
    int c = 0;
    
    for (j = 1; j <= col; j++)//打印列号
    {
        printf("  %d ", j);
    }
    printf("\n");//换行
    for (c = 1; c <= col; c++)//打印上面的横杠
    {
        if (c == 1)
        {
            printf(" ");
        }
        printf("--- ");
    }
    printf("\n");//换行
    
    for (i = 1; i <= row; i++)//打印每行的内容
    {
        printf("%d", i);//打印行号
        for (j = 1; j <= col; j++)//打印每列的内容
        {
            printf(" %c", board[i][j]);
            printf(" |");//打印每个字符之间的分隔竖杠
        }
        printf("\n");//换行
        int s = 0;
        printf(" ");
        for (s = 1; s <= row; s++)//打印分割行
        {
            printf("---|");
        }
        printf("\n");//换行
    }
    printf("\n");//打印每一行之后换行
}
 

4.在mina数组中放置雷 

我们要将雷随机的放到面数组中,这里也就用到了随机数生成器,用‘1’来表示雷,生成随机的坐标,然后判断这里是否是‘0‘,如果是就将雷放进去 

//放置雷
void Place_mine(char mina[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int count = MINE;
    while (count)
    {
        x = rand() % ROW + 1;
        y = rand() % COL + 1;
        if (mina[x][y] == '0')
        {
            mina[x][y] = '1';
            count--;
        }
    }
} 

5.排雷并显示周围雷的信息 (递归展开)

将雷布置好以后,下面就该进行排雷

输入一个合法的坐标后,进行判断,如果是雷那么结束游戏。如果不是雷那么判断此坐标周围 有没有雷,如果没有进行展开,直到周围有雷停止,然后显示雷的信息,并进行判断是否将雷排完了,如果此坐标周围有雷就进行显示,不展开。

周围雷的数量:

根据输入的坐标 x y,可以找到周围的8个坐标:[x][ y-1] ,[x][y+1]  ,[x-1][y],[x+1][y],[x-1][y-1],[x-1][y+1],[x+1][y-1],[x+1][y+1].

将8个坐标加在一起得出来的数字,就是雷的数量,但要注意的是棋盘中的1和0是字符,根据ASCII码表可知字符数字减去字符0,就得到数字。那么可以求出周围的雷

代码如下: 

//周围雷的数量
int Mine_amount(char mina[ROWS][COLS], int x, int y)
{
	return mina[x][y - 1] + mina[x][y + 1] + mina[x + 1][y - 1] + mina[x + 1][y + 1] +
		mina[x - 1][y] + mina[x + 1][y] + mina[x - 1][y - 1] + mina[x - 1][y + 1] -
		8 * '0';
}

根据这8个坐标,再找到周围的坐标来排查,如果还没有就继续,如果有就显示雷的信息并停止

坐标周围有没有雷,进行展开

代码如下:

//如果坐标周围没有雷就进行展开
open_map(char mina[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	if (x >= 1 && x <= ROW&&y >= 1 && y <= COL)
	{
		int ret = Mine_amount(mina, x, y);//周围雷的数量
		if (ret == 0)
		{
			show[x][y] = ' ';
			if (show[x - 1][y] == '*'&&x - 1 > 0 && x - 1 < ROWS&&y > 0 && y < COLS)
				open_map(mina, show, x - 1, y);
			if (show[x - 1][y - 1] == '*'&&x - 1 > 0 && x - 1 < ROWS&&y - 1 > 0 && y - 1 < COLS)
				open_map(mina, show, x - 1, y - 1);
			if (show[x - 1][y + 1] == '*'&&x - 1 > 0 && x - 1 < ROWS&&y + 1 > 0 && y + 1 < COLS)
				open_map(mina, show, x - 1, y + 1);
			if (show[x][y - 1] == '*'&&x > 0 && x < ROWS&&y - 1 > 0 && y - 1 < COLS)
				open_map(mina, show, x, y - 1);
			if (show[x][y + 1] == '*'&&x > 0 && x < ROWS&&y + 1 > 0 && y + 1 < COLS)
				open_map(mina, show, x, y + 1);
			if (show[x + 1][y] == '*'&&x + 1 > 0 && x + 1 < ROWS&&y > 0 && y < COLS)
				open_map(mina, show, x + 1, y);
			if (show[x + 1][y - 1] == '*'&&x + 1 > 0 && x + 1 < ROWS&&y - 1 > 0 && y - 1 < COLS)
				open_map(mina, show, x + 1, y - 1);
			if (show[x + 1][y + 1] == '*'&&x + 1 > 0 && x + 1 < ROWS&&y + 1 > 0 && y + 1 < COLS)
				open_map(mina, show, x + 1, y + 1);
		}
		else
		{
			show[x][y] = ret + '0';
		}
	}
}

6.判断是否将雷排完 

每下一次坐标,都进行一次判断,判断show数组中“*”的个数是否和雷数相等 ,相等就结束游戏,不相等就继续,使用循环来检测每一个坐标


//判断是否将雷排完
int iswin(char show[ROWS][COLS], int row, int col)
{
	int count = 0;
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] == '*')
			{
				count++;
			}
		}
	}
	return count;
}

 

三.游戏效果和代码 

1.游戏效果: 

 

2.游戏代码 

1.game.h头文件

#define ROW 9//mina数组的行
#define COL 9//mina数组的列
#define ROWS ROW+2//show数组的行
#define COLS COL+2//show数组的列
#define MINE 10//地雷的个数
//头文件
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

//初始化mina ,show函数
void Initializ(char board[ROWS][COLS], int rows, int cols, char str);
//打印两个数组
void Disprint(char board[ROWS][COLS], int row, int col);
//放置雷
void Place_mine(char mina[ROWS][COLS], int row, int col);
//排雷并显示雷的信息
void Message_mine(char mina[ROWS][COLS], char show[ROWS][COLS], int row, int col);

2.test.c 文件

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"//引用头文件
void menu()//菜单
{
	printf("|-----------------------------------------|\n");
	printf("|-------1.开始游戏------0.退出游戏--------|\n");
	printf("|-----------------------------------------|\n");

}

void game()//游戏函数
{//创建两个数组
	char mina[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
//将mina初始化为‘0’,将show初始化为‘*’
	Initializ(mina, ROWS, COLS, '0');
	Initializ(show, ROWS, COLS, '*');
	//打印出数组和行号
	//Disprint(mina, ROW, COL);
	Disprint(show, ROW, COL);
	//在mina中放置雷
	Place_mine(mina, ROW, COL);
	//Disprint(mina, ROW, COL);
	//排雷并显示雷的信息
	Message_mine(mina, 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");
			break;
				
		}
	} while (input);
}
int main()
{
	test();//函数
	return 0;
}

 3.game.c文件

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"
//对两个数组进行初始化
void Initializ(char board[ROWS][COLS], int rows, int cols, char str)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)

	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = str;
		}
	}
}
//打印棋盘
void Disprint(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int c = 0;
	
	for (j = 1; j <= col; j++)//打印列号
	{
		printf("  %d ", j);
	}
	printf("\n");//换行
	for (c = 1; c <= col; c++)//打印上面的横杠
	{
		if (c == 1)
		{
			printf(" ");
		}
		printf("--- ");
	}
	printf("\n");//换行
	
	for (i = 1; i <= row; i++)//打印每行的内容
	{
		printf("%d", i);//打印行号
		for (j = 1; j <= col; j++)//打印每列的内容
		{
			printf(" %c", board[i][j]);
			printf(" |");//打印每个字符之间的分隔竖杠
		}
		printf("\n");//换行
		int s = 0;
		printf(" ");
		for (s = 1; s <= row; s++)//打印分割行
		{
			printf("---|");
		}
		printf("\n");//换行
	}
	printf("\n");//打印每一行之后换行
}
//放置雷
void Place_mine(char mina[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = MINE;
	while (count)
	{
		x = rand() % ROW + 1;
		y = rand() % COL + 1;
		if (mina[x][y] == '0')
		{
			mina[x][y] = '1';
			count--;
		}
	}
}
//周围雷的数量
int Mine_amount(char mina[ROWS][COLS], int x, int y)
{
	return mina[x][y - 1] + mina[x][y + 1] + mina[x + 1][y - 1] + mina[x + 1][y + 1] +
		mina[x - 1][y] + mina[x + 1][y] + mina[x - 1][y - 1] + mina[x - 1][y + 1] -
		8 * '0';
}

//判断是否将雷排完
int iswin(char show[ROWS][COLS], int row, int col)
{
	int count = 0;
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] == '*')
			{
				count++;
			}
		}
	}
	return count;
}

//如果坐标周围没有雷就进行展开
open_map(char mina[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	if (x >= 1 && x <= ROW&&y >= 1 && y <= COL)
	{
		int ret = Mine_amount(mina, x, y);//周围雷的数量
		if (ret == 0)
		{
			show[x][y] = ' ';
			if (show[x - 1][y] == '*'&&x - 1 > 0 && x - 1 < ROWS&&y > 0 && y < COLS)
				open_map(mina, show, x - 1, y);
			if (show[x - 1][y - 1] == '*'&&x - 1 > 0 && x - 1 < ROWS&&y - 1 > 0 && y - 1 < COLS)
				open_map(mina, show, x - 1, y - 1);
			if (show[x - 1][y + 1] == '*'&&x - 1 > 0 && x - 1 < ROWS&&y + 1 > 0 && y + 1 < COLS)
				open_map(mina, show, x - 1, y + 1);
			if (show[x][y - 1] == '*'&&x > 0 && x < ROWS&&y - 1 > 0 && y - 1 < COLS)
				open_map(mina, show, x, y - 1);
			if (show[x][y + 1] == '*'&&x > 0 && x < ROWS&&y + 1 > 0 && y + 1 < COLS)
				open_map(mina, show, x, y + 1);
			if (show[x + 1][y] == '*'&&x + 1 > 0 && x + 1 < ROWS&&y > 0 && y < COLS)
				open_map(mina, show, x + 1, y);
			if (show[x + 1][y - 1] == '*'&&x + 1 > 0 && x + 1 < ROWS&&y - 1 > 0 && y - 1 < COLS)
				open_map(mina, show, x + 1, y - 1);
			if (show[x + 1][y + 1] == '*'&&x + 1 > 0 && x + 1 < ROWS&&y + 1 > 0 && y + 1 < COLS)
				open_map(mina, show, x + 1, y + 1);
		}
		else
		{
			show[x][y] = ret + '0';
		}
	}
}
//排雷并显示雷的信息
void Message_mine(char mina[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int len = 0;
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入坐标:\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= ROW&&y >= 1 && y <= COL&&show[x][y] == '*')
		{
			if (mina[x][y] == '1')
			{
				printf("很遗憾!你踩到雷了!!\n");
				Disprint(mina, ROW, COL);
				break;
			}
			else
			{				
					open_map(mina, show, x, y);//如果坐标周围没有雷就进行展开
					len = iswin(show, ROW, COL);//判断是否将雷排完
					Disprint(show, ROW, COL);
					if (len == MINE)
					{
						printf("恭喜你!排雷成功!!\n");
						Disprint(mina, ROW, COL);
						break;
					}							
			}
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	}			
}

总结

 以上就是本篇 <扫雷>所有内容,需要知道扫雷游戏的原理和结构思路,然后再分成一个个小步实现功能,最后整合在一起并做一些修改和完善来实现游戏的功能。注:游戏代码可以在vs编译器上完美运行!


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

'...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值