【C语言】扫雷游戏——控制台版

目录:

1、设计思路

        1.1函数概要设计

        1.2流程

2、函数实现

3、文件及函数布置


1、设计思路

        1、1流程

                扫雷游戏,首先让玩家知晓如何进入游戏,退出游戏,这里需要给玩家提示,设计一个菜单选项函数menu(),想支持玩家一局一局的连续玩,玩家可选择继续游戏,或者退出游戏,该过程是需要一个循环实现,同时里面包含不同分支,进入游戏分支和退出游戏分支,同时可甄别玩家输入的选项是否合法。

                扫雷开始前,需要准备一个棋盘,显示给玩家,同时需要对该棋盘上进行布雷,为实现这两个目的,设置两个相同大小的数组,一个用于显示给玩家show_border[][],一个用于保存布雷的位置mine[][]。定义这两个数组时,对数组进行初始化,这里引入初始化函数Init()实现该功能。初始化函数中 对show_border[][]类型选用字符数组 ,初始化为'*'可以很好的隐藏雷的位置,mine[][]选用字符型数组,初始化为字符‘0’。在mine数组中完成初始化以后,需要在该数组中随机布雷,引入set_mine()函数,布雷的数量需要提前设置,传入该函数,每次布雷,使用rand()进行随机选择行和列,将雷所在位置元素设置为'1',表示该位置有一个雷。由于是随机布置,有可能会选到相同的位置,为此需进行判断。实现连续布雷,需要以布雷数量作为参数设计一个循环。为方便将棋盘显示给玩家,引入print_函数,将棋盘打印给玩家。考虑到在排雷过程中计算每个位置周围8个位置的布雷数量,为计数方便,将需打印的出来的棋盘外围加一层,例如,打印的棋盘为9*9时,show_border 和mine均设置为11*11。

                扫雷游戏开始,需使用一个计数变量来记录玩家总共的排雷次数,以便判断是否已将全部雷排除,退出本次排雷游戏,引入fine_mine()函数实现玩家可以连续排雷,所以排雷在一个循环中完成。当玩家选择排雷位置时,需要判断玩家输入的位置是否合法,是否在打印的棋盘内,同时该位置没有排查过,方可进行排雷, 当该位置有雷,需提示玩家排雷失败,退出排雷循环,退出游戏。引入count_mine()函数计算排雷位置周围的布雷数量,当进入该函数时,表明该位置是没有雷的,如此在计算周围8个位置的雷时,可以连同当前位置进行计算,不会对结果造成影响,可以设置一个嵌套循环排查3*3 9个位置的布雷数量。将计算出周围布雷数量填到当前位置,当当前位置没有雷时,可以自动排查周围位置的雷数量,即进行递归,可以设计逐个排查周围8个位置,需注意为避免出现死循环,对这8个位置进行限制,其一,该位置没有雷(上面已经满足该条件),该位置没有被排查过,show_border数组该位置为‘*’表示该位置没有被排查,为防止该位置为最外一层位置,即第一行、最后一行、第一列、最后一列,会造成死循环。对该位置坐标需进行限制为打印数组的坐标范围内,也可以设计一个嵌套循环调用3*3,共9次递归函数,实现对该位置周围位置的排查。

具体流程如下:

                

2、函数实现

        菜单函数:

void menu_1()
{
	printf("****************************\n");
	printf("***** 1、play  0、exit *****\n");
	printf("****************************\n");
}

        初始化函数

void init_(char show_board[ROW_][COL_],char mine[ROW_][COL_],int row_,int col_)
{
	int i = 0;
	int j = 0;

	for (i = 0; i < row_; i++)
	{
		for (j = 0; j < col_; j++)
		{
			show_board[i][j] = '*';
			mine[i][j] = '0';
		}
	}
}

打印函数

//便于玩家观察棋盘首行和首列分别打印行号和列号,打印部分的数组与show_border 和mine 同行同列
void print_(char arr[ROW_][COL_],int row,int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= row; i++)
	{
		for (j = 0; j <= col; j++)
		{
			if (i == 0)
			{
				printf("%c ", j + '0');
			}
			else if(j == 0)
			{
				printf("%c ", i + '0');
				
			}
			else
			{
				printf("%c ", arr[i][j]);
			}
			
		}
		printf("\n");
	}
	
}

布雷函数:

        

void set_mine(char mine[ROW_][COL_],int row,int col,int sum)
{
	int i = 0;
	int j = 0;
	//for (int k = 0; k < sum; k++)//该屏蔽部分,忽略了已布雷位置是不能布雷的。
	//{
	//	i = rand() % row + 1;
	//	j = rand() % col + 1;
	//	brr[i][j] = '1';
	//}
	while (sum)
	{
		i = rand() % row + 1;//用于生成随机数
		j = rand() % col + 1;
		if (mine[i][j] == '0')//当该位置没有布置雷,可以在该位置布置
		{
			mine[i][j] = '1';
			sum--;
		}

	}
}

计算布雷数量函数

void count_mine(char show_board[ROW_][COL_], char mine[ROW_][COL_], int row, int col,int*p_win)
{
	int count = 0;
	int i = 0;
	int j = 0;
	int m = 0;
	int n = 0;
	int row_1 = 0;
	int col_1 = 0;
	int row_ = ROW_;
	int col_ = COL_;
	for (i = -1; i < 2; i++)
	{
		for (j = -1; j < 2; j++)
		{
			if (row + i >= 0 && row + i < row_ && col + j >= 0 && col + j < col_)
			{
				if (mine[row + i][col + j] == '1')
				{
					count++;
				}
			}

		}
	}
	(* p_win)++;
	show_board[row][col] = '0' + count;//将排查结果记录

	if (count == 0)//说明周围没有雷,且该位置没有雷
	{
		for (m = -1; m < 2; m++)
		{
			for (n = -1; n < 2; n++)
			{
				row_1 = row + m;
				col_1 = col + n;
				if (show_board[row_1][col_1] == '*'&& row_1>= 1&&row_1<=ROW&&col_1>=1&&col_1<=COL)//判断递归条件:该位置没有被排查过,该位置合法
				{
					count_mine(show_board, mine, row_1, col_1,p_win);
				}
			}
		}
	}
}

排雷函数

//返回玩家排雷次数,以供判断玩家是否成功排雷结束
int find_mine(char arr[ROW_][COL_], char brr[ROW_][COL_])
{
	int win = 0;
	while (win < ((COL * ROW) - SUM))
	{
		int row = 0;
		int col = 0;
		int count = 0;
		int i = 0;
		int j = 0;
		printf("开始扫雷->\n");
		printf("请输入坐标->\n");
		scanf("%d%d", &row, &col);
		if (row >= 1 && row <= ROW && col >= 1 && col <= COL)
		{
			if (arr[row][col] != '*')
			{
				printf("该位置已扫过,请重新输入->\n");
			}
			else
			{
				if (brr[row][col] == '1')
				{
					printf("被炸死了\n");
					break;
				}
				else
				{
					count_mine(arr, brr, row, col, &win);
					print_(arr, ROW, COL);
				}
			}
		}
		else
		{
			printf("输入非法坐标,请重新输入->\n");
		}

	}
	return win;
}

排雷游戏函数

void game_1()
{
	char show_board[ROW_][COL_];
	char mine[ROW_][COL_];
	init_(show_board, mine, ROW_, COL_);
	print_(show_board, ROW, COL);

	set_mine(mine, ROW, COL, SUM);

	//print_(mine, ROW, COL);
	int win = 0;
	win = find_mine(show_board, mine);
	if (win == ((COL * ROW) - SUM))
	{
		printf("已排除全部雷\n");
		print_(mine, ROW, COL);
	}



}

3、文件及函数布置

        该程序包含3个文件 test.c 、minesweeping.h、minesweeping.c,test.c中放置排雷游戏函数和测试函数即主函数。主函数如下:

# include "minesweeping.h"
int main()
{
	srand((unsigned int) time(NULL));//随机数产生器的初始值 (种子值)
	int input = -1;
	while (input)
	{
		menu_1();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			printf("游戏开始->\n");
			game_1();
			break;
		}
		case 0:
		{
			printf("游戏退出->\n");
			break;
		}
		default:
		{
			printf("输入错误,请重新输入->\n");
			break;
		}
			
		}
	}
	return 0;
}

引入函数的实现,均放置在minesweeping.c,minesweeping.h中放置头文件,和函数声明。minesweeping.h 如下所示,其中的ROW COL表示打印的行和列,而ROW_ 和COL_ 表示show_mine 和mine的行和列,采用宏定义方式,可实现快速扩展。


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


# define ROW 4
# define COL 4
# define ROW_ ROW+2
# define COL_ COL+2
# define SUM 15//雷数量
void menu_1();
void game_1();
void init_(char show_board[ROW_][COL_], char mine[ROW_][COL_], int row_, int col_);
void print_(char arr[ROW_][COL_], int row, int col);
void set_mine(char mine[ROW_][COL_], int row, int col, int sum);
void count_mine(char show_mine[ROW_][COL_], char mine[ROW_][COL_], int row, int col,int* p_win);
int find_mine(char show_mine[ROW_][COL_], char mine[ROW_][COL_]);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值