扫雷游戏C语言基础版

1.扫雷游戏设计分析

1.1游戏功能说明

  • 使用控制台实现经典的扫雷游戏
  • 游戏棋盘为9X9
  • 默认随即布置十个雷
  • 可以通过每个方块对应的坐标排查雷

1.2游戏的设计分析

当我们在扫雷的过程中,布置的雷和排查出的不是雷的的方块的信息都要存储,我们首先想到的就是创建一个9*9的数组来存储信息。在这里插入图片描述

如果这个位置布置雷,我们就存放1,没有布置雷就存放0
在这里插入图片描述

假如我们查询坐标(2,2),我们需要访问周围八个格子,统计周围有一个雷
但是假如我们排查坐标(3,8),当我们访问周围八个格子时,最下面三个格子就会越界
在这里插入图片描述
为了防止越界我们可以把棋盘扩大一圈,变成11X11,但在布置雷和扫雷时只能在中间9X9的区域进行操作在这里插入图片描述
这样就解决了越界的问题,还能让每个格子对应坐标更准确。

我们继续分析,当我们在棋盘上布置了雷,雷的为1,非雷为0。假设我们排查了一个位置后,这个坐标周围有1个雷,那我需要将排查出雷的信息记录下来,并显示给玩家。那么这个信息应该存储在哪呢?如果我们存储在布置好雷的数组中,如果周围有一个雷,那么雷的信息和周围雷数量的信息就会产生混淆。
在这里插入图片描述
当然是有解决办法的啦:我们专门再创建一个棋盘(对应数组show),就用来存放排查出雷的信息,同时这个棋盘也展示给玩家。
而另一个棋盘(对应数组mine),就用来存放布置好雷的信息,这个棋盘不用来展示。

同时为了保持游戏性,show棋盘开始全部初始化为字符’*‘,为了保持数组类型一致,方便后续调用,我们将mine棋盘最开始也全部初始化为字符’0’,布置雷的地方为字符’1’
在这里插入图片描述

2.代码部分

2.1代码功能详细介绍

为了保持程序的高内聚低耦合,让当代码逻辑更清晰,我们这里可以设计三个文件:

test.c//文件中写游戏的测试逻辑
game.c//文件中写游戏中函数的实现等
game.h//文件中写游戏需要的数据类型的定义和函数声明等

2.1.1 game.h

首先从头game.h开始

#pragma once
//头文件包含,stdlib.h为随机数需要的文件,time.h为生成随机数时需要的种子的文件
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

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

//展示棋盘
void DisplayBoard(char board[11][11],int row,int col);

//布置雷
void SetMine(char board[11][11],int row,int col);

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

.

.

2.1.2 test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"
void menu()
{
	printf("--------------------\n");
	printf("********************\n");
	printf("****** 1. paly******\n");
	printf("****** 0. exit******\n");
	printf("********************\n");
	printf("--------------------\n");

}


int main()
{
	int input = 0;
	
	//生成随机数rand时需要的调用srand来设置种子,放在main函数中整个程序只需要调用一次
	srand((unsigned int)time(NULL));
	do
	{
		//打印菜单
		menu();
		printf("请选择>:\n" );
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			//输入1开始游戏
			game();
			break;
		case 0:
			//输入0退出游戏
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择>:\n");
			break;
		}
	} while (input);//当输入0时,意味着选择退出游戏,同时跳出循环

	return 0;
}

我们可以先运行一下测试代码逻辑:
在这里插入图片描述

输入1,进行游戏(这里game函数还没实现QAQ only test):
在这里插入图片描述

输入0,退出游戏:
在这里插入图片描述
.

.

test.c中game()函数

void game()
{
	char mine[11][11];//存放雷和非雷的信息
	char show[11][11];//存放排查出的信息
	
	//初始化棋盘:mine数组最开始全是'0',show数组最开始全是'*'
	//这里我们传递4个参:数组名、行、列和数组里最终初始化后的元素
	InitBoard(mine, 11, 11, '0');
	InitBoard(mine, 11, 11, '*');

	//初始化完毕后,我们就要展示我们的棋盘啦;
	DisplayBoard(show, 9, 9);//我们只展示中间9X9的区域
	
	//然后布置雷到mine数组
	SetMine(mine, 9, 9);

	//扫雷开始!(排查雷)
	FindMine(mine, show, 9, 9);
}

2.1.3 game.c

终于到了我们上面定义的函数的实现的部分了!接下来我们开始讲解这些函数是怎么实现的

- 初始化棋盘函数InitBoard:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void InitBoard(char board[11][11], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			//遍历每个元素,进行初始化,set接收这个棋盘里将要初始化的元素
			//当我们初始化show棋盘时,将'0'传到set里,则初始化mine棋盘时,将'*'传到set
			board[i][j] = set;
		}
	}
}

.

.

-展示棋盘函数DisplayBoard:

我们只需要打印出中间9X9的区域
当然我们也需要将行和列的下标给显示出来,方便后面扫雷

void DisplayBoard(char board[11][11], int row, int col)
{
	int i = 0;
	printf("-------------------\n");

	for (i = 0; i <= 9; i++)
	{
		//打印行下标
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= 9; i++)
	{
		printf("%d ", i);//打印列下标
		int j = 0;
		for (j = 1; j <= 9; j++)
		{
			//通过遍历打印出中间9x9的元素
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}
	printf("-------------------\n");
}		

测试运行:
在这里插入图片描述

-布置雷函数SetMine:
void SetMine(char board[11][11], int row, int col)
{
	//同样的,我们也只能在中间9X9的区域布置雷
	//布置十个雷
	int count = 10;
	while (count)
	{
		//使用rand函数生成随机数(x为行,y为列)
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		//当确保这个坐标没有雷(里面存的是'0')时,布置雷(改为'1')
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;//每布置完一个count--
		}
	}

}

这里我们可以查看一下布置完雷之后的棋盘:
在这里插入图片描述

.

.

-排查雷函数FindMine:
void FindMine(char mine[11][11], char show[11][11], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	//结束游戏的条件就是:每次成功排雷之后win就++当win的值等于整个棋盘减去雷的数量的值,扫雷成功
	while (win<9*9-10)
	{
		printf("请输入要排查的坐标>:");
		scanf("%d %d", &y, &x);
		//判断输入的坐标是否为合法输入
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			//当输入的坐标对应的mine数组里存的是'1' 说明踩到雷了,游戏结束
			if (mine[x][y] == '1')
			{
				printf("很遗憾,游戏失败QAQ\n");
				break;
			}
			else
			{
				//当输入的坐标正确且没有踩到雷,我们就要排查这个坐标周围有几个雷,并且将周围雷的数量存在show数组中
				//这里我们单独写一个函数来排查周围雷的数量,并返回到count中
				int count = GetMine_count(mine, x, y);

				//因为最终返回的是数字,我们要将其变为字符才能将其存到show数组中,且表达的数量不能变化
				//这时我们就可以让其加上一个字符'0'。例如数字1加上一个字符'0'后变为字符'1'
				show[x][y] = count + '0';
				DisplayBoard(show, 9, 9);
				win++;
			}
		}
		else
		{
			printf("请输入正确坐标>:\n");
		}
	}
	if (win == 9 * 9 - 10)
	{
		printf("恭喜你!排雷成功\n");
	}
}
-排查周围雷数量的函数GetMine_count(嵌套在FindMine函数中):

在这里插入图片描述
如图所示当我们排查坐标(x,y)周围雷的数量时,因为这个是mine数组,此时里面存放的是字符’0’或’1’,又因为字符’0’减去数字0得到数字0,字符’01’减去数字1得到数字1(根据ACSII码表)。
所以我们将周围八个元素全部相加,最后再减去八个字符’0’,就得到周围雷的数量啦

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

2.2 游戏界面

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

2.3 代码全貌

game.h

#pragma once
//头文件包含,stdlib.h为随机数函数rand需要的文件,time.h为生成随机数时需要的种子的文件
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

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

//展示棋盘
void DisplayBoard(char board[11][11], int row, int col);

//布置雷
void SetMine(char board[11][11], int row, int col);

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

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"
void menu()
{
	printf("--------------------\n");
	printf("********************\n");
	printf("****** 1. paly******\n");
	printf("****** 0. exit******\n");
	printf("********************\n");
	printf("--------------------\n");

}

void game()
{
	char mine[11][11];//存放雷和非雷的信息
	char show[11][11];//存放排查出的信息
	
	//初始化棋盘:mine数组最开始全是'0',show数组最开始全是'*'
	//这里我们传递4个参:数组名、行、列和数组里最终初始化后的元素
	InitBoard(mine, 11, 11, '0');
	InitBoard(show, 11, 11, '*');

	//初始化完毕后,我们就要展示我们的棋盘啦;
	DisplayBoard(show, 9, 9);//我们只展示中间9X9的区域
	
	//然后布置雷到mine数组
	SetMine(mine, 9, 9);
	//DisplayBoard(mine, 9, 9);
	//扫雷开始!(排查雷)
	FindMine(mine, show, 9, 9);
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		//打印菜单
		menu();
		printf("请选择>:\n" );
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			//输入1开始游戏
			printf("开始游戏!\n");
			game();
			break;
		case 0:
			//输入0退出游戏
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择>:\n");
			break;
		}
	} while (input);//当输入0时,意味着选择退出游戏,同时跳出循环

	return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void InitBoard(char board[11][11], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			//遍历每个元素,进行初始化,set接收这个棋盘里将要初始化的元素
			board[i][j] = set;
		}
	}
}
void DisplayBoard(char board[11][11], int row, int col)
{
	int i = 0;
	printf("-------------------\n");
	for (i = 0; i <= 9; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= 9; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= 9; j++)
		{
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}
	printf("-------------------\n");
}		
void SetMine(char board[11][11], int row, int col)
{
	//同样的,我们也只能在中间9X9的区域布置雷
	//布置十个雷
	int count = 10;
	while (count)
	{
		//使用rand函数生成随机数(x为行,y为列)
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		//当确保这个坐标没有雷(里面存的是'0')时,布置雷(改为'1')
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;//每布置完一个count--
		}
	}

}
int GetMine_count(char mine[11][11], int x, int y)
{
	return	mine[x - 1][y - 1] +
			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] - 8 * '0';
}
void FindMine(char mine[11][11], char show[11][11], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	//结束游戏的条件就是:每次成功排雷之后win就++当win的值等于整个棋盘减去雷的数量的值,扫雷成功
	while (win<9*9-10)
	{
		printf("请输入要排查的坐标>:");
		scanf("%d %d", &y, &x);
		//判断输入的坐标是否为合法输入
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			//当输入的坐标对应的mine数组里存的是'1' 说明踩到雷了,游戏结束
			if (mine[x][y] == '1')
			{
				printf("很遗憾,游戏失败QAQ\n");
				break;
			}
			else
			{
				//当输入的坐标正确且没有踩到雷,我们就要排查这个坐标周围有几个雷,并且将周围雷的数量存在show数组中
				//这里我们单独写一个函数来排查周围雷的数量,并返回到count中
				int count = GetMine_count(mine, x, y);

				//因为最终返回的是数字,我们要将其变为字符才能将其存到show数组中,且表达的数量不能变化
				//这时我们就可以让其加上一个字符'0'。例如数字1加上一个字符'0'后变为字符'1'
				show[x][y] = count + '0';
				DisplayBoard(show, 9, 9);
				win++;
			}
		}
		else
		{
			printf("请输入正确坐标>:\n");
		}
	}
	if (win == 9 * 9 - 10)
	{
		printf("恭喜你!排雷成功\n");
	}
}

谢谢支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值