手把手教你用c语言实现扫雷操作(可能是史上最简单的了吧还有完整代码呢)

  今天我们要做的就是用C语言写出扫雷游戏的代码。对不起,今天是一个没有骚话的很正经的分享。还请继续看下去。不想看讲解的,完整代码在文末。OK,进入正文!
  在写代码之前,我们应该要想想设计步骤。同上次写三子棋一样,我们第一步要做的就是打印游戏开始菜单,为了程序整体看上去显得比较整齐,我们把游戏菜单也用一个函数实现。代码如下。

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

  当玩家选择玩游戏后,也就是正式要设计游戏部分了,我们还是要先初始化两个二维数组,初始化两个的目的是分清设计者雷盘和玩家雷盘,我们程序员需要能看到哪些地方有雷哪些地方没有雷,而我们展示给玩家的是一个隐藏了雷的雷盘。所以需要初始化两个雷盘。
  这里的ROWS和COLS是我们雷盘的行数和列数,进行初始化时我没有用for循环(比较麻烦,但便于理解,可自行尝试)而是用了memset库函数,这个函数的具体用法如果大家不懂可以自行查阅,这里不做陈述。初始化了雷盘后就要给雷盘里赋值了,我们将玩家雷盘全初始化为’*'星号,将设计者雷盘初始化为’0’字符0。这里为什么将设计者雷盘初始化为字符0而不是其他符号,我们在这里先卖个关子,在后面会解释。

void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)  //初始化雷盘
{
  memset(&arr[0][0], set, rows*cols*sizeof(arr[0][0]));
}

  雷盘初始化之后为了看看我们的雷盘到底有没有初始化好,我们还需要一个打印函数,以便我们将雷盘打印出来检测。打印出来的本应该只是一个雷盘,但为了输入坐标方便,我们将雷盘加上行号和列号。代码如下:

void DisplayBoard(char arr[ROWS][COLS], int row, int col)  //打印雷盘
{
	int i = 0;
	int j = 0;
	for(i=0; i<=col; i++)
	{
		printf("%d ",i);
	}
	printf("\n");
	for(i=1; i<=row; i++)
	{
		printf("%d ",i);
		for(j=1; j<=col; j++)
		{
			printf("%c ",arr[i][j]);
		}
		printf("\n");
	}
}

  将雷盘初始化好打印后也没问题,我们就应该向雷盘中布雷了。布雷必定是一个随机的过程,所以我们需要用到随机数,为了让系统产生的随机数在我们雷盘的行和列内,需要对随机数加以限制。并且在布雷前应该先检查这个坐标有没有雷,如果已经有雷了,我们自然要重新选择地方布雷。每布一个雷,总雷数就要减一。

void SetMine(char arr[ROWS][COLS], int row, int col)  //布置雷
{
	int count = Easy_Count;
	int x = 0;
	int y = 0;
	while(count)
	{
		x = rand()%row+1;
		y = rand()%col+1;
		if(arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}

  完成了上述操作后,我们就应该扫雷了。在扫雷之前我们需要弄清楚几个问题。首先我们为了玩家的游戏体验,是不是让他第一次不被雷炸死,也就是如果玩家第一次踩到雷了,我们需要将雷移到别的地方,保证第一次安全不被炸死。其次如果玩家踩到了非雷的地方,我们是不是应该将这个坐标周围8个位置的雷数告诉玩家,显示出来。再有是不是还需要展开功能呢,如果这个坐标周围8个坐标也都没有雷,我们是不是可以将它们展开,直到遇到雷呢。这样其实就跟我们平时在电脑上玩的扫雷差不多了。所以我们的扫雷函数中应该有实现这几个功能的函数。
  首先是我们获取周围雷数的函数。还记得我们开始给设计者雷盘布置时,没有雷的地方都是字符0,有雷的地方是字符1。现在我们需要获取一个坐标周围的雷数时,只需要将它们加起来就是了。而不用循环便利。

int GetMineCount(char mine[ROWS][COLS], int x, int y)  //获取雷数
{
	return mine[x-1][y-1]+mine[x-1][y]
	+mine[x-1][y+1]+mine[x][y-1]+
	mine[x][y+1]+mine[x+1][y-1]+
	mine[x+1][y]+mine[x+1][y+1]-8*48;

}

  下面是第一次保证安全的函数,这个很简单,如果它是雷的话,我们给它重新赋值,让它不是雷就可以了。

void safe(char mine[ROWS][COLS], int x, int y)  //第一次安全
{
					mine[x][y] = '0';
					x = rand()%9+1;
					y = rand()%9+1;
					mine[x][y] = '1';
}

  我们还需要一个判断函数,不然什么时候扫雷结束啊。总不能一直扫下去吧。当玩家没被雷炸死时,这个坐标就会显示出数字。那如果剩下的没扫的地方的和是总雷数,那就是玩家把雷扫完了,也就是游戏胜利了。

int Iswin(char show[ROWS][COLS], int row, int col)//判断胜利条件
{
	int i = 0;
	int j = 0;
	int count = 0;
	for(i=1; i<=row; i++)
	{
		for(j=1; j<=col; j++)
		{
			if(show[i][j] == '*')
			{
				count++;
			}
		}
	}
	return count;
}

  接下来是展开函数,也就是遍历该坐标周围每一点,查它们的周围有没有雷,这个比较简单。

void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)  //展开雷阵
{
    int ret = 0;
    ret = GetMineCount(mine, x, y);
    if (ret == 0)
    {
        show[x][y] = ' ';
        if (x - 1>0 && y>0 && show[x - 1][y] == '*')
            OpenMine(mine, show, row, col, x - 1, y);
		   
        if (x - 1>0 && y + 1 <= col && show[x - 1][y + 1] == '*')
            OpenMine(mine, show, row, col, x - 1, y + 1);
		

        if (x>0 && y + 1 <= col && show[x][y + 1] == '*')
            OpenMine(mine, show, row, col, x, y + 1);
		
        if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*')
            OpenMine(mine, show, row, col, x + 1, y + 1);
		
        if (x + 1 <= row && y>0 && show[x + 1][y] == '*')
            OpenMine(mine, show, row, col, x + 1, y);
		
        if (x + 1 <= row && y - 1>0 && show[x + 1][y - 1] == '*')
            OpenMine(mine, show, row, col, x + 1, y - 1);
		
        if (x>0 && y - 1>0 && show[x][y - 1] == '*')
            OpenMine(mine, show, row, col, x, y - 1);
		

        if (x - 1>0 && y - 1>0 && show[x - 1][y - 1] == '*')
            OpenMine(mine, show, row, col, x - 1, y - 1);
		
    }
    else
    {
        show[x][y] = GetMineCount(mine, x, y) + '0';
    }
}

  完成了上述准备工作后我们就可以正式开始扫雷了。

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)  //排雷
{		
	int x = 0;
	int y = 0;
	int times = 0;
	int win = 0;
	int count = 0;
	while(Iswin(show, row, col) != Easy_Count)
	{
		printf("输入你要排查的坐标:");
		scanf("%d%d",&x, &y);
		times++;
		if(x>=1 && x<=row && y>=1 && y<=col)  //判断坐标合法
		{
			
			if(mine[x][y] == '1' )  //为雷分为第一次为雷和其他次为雷
			{
					if(1 == times)  //第一次为雷抢救一下
					{						
							safe(mine, x, y);
							count = GetMineCount(mine, x, y);
							show[x][y] = count+48;
							OpenMine(mine, show, ROW, COL, x, y);
							DisplayBoard(show, row ,col);
							win++;						
					}
					else  //不是第一次不抢救
					{			
						printf("很遗憾,你被炸死了\n");
						DisplayBoard(mine, row, col);
						break;
					}
			}
				
			if(mine[x][y] == '0')  //输入坐标不是雷
			{
				count = GetMineCount(mine, x, y);  //获取周围雷数
				show[x][y] = count+48;  //显示雷数
			    OpenMine(mine, show, ROW, COL, x, y);
				DisplayBoard(show, row ,col);
				win++;
			}
		}

		else 
		{
		  printf("输入坐标无效,重新输入\n");
		}
	}
	if(Iswin(show, row, col) == Easy_Count)  //获胜条件
	 {
		printf("恭喜你,排雷成功\n");
		printf("共计扫雷次数为%d\n",times);
		DisplayBoard(mine, row, col);
	}
}

  至此我们的函数的游戏部分就完成了,我们需要把它串起来。
完整代码如下,大家自行就能看懂。


  我们将所有代码分成这三个部分,game.h里放我们所有自己编写的函数的头文件。game.c里放我们自己编写的函数。teat.c里面放我们的主函数,以及将游戏串起来的game函数。

   game.h内的代码

#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>
#include<string.h>
#include<time.h>
#include<stdlib.h>

#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
#define Easy_Count 10

void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);  //初始化雷阵
void DisplayBoard(char arr[ROWS][COLS],int row, int col);  //打印雷盘
void SetMine(char arr[ROWS][COLS], int row, int col);  //布置雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);  //扫雷
int GetMineCount(char mine[ROWS][COLS], int row, int col);  //获取周围雷数
void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y);  //展开雷阵

void is_win(char mine[ROWS][COLS], int x, int y);
#endif //__GAME_H__  

   game.c内的代码

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)  //初始化雷盘
{
  memset(&arr[0][0], set, rows*cols*sizeof(arr[0][0]));
}

void DisplayBoard(char arr[ROWS][COLS], int row, int col)  //打印雷盘
{
	int i = 0;
	int j = 0;
	for(i=0; i<=col; i++)
	{
		printf("%d ",i);
	}
	printf("\n");
	for(i=1; i<=row; i++)
	{
		printf("%d ",i);
		for(j=1; j<=col; j++)
		{
			printf("%c ",arr[i][j]);
		}
		printf("\n");
	}
}

void SetMine(char arr[ROWS][COLS], int row, int col)  //布置雷
{
	int count = Easy_Count;
	int x = 0;
	int y = 0;
	while(count)
	{
		x = rand()%row+1;
		y = rand()%col+1;
		if(arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)  //获取雷数
{
	return mine[x-1][y-1]+mine[x-1][y]
	+mine[x-1][y+1]+mine[x][y-1]+
	mine[x][y+1]+mine[x+1][y-1]+
	mine[x+1][y]+mine[x+1][y+1]-8*48;

}
void safe(char mine[ROWS][COLS], int x, int y)  //第一次安全
{
					mine[x][y] = '0';
					x = rand()%9+1;
					y = rand()%9+1;
					mine[x][y] = '1';
}

int Iswin(char show[ROWS][COLS], int row, int col)//判断胜利条件
{
	int i = 0;
	int j = 0;
	int count = 0;
	for(i=1; i<=row; i++)
	{
		for(j=1; j<=col; j++)
		{
			if(show[i][j] == '*')
			{
				count++;
			}
		}
	}
	return count;
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)  //排雷
{		
	int x = 0;
	int y = 0;
	int times = 0;
	int win = 0;
	int count = 0;
	while(Iswin(show, row, col) != Easy_Count)
	{
		printf("输入你要排查的坐标:");
		scanf("%d%d",&x, &y);
		times++;
		if(x>=1 && x<=row && y>=1 && y<=col)  //判断坐标合法
		{
			
			if(mine[x][y] == '1' )  //为雷分为第一次为雷和其他次为雷
			{
					if(1 == times)  //第一次为雷抢救一下
					{						
							safe(mine, x, y);
							count = GetMineCount(mine, x, y);
							show[x][y] = count+48;
							OpenMine(mine, show, ROW, COL, x, y);
							DisplayBoard(show, row ,col);
							win++;						
					}
					else  //不是第一次不抢救
					{			
						printf("很遗憾,你被炸死了\n");
						DisplayBoard(mine, row, col);
						break;
					}
			}
				
			if(mine[x][y] == '0')  //输入坐标不是雷
			{
				count = GetMineCount(mine, x, y);  //获取周围雷数
				show[x][y] = count+48;  //显示雷数
			    OpenMine(mine, show, ROW, COL, x, y);
				DisplayBoard(show, row ,col);
				win++;
			}
		}

		else 
		{
		  printf("输入坐标无效,重新输入\n");
		}
	}
	if(Iswin(show, row, col) == Easy_Count)  //获胜条件
	 {
		printf("恭喜你,排雷成功\n");
		printf("共计扫雷次数为%d\n",times);
		DisplayBoard(mine, row, col);
	}
}





void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)  //展开雷阵
{
    int ret = 0;
    ret = GetMineCount(mine, x, y);
    if (ret == 0)
    {
        show[x][y] = ' ';
        if (x - 1>0 && y>0 && show[x - 1][y] == '*')
            OpenMine(mine, show, row, col, x - 1, y);
		   
        if (x - 1>0 && y + 1 <= col && show[x - 1][y + 1] == '*')
            OpenMine(mine, show, row, col, x - 1, y + 1);
		

        if (x>0 && y + 1 <= col && show[x][y + 1] == '*')
            OpenMine(mine, show, row, col, x, y + 1);
		
        if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*')
            OpenMine(mine, show, row, col, x + 1, y + 1);
		
        if (x + 1 <= row && y>0 && show[x + 1][y] == '*')
            OpenMine(mine, show, row, col, x + 1, y);
		
        if (x + 1 <= row && y - 1>0 && show[x + 1][y - 1] == '*')
            OpenMine(mine, show, row, col, x + 1, y - 1);
		
        if (x>0 && y - 1>0 && show[x][y - 1] == '*')
            OpenMine(mine, show, row, col, x, y - 1);
		

        if (x - 1>0 && y - 1>0 && show[x - 1][y - 1] == '*')
            OpenMine(mine, show, row, col, x - 1, y - 1);
		
    }
    else
    {
        show[x][y] = GetMineCount(mine, x, y) + '0';
    }
}

   test.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 mine[ROWS][COLS] = {0};
	char show[ROWS][COLS] = {0};
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	DisplayBoard(show, ROW, COL);
	SetMine(mine,ROW,COL);
	//DisplayBoard(mine, ROW, COL);
	FindMine(mine, show, ROW, COL);
	

}
int main()
{  
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
	menu();
	printf("请选择:");
	scanf("%d",&input);
	switch(input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏\n");
		break;
	default:
		printf("重新输入\n");
		break;
	}
  }while(input);
  return 0;
}

我们来放几张游戏效果图大家感受一下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43232778/article/details/83273561