C语言函数(三):数组和函数实现扫雷游戏

目录

  • 1.扫雷游戏的分析和设计
    • 1.1.扫雷游戏的功能说明
    • 1.2.游戏的分析与设计
      • 1.2.1 数据结构的分析
      • 1.2.2 文件结构设计
  • 2.扫雷游戏的代码实现

1.扫雷游戏的分析和设计

1.1.扫雷游戏的功能说明

  • 使用控制台实现经典的扫雷游戏
  • 游戏可以通过菜单实现继续玩游戏或者退出游戏
  • 扫雷的棋盘是9*9的格子
  • 默认随机排布10个雷
  • 排查雷
    • 如果位置不是雷,则显示周围有几个雷
    • 如果是雷,则炸死游戏结束
    • 把除10个雷之外的所有雷都找出来,排雷成功,游戏结束

游戏界面
C语言函数(三):数组和函数实现扫雷游戏_第1张图片C语言函数(三):数组和函数实现扫雷游戏_第2张图片
C语言函数(三):数组和函数实现扫雷游戏_第3张图片

1.2.游戏的分析与设计

1.2.1 数据结构的分析

扫雷的过程中,布置的雷和排出的雷都需要被存储,因为如果将两种都放在一起,就分别不出这个位置是雷的位置还是周围8个格子的雷的总数。

因为我们需要在99的棋盘上布置雷的信息和排查雷,首先想到的是创建一个99的数组来实现棋盘。C语言函数(三):数组和函数实现扫雷游戏_第4张图片

那如果这个位置布置雷,就存放1,没有布置雷就存放0。
当这个位置不是雷的时候,就需要统计周围8个位置的和,然后存放到当前位置。
那如果在计算边角时进行计算,就会发生数组越界的问题,为了解决这个问题,我们可以再在周围加一圈构成11*11的棋盘,这样就不会发生数组越界了。
解决了这个问题,就可以关注两个数组的问题了,因为我们的展示界面全是由 *构成的,而排查雷需要使用数字来表示,那我们可以使用数字字符来表示数值,最后将字符转化为数字就行了

1.2.2 文件结构设计

这里我们设置3个文件

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

2.扫雷游戏的代码实现

第一步:菜单设置

test.c

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

int main() {
	int input = 0;
	//srand((unsigned int)time(NULL));//使用时间种子
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);

		if (input == 1) {
			//printf("ready\n");
			game();
		}
		else if(input == 0) {
			printf("end\n");
		}
		else {
			printf("输入错误,重新输入\n");
		}

	} while (input);

	return 0;
}
}

这样就可输出菜单,选择1的话就可以开始游戏,选择0退出游戏,选择错误重新选择

第二步:游戏函数

test.c

void game(void) {
	//设置棋盘的格数,,11*11的棋盘不会出现越界问题
	char mine[ROWS][COLS];//11
	char show[ROWS][COLS];//11

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

}

game.h

#include

#define COL 9
#define ROW 9

#define ROWS ROW+2
#define COLS COL+2

//初始化棋盘函数
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type);

game.c

#include"game.h"
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type) {
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			borad[i][j] = type;
		}
	}
}

这个函数的作用是创建数组,初始化棋盘,分别将数据类型和函数实现写在头文件中

第三步:打印棋盘

test.c

void game(void) {
	//设置棋盘的格数,,11*11的棋盘不会出现越界问题
	char mine[ROWS][COLS];//11
	char show[ROWS][COLS];//11

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

	//打印棋盘
	Printborad(show, ROW, COL);
	Printborad(mine, ROW, COL);
}

game.h


#define COL 9
#define ROW 9

#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘函数
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type);
//打印棋盘函数
void Printborad(char borad[ROW][COL], int row,int col);

game.c

void Printborad(char borad[ROW][COL],int row,int col) {
	for (int i = 0; i <= row; i++) {
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++) {
		printf("%d ", i);
		for (int j = 1; j <= col; j++) {
			printf("%c ",borad[i][j]);
		}
		printf("\n");
	}
}

这个函数用以打印棋盘,可以看出棋盘的规划是否正确,当然我们只用打印show棋盘,不用打印mine棋盘,因为mine棋盘可以看到的全是0,这里为了不多写一个函数用来分别打印’*‘和’0’,所有我们再传一个一个参数type,告诉Printboard函数应该打印什么字符。

第四步:布置雷

test.c

void game(void) {
	//设置棋盘的格数,,11*11的棋盘不会出现越界问题
	char mine[ROWS][COLS];//11
	char show[ROWS][COLS];//11

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

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

	//布置雷
	SetMine(mine, ROW, COL);
	Printborad(mine, ROW, COL);//查看是否将雷布置好了
}
int main() {
	int input = 0;
	srand((unsigned int)time(NULL));//使用时间种子
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);

		if (input == 1) {
			//printf("ready\n");
			game();
		}
		else if(input == 0) {
			printf("end\n");
		}
		else {
			printf("输入错误,重新输入\n");
		}

	} while (input);

	return 0;
}

game.h

#include//使用时间种子
#include//使用随机数

#define COUNT 10//10个雷

//布置雷函数
void SetMine(char borad[ROW][COL], int row, int col);

game.c

void SetMine(char borad[ROW][COL], int row, int col) {
	//产生随机数
	int count = COUNT;
	while (count) {
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (borad[x][y] == '0') {
			borad[x][y] = '1';
			count--;
		}
	}

}

这里使用随机数设置雷的位置坐标,需要包含头文件#include
#include,使用语句srand((unsigned int)time(NULL));确定时间种子,这样就可以将雷布置进去了,可以使用Printborad(mine, ROW, COL);打印棋盘看看雷布置的正确与否。

第五步:排查雷

test.c

void game(void) {
	//设置棋盘的格数,,11*11的棋盘不会出现越界问题
	char mine[ROWS][COLS];//11
	char show[ROWS][COLS];//11

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

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

	//布置雷
	SetMine(mine, ROW, COL);
	Printborad(mine, ROW, COL);//查看是否将雷布置好了

	//排查雷
	FindMine(mine, show, ROW, COL);

}

game.h

void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col);

game.c

int GetMineCount(char mine[ROWS][COLS], int x, int y) {
	return (mine[x - 1][y] + mine[x - 1][y - 1] +mine[x-1][y+1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x][y + 1] + mine[x + 1][y + 1] - 8 * '0');
}

void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col) {
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col- COUNT) {
		printf("输入要查看的坐标:>");
		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col) {
			if (mine[x][y] == '1') {
				printf("很遗憾,你被炸死了\n");
				Printborad(show, ROW, COL);
				break;
			}
			else {
				//说明此处不是雷,则统计周围8个雷
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				Printborad(show, ROW, COL);
				win++;
			}
		}
		else {
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - COUNT) {
		printf("恭喜,排雷成功\n");
		Printborad(mine, ROW, COL);
	}
}

使用FindMine函数排查雷,先输入要查看的坐标,如果坐标符合规定,则看这个坐标是否是雷,如果不是则计算周围8个位置的和并输出在棋盘上,当排查完71个没有雷的位置后,游戏成功。如果该位置非法,则重新输入。

以上涉及到一个重要的知识点,那就是:如何将数字字符转化为数字
可以直接使用数字字符减去字符0,比如:
‘0’ - ‘0’ = 0
‘1’ - ‘0’ = 1
‘55’ - ‘0’ = 55
这是因为字符之间的减法是减的ASCII码值,所以ASCII值相减就可以得到数字。

完整代码:
game.h

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include//使用时间种子
#include//使用随机数

#define COUNT 10//10个雷

#define COL 9
#define ROW 9

#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘函数
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type);
//打印棋盘函数
void Printborad(char borad[ROW][COL], int row,int col);
//布置雷函数
void SetMine(char borad[ROW][COL], int row, int col);
//排查雷
void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col);

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type) {
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			borad[i][j] = type;
		}
	}
}

void Printborad(char borad[ROW][COL],int row,int col) {
	for (int i = 0; i <= row; i++) {
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++) {
		printf("%d ", i);
		for (int j = 1; j <= col; j++) {
			printf("%c ",borad[i][j]);
		}
		printf("\n");
	}
}


void SetMine(char borad[ROW][COL], int row, int col) {
	//产生随机数
	int count = COUNT;
	while (count) {
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (borad[x][y] == '0') {
			borad[x][y] = '1';
			count--;
		}
	}

}

int GetMineCount(char mine[ROWS][COLS], int x, int y) {
	return (mine[x - 1][y] + mine[x - 1][y - 1] +mine[x-1][y+1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x][y + 1] + mine[x + 1][y + 1] - 8 * '0');
}

void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col) {
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col- COUNT) {
		printf("输入要查看的坐标:>");
		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col) {
			if (mine[x][y] == '1') {
				printf("很遗憾,你被炸死了\n");
				Printborad(show, ROW, COL);
				break;
			}
			else {
				//说明此处不是雷,则统计周围8个雷
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				Printborad(show, ROW, COL);
				win++;
			}
		}
		else {
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - COUNT) {
		printf("恭喜,排雷成功\n");
		Printborad(mine, ROW, COL);
	}
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu(void) {
	printf("******************\n");
	printf("******1.play******\n");
	printf("******0.exit******\n");
	printf("******************\n");
}

void game(void) {
	//设置棋盘的格数,,11*11的棋盘不会出现越界问题
	char mine[ROWS][COLS];//11
	char show[ROWS][COLS];//11

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

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

	//布置雷
	SetMine(mine, ROW, COL);
	Printborad(mine, ROW, COL);//查看是否将雷布置好了

	//排查雷
	FindMine(mine, show, ROW, COL);

}
int main() {
	int input = 0;
	srand((unsigned int)time(NULL));//使用时间种子
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);

		if (input == 1) {
			//printf("ready\n");
			game();
		}
		else if(input == 0) {
			printf("end\n");
		}
		else {
			printf("输入错误,重新输入\n");
		}

	} while (input);

	return 0;
}

感谢观看!

/考研势在必行/

你可能感兴趣的:(C语言,c语言,游戏,开发语言,算法,数据结构,考研,visual,studio,code)