C语言两百行代码实现简易扫雷

C语言两百行代码实现简易扫雷_第1张图片

文章目录

  • 前言
  • 一.代码实现
  • 二.设计思路
    • main()函数搭建框架
    • reset ( )函数
    • dis_play( )函数
    • setmine( )函数
    • player_move( )函数


前言

扫雷应该是我们接触到的第一个电脑游戏,用c语言实现扫雷对初学者来说是一个不错的锻炼
编写扫雷只需要用到数组、函数和生成随机数的知识,所以比较适合成为编程学习者编写的第一个小游戏。

如果不熟悉生成随机数的知识,可以去我的上一篇文章看看《C生成随机数》


一.代码实现

第一部分是源码复制就可以使用,每一个自定义函数在第二部分设计思路中都有详细解释,结合代码实现设计思路理解会有一个更好的效果

#define _CRT_SECURE_NO_WARNINGS 1

#include
#include
#include
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
#define MINE_NUMBER 10



void reset(char arr[ROWS][COLS], char ch)//将数组的每一个元素赋值为给定值
{
	for (int i = 0; i < ROWS; i++)
	{
		for (int j = 0; j < COLS; j++)
		{
			arr[i][j] = ch;
		}
	}
}

void setmine(char arr[ROWS][COLS])//利用生成随机数的知识使用随机的行号列标在mine数组放置地雷直到将宏定义的地雷数放置完
{
	int mine_number = MINE_NUMBER;
	int row = rand() % 9 + 1;//生成一到九的行号
	int col = rand() % 9 + 1;//生成一到九的列标

	while (mine_number > 0)
	{
		if (arr[row][col] == '0')//用来不是地雷的地方才能放置地雷
		{
			arr[row][col] = '1';//安装地雷
			mine_number--;
		}
		else
		{
			row = rand() % 9 + 1;
			col = rand() % 9 + 1;
		}

	}
}

void display(char arr[ROWS][COLS])
{
	for (int i = 0; i <= COL; i++)
	{
		printf(" %d  ", i);//打印行号
	}
	printf("\n\n");
	for (int i = 1; i <= ROW; i++)//第一个和第二个for进去分别打印一行数组和一条分割线
	{                             //数组行为:(空格)元素(空格)|(空格)元素(空格)|(空格)元素(空格)  
								  //分割线为: -      -      -   |   -      -     -   |   -     -      -
		printf(" %d  ", i);//打印列标

		for (int j = 1; j <= COL; j++)
		{

			printf(" %c ", arr[i][j]);
			if (j < COL)
			{
				printf("|");//为了美观,不打印最后一个'|'
			}

		}
		printf("\n");
		printf("    ");


		for (int k = 1; k <= COL; k++)
		{
			printf("---");
			if (k < COL)
			{
				printf("|");//为了美观,不打印最后一个'|'
			}

		}
		printf("\n");
	}
}







char nearmine(char mine[ROWS][COLS], int row, int col)//返回所选坐标字符型的地雷数量
{
	return (mine[row - 1][col - 1] + mine[row - 1][col] + mine[row - 1][col + 1] + mine[row][col - 1] + mine[row][col + 1]
		+ mine[row + 1][col - 1] + mine[row + 1][col] + mine[row + 1][col + 1] - 7 * '0');
}

int player_move(char mine[ROWS][COLS], char show[ROWS][COLS])//首先输入合法坐标然后玩家移动,每一步结果只有两个:踩到雷还有没踩到

{
	int row = 0, col = 0;
	int flag = 1;
	do//输入合法坐标,在行号列标范围内,并且没有被走过
	{
		printf("\n---------------------------------------输入坐标,中间用空格隔开:>");
		scanf("%d %d", &row, &col);
		if (row >= 1 && row <= 9 && col >= 1 && col <= 9 && show[row][col] == '*')
			flag = 0;
		else
			printf("输入错误\n");
	} while (flag);
	if (mine[row][col] == '1')//踩到雷,返回-1
		return -1;
	else
	{
		show[row][col] = nearmine(mine, row, col);//nearmine将会返回字符型的地雷数
												  //将用来展示的show数组的相应坐标的元素赋值为周围的地雷数
		return 1;
	}

}

void meau()//菜单
{
	printf("------------------\n");
	printf("|     1.play     |\n");
	printf("|----------------|\n");
	printf("|     0.exit     |\n");
	printf("------------------\n");

}


void game()
{

	char mine[ROWS][COLS];//mine:地雷
	char show[ROWS][COLS];
	reset(mine, '0');//初始化mine为全零
	reset(show, '*');//初始化reset为全*
	setmine(mine);//安置地雷
	//display(mine);
	display(show);//展现
	int count = 0;

	do
	{
		int move = player_move(mine, show);
		if (move == -1)//踩到雷游戏结束
		{
			printf("\n---------------------------------------踩到地雷,游戏结束>\n");
			display(mine);
			break;

		}
		else if (move == 1)//没有踩到雷则步数count加一
		{
			count++;
			if (count == ROW * COL - MINE_NUMBER)//判断是否走完了步数,走完了游戏就成功了
			{
				printf("\n---------------------------------------排除地雷,游戏结束>\n");
				display(mine);
				break;

			}

		}

		display(show);

	} while (1);



}

int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	do
	{
		meau();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game(); break;
		case 0:
			break;
		default:
			printf("输入错误,请重新输入\n"); break;

		}

	} while (input);
	return 0;



}

二.设计思路

main()函数搭建框架

1.main()函数搭建框架:像所有的电脑游戏一样,我们需要一个菜单,通过菜单选择进入游戏和退出游戏,当一盘游戏结束时可以再次选择进入或者退出,菜单用printf()打印就可以解决,循环的进入游戏用do while()循环就可以解决

void meau()//菜单
{
	printf("------------------\n");
	printf("|     1.play     |\n");
	printf("|----------------|\n");
	printf("|     0.exit     |\n");
	printf("------------------\n");

}


void game()
{
    char mine[ROWS][COLS] = {0};//mine:地雷
	char show[ROWS][COLS] = {0};//show: 展示。0
	
  ········
}

int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	do
	{
		meau();
		scanf("%d", &input);
		switch (input)
		{
		case 1 :
			game(); break;
		case 0 :
			break;
		default:
			printf("输入错误,请重新输入\n"); break;

		}

	} while (input);
	return 0;

	
	
}

当我们输入1,进入case 1时,将运行game()函数,game函数中的代码为具体游戏的实现
我们需要一个容器来存放游戏数据,二维数组是最好的选择,我们创建一个字符数组mine存放数据,一般扫雷游戏都是9X9的棋盘界面,所以我们可以设置行数和列数都为9,但在实际代码运行中9行9列还是不够的,会出现数组下标越界,所以最好在原来的上下左右各放一行将原来的9x9数组包起,所以我们实际需要一个11x11的数组,由于我们经常会使用,不妨对它宏定义一下

#define ROW 9
#define COL 9

#define ROWS 11
#define COLS 11

考虑到扫雷游戏中每选择一步如果没有踩雷,都会修改字符数组mine[ROW][COL]的相应元素来显示周围的地雷个数,这种修改会对游戏造成影响,所以不妨再定义一个数组show[ROW][COL],专门显示地雷数量,将判断和显示分离开

char mine[ROW][COL]:存放放置地雷和非地雷数据,我们用字符‘0’表示安全区;字符‘1’表示地雷,通过赋值填满数组
char show[ROW][COL]:当初用来展示的数组,初始化时全部赋值为字符‘*’,每选择一步,就在相应元素处返回周围地雷个数(mine数组相应元素周围‘1’的个数)

reset ( )函数

reset() :我们完成一局扫雷,还想下该怎么办?这时候我们构造一个函数reset(),将mine和show数组的每一个元素重置为‘0’和‘*’

该函数实际功能就是把接收到的数组中全部元素赋值为给定符号

reset()函数,遍历数组,赋值为给定字符

void reset(char arr[ROWS][COLS], char ch)//将数组的每一个元素赋值为给定值
{
	for (int i = 0; i < ROWS; i++)
	{
		for (int j = 0; j < COLS; j++)
		{
			arr[i][j] = ch;
		}
	}
}

dis_play( )函数

dis_play( ):我们扫雷肯定需要“雷区”来显示我们的数据,我们通过构造一个函数dis_play()将数组打印出来来实现这一功能

dis_play()功能就是借助’|'和‘_’等特殊字符,将数组以类棋盘形式打印出来

void display(char arr[ROWS][COLS])//借助于‘|’和‘-’,将数组以游戏界面的显示打印出来
{
	for (int i = 0; i <= COL; i++)
	{
		printf(" %d  ", i);//打印行号
	}
	printf("\n\n");
	for (int i = 1; i <= ROW; i++)//第一个和第二个for进去分别打印一行数组和一条分割线
	{                             //数组行为:(空格)元素(空格)|(空格)元素(空格)|(空格)元素(空格)  
								  //分割线为: -      -      -   |   -      -     -   |   -     -      -
		printf(" %d  ", i);//打印列标

		for (int j = 1; j <= COL; j++)
		{

			printf(" %c ", arr[i][j]);
			if (j < COL)
			{
				printf("|");//为了美观,不打印最后一个'|'
			}

		}
		printf("\n");
		printf("    ");


		for (int k = 1; k <= COL; k++)
		{
			printf("---");
			if (k < COL)
			{
				printf("|");//为了美观,不打印最后一个'|'
			}

		}
		printf("\n");
	}

}



运行代码,打印雷区
C语言两百行代码实现简易扫雷_第2张图片

运行代码,打印show
C语言两百行代码实现简易扫雷_第3张图片

setmine( )函数

setmine( ):经过reset()初始化后的mine数组中是没有地雷的,我们需要利用生成随机数的知识放置地雷,这时我们构建一个函数完成

使用头文件#include中的rand()函数可以生成一个0~32767的伪随机数,但使用rand()前先要使用srand()设置伪随机数起点
起点只要写一次,我们将srand((unsigned)time(NULL))定义在主函数,此处是一种固定的写法,time()函数需要引头文件
将rand()%9+1即%ROW+1可以生产1~9这九个随机数,可以用来做数组的行号和列标

int main()
{
	int input = 0;
	srand((unsigned)time(NULL));//设置起点的固定写法
	do
	{
		meau();
		scanf("%d", &input);
		switch (input)
		{
		case 1 :
			game(); break;
		case 0 :
			break;
		default:
			printf("输入错误,请重新输入\n"); break;

		}

	} while (input);
	return 0;

	
	
}

void setmine(char arr[ROWS][COLS])//利用生成随机数的知识使用随机的行号列标在mine数组放置地雷直到将宏定义的地雷数放置完
{
	int mine_number = MINE_NUMBER;
	int row = rand() % 9 + 1;//生成一到九的行号
	int col = rand() % 9 + 1;//生成一到九的列标

	while (mine_number > 0)
	{
		if (arr[row][col] == '0')//用来不是地雷的地方才能放置地雷
		{
			arr[row][col] = '1';//安装地雷
			mine_number--;
		}
		else
		{
			row = rand() % 9 + 1;
			col = rand() % 9 + 1;
		}

	}
	

运行代码–setmine()前
C语言两百行代码实现简易扫雷_第4张图片

运行代码–setmine()后
C语言两百行代码实现简易扫雷_第5张图片

player_move( )函数

player_move( ):扫雷用的棋盘打印好了,地雷放置好了下面要实现的就是移动这一个操作了,扫雷的移动只有两个结果:踩到雷还有没踩到雷,游戏扫胜利就是把除了雷之外的地块都走一次。另外,当我们每一次没有踩到雷时,要返回这个地块周围的地雷数>>

player_move()函数函数分为两个功能,第一个功能实现合法输入,输入的行号列标都应该在1~9这个范围中,另外,之前排除过的部分就不能再踩了。第二功能实现判断,踩到了雷就返回-1,没有踩到就返回1,并且应该赋值周围地雷雷数给show数组的相应元素,这个操作我们可以构造nearmine()函数完成,由于是字符型数组,nearmine()函数也要返回字符型的数字

char nearmine(char mine[ROWS][COLS], int row, int col)//返回所选坐标周围8格字符型的地雷数量
{
   //return 周围8格地雷数的ascll码值用下面这种方法就可以完成
	return (mine[row - 1][col - 1] + mine[row - 1][col] + mine[row - 1][col + 1] + mine[row][col - 1] + mine[row][col + 1]
		+ mine[row + 1][col - 1] + mine[row + 1][col] + mine[row + 1][col + 1] - 7 * '0');
}

int player_move(char mine[ROWS][COLS], char show[ROWS][COLS])//首先输入合法坐标然后玩家移动,每一步结果只有两个:踩到雷还有没踩到
                                                             
{
	int row = 0, col = 0;
	int flag = 1;
	do//输入合法坐标,在行号列标范围内,并且没有被走过
	{
		printf("\n---------------------------------------输入坐标,中间用空格隔开:>");
		scanf("%d %d", &row, &col);
		if (row >= 1 && row <= 9 && col >= 1 && col <= 9 && show[row][col] == '*')
			flag = 0;
		else
			printf("输入错误\n");
	} while (flag);
	if (mine[row][col] == '1')//踩到雷,返回-1
		return -1;
	else
	{
		show[row][col] = nearmine(mine, row, col);//nearmine将会返回字符型的地雷数
		                                          //将用来展示的show数组的相应坐标的元素赋值为周围的地雷数
		return 1;
	}



}

game( )

在game()函数我们编写程序去接收player_move( )函数返回的“-1”和“1”,接收到“1”,踩到地雷,游戏结束
接收到“1”,步数count++,并且判断conut是否等于非地雷地块的数量,一旦相等,游戏胜利,并且结束

void game()
{
	
	char mine[ROWS][COLS] ;//mine:地雷
	char show[ROWS][COLS] ;
	reset(mine,'0');//初始化mine为全零
	reset(show,'*');//初始化reset为全*
	setmine(mine);//安置地雷
	//display(mine);
	display(show);//展现
	int count = 0;
	
	do
	{
		int move = player_move(mine, show);
		if (move==-1)//踩到雷游戏结束
		{
			printf("\n---------------------------------------踩到地雷,游戏结束>\n");
			display(mine);
			break;

		}
		else if (move == 1)//没有踩到雷则步数count加一
		{
			count++;
			if (count == ROW * COL - MINE_NUMBER)//判断是否走完了步数,走完了游戏就成功了
			{
				printf("\n---------------------------------------排除地雷,游戏结束>\n");
				display(mine);
				break;

			}

		}
		
		display(show);
		
	} while (1);

	

}

整理不易,如果有帮助的话,那就给个三联吧,谢谢

你可能感兴趣的:(c语言,c++,算法)