【C语言】实现扫雷小游戏(附源码)

前言


实现扫雷小游戏,我们应该先来了解它的游戏规则,再来理解它的实现逻辑。

游戏规则

  • 我们随便找到一个棋盘上的坐标,打开该坐标的格子可能是数字,可能是地雷,也可能是空白。
  • 如果我们打开的是地雷的话,那我们就输了
  • 如果我们打开的是数字,则代表周围会有雷,数字几则代表以该坐标为中心周围的八个坐标内有几个雷
  • 而如果是空白的话,那么就会往周围炸开一片,直至遇到是数字的坐标则不继续炸开

如图:
在这里插入图片描述

实现逻辑

  • 我们要先建立一个菜单,来实现玩家与电脑之间的交互
  • 我们需要有两个棋盘,其中一个棋盘用来实现玩家与电脑之间的交互,另外一个用来埋雷
  • 输入一个坐标,随后该坐标对应的点展开,展开的可能是数字,可能是地雷,也可能是空白。
  • 如果是空白的话,需要用递归的思想来进行展开一片连续的空白。
  • 同时,我们要有一个用来计数的变量,这个变量用来判断我们是否将雷全部排完。

1. 实现步骤


由于涉及到的函数较多,所以我们可以用一个头文件(game.h),两个源文件(分别是main函数的运行(test.c) 和 我们要实现的游戏逻辑函数(game.c) )来完成这些操作。

1.1 源文件(test.c)

#include "game.h"

void meun()
{
	printf("**************************\n");
	printf("*****     1.play     *****\n");
	printf("*****     0.exit     *****\n");
	printf("**************************\n");
}

void game()
{
	char show[ROW][COL] = { 0 };
	char mine[ROW][COL] = { 0 };
	//初始化棋盘
	Init_chessboard(show, ROW, COL, '*');
	Init_chessboard(mine, ROW, COL, '0');
	//打印棋盘
	Print_chessboard(show, ROW, COL);
	Print_chessboard(mine, ROW, COL);
	//埋雷
	Lay_mines(mine, ROW, COL);
	Print_chessboard(mine, ROW, COL);
	
	//玩家操作
	Player_move(show, mine, ROW, COL);
}

int main()
{
	//生成随机数种子,在main函数中使用一次以后,
	//后面使用到rand函数就会随机生成数值
	srand((unsigned int)time(NULL));
	int input = 0;
	//我们do...while语句可以方便我们能自主控制开始/退出游戏
	do
	{
		meun();//打印菜单,以方便人机互动
		scanf("%d", &input);
		switch (input)
		{
		case 1:game();该函数则是我们要实现的一个函数
		break;
		case 0:printf("退出游戏\n");break;
		default:printf("输入有误,请重新输入\n");break;
		}
	} while (input);
	return 0;
}

1.2 头文件(game.h)的准备

那么在头文件(game.h)中我们应该做哪些准备呢:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//定义棋盘的横纵坐标数量
#define ROWS 9
#define COLS 9

//棋盘的横纵坐标数量是用来方便玩家操作的,
//而我们应该在此基础上多增加两格,
//目的是为了操作数组的时候防止越界
#define ROW (ROWS + 2) 
#define COL (COLS + 2)


#define NUM 10//雷的个数

//我们可以调节雷的个数和横纵坐标的大小来设计游戏的难度

//初始化棋盘
void Init_chessboard(char chessboard[ROW][COL],int row,int col,char ch);
//打印棋盘
void Print_chessboard(char chessboard[ROW][COL], int row, int col);
//埋雷
void Lay_mines(char chessboard[ROW][COL], int row, int col);

//玩家操作
void Player_move(char show[ROW][COL], char mine[ROW][COL], int row, int col);
//周围雷的个数
int around_mines(char mine[ROW][COL], int x, int y);

//实现扫雷中炸开一片的效果
void view_clear(char show[ROW][COL], char mine[ROW][COL], int x, int y);

我们在头文件game.h中同时也包含了一些头文件,而我们包含在头文件中的目的是为了方便能让两个源文件同时能够用到我们定义的头文件(game.h)中的内容。

而后面的函数,则是我们需要实现的一些游戏逻辑函数,在头文件里面声明一下,在game.c中来实现这些函数。

1.3 game.c的实现

#include "game.h"
//定义一个全局变量,每展开一个坐标就减一,
//直到该变量等于雷的个数
int count_mine = ROWS * COLS;

//初始化棋盘
void Init_chessboard(char chessboard[ROW][COL], int row, int col, char ch)
{
	int i = 0;
	for (i = 0;i < row;i++)
	{
		int j = 0;
		for (j = 0;j < col;j++)
		{
			chessboard[i][j] = ch;
		}
	}
}
//打印棋盘
void Print_chessboard(char chessboard[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0;i < row - 1;i++)
	{
		if (i == 0)
		{
			printf(" | ");
		}
		else
			printf("%d ", i);
	}
	printf("\n");
	for (i = 0;i < row - 1;i++)
	{
		printf("--");
	}
	printf("\n");
	for (i = 1;i < row - 1;i++)
	{
		int j = 0;
		for (j = 0;j < col - 1;j++)
		{
			if (j == 0)
			{
				printf("%d| ", i);
			}
			else
				printf("%c ", chessboard[i][j]);
		}
		printf("\n");
	}
	printf("\n");

}
//埋雷
void Lay_mines(char chessboard[ROW][COL], int row, int col)
{
	int count = NUM;
	while (count)
	{
		int x = rand() % ROWS + 1;//结果是 1 - 9
		int y = rand() % COLS + 1;//结果是 1 - 9
		if (chessboard[x][y] == '0') //确保能埋满我们需要埋的雷的个数
		{
			chessboard[x][y] = '1';
			count--;
		}
	}
}

//玩家操作
void Player_move(char show[ROW][COL], char mine[ROW][COL], int row, int col)
{
	while (1)
	{
		int x = 0, y = 0;
		printf("请输入坐标:\n");

		scanf("%d %d", &x, &y);
		if ((x >= 1 && x <= row - 1) && (y >= 1 && y <= col - 1))
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你已被炸死\n");
					Print_chessboard(mine, row, col);
					//失败以后重置这个用来计数的变量,保证游戏胜利以后还能继续玩
					count_mine = ROWS * COLS;
					break;
				}
				else
				{
					view_clear(show, mine, x, y);
					Print_chessboard(show, row, col);
					//Print_chessboard(mine, row, col);//该代码是用于测试时判断雷所在位置
					if (count_mine == NUM)
					{
						printf("恭喜你,以将所有雷排除\n");
						//胜利以后重置这个用来计数的变量,保证游戏胜利以后还能继续玩
						count_mine = ROWS * COLS;
						break;
					}
				}
			}
			else
			{
				printf("该坐标已被使用,请重新输入\n");
			}
		}
		else
		{
			printf("输入的坐标有误,请重新输入\n");
		}
	}
}

//周围雷的个数
int around_mines(char mine[ROW][COL], int x, int y)
{
	//前面埋雷函数中,我们让字符'1'为雷,
	//到这里我们就可以以x,y为中心去判断周围八个坐标有几个雷
	char ret = (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y - 1] +
		mine[x][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0');
	return ret;//返回的就是雷的个数
}

//实现扫雷中炸开一片的效果
void view_clear(char show[ROW][COL], char mine[ROW][COL], int x, int y)
{
	if ((x >= 1 && x < ROW - 1) && (y >= 1 && y < COL - 1))
	{
		if (around_mines(mine, x, y) == '0')
		{
			count_mine--;
			show[x][y] = ' ';
			int i = 0, j = 0;
			for (i = x - 1;i <= x + 1;i++)
			{
				for (j = y - 1;j <= y + 1;j++)
				{
					if (show[i][j] == '*')
						view_clear(show, mine, i, j);
				}
			}
		}
		else
		{
			count_mine--;
			show[x][y] = around_mines(mine, x, y);
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hyt的笔记本

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

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

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

打赏作者

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

抵扣说明:

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

余额充值