扫雷游戏(C语言)

目录

游戏介绍

游戏整体框架

游戏具体功能及实现

棋盘的定义

棋盘的初始化

布置雷

排查雷

获取周围雷的个数

打印棋盘

游戏完整代码


游戏介绍

扫雷游戏规则就是:玩家选择一个方格,若此方格没有地雷,那么该方格显示与它相邻的八个方格中雷的个数,若此方格有雷,则游戏失败,当玩家把除了有雷的方格外的其他方格都成功翻开时游戏胜利!

游戏整体框架

我们还是利用多文件进行编程,养成良好习惯,为以后公司团队合作编程打下基础,因此该游戏分成了三个文件来编写:

test.c:游戏逻辑的测试,包含游戏菜单的打印,游戏设计的基本逻辑的展示

game.c:游戏功能的具体实现,这部分是整个游戏的核心代码,一般不会展示给用户

game.h:相关头文件的包含,符号的声明以及函数的声明

游戏具体功能及实现

棋盘的定义

对于扫雷游戏,我们遇到的第一个问题就是:如何表示扫雷的棋盘及如何存放布雷、排雷的数据,我们发现,二维数组可以很好地解决这个问题

//完成扫雷游戏
char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'
char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10

如上,我们定义了两个棋盘,分别用来保存布雷和排雷的信息,避免二者相互干扰或者相互覆盖;同时,我们可以使用宏来定义棋盘的大小以及雷的个数,这样做的好处是当我们以后想使用更大的棋盘或者想增加扫雷的难度的时候,我们只需要改动这里即可,增加了代码的可维护性

这里定义两个不同的ROW和COL,其实是为后面的排雷做铺垫:

如图,当我们排查1位置时,如果1处不是雷,那么将依次检查周围8个坐标是否有地雷,如果有,就会把雷的数量显示在1位置处;但是,当我们排查2位置时,会发现,数组排雷时发生了越界,所以为了避免数组越界,在定义数组时我们直接在上下左右四个方向各多给一行的空间,并把这些空间中的数据初始化为非雷,这样就解决了数组越界的问题

棋盘的初始化

把mine数组元素全部初始化为字符0,把show数组元素全部初始化为字符*

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

//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
布置雷

有两个需要注意的地方:

1.用于随机生成坐标的rand函数的种子srand函数只需要在main函数中声明一次即可

2.在布置雷的时候需要检查该位置是否已经有雷,避免重复布置

void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1;//1~9
		int y = rand() % col + 1;//1~9
		if (arr[x][y] == '0')//检查该位置是否有雷
		{
			arr[x][y] = '1';
			count--;
		}
	}
}
排查雷

排查雷的时候我们首先需要让用户输入要排查的坐标,然后判断坐标的合法性以及该坐标是否已经被排查,然后判断该坐标是否有雷,如果没有,就检查周围的坐标,直到全部检查出即可

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//11*11的棋盘
{
	int x, y, win = 0;//用来标记是否取得胜利
	
	while (win<row*col-EASY_COUNT)
	{
		printf("请输入要排查的坐标(例,6 5):");
		scanf("%d %d", &x, &y);
		//判断坐标的有效性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死\n");
					DisplayBoard(mine, ROW, COL);
					break;
				}
				else
				{
					//该坐标不是雷,就得统计坐标周围有几个雷
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该坐标已被排查,请重新输入:");
			}
		}
		else
		{
			printf("请重新输入:");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功!\n");
		DisplayBoard(mine, ROW, COL);
	}
}
获取周围雷的个数
static int GetMineCount(char mine[ROWS][COLS], int x, int y)//只能在这个文件中使用-static
{
	int i = 0, j = 0, count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)
		{
			count += mine[i][j] - '0';
		}
	}
	return count;
}
打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0, j = 0;
	printf("------扫雷游戏------");
	printf("\n");
	for (i = 0; i <= col; i++)//打印列号
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

游戏完整代码

test.c

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "game.h"
void menu()
{
	printf("在该游戏中,排查出埋着的10个雷即可获得成功!\n");
	printf("**************\n");
	printf("****1.play ***\n");
	printf("****0.exit ***\n");
	printf("**************\n");
}
void game()
{
	//完成扫雷游戏
	char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'
	char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	
	//布置雷
	SetMine(mine, ROW, COL);
	//打印棋盘
	//DisplayBoard(mine, ROW, COL);
	DisplayBoard(show, ROW, COL);
	//排查雷
	FindMine(mine, show, ROW, COL);
}
void test()
{
	int input;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("游戏开始\n");
			game();//输入1开始游戏
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("请重新选择:");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0, j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			arr[i][j] = set;
		}
	}
}
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0, j = 0;
	printf("------扫雷游戏------");
	printf("\n");
	for (i = 0; i <= col; i++)//打印列号
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}
void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1;//1~9
		int y = rand() % col + 1;//1~9
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}
//static int GetMineCount(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';
//}
//另一种写法:
static int GetMineCount(char mine[ROWS][COLS], int x, int y)//只能在这个文件中使用-static
{
	int i = 0, j = 0, count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)
		{
			count += mine[i][j] - '0';
		}
	}
	return count;
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//11*11的棋盘
{
	int x, y, win = 0;//用来标记是否取得胜利
	
	while (win<row*col-EASY_COUNT)
	{
		printf("请输入要排查的坐标(例,6 5):");
		scanf("%d %d", &x, &y);
		//判断坐标的有效性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死\n");
					DisplayBoard(mine, ROW, COL);
					break;
				}
				else
				{
					//该坐标不是雷,就得统计坐标周围有几个雷
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该坐标已被排查,请重新输入:");
			}
		}
		else
		{
			printf("请重新输入:");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功!\n");
		DisplayBoard(mine, ROW, COL);
	}
}

game.h

#define _CRT_SECURE_NO_WARNINGS
#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 arr[ROWS][COLS], int rows, int cols, char set);

//布置雷的信息
void SetMine(char arr[ROWS][COLS], int row, int col);
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col);

扫雷游戏

由于技术有限,暂且编写一个基础版,带我完善之后,将终极版发布出来,敬请期待...

相关推荐
DARLING Zero two♡3 小时前
关于我、重生到500年前凭借C语言改变世界科技vlog.16——万字详解指针概念及技巧
c语言·开发语言·科技
QAQ小菜鸟4 小时前
一、初识C语言(1)
c语言
何曾参静谧4 小时前
「C/C++」C/C++ 之 变量作用域详解
c语言·开发语言·c++
互联网打工人no14 小时前
每日一题——第一百二十一题
c语言
朱一头zcy5 小时前
C语言复习第9章 字符串/字符/内存函数
c语言
此生只爱蛋5 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
何曾参静谧6 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
lulu_gh_yu7 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
~yY…s<#>8 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
EricWang135810 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端