扫雷(C语言版)

Posted 鹿九丸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了扫雷(C语言版)相关的知识,希望对你有一定的参考价值。

目录

1、需求分析

2、程序架构

3、代码实现(分函数呈现)

(1)主函数代码实现

分析:

异常处理:

(2)游戏主函数实现

分析:

(3)初始化函数的实现

分析:

(4)展示函数的实现

分析:

(5)埋雷函数的实现

分析:

(6)扫雷函数的实现

分析:

(7)头文件的引入、函数声明、难度的提高

分析:

4、代码实现(分文件呈现)

test.c代码

game.h代码

game.c代码


1、需求分析

通过C语言实现简单的扫雷小游戏,由于创作者水平有限,未在该游戏中实现图形化界面,同时在真正扫雷游戏中点一个位置成功扫雷多个坐标的功能也未实现,功能较为简单,敬请原谅!

2、程序架构

程序分为test.c、game.c两个源文件和game.h一个头文件。

test.c:主函数接口引入。

game.c:游戏的相关函数实现。

game.h:头文件引入、函数声明。

3、代码实现(分函数呈现)


(1)主函数代码实现

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;
		}
	} while (input);

}
int main()
{
	test();
	return 0;
}

分析:

1.主函数中引入了随机种子,生成随机数来方便后续的雷的生成

2.在通过menu()菜单呈现后,通过switch进行接口接入,当用户输入1时可以进行游戏,当用户输入0时即退出游戏。

3.总体是通过do while循环实现的,但巧妙的利用了将用户输入的数据填入while后面的括号中,即当用户输入0时while条件判断失败,游戏就终止。

异常处理:

在switch中虽然没有通过default可以进行异常处理,但当用户输入只要不为0的数据时,循环仍旧自动进行,在输入非0和非1的数据后,程序会要求玩家进行重新输入,会再次进入循环,实际上就已经相当于另类的异常处理。

(2)游戏主函数实现

void game()
{
	char mine[ROWS][COLS] = { 0 };//存取放置好雷的信息的雷盘
	char show[ROWS][COLS] = { 0 };//存取展示给用户的信息的雷盘
	Init_board(mine, ROWS, COLS, '0');//初始化雷盘
	Init_board(show, ROWS, COLS, '*');//初始化展示的雷盘
	Set_mine(mine, ROW, COL,EASY_COUNT);//埋雷
	Display_board(show, ROW, COL);//展示想要展示雷盘
	Find_mine(mine, show, ROWS, COLS);//排雷游戏开始
}

分析:

1.为什么要建立两个雷盘?第一个雷盘是我们用来初始化雷的,即埋雷的,第二个雷盘是用来显示给玩家的,即显示玩家在哪个位置排雷了,并且以这个位置为中心的3*3的格子里有多少雷,也许大家会问,一个雷盘不好吗?一个雷盘当然也没有问题,但两个雷盘能够更好的对后续操作进行更好的处理,特别是我们在计算以我们要扫的格子为中心3*3范围内有多少雷时,第一个雷盘我们初始化了为1*11,这样是为了我们更好的计算我们要扫的位置处周围有多少雷。

给大家展示一下两个雷盘:

 左边的雷盘为埋好雷的雷盘,右边的雷盘为呈现给玩家的雷盘。

2、初始化的第一个雷盘(11*11),我们将其全部都初始化为0,在后续的埋雷的过程中,将雷的位置的数据赋值为1,初始化展示的雷盘是将所有的位置的数据初始化为字符'*',后面我们排雷后将其赋值为我们排的地方的周围存在的雷的数量。

3.展示雷盘和初始化雷盘不一样,展示雷盘只需要用9*9即可,并不需要将11*11都展示出来,11*11只是为了我们更好的计算扫雷的位置周围的雷的数量。

(3)初始化函数的实现

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

分析:

雷盘初始化函数并不复杂,简单的运用for循环即可,需要注意的是,我们要根据初始化的雷盘不同在函数的最后一个参数的位置填入不同的字符。

(4)展示函数的实现

void Display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <=row; i++)
	{
		printf("%d ", i);
	}
	printf("\\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\\n");
	}
}

分析:

1.该展示函数中,第一个for循环是为了显示出列坐标来,方便玩家后续进行输出想要扫雷的坐标。

2.内层for循环前面的printf("%d",i)是为了显示出横坐标来坐标来。

3.需要注意的是不要忘了换行操作!

4.展示函数从1到9展示即可,因为不需要展示0下标和10下标的,这两个下标只是为了我们方便计算周围雷的数量,因为我们不需要考虑边缘位置的特殊性。

(5)埋雷函数的实现

void Set_mine(char mine[ROWS][COLS], int row, int col,int count)
{
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

分析:

1.这个函数中count为我们想要埋雷的数量,每成功埋一个雷,count就会减1,当count为0时,埋雷全部结束,此时也将跳出循环。

2.这个函数中我们在生成雷的位置时之所以要+1的原因是因为,在前面我们开辟的是一个11*11的雷盘,我们想要埋雷的位置或者说我们想要在数组中对应的埋雷的位置是1到9,而对8取模得到的结果范围为0到8,加1之后为1到9。

3.为什么要将雷的位置的数据赋值为1?是为了在后面计算周围雷得数量,即将周围坐标的数据加起来即可得到周围雷的数量之和。

(6)扫雷函数的实现

void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < (rows - 2) * (cols - 2) - EASY_COUNT)
	{
		printf("请输入你要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x > ROW || x<0 || y>COL || y < 0)
		{
			printf("输入错误,请重新输入!\\n");
		}
		else
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了!\\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else
			{
				show[x][y] = count_num(mine, x, y)+'0';
				Display_board(show, ROW, COL);
				win++;
			}
		}
	}
	if (win == (rows - 2) * (cols - 2) - EASY_COUNT)
	{
		printf("排雷成功!\\n");
	}
}
static int count_num(char mine[ROWS][COLS], int x, int y)
{
	return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x + 1][y] +
		mine[x + 1][y - 1] + mine[x + 1][y + 1] + mine[x - 1][y + 1] + mine[x][y + 1] +
		mine[x][y - 1]-8*'0';
}

分析:

1.while后面的括号的意义:就是当我们扫完全部的雷后就跳出循环并通过后面的if条件进行判断是否将雷完全扫完,如果扫完就输出扫雷成功。

2.在输入坐标后,有两个分支,第一个分支就是如果坐标对应的位置是1,即雷,就会显示扫雷失败,,如果不是雷,就跳转到定义的count_num()计算该坐标周围雷的数量,该函数的实现就是将周围坐标所存储的值相加,减去8*‘0’,至于为什么需要减去字符0呢?因为我们在开辟雷盘时定义的数据类型是字符型,此处通过计算得到的数据是整型,减去‘0’之后得到的数据即为字符型真正对应的整型,后面存入要展示的雷盘时加上‘0’,也是为了将其由整型转换为字符型,方便存入雷盘中。

(7)头文件的引入、函数声明、难度的提高

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10

void menu();//菜单函数声明
void game();//游戏主初始化函数声明
void Init_board(char board[ROWS][COLS], int rows, int cols, char ch);//初始化函数声明
void Set_mine(char mine[ROWS][COLS], int row, int col,int count);//埋雷函数声明
void Display_board(char board[ROWS][COLS], int row, int col);//展示函数声明
void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);//扫雷函数声明

分析:

ROW即为雷盘的真正行数,COL即为雷盘的真正列数,EASY_COUNT即为雷的数量,如果大家想要提高游戏的难度,可以通过改变ROW、COL、EASY_COUNT即可。

4、代码实现(分文件呈现)

test.c代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//游戏函数
void game()
{
	char mine[ROWS][COLS] = { 0 };//存取放置好雷的信息的雷盘
	char show[ROWS][COLS] = { 0 };//存取展示给用户的信息的雷盘
	Init_board(mine, ROWS, COLS, '0');//初始化雷盘
	Init_board(show, ROWS, COLS, '*');//初始化展示的雷盘
	Set_mine(mine, ROW, COL,EASY_COUNT);//埋雷
	Display_board(show, ROW, COL);//展示想要展示雷盘
	Find_mine(mine, show, ROWS, COLS);//排雷游戏开始
}
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;
		}
	} while (input);

}
int main()
{
	test();
	return 0;
}

game.h代码

#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10

void menu();//菜单函数声明
void game();//游戏主初始化函数声明
void Init_board(char board[ROWS][COLS], int rows, int cols, char ch);//初始化函数声明
void Set_mine(char mine[ROWS][COLS], int row, int col,int count);//埋雷函数声明
void Display_board(char board[ROWS][COLS], int row, int col);//展示函数声明
void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);//扫雷函数声明

game.c代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//菜单
void menu()
{   
	printf("***********************\\n");
	printf("*******  1.play  ******\\n");	
	printf("*******  0.exit  ******\\n");
	printf("***********************\\n");
}
//初始化函数
void Init_board(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}
//展示函数
void Display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <=row; i++)
	{
		printf("%d ", i);
	}
	printf("\\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\\n");
	}
}
//埋雷函数
void Set_mine(char mine[ROWS][COLS], int row, int col,int count)
{
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
//扫雷函数
void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < (rows - 2) * (cols - 2) - EASY_COUNT)
	{
		printf("请输入你要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x > ROW || x<0 || y>COL || y < 0)
		{
			printf("输入错误,请重新输入!\\n");
		}
		else
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了!\\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else
			{
				show[x][y] = count_num(mine, x, y)+'0';
				Display_board(show, ROW, COL);
				win++;
			}
		}
	}
	if (win == (rows - 2) * (cols - 2) - EASY_COUNT)
	{
		printf("排雷成功!\\n");
	}
}
static int count_num(char mine[ROWS][COLS], int x, int y)
{
	return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x + 1][y] +
		mine[x + 1][y - 1] + mine[x + 1][y + 1] + mine[x - 1][y + 1] + mine[x][y + 1] +
		mine[x][y - 1]-8*'0';
}

以上是关于扫雷(C语言版)的主要内容,如果未能解决你的问题,请参考以下文章

C语言实现简易版 扫雷 步骤及代码

如何用C语言快速实现初级版扫雷(步骤详细)

C语言的扫雷简化版

C语言版扫雷(纯代码)

C语言实现扫雷简易版

扫雷(C语言版)