扫雷(递归实现版)-新年快乐

扫雷(递归实现版)-新年快乐,第1张

扫雷(递归实现版)-新年快乐

  • 目录

    思路

    清晰的逻辑。

    菜单

    棋盘

    两个棋盘初始化

    布置雷

    排雷

    判断输赢

    text.c实现

    game.c实现

    game.h实现

    递归部分详解


    思路 清晰的逻辑。


    为方便将其分为三个文件:text.c(测试) game.c(函数实现) game.h(头文件声明)

    排雷的时候为了方便,我们需要将每一行每一列对应的行数,列数打印出来。

    #define LEI 10
    #define ROW 10
    #define LOW 10
    
    #define ROWS ROW+2
    #define LOWS LOW+2
    //在定义棋盘的长宽时,特意加上2,便于标记行数列数。

    菜单


    打印的菜单只需要有开始游戏、退出游戏的选项即可

    void menu()
    {
    	printf("*************************************n");
    	printf("************1.开始游戏***************n");
    	printf("************0.退出游戏***************n");
    	printf("*************************************n");
    
    }

    棋盘


      雷盘棋盘

    扫雷需要先记录雷的信息再进行排雷,如果使用一个棋盘太过于复杂,所以我们使用两个棋盘,一个用于布置雷,一个用于玩家排雷。

    两个棋盘初始化


    布置雷的棋盘初始化,将字符‘0’作为非雷,字符‘1’作为雷。

    玩家盘将字符‘*’作为还没有扫的地方

        board(arr1, ROWS, LOWS, '0');//雷盘
    	board(arr2, ROWS, LOWS, '*');//玩家盘

    因为两个的初始化方式不同,所以我们采用传参ret初始化

    //初始化棋盘
    void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
    {
    	int i = 0;
    	for (i = 0; i < rows; i++)
    	{
    		int j = 0;
    		for (j = 0; j < lows; j++)
    		{
    			arr1[i][j] = ret;
    		}
    	}

    布置雷


    布置的雷放置需要随机,所以采用两个随机数来定位坐标。

    //布置雷
    void Get_lei(char arr1[ROWS][LOWS], int row, int low)
    {
    	int count = LEI;
    	while (count)
    	{
    		int x = rand() % row + 1;
    		int y = rand() % low + 1;
    		if (arr1[x][y] == '0')
    		{
    			arr1[x][y] = '1';
    			count--;
    		}
    	}
    	//displayboard(arr1, ROW, LOW);//用于测试
    }

    排雷


    当我们输入一个坐标时,我们需要知道这个坐标周围雷的个数,定义一个Get_num函数来获取雷个数。但此时只能获取一个坐标的信息,我们知道一般的扫雷,如果当前坐标雷的个数为0,就会展开,这个过程较为复杂,所以我们使用递归来实现

    //玩家盘
    static int Get_num(char arr1[ROWS][LOWS],int x, int y)//获得当前坐标周围雷的个数
    {
    	int count = 0;
    	int i = 0;
    	for (i = x - 1; i <= x + 1; i++)
    	{
    		int j = 0;
    		for (j = y - 1; j <= y + 1; j++)
    		{
    			if (arr1[i][j] == '1')
    			{
    				count++;
    			}
    		}
    
    	}
    	return count;
    }
    //判断是否展开,实现函数
    static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
    {
    	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
    	{
    		int ret = Get_num(arr1, x, y);
    		if (ret != 0)
    			arr2[x][y] = ret + '0';//记录雷的个数
    		//递归散开
    		else if (arr1[x][y] != ' ')
    		{
    			arr2[x][y] = '0';
    			arr1[x][y] = ' ';
    			int i = 0;
    			for (i = x - 1; i <= x + 1; i++)
    			{
    				int j = 0;
    				for (j = y - 1; j <= y + 1; j++)
    				{
    					Judge(arr2, arr1, i, j);
    				}
    			}
    		}
    		else
    		{
    			return;
    		}
    	}
    }

    判断输赢


    输:即每排一次雷,检查一下雷盘对应的信息,如果是雷,就被炸死,如果不是,就继续排雷。


    赢:当玩家将所有的非雷的区域都排查出来时,判断为赢。(这里采用一个计数器,没排一次雷计数器就++一下,当计数器与总的非雷的区域数目相同时,判断为赢)

    void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
    {
    	int x = 0;
    	int y = 0;
    	while (1)
    	{
    		printf("请输入坐标:>");
    		scanf("%d,%d", &x, &y);
    		if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
    		{
    			if (arr1[x][y] == '1')
    			{
    				arr2[x][y] = '#';
    				displayboard(arr2, ROW, LOW);//排雷
    				printf("遗憾你输了n");
    				break;
    			}
    			else
    			{
    				Judge(arr2, arr1, x, y);
    				displayboard(arr2, ROW, LOW);//排雷
    			}
    		}
    		else
    		{
    			printf("输入错误!n");
    		}
    
    		//判断扫雷是否赢
    		int i = 0, flag = 0;
    		for (i = 1; i <= ROW; i++)
    		{
    			int j = 0;
    			for (j = 1; j <= LOW; j++)
    			{
    				if (arr2[i][j] != '*')
    				{
    					flag++;
    				}
    			}
    		}
    		if (flag == ROW*LOW - LEI)
    		{
    			printf("你赢了!n");
    			break;
    		}
    	}
    }
    

    text.c实现


    #define  _CRT_SECURE_NO_WARNINGS 1
    
    #include "game.h"
    //菜单
    void menu()
    {
    	printf("*************************************n");
    	printf("************1.开始游戏***************n");
    	printf("************0.退出游戏***************n");
    	printf("*************************************n");
    
    }
    
    
    void game()
    {
    	//初始化棋盘
    	char arr1[ROWS][LOWS] = { 0 };//雷盘
    	char arr2[ROWS][LOWS] = { 0 };//玩家盘
    	board(arr1, ROWS, LOWS, '0');
    	board(arr2, ROWS, LOWS, '*');
    	//打印棋盘
    	//displayboard(arr1, ROW, LOW);//布置雷
    	displayboard(arr2, ROW, LOW);//排雷
    	//布置雷
    	Get_lei(arr1,ROW,LOW);
    	//排雷
    	Out_lei(arr2,ROW,LOW, arr1);
    
    }
    int main()
    {
    	int input = 0;
    	srand((unsigned int)time(NULL));
    	do
    	{
    		menu();
    		printf("请选择:>");
    		scanf("%d",&input);
    		switch (input)
    		{
    		case 1:
    		{
    			printf("扫雷n");
    			game();
    			break;
    		}
    		case 0:
    		{
    			printf("退出游戏n");
    			break;
    		}
    		default:
    		{
    			printf("选择错误n");
    			break;
    		}
    		}
    	} while (input);
    
    	return 0;
    }

    game.c实现


    #define  _CRT_SECURE_NO_WARNINGS 1
    
    #include "game.h"
    
    //初始化棋盘
    void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
    {
    	int i = 0;
    	for (i = 0; i < rows; i++)
    	{
    		int j = 0;
    		for (j = 0; j < lows; j++)
    		{
    			arr1[i][j] = ret;
    		}
    	}
    }
    
    //打印棋盘
    void displayboard(char arr1[ROWS][LOWS], int row, int low)
    {
    	printf("<———扫雷游戏———>n");
    	int i = 0;
    	for (i = 1; i <= row; i++)
    	{
    		int j = 0;
    		if (i == 1)
    		{
    			for (j = 0; j <= low; j++)
    			{
    				printf("%2d ", j);
    			}
    			printf("n");
    		}
    
    		for (j = 1; j <= low; j++)
    		{
    			if (j == 1)
    			{
    				printf("%2d ", i);
    			}
    			
    			printf("%2c ", arr1[i][j]);
    		}
    		printf("n");
    	}
    	printf("<———扫雷游戏———>n");
    
    }
    
    //布置雷
    void Get_lei(char arr1[ROWS][LOWS], int row, int low)
    {
    	int count = LEI;
    	while (count)
    	{
    		int x = rand() % row + 1;
    		int y = rand() % low + 1;
    		if (arr1[x][y] == '0')
    		{
    			arr1[x][y] = '1';
    			count--;
    		}
    	}
    	//displayboard(arr1, ROW, LOW);
    }
    //玩家盘
    static int Get_num(char arr1[ROWS][LOWS],int x, int y)
    {
    	int count = 0;
    	int i = 0;
    	for (i = x - 1; i <= x + 1; i++)
    	{
    		int j = 0;
    		for (j = y - 1; j <= y + 1; j++)
    		{
    			if (arr1[i][j] == '1')
    			{
    				count++;
    			}
    		}
    
    	}
    	return count;
    }
    //判断是否展开,实现函数
    static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
    {
    	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
    	{
    		int ret = Get_num(arr1, x, y);
    		if (ret != 0)
    			arr2[x][y] = ret + '0';
    		//递归散开
    		else if (arr1[x][y] != ' ')
    		{
    			arr2[x][y] = '0';
    			arr1[x][y] = ' ';
    			int i = 0;
    			for (i = x - 1; i <= x + 1; i++)
    			{
    				int j = 0;
    				for (j = y - 1; j <= y + 1; j++)
    				{
    					Judge(arr2, arr1, i, j);
    				}
    			}
    		}
    		else
    		{
    			return;
    		}
    	}
    }
    void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
    {
    	int x = 0;
    	int y = 0;
    	while (1)
    	{
    		printf("请输入坐标:>");
    		scanf("%d,%d", &x, &y);
    		if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
    		{
    			if (arr1[x][y] == '1')
    			{
    				arr2[x][y] = '#';
    				displayboard(arr2, ROW, LOW);//排雷
    				printf("遗憾你输了n");
    				break;
    			}
    			else
    			{
    				Judge(arr2, arr1, x, y);
    				displayboard(arr2, ROW, LOW);//排雷
    			}
    		}
    		else
    		{
    			printf("输入错误!n");
    		}
    
    		//判断扫雷是否赢
    		int i = 0, flag = 0;
    		for (i = 1; i <= ROW; i++)
    		{
    			int j = 0;
    			for (j = 1; j <= LOW; j++)
    			{
    				if (arr2[i][j] != '*')
    				{
    					flag++;
    				}
    			}
    		}
    		if (flag == ROW*LOW - LEI)
    		{
    			printf("你赢了!n");
    			break;
    		}
    	}
    }
    
    
    

    game.h实现


    #pragma once
    
    #include 
    #include 
    
    #define LEI 10
    #define ROW 10
    #define LOW 10
    
    #define ROWS ROW+2
    #define LOWS LOW+2
    
    //初始化棋盘
    void board(char arr1[ROWS][LOWS],int rows,int lows,char ret);
    
    //打印棋盘
    void displayboard(char arr1[ROWS][LOWS], int row, int low);
    
    //布置雷
    void Get_lei(char arr1[ROWS][LOWS], int row, int low);
    //玩家盘
    void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS]);

    递归部分详解


    递归条件:1.有停止的条件。2.每一次递归都会向这个条件靠拢。


    那么这里的停止条件是什么呢?

    递归:当返回雷的个数为0时,就符合继续递归的条件,我们需要将当前坐标周围的点全部排除。且需要将已经排查了的坐标做一个标记,否则就会不停的排查下去,就会形成死递归。所以


    停止条件:当前这个坐标是已被排查过的,就停止递归。


    因为每一次排查都会的一个标记,所以这就是那个不断向停止条件靠拢的过程。

    //判断是否展开,实现函数
    static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
    {
    	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
    	{
    		int ret = Get_num(arr1, x, y);
    		if (ret != 0)
    			arr2[x][y] = ret + '0';
    		//递归散开
    		else if (arr1[x][y] != ' ')
    		{
    			arr2[x][y] = '0';//玩家盘
    			arr1[x][y] = ' ';//雷盘
    			int i = 0;
    			for (i = x - 1; i <= x + 1; i++)
    			{
    				int j = 0;
    				for (j = y - 1; j <= y + 1; j++)
    				{
    					Judge(arr2, arr1, i, j);
    				}
    			}
    		}
    		else
    		{
    			return;
    		}
    	}
    }
    

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/zaji/5710400.html

  • (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    上一篇 2022-12-17
    下一篇 2022-12-17

    发表评论

    登录后才能评论

    评论列表(0条)

    保存