简易扫雷(v1)

目录

设计

1.游戏功能

1.通过坐标判断,来进行扫雷

2.设计思路

1.开始菜单

2.游戏的过程

2.1棋盘

2.2信息的存储

2.3数据类型的选择

2.4文件结构

代码实现

1.首先是game.h文件的内容:

2.其次是game.c文件的内容:

2.1初始化棋盘的函数:

2.2打印棋盘的函数:

2.3布置雷的函数:

2.4记录雷数量的函数:

2.5扫雷函数:

3.最后是test.c文件:

    1.菜单函数:

2.游戏函数:

3.主函数:

最后是扫雷的完整文件:


设计

1.游戏功能

1.通过坐标判断,来进行扫雷

2.同时会在棋盘上显示周边的雷数量

3.雷的数量有10个

4.默认格子数为9*9

5.找到雷,游戏就会失败

6.排出了所有雷,即为成功。

2.设计思路

1.开始菜单

菜单的实现,可以通过设计一个自定义函数来完成,无需返回值。

具体的选择(比如玩游戏或者退出)可以在主函数中通过switch进行判断

2.游戏的过程

2.1棋盘

棋盘的构成有两部分,一个是11*11,一个是9*9的。9*9是实际打印给玩家看的。

之所以设计成两个,是因为扫雷过程中需要对周围一圈雷的数量进行计算,若只有9*9,实际操作中会超过数组的边界,造成错误。

2.2信息的存储

整个棋盘需要的数组,默认的棋盘;装有雷信息的棋盘;存储周围雷的数量;

但实际上默认的棋盘只会在游戏开始出现一次,因此:周围雷的数量可以在默认的棋盘上进行展示,从数组的角度,只需把雷的数量(变量)放在默认的棋盘上(数组),而不必额外创建数组。

设show数组为默认的棋盘(也是后面雷数量展示的),mine数组为布置的雷。

2.3数据类型的选择

具体的数据上,考虑到实际上有3种数据要记录,雷,非雷,雷的个数。

虽然在展示上(也就是数组上)已经省略到2个,但实际过程中还是要考虑到3种数据的不同。

如果只用数字来记录,会出现雷的数量与雷与非雷的标识冲突(比如相邻的两个坐标,一个坐标如果在展示了自身周围的雷数量后从0变成1(1也代表着雷),另一个坐标也要扫描,那么这时候就会出现把本不是雷的格子也识别成了雷)。

因此采用字符来表示,同时由于字符型也是可以进行计算的,因此不影响数量的记录

2.4文件结构

game.c文件:设计具体游戏的函数,一共5个自定义函数。

初始化棋盘的(将show数组和mine数组进行初始化,分别给定默认的信息‘0’‘*’)

打印棋盘的(每次输入坐标前打印show数组,用来提示游戏进度,失败后打印mine数组,展示本局游戏的雷信息)

布置雷的(主要是对mine数组进行赋值,用随机数来实现随机坐标含有雷。)

记录已确认输入的坐标周围一圈雷的数量的记录函数(这个函数不需要在头文件中额外声明,是作为被嵌套函数被接下来的扫雷函数嵌套,因为其展示是show数组中,实现需要在扫雷函数中实现)

扫雷函数(实现判断是否为雷,是雷的打印mine数组,不是雷的,根据记录函数的返回值,填入show数组,重新打印show数组)

game.h:头文件,主要是声明自定义函数和一些变量,比如行数和列数(因为用变量的话,后期修改难度也更加方便),雷的数量。

test.c:包含主函数的文件,是程序的主体部分。主要是菜单函数的定义,以及游戏函数的定义(主要是调用game.c文件中已设计好的函数),以及主函数的定义(确定游戏的流程)

代码实现

1.首先是game.h文件的内容:

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

#define easy_count 10   //雷的数量
#define ROW 9   //棋盘真正的行数
#define COL 9  //棋盘真正的列数
#define ROWS ROW+2  //棋盘外一圈的行数
#define COLS COL+2  //棋盘外一圈的列数


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 board[ROWS][COLS], int row, int col);//设置雷
void findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //排雷

2.其次是game.c文件的内容:

2.1初始化棋盘的函数:

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;//set具体的值由主函数那边赋予,因为要考虑到mine数组和show数组
                              //都需要初始化
		}
	}
}

2.2打印棋盘的函数:

void displayboard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("-----排雷游戏-----\n");
	for (i = 0; i <= col; i++)//打印坐标轴的横坐标轴
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印坐标轴的纵坐标轴
		int j = 0;
		for (j = 1; j <= col; j++)//打印棋盘内容
		{
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}

}

2.3布置雷的函数:
 

void setmine(char board[ROWS][COLS], int row, int col)
{
	int count = easy_count;//将预设好的雷的数量赋值给count变量
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;//通过count变量的减少,当count=0也就是当雷布置数量达到预设好的后,就会结束循坏
		}
	}
}

2.4记录雷数量的函数:

int getminecount(char board[ROWS][COLS], int x, int y)
{
	return (board[x - 1][y - 1] + board[x][y - 1] + board[x + 1][y - 1]
 + board[x - 1][y] + board[x + 1][y] + board[x - 1][y + 1]
 + board[x][y + 1] + board[x + 1][y + 1] - 8 * '0');
}//通过坐标的增减来取到周围一圈的格子存储的数,因为数组都是字符型,
'0'的asc码是48,'1'的asc码是49,
所以一圈相加后,再减去8个48,多出来的部分就是雷的数量.
//注意,这里的返回值类型是int整型

2.5扫雷函数:

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 - easy_count)//满足条件说明还有不是雷的坐标没被输入
	{
		printf("请输入要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//限定坐标范围,因为数组的范围是11*11
//而实际棋盘应该是9*9
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				displayboard(mine,row,col);//失败后打印本局游戏雷的信息,也就是mine数组
				break;
			}
			else
			{
				int count = getminecount(mine, x, y);//调用记录函数,赋予数量给
//count,但要注意的是记录函数的返回值是int整型,所以这里的count类型也是int
				show[x][y] = count + '0';//注意count存的是int整型,所以如果雷的
//数量是1,那么1+'0'是1+48,也就是整型1+字符'0'的asc码48
				displayboard(show, row, col);//打印show数组现在的状态,也就是
//提示游戏进度
				win++;//执行了上面的循坏体,也就是说输入的坐标不是雷,那win就要+1,推动游戏进度。
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - easy_count)//当上面的循坏条件不满足后,就应当满足这里的条件
//也就是说已经找到了所有不是雷的坐标。游戏成功了。
	{
		printf("恭喜你,排雷成功\n");
		displayboard(mine, row, col);//游戏成功后,打印一次雷的信息,也就是mine数组
	}
}

3.最后是test.c文件:

    1.菜单函数:

void menu()
{
	printf("**************\n");
	printf("****1.play****\n");
	printf("****2.exit****\n");
	printf("**************\n");
}

2.游戏函数:

void game()
{
	char mine[ROWS][COLS];//存放雷的信息
	char show[ROWS][COLS];//存放排出的雷
	initboard(mine, ROWS, COLS, '0');
	initboard(show, ROWS, COLS, '*');
	displayboard(show, ROW, COL);
	setmine(mine, ROW, COL);
	findmine(mine, show, ROW, COL);

}

3.主函数:

int main()
{
	srand((unsigned int)time(NULL));//生成随机数种子
	int input=0;
	do
	{
		menu();//弹出菜单
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 2:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0 ;
}

最后是扫雷的完整文件:

saolei2 · 孟新大人/c-xuexi - 码云 - 开源中国 (gitee.com)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值