Bootstrap

实现经典小游戏《扫雷》

扫雷是一款锻炼逻辑思维和策略规划能力的经典游戏,今天咱们就自己动手,用代码给自己写一个简易的扫雷游戏~

一.概述

咱们主要还是用C来实现。首先先分析扫雷的组成结构和游戏玩法:它是由一个正方形棋盘构成,棋盘里随机产生一定数量的雷,需要咱们根据游戏提供的参考信息将所有没有雷的位置排查出来。

然后咱们就可以根据游戏需求,一步一步用代码的形式将游戏功能实现。那咱们就开始吧@

二.游戏代码的布局

咱们先创建一个项目,在项目中建立两个C文件,一个用来放置游戏功能的主要代码,另一个则用来测试游戏功能。再自定义一个头文件 "game.h",把需要使用的库函数、自定义函数声明以及一些宏定义放在里面,这样方便咱们检查和调整代码,也让咱们的代码风格更加规范有序。

就像这样子~

咱们可以先把需要用到的函数先在自定义里声明出来,然后再一个一个实现,这样就能让咱们思路更加清晰。就像这样~(但如果小伙伴们刚开始想不到这么多,也可以先写,然后再放置)

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

//实现游戏功能区
#define ROW 9 
#define COL 9

//整个棋盘
#define ROWS ROW+2
#define COLS COL+2

//自定义雷的数量
#define MINE_COUNT 10

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);

//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col);

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

三.游戏的实现

这里咱们先把游戏拆分成几个部分,然后选用独立的函数分别实现,这样方便咱测试和调整功能。

首先得把棋盘制作出来。考虑到咱们游戏的简易,咱们可以使用两个棋盘,一个用来排雷,一个用来显示咱们已经排好雷的信息(当然,如果想加大游戏难度,咱们后续也可以调整,只显示一个棋盘)

因为要用坐标来定位棋盘信息,所以咱们采用二维数组来实现。咱们在游戏测试C文件中定义一个game() 函数,在里面调用所有与游戏功能相关的函数来实现整个游戏功能。

void game()
{
	//1. 需要存放布置好的雷的信息,存放排查出的雷的信息,我们需要2个二维数组
	//2. 排查边缘坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
	char mine[ROWS][COLS] = { 0 };//布置好的雷的信息
	char show[ROWS][COLS] = { 0 };//排查出的雷的信息
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0'); //后续以 '1' 为雷。先以'0'初始化
	InitBoard(show, ROWS, COLS, '*'); //用 '*'来掩盖展现的棋盘

	//打印棋盘
	DisplayBoard(show, ROW, COL);

	//布置雷
	SetMine(mine, ROW, COL);
	DisplayBoard(mine, ROW, COL);
	//排查雷
	FindMine(mine, show, ROW, COL);
}

这里咱们利用分支和循环语句来实现棋盘的打印,然后呢,使用时间戳来生成随机数,通过取模再加 1 的方法产生 0~9 的值,生成随机坐标,并通过数组赋值的方式进行 “埋雷”。

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");
	}
	printf("------------扫雷-------------\n");
}

void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = MINE_COUNT; //雷的数量,在自定义头文件中定义
	while (count)
	{
		//生成随机坐标
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';//布置雷
			count--; //当其为0时,结束埋雷
		}

	}

}

游戏棋盘的实现~

用来显示随机放置的雷的棋盘(如果想要增加游戏难度,可以隐藏)

紧接着就是扫雷了。

游戏玩家通过输入坐标的方式来排查相应的位置,如果输入的坐标没有“埋雷”的话,就返回一个值,而这个值就是该坐标周围八个坐标里雷的个数。当玩家把所有雷都排查完之后,游戏结束,玩家成功完成游戏。

//输入坐标周围的八个位置雷的数量
int get_mine_count(char mine[ROW][COL], 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 - MINE_COUNT))
	{
		printf("请输入你要排查的坐标\n");
		scanf("%d %d", &x, &y);
		if (x > 0 && x <= row && y > 0 && y <= col)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已经排查过了,请重新输入\n");
				continue;
			}

			else if (mine[x][y] == '1')
			{
				printf("很遗憾,你踩到雷了\n");
				printf("还想要再来一局吗?\n");
				break;
			}
			else
			{

				int n = get_mine_count(mine, x, y);
				show[x][y] = n + '0';
				DisplayBoard(show, ROW, COL);
				win++;

			}
		}
		else
			printf("坐标不规范,请重新输入\n");
	}
	if (win == (row * col - MINE_COUNT))
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}

}

可能有些小伙伴会对这个用来排查输入坐标周围雷的数量的函数有些疑惑,没关系,解释完就懂了~。

因为咱们棋盘里没有雷的位置放置的是字符 '0',有雷的位置放置的是字符 '1' ,通过ASCII表咱们可以知道,字符'0'到 ' 8',中间每个字符的ASCII值都相差1,通过减去8个字符 ‘0’的方式确定 ‘ 1‘ 的个数,也就是雷的个数,又因为咱们返回值为整型,所以通过接收值加’0‘的方式,在输入的坐标位置就能使用字符型打印出其周围雷的个数。

最后呢,也剩一些比较简单的部分了。这个部分主要用来引导玩家游戏,以及是否进行游戏的功能的实现,直接看代码吧~

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;
}

四.码源以及游戏演示

//                                 自定义头文件


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

//实现游戏功能区
#define ROW 9 
#define COL 9

//整个棋盘
#define ROWS ROW+2
#define COLS COL+2

//自定义雷的数量
#define MINE_COUNT 10

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);

//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col);

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);






 //                             游戏功能




#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");
	}
	printf("------------扫雷-------------\n");
}

void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = MINE_COUNT; //雷的数量,在自定义头文件中定义
	while (count)
	{
		//生成随机坐标
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';//布置雷
			count--;
		}

	}

}
//输入坐标周围的八个位置雷的数量
int get_mine_count(char mine[ROW][COL], 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 - MINE_COUNT))
	{
		printf("请输入你要排查的坐标\n");
		scanf("%d %d", &x, &y);
		if (x > 0 && x <= row && y > 0 && y <= col)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已经排查过了,请重新输入\n");
				continue;
			}

			else if (mine[x][y] == '1')
			{
				printf("很遗憾,你踩到雷了\n");
				printf("还想要再来一局吗?\n");
				break;
			}
			else
			{

				int n = get_mine_count(mine, x, y);
				show[x][y] = n + '0';
				DisplayBoard(show, ROW, COL);
				win++;

			}
		}
		else
			printf("坐标不规范,请重新输入\n");
	}
	if (win == (row * col - MINE_COUNT))
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}

}








//                                  游戏测试及运行




#include "game.h"

void menu()
{

	printf("************ 扫雷游戏 ************\n");
	printf("**********************************\n");
	printf("***********  1 - play  ***********\n");
	printf("***********  0 - exit  ***********\n");
	printf("**********************************\n");
}


void game()
{
	//1. 需要存放布置好的雷的信息,存放排查出的雷的信息,我们需要2个二维数组
	//2. 排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
	char mine[ROWS][COLS] = { 0 };//布置好的雷的信息
	char show[ROWS][COLS] = { 0 };//排查出的雷的信息
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0'); //后续以 '1' 为雷。先以'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");
			break;
		}
	} while (input);

}



int main()
{
	test();

	return 0;
}



















游戏运行

五.总结

这个游戏的实现主要是用到了二维数组、分支和循环语句、以及函数等相关知识,基本还是比较容易上手的,所以小伙伴们可以大胆尝试着去写一下~

祝小伙伴们早日成为技术大牛@

;