您现在的位置是:群英 > 开发技术 > 编程语言
用C语言做扫雷游戏的思路和方法是什么?
Admin发表于 2021-12-27 19:00:471231 次浏览

    扫雷游戏想必大家都有玩过吧,如果我们自己编程该怎样做呢?这篇文章就给大家来分享扫雷游戏的实现,这里是用C语言实现的,下文介绍了实现思路、方法及代码,文中示例代码介绍的很详细,感兴趣的朋友接下来一起跟随小编看看吧。

        一,设计思路

         这便是一个标准的扫雷,换做代码实现,我们需要考虑以下几点:

        1.棋盘的设计与初始化

        2.在棋盘中放入雷

        3.统计雷数

        4.如何实现“一片”的效果

        5.输赢的判断

        接下来我们进行具体操作。

        二.实现方式

        1.菜单的打印

        对任意一个游戏,菜单是必不可少的,也是最简单的部分,直接上代码

    void menu()
    {
    	printf("------------------扫雷------------------\n");
    	printf("---------------1.开始游戏---------------\n");
    	printf("---------------0.退出游戏---------------\n");
    }
    int main()
    {
    	srand((unsigned int)time(NULL));
    	int a = 0;
    	do
    	{
    		menu();
    		scanf("%d", &a);
    		if (a == 0)
    		{
    			break;
    		}
    		game();
    	} while (a);
    	return 0;
    }

        其中srand是为了求随机值,用来布置雷

        2.game函数

        主菜单完后进入game函数,在game函数里我们就要开始主要的游戏部分,如棋盘初始化与打印等,当然这些步骤都依靠函数完成,game函数只相当于集合了一系列的游戏模块

    void game()
    {
    	char mine[ROWS][COLS];
    	char show[ROWS][COLS];
    	initeboard(mine, ROWS, COLS, '0');
    	initeboard(show, ROWS, COLS, '*');//初始棋盘
    	displayboard(show, ROW, COL);//打印棋盘
    	mine_make(mine, ROW, COL);//设置雷
    	//displayboard(mine, ROW, COL);
    	find_mine(mine, show, ROWS, COLS);//排查雷
     
    }

        3.棋盘的初始化与打印

        可以看到,我在game函数里初始了两个棋盘,为什么要两个呢?

        其实,一个是为了放置了雷,一个为了展示给玩家,为什么不用一个呢,我们要在放雷处用'1',表示不放雷处用‘0',这样计算一个坐标周围雷的数量就会更简单,接下来看一段代码:

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

        这里我们看到定义了一个ROWS和COLS这又是为何呢?

        回归棋盘

         扫雷时当你确认一个点时,它会对此点周围的八个点进行排查看是否有泪,当坐标位于红线处时没有无法判断八个,因此有了ROWS与COLS,这时,有人就会问了:那埋雷的地方用ROW COL就可以了,还不用担心雷跑到外边我们加的框,想法很好,但我们有两个棋盘,必须对应,而且也不存在跑出雷的情况,往下分析你就会知道

    void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盘初始化,此处用了个节省步骤的方法,不用两个棋盘依次初始化
    {
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < rows; i++)
    	{
    		for (j = 0; j < cols; j++)
    		{
    			board[i][j] = s;
    		}
    	}
    }
    void displayboard(char board[ROWS][COLS], int row, int col)//棋盘打印
    {
    	int i = 0;
    	int j = 0;
    	printf(" ");//与行中打印的0%d对应
    	for (j = 0; j <=col; j++)
    	{
    		printf(" %d  ", j);
    	}
    	printf("\n");
    	printf("-");
    	for (j = 1; j <= col + 1; j++)
    	{
    		printf("---");
    		printf("|");
    	}
    	printf("\n");//列对应打印完成
    	for (i = 1; i <= row; i++)
    	{
    		if (i <= 9)
    		{
    			printf(" 0%d ", i);
    		}
    		else
    		printf(" %d ", i);
    		printf("|");
    		for (j = 1; j <= col; j++)
    		{
    			printf(" %c ", board[i][j]);
    			printf("|");
    		}
    		printf("\n");
    		printf("-");
    		for (j = 1; j <= col+1; j++)
    		{
    			printf("---");
    			printf("|");
    		}
    		printf("\n");//行对应嵌套在内部 打印的数前加0是为了让当行数大于9时能够对应 如09与10
    	}
    }

        棋盘的打印做了行列对应,所以可能有点不明显

         4.雷的放置,雷的个数

        雷的放置很简单,在棋盘‘0',处放置就行,因为我们对随机数的算式使随机数只会出现在0-9没有跑出的情况

    mine_make(char mine[ROWS][COLS], int row, int col)//设置雷
    {
    	int count = 10;
    	while (count)
    	{
    		int x = rand() % 10;
    		int y = rand() % 10;
    		if (mine[x][y] == '0')
    		{
    			mine[x][y] = '1';
    			count--;
    		}
    	}
    }

        雷的个数就需要一定考虑了:

        首先,我们需要把周围八个位置是否有雷,有多少个雷判断出来,这时我们设计‘0' ‘1'类型就排上用场了,但是注意,这是字符,不是数字

         一张表 让我们知道如何转型

        当然返回的数字记得转成字符类型

    int get_mine(char mine[ROWS][COLS], int i, int j)//得到一个坐标附近雷的个数
    {
    	return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
    		mine[i][j - 1] + mine[i][j + 1] +
    		mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';
    //此处我们的数字其实是字符,用此方法可以转为数字整形
    }

        5.递归实现一片效果

        当不为雷是会展开附近一片不为雷,提高游戏效率

    void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//递归方法实现一大片
    {
    	show[x][y] = ' ';//先让输入金的坐标处变为空格,因为已经判定过雷所以可以直接转空格
    	int i = 0;
    	int j = 0;
    	int ret = 0;
    	for (i = x - 1; i <= x + 1; i++)
    	{
    		for (j = y - 1; j <= y + 1; j++)//嵌套for循环表示输入坐标包括自生及周围八个
    		{
    			if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')
    //防止出现负坐标,避免有雷,避免输入重复
    			{
    				ret = get_mine(mine, i, j);//判断ret是0或非0,并得出周围雷数
    				if (!ret)//如果ret=0,!ret便是非0;为真
    				{
    					spread(show, mine, i, j);//递归
    				}
    				if (ret)//ret!=0时为真,便打印数
    				{
    					show[i][j] = ret + '0';//使数字转成对应字符
    				}
    			}
     
    		}
    	}
    }

        效果展示:

         6.排查雷

        负责判断是否被炸死及游戏胜利

    void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
    {
    	printf("请输入坐标\n");
    	int i = 0;
    	int j = 0;
    	int win = 0;
    	while (row*col-10)
    //因为是十个雷,所以是—10,因为下总数减10就赢了,所以可以以此跳出循环,当然要是雷部位10,定一个变量就行,此处就不改了
    	{
    		scanf("%d %d", &i, &j);
    		if (mine[i][j] == '1')
    		{
    			printf("你挂了\n");
    			displayboard(mine, ROW, COL);
    			break;
    		}
    		else
    		{
    			show[i][j] = get_mine(mine, i, j)+'0';
    			spread(show,mine, i, j);
    			displayboard(show, ROW, COL);
    			win++;
    		}		
    	}
    	if (win ==row * col - 10)
    	{
    		printf("恭喜你,成功了\n");
    		displayboard(mine, ROW, COL);
    	}
    }

        具体注释都在代码里了

        正常情况把打印雷盘注释就行,就可以正常游戏了

         三.完整代码

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #define ROW 10
    #define COL 10
    #define ROWS ROW+2
    #define COLS COL+2
    void menu()
    {
    	printf("------------------扫雷------------------\n");
    	printf("---------------1.开始游戏---------------\n");
    	printf("---------------0.退出游戏---------------\n");
    }
    void initeboard(char board[ROWS][COLS], int cols, int rows,char s)
    //棋盘初始化,此处用了个节省步骤的方法,不用两个棋盘依次初始化
    {
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < rows; i++)
    	{
    		for (j = 0; j < cols; j++)
    		{
    			board[i][j] = s;
    		}
    	}
    }
    void displayboard(char board[ROWS][COLS], int row, int col)//棋盘打印
    {
    	int i = 0;
    	int j = 0;
    	printf(" ");//与行中打印的0%d对应
    	for (j = 0; j <=col; j++)
    	{
    		printf(" %d  ", j);
    	}
    	printf("\n");
    	printf("-");
    	for (j = 1; j <= col + 1; j++)
    	{
    		printf("---");
    		printf("|");
    	}
    	printf("\n");//列对应打印完成
    	for (i = 1; i <= row; i++)
    	{
    		if (i <= 9)
    		{
    			printf(" 0%d ", i);
    		}
    		else
    		printf(" %d ", i);
    		printf("|");
    		for (j = 1; j <= col; j++)
    		{
    			printf(" %c ", board[i][j]);
    			printf("|");
    		}
    		printf("\n");
    		printf("-");
    		for (j = 1; j <= col+1; j++)
    		{
    			printf("---");
    			printf("|");
    		}
    		printf("\n");//行对应嵌套在内部 打印的数前加0是为了让当行数大于9时能够对应 如09与10
    	}
    }
    mine_make(char mine[ROWS][COLS], int row, int col)//设置雷
    {
    	int count = 10;
    	while (count)
    	{
    		int x = rand() % 10;
    		int y = rand() % 10;
    		if (mine[x][y] == '0')
    		{
    			mine[x][y] = '1';
    			count--;
    		}
    	}
    }
    int get_mine(char mine[ROWS][COLS], int i, int j)//得到一个坐标附近雷的个数
    {
    	return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
    		mine[i][j - 1] + mine[i][j + 1] +
    		mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';
    //此处我们的数字其实是字符,用此方法可以转为数字整形
    }
    void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//递归方法实现一大片
    {
    	show[x][y] = ' ';//先让输入金的坐标处变为空格,因为已经判定过雷所以可以直接转空格
    	int i = 0;
    	int j = 0;
    	int ret = 0;
    	for (i = x - 1; i <= x + 1; i++)
    	{
    		for (j = y - 1; j <= y + 1; j++)//嵌套for循环表示输入坐标包括自生及周围八个
    		{
    			if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')
    //防止出现负坐标,避免有雷,避免输入重复
    			{
    				ret = get_mine(mine, i, j);//判断ret是0或非0,并得出周围雷数
    				if (!ret)//如果ret=0,!ret便是非0;为真
    				{
    					spread(show, mine, i, j);//递归
    				}
    				if (ret)//ret!=0时为真,便打印数
    				{
    					show[i][j] = ret + '0';//使数字转成对应字符
    				}
    			}
     
    		}
    	}
    }
    void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
    {
    	printf("请输入坐标\n");
    	int i = 0;
    	int j = 0;
    	int win = 0;
    	while (row*col-10)
    //因为是十个雷,所以是—10,因为下总数减10就赢了,所以可以以此跳出循环,当然要是雷部位10,定一个变量就行,此处就不改了
    	{
    		scanf("%d %d", &i, &j);
    		if (mine[i][j] == '1')
    		{
    			printf("你挂了\n");
    			displayboard(mine, ROW, COL);
    			break;
    		}
    		else
    		{
    			show[i][j] = get_mine(mine, i, j)+'0';
    			spread(show,mine, i, j);
    			displayboard(show, ROW, COL);
    			win++;
    		}		
    	}
    	if (win ==row * col - 10)
    	{
    		printf("恭喜你,成功了\n");
    		displayboard(mine, ROW, COL);
    	}
    }
    void game()
    {
    	char mine[ROWS][COLS];
    	char show[ROWS][COLS];
    	initeboard(mine, ROWS, COLS, '0');
    	initeboard(show, ROWS, COLS, '*');//初始棋盘
    	displayboard(show, ROW, COL);//打印棋盘
    	mine_make(mine, ROW, COL);//设置雷
    	displayboard(mine, ROW, COL);
    	find_mine(mine, show, ROWS, COLS);//排查雷
     
    }
    int main()
    {
    	srand((unsigned int)time(NULL));
    	int a = 0;
    	do
    	{
    		menu();
    		scanf("%d", &a);
    		if (a == 0)
    		{
    			break;
    		}
    		game();
    	} while (a);
    	return 0;
    }
        

    总结

        以上就是用C语言实现扫雷游戏的介绍了,本文只是提供了一种实现思路,代码仅供参考,需要的朋友可以了解看看,希望对大家学习C语言有帮助,想要了解更多可以继续浏览群英网络其他相关的文章。

    文本转载自脚本之家

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

    相关信息推荐
    2021-11-12 18:02:43 
    摘要:这篇文章给大家分享的是Laravel框架如何实现登录跳转页面的功能。登录跳转页面功能是很常见的需求,小编觉得挺实用的,因此分享给大家做个参考,文中示例代码介绍的非常详细,感兴趣的朋友接下来一起跟随小编看看吧。
    2022-06-30 17:54:35 
    摘要:golang开发时debug的方法:首先使用go get命令获取delve工具;然后编写测试代码;接着使用dlv debug test.go命令开始调试go程序;最后可以使用b、c、n、s等命令来控制调试。
    2022-05-07 17:06:41 
    摘要:本篇文章带大家详细了解一下Bootstrap中的按钮组件。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
    云活动
    推荐内容
    热门关键词
    热门信息
    群英网络助力开启安全的云计算之旅
    立即注册,领取新人大礼包
    • 联系我们
    • 24小时售后:4006784567
    • 24小时TEL :0668-2555666
    • 售前咨询TEL:400-678-4567

    • 官方微信

      官方微信
    Copyright  ©  QY  Network  Company  Ltd. All  Rights  Reserved. 2003-2019  群英网络  版权所有   茂名市群英网络有限公司
    增值电信经营许可证 : B1.B2-20140078   粤ICP备09006778号
    免费拨打  400-678-4567
    免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
    微信公众号
    返回顶部
    返回顶部 返回顶部