C语言·贪吃蛇游戏(下)

news2024/11/25 20:22:49

        上节我们将要完成贪吃蛇游戏所需的前置知识都学完了,那么这节我们就开始动手写代码了

1. 程序规划

        首先我们应该规划好我们的代码文件,设置3个文件:snack.h 用来声明游戏中实现各种功能的函数,snack.c 用来实现函数,test.c 用来测试和运行这个游戏

                        

        然后我们将游戏的大概流程在test.c文件中写出来,因为我们会用到宽字符,所以要记得适配本地中文环境

                

2. 游戏数据结构设计

2.1 蛇身数据结构(链表)

        我们设计用链表来表示蛇身,链表的每个节点中需要存这节蛇身的坐标 x、y 和下一节点的地址,然后我们给蛇身节点结构体类型改个好写一点的名字

        链表的基础知识:数据结构·单链表-CSDN博客

                

2.2 维护整个游戏的结构体

        我们还要创建一个结构体,用来存放当前游戏的种种状态

        

        

        

3. 游戏开始前的初始化

        游戏的开始前初始化都在GameStart()函数中实现,那么我们着手开始写这个函数。

        首先,我们要先创建维护贪吃蛇游戏的结构体,将它的信息传到GameStart()中去,在snack.h中声明这函数,然后再在snack.c中实现它

        

        我们把这个函数种封装的功能先都展示出来,之后就不重复展示了

3.1 控制台信息设置及光标隐藏

        控制台为了美观我们设置成100列30行的,名字就叫做贪吃蛇

        运行以下发现控制台设置好了,并且光标也很好的隐藏了起来

3.2 打印欢迎信息

        WelcomeToGame()函数内部的大部分东西我们上节其实已经写过了,下面就展示一下

3.3 打印地图

        地图大小我们上节已经说过了,要设计一个27行58列的棋盘,然后我们用一个宏把每块墙写出来,方便写打印语句

                        

        在打印墙的时候上边界和下边界挨着打印就行,左边界和右边界的时候要在每次打印之前把光标都定一下位

        展示打印地图的代码:

                

3.4 初始化蛇

        蛇身我们采用链表的结构进行管理。最开始,我们展示5个蛇身,初始的蛇尾巴从(24,5)的位置开始,向右5节之后是蛇头,这里我们采用头插的方式依次创建节点并加入蛇身中。

        同时定义蛇尾初始位置的宏和蛇身形状的宏

                        ​​​​​​​        

        最后将贪吃蛇的所有状态进行初始化

3.5 创建食物

        创建食物时不能随意创建的,要满足一下四点要求:

        1. 食物是随机出现的,就是说坐标是随机的

        2. 坐标必须在墙内    (x:2~54  y:1~25)

        3. 坐标不能在蛇身上

        4. 横坐标必须是偶数

        创建的食物其实就相当于蛇的一段身体,所以我们之间用蛇身节点的结构体类型保存食物的()(位置)信息就行,然后食物的创建要满足上面的要求,最后要注意的是,我们想要生成真随机数,就不要忘了在程序开始时给rand()函数种种子srand()

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

4. 游戏的运行过程

        下面我们来完成GameRun()函数,首先将这个函数中要实现的功能理出来

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

4.1 打印帮助信息

        这个没啥好说的,定好位打印就行

        ​​​​​​​        

4.2 按键逻辑

        写一个do···while循环,当游戏状态是OK的情况下就一直循环,持续检测按键的状态,同时在这里把帮助信息也写一下。我们检测按键的时候写一个宏 KEY_PRESS  内容跟上节的一样,这里我就不展示了,最后我会把所有代码都贴出来的

        ​​​​​​​        

        pause()函数

                        

        

4.3 蛇的移动(走一步)

        这里我们的策略是在蛇头前面再创建一个节点,用来判断蛇要走的下一个位置是否有食物,这里要注意,当蛇向下走的时候不能直接向上走,向右走的时候不能像左走,以此类推。蛇的下一步的位置信息先全都存在新创建的节点中,等待接入蛇身

        

        ​​​​​​​        

4.3.1 蛇头下一步是食物

        ​​​​​​​            

4.3.2 蛇头下一步不是食物

        ​​​​​​​   ​​​​​​​        ​​​​​​​

4.3.3 检测撞墙

        撞墙简单,判断一下蛇头横纵坐标有没有跟墙重合就行

                

4.3.4 检测撞自己

        同理,蛇头的横纵坐标没有跟自身重合就行

5. 游戏结束善后的工作

        善后工作其实就是打印一下蛇的死亡原因,然后把,malloc的内存都释放掉

             ​​​​​​​

6. 复玩功能

        复玩功能我们之前已经写过很多次了,像扫雷中就有很详细的介绍,这里我就简单写一下了

        扫雷请参考:函数·扫雷游戏-CSDN博客

        ​​​​​​​        ​​​​​​​

7. 完整代码

        snack.h

#include<locale.h>
#include<stdlib.h>
#include<stdio.h>
#include<Windows.h>
#include<stdbool.h>
#include<time.h>

#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'

//蛇默认的起始坐标
#define POS_X 24
#define POS_Y 5

#define KEY_PRESS(vk) ((GetAsyncKeyState(vk) & 0x1) ? 1 : 0)

//游戏当前状态
enum GAME_STATUS
{
	OK = 1,//游戏正常运行
	ESC,//玩家按esc要退出
	KILL_BY_WALL,//蛇撞墙死
	KILL_BY_SELF //蛇撞自己死
};

//当前蛇在向哪个方向移动
enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};


//蛇身节点
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;



//贪吃蛇
typedef struct Snake
{
	pSnakeNode pSnake;//蛇头位置
	pSnakeNode pFood;//指向食物的指针
	int Score;//当前累计的分数
	int FoodWeight;//一个食物的分数
	//蛇休眠的时间
	//休眠时间越短,蛇移动的越块
	int SleepTime;
	enum GAME_STATUS status;//游戏当前的状态
	enum DIRECTION dir;//蛇当前走的方向
	//···
}Snake, * pSnake;


//修改光标位置
void SetPos(int x, int y);

//游戏开始前的初始化
void GameStart(pSnake ps);

//打印欢迎信息
void WelcomeToGame();
//创建地图
void CreateMap();
//初始化蛇
void InitSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);


//游戏的运行过程
void GameRun(pSnake ps);

//打印帮助信息
void PrintHelpInfo();
//蛇的移动
void SnakeMove(pSnake ps);
//蛇头下一步要走的坐标是否是食物
int NextIsFood(pSnake ps,pSnakeNode pNext);
//是食物就吃掉
void EatFood(pSnake ps, pSnakeNode pNext);
//不是食物就走一步
void NotEatFood(pSnake ps, pSnakeNode pNext);
//检测撞墙
void KillByWall(pSnake ps);
//检测撞自己
void KillBySelf(pSnake ps);


//游戏结束善后的善后工作
void GameEnd(pSnake ps);

        snack.c

#include"snack.h"


//修改光标位置
void SetPos(int x, int y)
{
	//获得设备句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//根据句柄设置光标位置
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);
}
//打印欢迎信息
void WelcomeToGame()
{
	//欢迎界面
	SetPos(38, 12);
	printf("欢迎来到贪吃蛇小游戏\n");
	SetPos(40, 20);
	system("pause");
	system("cls");//清空屏幕

	//操作介绍界面
	SetPos(20, 10);
	printf("用 ↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
	SetPos(37, 12);
	printf("加速能得到更高的分数\n");
	SetPos(40, 20);
	system("pause");
	system("cls");//清空屏幕

}



//打印地图
void CreateMap()
{
	int i = 0;
	//上边界
	SetPos(0, 0);
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//下边界
	SetPos(0, 26);
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//左边界
	for (int i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}

	//右边界
	for (int i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}



//初始化蛇
void InitSnake(pSnake ps)
{
	pSnakeNode cur = NULL;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)//节点创建失败
		{
			perror("InitSnake():malloc()");
			return;
		}
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;
		cur->next = NULL;

		//头插法
		if (ps->pSnake == NULL)
		{
			ps->pSnake = cur;
		}
		else
		{
			cur->next = ps->pSnake;
			ps->pSnake = cur;
		}
	}

	//打印蛇身
	cur = ps->pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}

	//贪吃蛇的其他信息初始化
	ps->dir = RIGHT;
	ps->FoodWeight = 10;
	ps->pFood = NULL;
	ps->Score = 0;
	ps->SleepTime = 200;
	ps->status = OK;
}

//创建食物
void CreateFood(pSnake ps)
{
	int x = 0, y = 0;

again:
	do
	{
		//当x不是偶数就再生成一次
		x = rand() % 53 + 2;
		y = rand() % 24 + 1;
	} while (x % 2 != 0);

	//坐标和蛇的身体的每个节点坐标比较
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}

	//创建食物
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("CreateFood():malloc()");
		return;
	}

	//食物其实就相当于一段蛇身,吃了之后把它接上去就行
	pFood->x = x;
	pFood->y = y;
	ps->pFood = pFood;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
}


//游戏开始前的初始化
void GameStart(pSnake ps)
{
	//控制台信息设置
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");

	//隐藏光标
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(handle, &CursorInfo);

	//打印欢迎信息
	WelcomeToGame();

	//打印地图
	CreateMap();

	//初始化蛇
	InitSnake(ps);
	
	//创建食物
	CreateFood(ps);
}





void PrintHelpInfo()
{
	SetPos(62,15);
	printf("1. 不能撞墙,不能咬到自己");
	SetPos(62, 16);
	printf("2. 用 ↑ ↓ ← → 控制蛇的移动"); 
	SetPos(62, 17);
	printf("3. F3为加速,F4为减速");

}

void pause()
{
	while (1)
	{
		Sleep(100);
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	}
}


//蛇头下一步要走的坐标是否是食物
int NextIsFood(pSnake ps, pSnakeNode pNext)
{
	if (ps->pFood->x == pNext->x && ps->pFood->y == pNext->y)
	{
		//下一个坐标是食物
		return 1;
	}
	else
	{
		//不是食物
		return 0;
	}
}

//是食物就吃掉
void EatFood(pSnake ps, pSnakeNode pNext)
{
	//是食物就把新节点头插
	pNext->next = ps->pSnake;
	ps->pSnake = pNext;

	//打印整条蛇
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//得分
	ps->Score += ps->FoodWeight;
	//释放被吃掉的食物
	free(ps->pFood);
	//新建一个食物
	CreateFood(ps);
}

//不是食物就走一步
void NotEatFood(pSnake ps, pSnakeNode pNext)
{
	//先把新节点头插进去
	pNext->next = ps->pSnake;
	ps->pSnake = pNext;
	//再释放一个蛇尾
	pSnakeNode pcur = ps->pSnake;
	while (pcur->next->next)
	{
		//这里捎带着把新蛇身打印
		SetPos(pcur->x, pcur->y);
		wprintf(L"%lc", BODY);
		pcur = pcur->next;
	}
	//先将尾节点的位置打印空白字符
	SetPos(pcur->next->x, pcur->next->y);
	printf("  ");//打印两个空格

	//最后free
	free(pcur->next);
	pcur->next = NULL;
}

//检测撞墙
void KillByWall(pSnake ps)
{
	if (ps->pSnake->x == 0 || \
		ps->pSnake->x == 56 || \
		ps->pSnake->y == 0 || \
		ps->pSnake->y == 26)
	{
		ps->status = KILL_BY_WALL;
	}
}

//检测撞自己
void KillBySelf(pSnake ps) 
{
	//从蛇头的下一个节点开始判断
	pSnakeNode cur = ps->pSnake->next;

	while (cur)
	{
		if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y)
		{
			//撞到自己身上了
			ps->status = KILL_BY_SELF;
			return;
		}
		cur = cur->next;
	}
}



//蛇的移动
void SnakeMove(pSnake ps)
{
	//在蛇头前创建一个检测下一个节点是什么的节点
	pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pNext == NULL)
	{
		perror("SnakeMove():malloc()");
		return;
	}
	pNext->next = NULL;

	switch (ps->dir)
	{
	case UP:
		pNext->x = ps->pSnake->x;
		pNext->y = ps->pSnake->y - 1;

		break;
	case DOWN:
		pNext->x = ps->pSnake->x;
		pNext->y = ps->pSnake->y + 1;
		break;
	case LEFT:
		pNext->x = ps->pSnake->x - 2;
		pNext->y = ps->pSnake->y;
		break;
	case RIGHT:
		pNext->x = ps->pSnake->x + 2;
		pNext->y = ps->pSnake->y;
		break;
	}

	//蛇头下一步要走的坐标是否是食物
	if (NextIsFood(ps, pNext))
	{
		//是食物就吃掉
		EatFood(ps, pNext);
	}
	else
	{
		//不是食物就走一步
		NotEatFood(ps, pNext);
	}

	//检测撞墙
	KillByWall(ps);
	//检测撞自己
	KillBySelf(ps);
}

//游戏的运行过程
void GameRun(pSnake ps)
{
	//打印帮助信息
	PrintHelpInfo();

	do
	{
		//当前的分数情况
		SetPos(62, 10);
		printf("总分:%d", ps->Score);
		SetPos(62, 11);
		printf("食物的分值:%02d", ps->FoodWeight);
		
		//检测按键
		//上、下、左、右、ESC、空格、F3、F4
		if (KEY_PRESS(VK_UP) && ps->dir != DOWN)
		{
			ps->dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->dir != UP)
		{
			ps->dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->dir != RIGHT)
		{
			ps->dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->dir != LEFT)
		{
			ps->dir = RIGHT;
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			//退出游戏
			ps->status = ESC;
			break;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			//暂停游戏
			pause();
		}
		else if (KEY_PRESS(VK_F3))
		{
			//睡眠时间不能无限减小,控制一下
			if (ps->SleepTime >= 80)
			{
				//加速,休眠时间变短
				ps->SleepTime -= 30;
				//每个食物得分增加
				ps->FoodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_F4))
		{
			//睡眠时间不能无限减小,控制一下
			if (ps->FoodWeight > 2)
			{
				//减速,休眠时间变长
				ps->SleepTime += 30;
				//每个食物得分减少
				ps->FoodWeight -= 2;
			}
		}

		//睡眠一下
		Sleep(ps->SleepTime);
		
		//蛇的移动
		SnakeMove(ps);

	} while (ps->status == OK);
}





//游戏结束善后的善后工作
void GameEnd(pSnake ps)
{
	SetPos(20, 11);
	switch (ps->status)
	{
	case ESC:
		printf("正常退出\n");

		break;
	case KILL_BY_WALL:
		printf("很遗憾,撞墙了!游戏结束\n");
		break;
	case KILL_BY_SELF:
		printf("很遗憾,自杀了!游戏结束\n");
		break;
	}
	//释放贪吃蛇的链表资源
	pSnakeNode cur = ps->pSnake;
	pSnakeNode del = ps->pSnake;
	while (cur)
	{
		del = cur;
		cur = cur->next;
		free(del);
	}
	ps->pSnake = NULL;

	//释放食物节点
	free(ps->pFood);
	ps->pFood = NULL;

}

        test.c

#include"snack.h"

void test()
{
	int ch;//getchar()返回的是整形ASCII码值
	do
	{
		//创建贪吃蛇游戏
		Snake snake = { 0 };
		GameStart(&snake);//游戏开始前的初始化
		GameRun(&snake);//游戏的运行过程
		GameEnd(&snake);//游戏结束善后的工作

		SetPos(25, 15);
		printf("再来一局吗?(Y/N):>");
		ch = getchar();
		getchar();//清理缓冲区的\n
	} while (ch == 'Y');
}


int main()
{
	srand((unsigned int)time(NULL));

	//修改适配本地中文环境
	setlocale(LC_ALL, "");

	//贪吃蛇游戏的测试
	test();

	//控制程序退出结语的位置
	SetPos(0, 27);

	return 0;
}

8. 结语

        那么到此,贪吃蛇游戏就写好了,当然,这个游戏的功能还有美观度还有待各位共同开发,如果说想要给这个游戏图形化一下,大家可以去 easyX 看看EasyX Graphics Library for C++,把这个库下载下来应该就能在VS上用了

        同时,我们的C语言讲解就告一段落了,下一阶段我将着手数据结构的相关知识

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

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

相关文章

javaScript的序列化与反序列化

render函数的基本实现 javaScript的序列化与反序列化 一&#xff0c;js中的序列化二&#xff0c;序列化三&#xff0c;反序列化四&#xff0c;总结 一&#xff0c;js中的序列化 js中序列化就是对象转换成json格式的字符串&#xff0c;使用JSON对象的stringify方法&#xff0c;…

R-YOLO

Abstract 提出了一个框架&#xff0c;名为R-YOLO&#xff0c;不需要在恶劣天气下进行注释。考虑到正常天气图像和不利天气图像之间的分布差距&#xff0c;我们的框架由图像翻译网络&#xff08;QTNet&#xff09;和特征校准网络&#xff08;FCNet&#xff09;组成&#xff0c;…

vue3-深入组件-依赖注入

Prop 逐级透传问题 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。 如果是多层级嵌套的组件&#xff0c;如何从一级传递到 3 级甚至更远呢。 若使用 props 则必须将其沿着组件链逐级传递下去&#xff0c;这会非常麻烦&#xff0c;所…

canvas路径剪裁clip(图文示例)

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

jupyter notebook显示的扩展很少,只有四五个--解决方案

如下&#xff1a;安装好只有四五个扩展 可以先删除 conda remove jupyter_nbextensions_configurator 然后使用pip安装 pip install jupyter_contrib_nbextensions jupyter contrib nbextensions install --user pip install jupyter_nbextensions_configurator jupyter nbex…

MySQL-运维-主从复制

一、概述 二、原理 三、搭建 1、服务器准备 2、主库配置 &#xff08;1&#xff09;、修改配置文件/etc/my.cnf &#xff08;2&#xff09;、重启MySQL服务器 &#xff08;3&#xff09;、登录mysql&#xff0c;创建远程链接的账号&#xff0c;并授予主从复制权限 &#xff0…

Kafka-服务端-GroupCoordinator

在每一个Broker上都会实例化一个GroupCoordinator对象&#xff0c;Kafka按照Consumer Group的名称将其分配给对应的GroupCoordinator进行管理&#xff1b; 每个GroupCoordinator只负责管理Consumer Group的一个子集&#xff0c;而非集群中全部的Consumer Group。 请注意与Kaf…

华媒舍:10个与汽车媒体国外传播有关的方向

随着近年来汽车销售市场的不断增加与发展&#xff0c;汽车媒体国外传播已经成为汽车行业里至关重要的一环。下面我们就详细介绍10个与汽车媒体国外传播有关的发展方向&#xff0c;并讨论这些趋势对全世界汽车行业的影响。 1.智能化媒体的兴起伴随着互联网的发展与发展&#xff…

2024年第4届IEEE软件工程与人工智能国际会议(SEAI 2024)

2024年第4届IEEE软件工程与人工智能国际会议(SEAI 2024)将于2024年6月21-23日在中国厦门举办。 SEAI旨在为软件工程与人工智能领域搭建高端前沿的交流平台&#xff0c;推动产业发展。本次会议将汇聚海内外的知名专家、学者和产业界优秀人才&#xff0c;共同围绕国际热点话题、核…

地理坐标系、空间坐标系、epsg查询网站

坐标系可用范围和详细信息的查询网站 简介 epsg.ruiduobao.com是一个可以查询gdal中所有坐标系信息的网站&#xff0c;可查询到坐标系的基准面、椭球体、中央子午线等相关信息&#xff0c;并对每个坐标系的可用范围在地图中进行了显示。详细信息可以看操作视频&#xff1a; e…

bank conflict

前置知识&#xff1a; shared memory 被分成 32 个 bank一个 warp 32 个线程每个 bank 4 byte如果同一 warp 中不同线程访问同一 bank 的不同地址则发生 bank conflict 请注意需要是一个 warp 中的不同线程&#xff01;如果一个线程访问 shared memory 的两个元素&#xff0c;…

【ArcGIS Pro】从0开始

1.导入excel&#xff0c;需要安装驱动程序 安装用于 Microsoft Excel 文件的驱动程序 https://pro.arcgis.com/zh-cn/pro-app/latest/help/data/excel/prepare-to-work-with-excel-in-arcgis-pro.htm 2.修改投影坐标系 点到地图图标上&#xff0c;右键才能设置坐标系。 3.…

MSVC++远程调试

1. 介绍 MSVC的调试功能非常强大&#xff0c;可以下断点&#xff0c;单步调试&#xff0c;查看堆栈变量信息等。实际用于生产的电脑环境复杂&#xff0c;更容易发生Bug。生产电脑&#xff0c;由于各种原因有些可能无法安装MSVC用来现场调试。基于打印日志&#xff0c;查看日志…

Elasticsearch:将文档级安全性 (DLS) 添加到你的内部知识搜索

作者&#xff1a;来自 Elastic Sean Story 你的企业很可能淹没在内部数据中。 你拥有问题跟踪、笔记记录、会议记录、维基页面、视频录制、聊天以及即时消息和私信。 并且不要忘记电子邮件&#xff01; 难怪如此多的企业都在尝试创造工作场所搜索体验 - 为员工提供集中、一站…

如何部署Docker Registry并实现无公网ip远程连接本地镜像仓库

文章目录 1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址 Docker Registry 本地镜像仓库,简单几步结合cpolar内网穿透工具实现远程pull or push (拉取和推送)…

java程序读取并控制串口设备

监听串口&#xff0c;接收它们发过来的数据&#xff0c;进行处理。 一、概况 前不久做的一个项目&#xff0c;需要读取水下传感器的数据。这些传感器通过串口与外界交互。我们写了一个java程序&#xff0c;接收传感器传送的数据&#xff0c;同时也下发命令&#xff0c;控制部…

车载电子电器架构 —— IP地址获取策略

车载电子电器架构 —— IP地址获取策略 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自…

DHCP简介

定义 动态主机配置协议DHCP&#xff08;Dynamic Host Configuration Protocol&#xff09;是一种用于集中对用户IP地址进行动态管理和配置的技术。即使规模较小的网络&#xff0c;通过DHCP也可以使后续增加网络设备变得简单快捷。 DHCP是在BOOTP&#xff08;BOOTstrap Protoc…

WiFi 7 的核心要点

目录 WiFi 7 是什么&#xff1f; WiFi 7 的主要feature功能&#xff1a; 320Mhz channel 4K QAM Multi-Link Operation (MLO)&#xff0c;多链路操作 512 block ACK OFDMA&#xff1a;multiple RUs to single STA. 总结&#xff1a;性能是第一优先级&#xff0c;WiFi 7&#xf…

Java的JVM学习一

一、java中的内存结构如何划分 栈和堆的区别&#xff1a; 栈负责处理运行&#xff0c;堆负债处理存储。 区域名称作用虚拟机栈用于存储正在执行的每个Java方法&#xff0c;以及其方法的局部变量表等。局部变量表存放了便器可知长度的各种基本数据类型&#xff0c;对象引用&am…