【C语言】万字教学,带你分步实现扫雷游戏(内含递归函数解析),剑指扫雷,一篇足矣

news2024/9/20 22:54:41

在这里插入图片描述

君兮_的个人主页

勤时当勉励 岁月不待人

C/C++ 游戏开发


带你轻松玩转扫雷游戏

  • 前言
  • 一. 扫雷游戏的介绍以及内部需要实现的功能解析
    • 1.什么是扫雷游戏
    • 2.扫雷游戏所需的几个步骤
  • 二.扫雷游戏的具体实现
    • 1.打印菜单
      • 菜单上的选择功能
    • 2.初始化以及打印棋盘
      • 初始化函数InitBoard
      • 打印棋盘的DisplayBoard函数
    • 3.设置地雷
      • 设置地雷SetMine函数
    • 4.玩家游玩及判断输赢
      • 获取周围地雷数函数GetMineCount
      • 递归函数ExpandBoard函数
      • 判断输赢函数FindMine
    • 5.game函数
  • 试玩一下扫雷游戏
  • 源码
    • game.h(头文件)
    • test.c(主函数文件)
    • game.c(定义函数的文件)
  • 总结

前言

Hello,这里是君兮_,今天更新一篇关于利用C语言实现扫雷游戏的博客。对于初学者来说,这也是一个非常容易上手的小项目,看完不妨自己试试哦!
废话不多说,我们直接开始吧!

一. 扫雷游戏的介绍以及内部需要实现的功能解析

1.什么是扫雷游戏

相信很多人在小时候都玩过扫雷游戏,但是还是为了防止某些同学不知道扫雷具体是在做什么,我这里还是带大家快速过一遍哦

在这里插入图片描述

  • 这是网页上随便搜索出来的一个扫雷游戏,链接如下,感兴趣的可以去试试:扫雷游戏

  • 扫雷游戏玩法是这样的

  • 1.如图所示,上面显示的是此时棋盘上有几颗雷
    在这里插入图片描述

  • 2.当我们点击某个坐标时,它会提示周边有几颗雷
    在这里插入图片描述

  • 3**.当我们点击的坐标中有雷时,我们就被“炸死”了,此时游戏结束**

在这里插入图片描述

  • 4.当我们把所有没有雷的坐标都点开后,说明我们排雷成功,游戏结束
  • 这里就不放成功的图片啦,以博主的实力(咳咳)过个扫雷游戏肯定是洒洒水啦~(其实是试了十分钟一次没过放弃了)

2.扫雷游戏所需的几个步骤

讲完什么是扫雷游戏后,咱们来讲讲我们要利用C语言实现这个”简单“小游戏的需要的几个步骤然后咱们一步一步实现。
根据以往的惯例,咱们还是画图说明吧

在这里插入图片描述

  • 好了,分析完具体要实现哪几个部分,咱们来分步实现这个小游戏

二.扫雷游戏的具体实现

1.打印菜单

  • 非常简单的一步,我就直接放代码啦
void menu()//打印菜单
{
	printf("*****************************\n");
	printf("*********** 1.play **********\n");
	printf("*********** 0.exit **********\n");
	printf("*****************************\n");

}

菜单上的选择功能

  • 对于分支选择的功能,switch语句非常满足我们的需要,代码如下:
int main()
{
	srand((unsigned int)time(NULL));生成随机数所需代码,后面会讲到
	int input = 0;

	do {

		menu();//先打印菜单提示玩家选择开始或结束游戏
		printf("请选择:> ");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;

		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);//退出即输入0,结束循环


	return 0;
}
  • 上面代码中,玩家输入1即开始游戏,输入0即退出游戏,输入其它数则提醒玩家输入错误并给与玩家重新选择的机会。

2.初始化以及打印棋盘

  • 现在我们来进行下一步,初始化及打印棋盘。
  • 在开始前我们先分析一下我们现在需要做的:
  • 1.我们希望打印两个棋盘,第一个棋盘中埋地雷,这个棋盘玩家应该是不可见的.第二个棋盘就像上面网页版扫雷游戏一样填充格子,玩家应该是可见的并且能够往上面输入坐标掀开格子判断是否有雷
  • 2.在第二个棋盘中出了打印格子,我们还应打印一些语句提醒玩家应该怎样玩游戏并把棋盘的行列标注出来。
  • 3.分析完这两点后,我们发现,二维数组能很好的满足我们的要求,此时我们不妨定义两个二维数组来实现两个棋盘的初始化与打印。
  • 4.于此同时,我们把没有雷的地方初始化为‘0’,把玩家能看到的棋盘初始化为‘*’。
    做完了具体分析,我们来用代码具体实现一下。
    注意:在定义或者使用某个函数时,我们应该优先在头文件中声明,下面是初始化函数与打印棋盘函数在头文件中的声明:
#define Row 9
#define Col 9
#define Rows Row+2
#define Cols Col+2


void InitBoard(char mine[Rows][Cols], int rows, int cols, char set);
void DisplayBoard(char board[Rows][Cols], int row, int col);

  • 我们现在打印的是一个9*9的棋盘,为了方便我们以后对这个棋盘大小的更改,我们用常数9定义了Row与Col,如果我们以后想更改棋盘大小只需改变定义Row与Col的常数大小即可。
    在这里插入图片描述
    - 前面我们提到了,我们会把周围地雷的数量放在中间这个格子中,为了防止出现图中这种情况,我们需要为这个棋盘多加看不见的两行两列,也就是传进去数组的大小应该加2.这就是上面传进的字符数组为:
//(Rows,Cols大小分别为Row+2,Col+2)
char mine[Rows][Cols]
char board[Rows][Cols]

的原因。

初始化函数InitBoard

void InitBoard(char mine[Rows][Cols], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			mine[i][j] = set;
		}
	}
}
  • 代码里set起到的作用就是初始化棋盘,当传进去需要埋雷的棋盘时set为’0’,当传进去玩家见到的棋盘时,初始化为‘*’

打印棋盘的DisplayBoard函数

  • 此时我们多传进去的数组的行数与列数可以用作修饰棋盘为我们的玩家做行与列的提示
  • 代码如下:
void DisplayBoard(char board[Rows][Cols], int row, int col)
{
	printf("******扫雷游戏开始*****\n");//提示玩家游戏开始
	int i = 0;
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);//打印列数
	}
	printf("\n");//打印完列数换行
	for (i = 1; i<=row; i++)
	{
		int j = 0;
		printf("%d ", i);//打印行数
		for (j = 1; j <=col; j++)
		{
			
			printf("%c ", board[i][j]);//打印棋盘
		}
		printf("\n");//每打印完一行换行

	}
}

  • 来看看具体效果
    在这里插入图片描述
  • 怎么说?效果是不是非常好?如果你看懂了,我们继续

3.设置地雷

  • 把棋盘设置好后,我们就该考虑一下我们地雷的设置以及如何放置了。
  • 首先,我们想到,如果在埋雷的棋盘中我们把所有坐标都给初始化为‘0’了,那我们就把有雷的地方设为‘1’吧(这里很重要,虽然设为别的也可以,但是这里设置为‘1’,自然是有原因的,我们稍后会讲到)。
  • 那我们的设好的雷应该怎么放呢?
  • 对于咱们这个扫雷游戏来说,自然希望每一次雷放置的位置都是不同的,不然一旦玩的次数多了,玩家摸清了我们放雷的老底,这个游戏岂不是玩不下去了?

在这里插入图片描述
那这个时候,我们就需要使用随机数函数

#include<stdio.h>//使用该函数所需头文件
#include<time.h>//使用time函数所需头文件
rand();
srand((unsigned int)time(NULL));//把时间函数置空传给srand同时由于srand要求参数必须为unsigned int型,把time(NULL)强制类型转换一下

  • 在三子棋那篇博客的随机数章节中,我具体全面的讲解了该函数应该怎么配合时间戳使用,这里就不再做过多介绍了,详细请看以下链接:【C语言】三子棋详解(包教包会的那种)

设置地雷SetMine函数

上面分析了这么多,我们来通过代码具体实现一下:

  • 引用该函数时先在头文件声明一下:
#define EasyCount 10//埋10个地雷
void SetMine(char mine[Rows][Cols], int row, int col);
  • 具体代码:
void SetMine(char mine[Rows][Cols], int row, int col)
{
	
	int count = EasyCount;//埋地雷的个数
	int i = 0;
	while (count)
	{
          //生成在1-9范围内的整数	
		int x = rand() % row + 1;
		int y = rand() % row + 1;
		//判断该位置是否已被埋雷
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;//埋雷成功,所需埋的地雷减1
		}
	}
}
  • 上面代码中还是有很多需要注意的地方的:
  • 1.我们为了判定我们到底需要埋多少个雷,定义了一个count,每当成功埋雷一次,count就减1,其中为了方便我们以后对所需埋雷数量的修改,我们在头文件中把一个常数赋给了EasyCount并让count引用,这样改变常数的大小即可改变我们想要埋雷的多少。
  • 2.我们不想把雷埋在棋盘外,为了防止这种情况的发生,我们把生成的随机数对棋盘大小取模再+1,确保我们的雷埋在棋盘中。
  • 效果如下:
    在这里插入图片描述
  • 这样咱们是不是就把雷埋进棋盘中了。

4.玩家游玩及判断输赢

当我们做好棋盘上的一切准备时,就该考虑玩家应该怎么玩了。

  • 第一,提示并引导玩家输入想要排雷的坐标。
  • 第二 ,判断输入的坐标是否合法,总不能排雷排到棋盘外吧。如果输入坐标不合法就提示玩家重新输入
  • 第三,输入正确坐标后,我们得判断该坐标是否有雷,即对于埋雷的棋盘,这里存放的是不是‘1’,是‘1’,说明此格子有雷,但被“炸死”我们也得让玩家“死”的明白,此时把埋雷的棋盘打印一遍并结束游戏。
  • 第四,不是雷,为了让游戏变得简单一点,我们可以把玩家输入坐标周围所有不是雷的格子全部显示出来,并在附近有雷的格子上显示此时附近所埋的地雷数,如图所示:
    在这里插入图片描述
  • 我们还是先把这部分拆分一下,先实现在中间的格子中显示周围地雷数

获取周围地雷数函数GetMineCount

  • 先在头文件声明该函数:
int GetMineCount(char mine[Rows][Cols], int x, int y);
  • 具体代码:
int GetMineCount(char mine[Rows][Cols], int x, int y)
{
	return mine[x - 1][y] + mine[x][y - 1] + mine[x - 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x + 1][y - 1] + mine[x - 1][y + 1]-8*'0';
}
  • 这里咱们把有地雷的坐标设为‘1’就起作用了。
    在这里插入图片描述

  • 如图,此时把周围所有有地雷的位置的‘1’加起来,是不是就得到周围存在的地雷数了?这就是上面一定要在埋雷坐标里存放‘1’的原因。

  • 好了好了,我知道这里其实还有很多疑问,我来一一解释一下:

  • 1. 为啥在最后要减去‘0’呢?

  • 注意:由于棋盘在初始化时是字符数组,咱们存进去的其实是字符‘1’,而此时我们希望传出去的是周围所有数字1之和,因此这里需要把所有‘1’相加之后再减去‘0’,这样传出的就是一个数字了。

  • 2.既然我们这里需要一个整型,为啥在初始化时传进去的不是一个整型数组呢?

  • 在咱们初始化时,初始化函数InitBoard是同时需要把两个棋盘都初始化的,由于玩家初始化时棋盘中为字符‘*’,因此定义InitBoard所需传进的数组必须是一个字符型的。当然,从实际上讲你也可以再重新定义一个函数进行埋雷棋盘的初始化,但是你觉得是重新定义一个函数简单还是把‘0’,‘1’转为对应的数字简单?答案显而易见。

递归函数ExpandBoard函数

这里比较难以理解,我尽量讲的细一点,如果看完还没理解的话,欢迎在评论区或者私信我指出你的疑问,我会第一时间回复的。

  • 当我们完成了在中间显示周围地雷数的目标后,为了使游戏难度降低一点,我们需要完成这样一件事:
    在这里插入图片描述
  • 判断该坐标周围的八个格子(即红色处)的周围除了该坐标剩下7个坐标中是否有雷,如果有雷,就在该格子处显示周围的雷的个数,不再进入下一次递归。
  • 如果没有雷,就把该坐标周围的格子全部点亮,就像这样。然后继续递归判断
    在这里插入图片描述
  • 有雷不再递归点亮格子的情况:
    在这里插入图片描述
    - 总结:也就是说,递归的条件是中间的格子为空,然后把它周边的8个格子当新一层的递归函数中的中心格子来计算,如果还为空就继续向外递归,不为空就停止了(即中间的格子为空时,把周边的8个格子带入下一层的递归中)。
  • 注意:在递归的过程中,不要把上一层已经判断过的空格子再判断一次(即此时里面的值已经不为’*'了),否则就会让该递归陷入死循环!!!
  • 代码实现如下:
  • 头文件中声明:
void ExpandBoard(char board[Rows][Cols], char mine[Rows][Cols], int row, int col, int* win);
  • 该函数定义:
void ExpandBoard(char board[Rows][Cols], char mine[Rows][Cols], int x, int y, int* win)
{
	
	if (x >= 1 && x <= Row && y >= 1 && y <= Col)//坐标必须在棋盘内
	{
		int ret = GetMineCount(mine, x, y);//获取周围雷的个数
		if (ret == 0)周围没雷
		{
			board[x][y] = '0';//把没雷的地方展开点亮为0
			int i = 0;
			//向四周八个格子递归
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					if (board[i][j] == '*')//防止已经展开的部分再次递归,进入死循环
					{
						ExpandBoard(board, mine, i, j, win);//递归
					}
				}
			}

		}
		else
		{
			board[x][y] = ret + '0';//周围有雷,把雷的个数以字符的形式放在中间格子中
		}

		  (*win)++;//记录展开的没有雷的格子的数量,方便判断输赢
	}
}
  • 建议上面那段话多读几遍,最好自己把网页版的扫雷游戏玩几次,结合它的展开方式理解上面关于递归的那段话

在这里插入图片描述

  • 当我第一次看上面关于递归的那段代码时,不禁感叹程序员就挺“秃然”的。
  • 加油,就剩最后一步辣
  • 如果你能坚持到最后,那我觉得这件事情------------------------------
    在这里插入图片描述
  • 小小放松一下,咱们继续

判断输赢函数FindMine

当理解了上面两个函数后,下面判断输赢的这个函数就比较好理解了。

  • 直接放代码:
  • 头文件中对函数的声明:
void FindMine(char board[Rows][Cols], char mine[Rows][Cols], int row, int col);
  • 该函数的定义:
void FindMine(char board[Rows][Cols],char mine[Rows][Cols], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while(win < row * col - EasyCount)//排的雷小于放置的雷,就继续排雷
	{
		printf("请输入要扫雷的坐标:>\n");
		scanf("%d %d",&x,&y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断排雷坐标合法性
		{
			if (board[x][y] == '*')//判断该坐标是否排查过
			{
				if (mine[x][y] == '1')
				{
					printf("恭喜你,被雷炸死了\n");
					DisplayBoard(mine, Row, Col);//打印埋雷棋盘,“死”的明白
					break;
				}
				else
				{
					
					ExpandBoard(board, mine, x, y, &win);//递归展开
		
					DisplayBoard(board, Row, Col);//打印展开后的棋盘
					printf("--------------还需翻开%d格--------------\n", row * col - EasyCount - win);//提示一下还要排多少格才能成功

					

				}
			}
			else
			{
				printf("该坐标已被排查过了,请重新输入\n");
			}
		}
		else
			printf("坐标非法,请重新输入\n");
		

	}
	if (win == (Row * Col - EasyCount))//所有雷都被找到
	{
		printf("恭喜你,排雷成功!\n");
		DisplayBoard(mine, Row, Col);
		
	}
}


  • 前面都基本解释过了,这里不做过多展开。有不明白的地方自己看上面代码注释即可。

5.game函数

当我们把所有模块功能都写好后,是时候写一个函数把所有模块封装在一起了 ,这就是我们接下来的game函数

  • 在主函数所在文件中,不需要声明,代码如下:
void game()
{
	char mine[Rows][Cols] = {0};//存放埋雷棋盘的数组
	char board[Rows][Cols] = {0};//存放玩家看到的棋盘的数组
	InitBoard(mine, Rows, Cols,'0');//初始化埋雷棋盘为'0'
	InitBoard(board, Rows,Cols,'*');//初始化玩家看到的棋盘为‘*’
	SetMine(mine, Row, Col);
	//DisplayBoard(mine, Row, Col);//打印埋雷棋盘,一般玩家不可见,自己调试的时候使用
	DisplayBoard(board, Row, Col);//打印玩家棋盘
	FindMine(board,mine, Row, Col);//判断输赢的函数
	
}

试玩一下扫雷游戏

  • 注意哦,当程序有bug的时候,不要傻愣愣的只设10个雷,这样你测一天都测不完的。
  • 测试结果如下:(棋盘中有80个雷)
  • 在这里插入图片描述
  • 正常结果如图(10个雷):
    在这里插入图片描述

源码

  • 把源码放这里哦,有需要自取。

game.h(头文件)

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define Row 9
#define Col 9
#define Rows Row+2
#define Cols Col+2
#define EasyCount 10

void InitBoard(char mine[Rows][Cols], int rows, int cols, char set);
void DisplayBoard(char board[Rows][Cols], int row, int col);
void SetMine(char mine[Rows][Cols], int row, int col);
void FindMine(char board[Rows][Cols], char mine[Rows][Cols], int row, int col);
int GetMineCount(char mine[Rows][Cols], int x, int y);
void ExpandBoard(char board[Rows][Cols], char mine[Rows][Cols], int row, int col, int* win);

test.c(主函数文件)

#include"game.h"
void menu()//打印菜单
{
	printf("*****************************\n");
	printf("*********** 1.play **********\n");
	printf("*********** 0.exit **********\n");
	printf("*****************************\n");

}
void game()
{
	char mine[Rows][Cols] = {0};//存放埋雷棋盘的数组
	char board[Rows][Cols] = {0};//存放玩家看到的棋盘的数组
	InitBoard(mine, Rows, Cols,'0');//初始化埋雷棋盘为'0'
	InitBoard(board, Rows,Cols,'*');//初始化玩家看到的棋盘为‘*’
	SetMine(mine, Row, Col);
	//DisplayBoard(mine, Row, Col);//打印埋雷棋盘,一般玩家不可见,自己调试的时候使用
	DisplayBoard(board, Row, Col);//打印玩家棋盘
	FindMine(board,mine, Row, Col);//判断输赢的函数
	
}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;

	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;
}

game.c(定义函数的文件)

#include"game.h"

void InitBoard(char mine[Rows][Cols], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			mine[i][j] = set;
		}
	}
}


void DisplayBoard(char board[Rows][Cols], int row, int col)
{
	printf("******扫雷游戏开始*****\n");
	//for(i=0;i<)
	int i = 0;
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i<=row; i++)
	{
		int j = 0;
		printf("%d ", i);
		for (j = 1; j <=col; j++)
		{
			
			printf("%c ", board[i][j]);
		}
		printf("\n");

	}
}

void SetMine(char mine[Rows][Cols], int row, int col)
{
	
	int count = EasyCount;
	int i = 0;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % row + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
int GetMineCount(char mine[Rows][Cols], int x, int y)
{
	return mine[x - 1][y] + mine[x][y - 1] + mine[x - 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x + 1][y - 1] + mine[x - 1][y + 1]-8*'0';
}
void ExpandBoard(char board[Rows][Cols], char mine[Rows][Cols], int x, int y, int* win)
{
	
	if (x >= 1 && x <= Row && y >= 1 && y <= Col)
	{
		int ret = GetMineCount(mine, x, y);
		if (ret == 0)
		{
			board[x][y] = '0';
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					if (board[i][j] == '*')
					{
						ExpandBoard(board, mine, i, j, win);
					}
				}
			}

		}
		else
		{
			board[x][y] = ret + '0';
		}

		  (*win)++;
	}
}
void FindMine(char board[Rows][Cols],char mine[Rows][Cols], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while(win < row * col - EasyCount)
	{
		printf("请输入要扫雷的坐标:>\n");
		scanf("%d %d",&x,&y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("恭喜你,被雷炸死了\n");
					DisplayBoard(mine, Row, Col);
					break;
				}
				else
				{
					
					ExpandBoard(board, mine, x, y, &win);
		
					DisplayBoard(board, Row, Col);
					printf("--------------还需翻开%d格--------------\n", row * col - EasyCount - win);

					

				}
			}
			else
			{
				printf("该坐标已被排查过了,请重新输入\n");
			}
		}
		else
			printf("坐标非法,请重新输入\n");
		

	}
	if (win == (Row * Col - EasyCount))
	{
		printf("恭喜你,排雷成功!\n");
		DisplayBoard(mine, Row, Col);
		
	}
}



总结

  • 今天的内容到此为止啦,扫雷游戏真的不算特别难,我希望看到这里的人都可以亲手独立实现一下(能坚持下来的大家都是好样的),只有你能够独立的把代码写出来,才能算真正的学会了。
  • 好了,如果你有任何的疑问欢迎在评论区指出,也欢迎随时私信我与我讨论,我看到会第一时间回复的,我们下次再见啦!!!

写到这里已经11000+了,这篇文章从早上开始写一直写到现在,主要花时间的地方是斟酌语句,我自己第一次看别人有关的文章时候雀氏是没怎么懂的,所以我希望我自己写的时候能配合图片啊啥的为大家解释的清楚容易理解一点。
新人创作不易,如果觉得这篇文章内容对你有所帮助的话,点个三连再走吧,谢谢大家了!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/659999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用测试驱动开发(TDD)来实现100%的测试覆盖率?

本文以 DDM 为例&#xff0c;简单地介绍一下如何用测试驱动开发(TDD, Test-Driven Development)的方法来驱动出这个函数库。 本文以DDM为例&#xff0c;简单地介绍一下如何用测试驱动开发&#xff08;TDD, Test-Driven Development)的方法来驱动出这个函数库。 DDM简介 DDM是…

vue-cli3的安装和项目创建

一 vue-cli3的安装 &#xff08;注意&#xff1a;vue-cli3在安装之前&#xff0c;需要先删除旧版本&#xff0c;即vue-cli2&#xff09; cnpm i -g vue/cli vue-cli3的卸载&#xff1a;cnpm uninstall -g vue/cli 然后用命令“vue -V”查看是否删除vue&#xff0c;如果没有删…

kafka原理架构深入

目录 1. 下载安装2. 命令行命令3. 概述3.1 定义3.2 基本架构 4. 架构深入4.1 生产者4.1.1 分区4.1.2 数据可靠性保证4.1.3 Exactly Once语义4.1.4 发送消息流程 4.2 broker4.2.1 日志结构4.2.2 存储策略4.2.3 Controller & ZooKeeper4.2.4 高效读写数据 4.3 消费者4.3.1 消…

模型-视图-控制器模式(MVC模式,10种常见体系架构模式之一)

、简介&#xff1a; 架构模式是一个通用的、可重用的解决方案&#xff0c;用于在给定上下文中的软件体系结构中经常出现的问题。架构模式与软件设计模式类似&#xff0c;但具有更广泛的范围。 模型-视图-控制器模式&#xff0c;也称为MVC模式。是软件工程中的一种软件架构模式&…

Word模板引擎poi-tl

文章目录 ◆ 方案对比◆ 版本◆ 特性◆ 模板◆ 数据◆ 输出◆ 数据模型◆ 标签1. 文本2. 图片3. 表格4. 列表5. 嵌套6. 区块对 ◆ SpingEL2. 单系列图标3. 多系列图标4. 组合图表 ◆ 配置1. 标签前后缀2. 标签类型3. 标签匹配值4. 标签值计算5. SpringEL6. 数据模型序列化7. 错…

设计模式之抽象工厂笔记

设计模式之抽象工厂模式笔记 说明Abstract Factory(抽象工厂)目录UML抽象工厂示例类图甜品抽象类甜品提拉米苏类甜品抹茶慕斯类 咖啡抽象类美式咖啡类拿铁咖啡类 甜品工厂接口美式风味的甜品工厂意大利风味的甜品工厂 测试类模式扩展 说明 记录下学习设计模式-抽象工厂模式的写…

吴恩达471机器学习入门课程3第1周——K-means

K-means 聚类 1 - 实现 K-means1.1 找到最近的质心练习11.2 计算质心均值练习2 2 - K-means在样本数据集上的应用3 - 随机初始化4 - K-means图像压缩4.1 数据集可视化处理数据 4.2图像像素上的 K-mean4.3 压缩图片 实现 K-means 算法&#xff0c;并将其用于图像压缩。 您将从一…

Autoware 跑 Demo(踩坑指南)

Autoware 跑 Demo&#xff08;踩坑指南&#xff09; 网上的博客和官方的教程&#xff0c;几乎都是一样的&#xff0c;但实际上跑不起来 Autoware 1.12学习整理–01–运行rosbag示例 Autoware入门学习&#xff08;三&#xff09;——Autoware软件功能使用介绍&#xff08;1/3&a…

MySQL的IF(exp1, exp2, exp3)、IFNULL(exp1, exp2)函数的用法

本章主要是讲解一下mysql的常用方法if()和ifnull()的使用 1、if(exp1, exp2, exp3) 如果表达式exp1成立&#xff0c;则返回的结果是表达式exp2&#xff0c;否则返回的是表达式exp3 案例&#xff1a;现在有一个星印类型表xingyin_type 通过这个表来介绍一下这个函数的使用 sel…

轻松掌握Seata源码分析之AT模式整体大纲流程跟踪

如下为订单和库存的实例代码&#xff0c;在事务开启处即订单服务处使用GlobalTransactional即可。当添加了异常代码使订单无法加一&#xff0c;这时减库存服务也会回滚&#xff0c;根据的就是undolog。回滚完undolog记录会被释放删除。 AT模式整体大纲流程跟踪如下&#xff1…

第37步 深度学习图像识别:CNN建模(Tensorflow)

基于WIN10的64位系统演示 一、写在前面 &#xff08;1&#xff09;深度学习图像识别的原理 我们思考一下&#xff0c;当你看到一张椅子的图片&#xff0c;你的大脑会告诉你这是个椅子&#xff0c;但你有没有想过&#xff1a;为什么你知道这是椅子&#xff0c;你的大脑是怎么…

【Spring Cloud 系列】Eureka控制台参数说明

【Spring Cloud 系列】Eureka控制台参数说明 前面我们在《Eureka使用详解》一文中介绍了Eureka的使用。本文将介绍Eureka控制板面各参数&#xff1a; System Status 编号名称说明1Environment环境&#xff0c;默认为test&#xff0c;该参数在实际使用过程中&#xff0c;可以不…

单目标应用:Tiki-taka算法(TTA)求解太阳能光伏模型MATLAB

一、四种太阳能光伏模型 随着石油、煤炭、天然气等不可再生能源的快速枯竭&#xff0c;以及空气环境的严重污染&#xff0c;可持续、无污染的能源供应成为热点和关键问题。风能、太阳能、水能、潮汐能等可再生能源的开发利用&#xff0c;必然在未来的可持续发展中发挥至关重要…

德国企业数据统计分析【1】-基于pandas的GENESIS ONLINE数据简单统计与柱状图可视化

引言: 德国拥有很多年销售额不超过50亿美元的中小企业,但他们却是某些细分制造、工业领域的翘楚。并且隐身于大众视野之外。此处,隐形冠军指的就是细分领域行业处于绝对领先地位并且年销售额不超过50亿美元的中小企业。这一概念是由德国著名中小企业管理学家赫尔曼西蒙创立的…

电脑开机密码忘记了怎么办?使用优盘重装系统

大家可以在网上搜索&#xff0c;其他方法。尽量找回密码。我这是因为已经很久没有使用这个电脑&#xff0c;而且c盘也没有怎么重要资料的情况下。我才选择重装系统的。 请慎重。 前期准备&#xff1a; 1、准备一个4G以上的U盘 2、备份U盘重要文件&#xff0c;制作过程中会格式…

「深度学习之优化算法」(五)差分进化算法

1. 差分进化算法简介 &#xff08;以下描述&#xff0c;均不是学术用语&#xff0c;仅供大家快乐的阅读&#xff09; 差分进化算法&#xff08;Differential Evolution Algorithm&#xff0c;DE&#xff09;是一种基于群体的进化算法&#xff0c;它模拟了群体中的个体的合作与竞…

黑马点评短信登录功能

一、基于session实现短信登录 1、发送短信验证码 流程图如下&#xff1a; 1、实现UserController下的sendCode方法&#xff1a; /*** 发送手机验证码*/PostMapping("/code")public Result sendCode(RequestParam("phone") String phone, HttpSession se…

微博粉丝清理工具丨2023年最新粉丝批量清理_微博怎么批量清理粉丝

2023年最新微博怎么批量清理粉丝&#xff1f;可能还有不少小伙伴不太清楚 接下来就为大家带来微博批量清理僵尸粉方法 有需要的朋友可以来了解一下&#xff0c;希望下文可以帮到大家 第一种&#xff1a;客服界面清粉方法 然后在客服中心界面选择修正粉丝; 最后点击一下确认就…

const修饰的成员函数

const修饰的成员函数 问题: 哪里出现编译报错了, 如何修改&#xff1f; class A { public:const int get1() const{a1 10;return a1;}private: int a1 0; }; int main() {A a;a.get1();return 0; }当时以为是a是一个非const对象&#xff0c;调用了const成员函数导致编译错误…

关于guacamole项目中的一点感悟与理解

关于guacamole项目中的一点想法 前言一、guacd模块启动相关二、一些感悟与理解参考 前言 Guacamole 是基于 Web 的 VNC 客户端&#xff0c;使用它可以通过web浏览器访问远程服务器终端并进行操作。它的基本架构如下图所示。 巧合之下&#xff0c;前段时间了解了项目中guacd模块…