贪吃蛇项目:GameRun与GameEnd部分:游戏的主体运行与善后部分

准备工作:打印得分信息

            在进行GameStart之前,我们需要在地图的右侧打印帮助信息,以及目前玩家的得分情况和一个食物在当前速度下的得分情况(加速的状态下按比例增加食物的分数,减速的状态下则相反),至于打印的方法,在上两篇文章中已经介绍完毕,这里我们直接给出实现代码:

void GameIntroduction()
{
	Set_Pos(65, 10);
	wprintf(L"↑ ↓ ← →进行移动\n");
	Set_Pos(65, 11);
	wprintf(L"退出游戏请按Esc\n");
	Set_Pos(65, 12);
	wprintf(L"暂停请按空格\n");
	Set_Pos(65, 13);
	wprintf(L"小键盘1,2键加减速\n");
}

void ScoreStat(pSnake ps)
{
	REPOSITION(63, 8);
	wprintf(L"当前总分数%d", ps->_Socre);
	REPOSITION(63, 7);
	wprintf(L"当前速度一个食物分数为%d", ps->_foodWeight);
}

void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
	} while (ps->_Status == OK);
}

           打印获得的成绩放在循环里面,则是因为每次玩家按完加减速之后,得分的权重都会改变,要实时更新。而我们的介绍信息则只需要打印一遍。

一,键位检测的实现

在此之前,我们要先定义一个宏:

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

            这里我们只需要知道它能检测键位是否被按过即可,不做过多介绍,如果想更为细节的了解,可以参考官网的解释:getAsyncKeyState 函数 (winuser.h) - Win32 apps | Microsoft Learn

接下来我们用多个if-else语句来实现玩家按下不同键位时的检测:

void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
		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_NUMPAD1))
		{
			if (ps->_SleepTime > 100)
			{
				ps->_SleepTime -= 50;
				ps->_foodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_NUMPAD2))
		{
			if (ps->_SleepTime < 500)
			{
				ps->_SleepTime += 50;
				ps->_foodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NOMAL;
			break;
		}
	} while (ps->_Status == OK);
}

           这里当玩家按上键时调整蛇的方向为上,但如果此时方向朝下调整方向为上,就会使蛇自己咬住自己。左右方向也是同理。下面为实现的暂停函数(Pause):

void Pause()
{
	while (!KEY_PRESS(VK_SPACE))
	{
		Sleep(200);
	}
}

当玩家在此按下空格键时,我们结束暂停的状态。

           当然,在每次检测完后,用Sleep函数暂停一下,至于暂停的时间,其实就是根据蛇的移动速度来设置:

Sleep(ps->_SleepTime);

二,蛇的移动函数的实现

2.1下一个位置节点的初始化

           我们这里使用SnakeMove来命名我们的移动函数。由于我们的链表需要使用malloc开辟,所以我们需要用malloc来开辟蛇的下一个位置的节点,当然在开辟完成后,我们还需要检验开辟是否成功:

	pSnakeNode NextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (NextNode == NULL)
	{
		perror("malloc():SnakeMove:NextNode");
		return;
	}

           我们已经知道,控制台的长宽之比为1 :2,所以,如果接下来蛇往左移动,则他的x坐标则需要增加两个字符位置,向上向下则只需要移动y一个字符位置即可:

NextNode->x = ps->_pSnake->x;
NextNode->y = ps->_pSnake->y;
NextNode->next = NULL;
switch (ps->_Dir)
{
	case RIGHT:
    {
		NextNode->x += 2;
		NextNode->y += 0;
		break;
	}
	case LEFT:
	{
		NextNode->x -= 2;
		NextNode->y += 0;
		break;
	}
	case UP:
	{
		NextNode->x += 0;
		NextNode->y += 1;
		break;
	}
	case DOWN:
	{
		NextNode->x += 0;
		NextNode->y -= 1;
		break;
	}
}

2.2判断下一个位置是否为食物

           接下来如果下一个位置为食物,或不为食物,我们也需要检测,首先我们设置一个函数NestIsFood来检验下一个位置是否为食物:

int NextIsFood(pSnakeNode psn, pSnake ps)
{
	return(psn->x == ps->_pFood->x && psn->y == ps->_pFood->y);
}

           直接返回值即可,如果下一个位置为食物,我们用EatFood函数将蛇的长度加一,否则我们使用NoFood来让蛇移动一格:

void EatFood(pSnake ps, pSnakeNode psn)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		Set_Pos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Socre += ps->_foodWeight;
	free(ps->_pFood);
	FoodInit(ps);
}
void NoFood(pSnake ps, pSnakeNode psn)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur->next->next)
	{
		Set_Pos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	REPOSITION(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

           这里我们说明一下NoFood函数中打印两个空格的原因,因为我们的蛇是通过打印移动的,所以当我们把NextNode节点接到蛇头上时,我们需要把最后一个节点删除,但仔细思考一下,上回打印蛇身的字符是否还会保留,这会使它遗留在屏幕上。所以我们要打印两个空格(因为我们的蛇身为宽字符占两个字节)将其从屏幕上抹除。

2.3判断蛇是否咬住自身或撞墙

           这里我们用两个函数KillByWall,KillBySelf来分别表示蛇是否撞墙,蛇是否咬住自己。是否撞墙我们只需要判断蛇头位置是否与墙体位置重合,而是否咬住自己只需要判断蛇头位置是否与自身的其他部分重合:

int KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake->next;
	while (cur)
	{
		if ((ps->_pSnake->x == cur->x) && (ps->_pSnake->y == cur->y))
		{
			ps->_Status = KILL_BY_SELF;
			return 1;
		}
		cur = cur->next;
	}
	return 0;
}

int 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;
		return 1;
	}
	return 0;
}

           其实设置为void类型也可以,不过为了区分情况,方便起见,我用返回1或0来区分是否撞墙(咬自己)。

2.4GameRun部分代码

void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
		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_NUMPAD1))
		{
			if (ps->_SleepTime > 100)
			{
				ps->_SleepTime -= 50;
				ps->_foodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_NUMPAD2))
		{
			if (ps->_SleepTime < 500)
			{
				ps->_SleepTime += 50;
				ps->_foodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NOMAL;
			break;
		}
		Sleep(ps->_SleepTime);
		SnakeMove(ps);
	} while (ps->_Status == OK);
}

2.5SnakeMove部分代码

void SnakeMove(pSnake ps)
{
	pSnakeNode NextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (NextNode == NULL)
	{
		perror("malloc():SnakeMove:NextNode");
		return;
	}
	NextNode->x = ps->_pSnake->x;
	NextNode->y = ps->_pSnake->y;
	NextNode->next = NULL;
	switch (ps->_Dir)
	{
		case RIGHT:
	    {
			NextNode->x += 2;
			NextNode->y += 0;
			break;
		}
		case LEFT:
		{
			NextNode->x -= 2;
			NextNode->y += 0;
			break;
		}
		case UP:
		{
			NextNode->x += 0;
			NextNode->y += 1;
			break;
		}
		case DOWN:
		{
			NextNode->x += 0;
			NextNode->y -= 1;
			break;
		}
	}
	if (NextIsFood(NextNode,ps))
	{
		EatFood(ps, NextNode);
	}
	else
	{
		NoFood(NextNode,ps);
	}

	KillByWall(ps);
	KillBySelf(ps);
}

三,GameEnd部分

           这一部分其实没有什么好说的,因为我们上面的代码已经将蛇的状态信息设置好了,所以我们这里只需要根据上面储存进去的信息来打印我们目前的游戏状态即可:

void GameEnd(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake;
	Set_Pos(24, 12);
	switch (ps->_Status)
	{
	case END_NOMAL:
		printf("你主动退出游戏\n");
		break;
	case KILL_BY_SELF:
		printf("你咬到自己了 ,游戏结束!\n");
		break;
	case KILL_BY_WALL:
		printf("你撞墙了,游戏结束!\n");
		break;
	}
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}

四,完整游戏代码

4.1Snake.h

#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <windows.h>
#include <stdlib.h>
#include <locale.h>
#include <time.h>

#define WALL L'□'
#define FOOD L'★'
#define BODY L'●'
#define POS_X 24
#define POS_Y 5

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

typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;

typedef struct Snake
{
	pSnakeNode _pSnake;//维护整条蛇的指针
	pSnakeNode _pFood;//维护⻝物的指针
	enum DIRECTION _Dir;//蛇头的⽅向,默认是向右
	enum GAME_STATUS _Status;//游戏状态
	int _Socre;//游戏当前获得分数
	int _foodWeight;//默认每个⻝物10分
	int _SleepTime;//每⾛⼀步休眠时间
}Snake, * pSnake;

enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};

enum GAME_STATUS
{
	OK,//正常运⾏
	KILL_BY_WALL,//撞墙
	KILL_BY_SELF,//咬到⾃⼰
	END_NOMAL//正常结束
};

void REPOSITION(short x, short y);//调整输入的光标位置

void WelcomeMenu();//设置欢迎与介绍菜单

void GameMap();//设置游戏地图

void GameIntroduction();//设置在游戏过程中的提醒

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

void SnakeInit(pSnake ps);//蛇身的初始化

void FoodInit(pSnake ps);//初始化食物

void GameRun(pSnake ps);//游戏主体运行部分

void ScoreStat(pSnake ps);//分数统计

void Pause();//空格暂停

void SnakeMove(pSnake ps);//控制蛇移动的函数

int NextIsFood(pSnakeNode psn, pSnake ps);//判断下一个位置是否为食物

void EatFood(pSnake ps, pSnakeNode psn);//是食物的情况下吃掉食物

void NoFood(pSnakeNode psn, pSnake ps);//非食物的情况下进行移动

int KillBySelf(pSnake ps);

int KillByWall(pSnake ps);

void GameEnd(pSnake ps);

4.2Snake.c

           这里面的设置位置函数是REPOSITION(这是我第一遍做成功的代码,至于文章里面Set_Pos是我为了写文章又重新写了一遍代码)。

#include "snake.h"

void REPOSITION(short x, short y)
{
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput,pos);
}

void WelcomeMenu()
{
	REPOSITION(35, 10);
	wprintf(L"欢迎来到贪吃蛇小游戏");
	REPOSITION(35, 20);
	system("pause");
	system("cls");
	REPOSITION(35, 10);
	wprintf(L"按 ↑ ↓ ← →键操控贪吃蛇移动\n");
	REPOSITION(35, 11);
	wprintf(L"按小键盘‘1’或‘2’键加速或减速\n");
	REPOSITION(35, 12);
	wprintf(L"Tips:加速吃食物有额外分数加成");
	REPOSITION(35, 20);
	system("pause");
	system("cls");
}


void GameMap()
{
	REPOSITION(0, 0);
	int i = 0;
	for (; i < 58; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	REPOSITION(0, 26);
	for (i = 0; i < 58; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	for (i = 1; i < 26; i++)
	{
		REPOSITION(0, i);
		wprintf(L"%lc", WALL);
	}
	for (i = 1; i < 26; i++)
	{
		REPOSITION(56, i);
		wprintf(L"%lc", WALL);
	}
}


void GameIntroduction()
{
	REPOSITION(65, 10);
	wprintf(L"↑ ↓ ← →进行移动\n");
	REPOSITION(65, 11);
	wprintf(L"退出游戏请按Esc\n");
	REPOSITION(65, 12);
	wprintf(L"暂停请按空格\n");
	REPOSITION(65, 13);
	wprintf(L"小键盘1,2键加减速\n");
}


void GameStart(pSnake ps)
{
	srand((unsigned int)time(NULL));
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo = { 25,false };
	SetConsoleCursorInfo(houtput, &CursorInfo);
	WelcomeMenu();
	GameMap();
	SnakeInit(ps);
	FoodInit(ps);
}

void SnakeInit(pSnake ps)
{
	int i = 0;
	pSnakeNode cur = NULL;
	for (i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("SnakeInit():malloc()cur:");
			return;
		}
		cur->next = NULL;
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;
		if (ps->_pSnake == NULL)
		{
			ps->_pSnake = cur;
		}
		else
		{
			cur->next = ps->_pSnake;
			ps->_pSnake = cur;
		}
	}
	cur = ps->_pSnake;
	while (cur)
	{
		REPOSITION(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Dir = RIGHT;
	ps->_foodWeight = 10;
	ps->_SleepTime = 300;
	ps->_Socre = 0;
	ps->_Status = OK;
}


void FoodInit(pSnake ps)
{
	int x = 0;
	int y = 0;
	again:
	do
	{
		x = rand()%53 + 2;
		y = rand()%24 + 1;
	} while (x % 2 != 0);
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		if (cur->x == x && cur->y == y)
		goto again;
		cur = cur->next;
	}
	pSnakeNode cur2 = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (cur2 == NULL)
	{
		perror("malloc():FoofInit:cur2:");
		return;
	}
	cur2->next = NULL;
	cur2->x = x;
	cur2->y = y;
	REPOSITION(x, y);
	wprintf(L"%lc", FOOD);
	ps->_pFood = cur2;
	cur2 = NULL;
}

void ScoreStat(pSnake ps)
{
	REPOSITION(63, 8);
	wprintf(L"当前总分数%d", ps->_Socre);
	REPOSITION(63, 7);
	wprintf(L"当前速度一个食物分数为%d", ps->_foodWeight);
}

void Pause()
{
	while (!KEY_PRESS(VK_SPACE))
	{
		Sleep(200);
	}
}

int NextIsFood(pSnakeNode psn, pSnake ps)
{
	return(psn->x == ps->_pFood->x && psn->y == ps->_pFood->y);
}

void EatFood(pSnake ps,pSnakeNode psn)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		REPOSITION(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Socre += ps->_foodWeight;
	free(ps->_pFood);
	FoodInit(ps);
}

void NoFood(pSnakeNode psn,pSnake ps)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur->next->next)
	{
		REPOSITION(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	REPOSITION(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

int 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;
		return 1;
	}
	return 0;
}

int KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake->next;
	while (cur)
	{
		if ((ps->_pSnake->x == cur->x)&& (ps->_pSnake->y == cur->y))
		{
			ps->_Status = KILL_BY_SELF;
			return 1;
		}
		cur = cur->next;
	}
	return 0;
}

void SnakeMove(pSnake ps)
{
	pSnakeNode NextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (NextNode == NULL)
	{
		perror("malloc():SnakeMove:NextNode");
		return;
	}
	NextNode->x = ps->_pSnake->x;
	NextNode->y = ps->_pSnake->y;
	NextNode->next = NULL;
	switch (ps->_Dir)
	{
		case RIGHT:
	    {
			NextNode->x += 2;
			NextNode->y += 0;
			break;
		}
		case LEFT:
		{
			NextNode->x -= 2;
			NextNode->y += 0;
			break;
		}
		case UP:
		{
			NextNode->x += 0;
			NextNode->y += 1;
			break;
		}
		case DOWN:
		{
			NextNode->x += 0;
			NextNode->y -= 1;
			break;
		}
	}
	if (NextIsFood(NextNode,ps))
	{
		EatFood(ps, NextNode);
	}
	else
	{
		NoFood(NextNode,ps);
	}

	KillByWall(ps);
	KillBySelf(ps);
}


void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
		if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
		{
			ps->_Dir = DOWN;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
		{
			ps->_Dir = UP;
		}
		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_NUMPAD1))
		{
			if (ps->_SleepTime > 100)
			{
				ps->_SleepTime -= 50;
				ps->_foodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_NUMPAD2))
		{
			if (ps->_SleepTime < 500)
			{
				ps->_SleepTime += 50;
				ps->_foodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NOMAL;
			break;
		}
		Sleep(ps->_SleepTime);
		SnakeMove(ps);
	} while (ps->_Status == OK);
}

void GameEnd(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake;
	REPOSITION(24, 12);
	switch (ps->_Status)
	{
	case END_NOMAL:
		printf("你主动退出游戏\n");
		break;
	case KILL_BY_SELF:
		printf("你咬到自己了 ,游戏结束!\n");
		break;
	case KILL_BY_WALL:
		printf("你撞墙了,游戏结束!\n");
		break;
	}
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}

4.3test.c

#include "snake.h"

void test()
{
	int ch = 0;
	do
	{
		Snake snake = { 0 };
		GameStart(&snake);//游戏初始化
		GameRun(&snake);//游戏运行
		GameEnd(&snake);//游戏的善后处理
		REPOSITION(20, 15);
		printf("再来一局吗?(y/n):");
		ch = getchar();
		getchar();
	} while (ch == 'y');
	system("cls");
}

int main()
{
	setlocale(LC_ALL, "");
	test();
	return 0;
}

           贪吃蛇的内容到这里就完结了,至于下一次更新要到7月10号左右了(一是过暑假了想摸会鱼,二是在c语言准备开数据结构的新坑),我们下篇文章见。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第 27 篇 : 搭建maven私服nexus

官网文档 1. 下载应该很慢, 最好是能翻墙 nexus-3.69.0-02-java8-unix.tar.gz 2. 上传到/usr/local/src, 解压及重命名 tar -zxvf nexus-3.69.0-02-java8-unix.tar.gz rm -rf nexus-3.69.0-02-java8-unix.tar.gz mv nexus-3.69.0-02 nexus ls3. 修改配置 cd /usr/local/sr…

人工智能与大数据:新时代的技术融合与未来展望

引言 在信息化和数字化迅猛发展的今天&#xff0c;人工智能&#xff08;AI&#xff09;和大数据&#xff08;Big Data&#xff09;已成为推动社会变革和技术进步的两大支柱。随着互联网的普及、计算能力的提升以及数据获取手段的多样化&#xff0c;AI和大数据技术的应用愈发广泛…

GD32调试篇:ST-LINK utility工具下载安装

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 向上代码兼容GD32F450ZGT6中使用 后续项目主要在下面该专栏中发布&#xff1a; https://blog.csdn.net/qq_62316532/category_12608431.html?spm1001.2014.3001.5482 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转…

怎么打印加密的pfd文件,有那些方法?

现在人们的保密意识越来越强了,越来越多的人在完成pdf文档后就会对文档进行保护&#xff0c;但有的PDF文档被添加了密码&#xff0c;限制了打印的权限&#xff0c;导致我们想打印PDF文档的时候就提示我们要输入密码。面对这种情况&#xff0c;我们要怎样才能把PDF文档打印出来呢…

Blast L2空投教学,好用的Blast钱包推荐bitget

什么是 Blast L2&#xff1f; Blast&#xff08;web3.bitget.com/en/&#xff09;是一个与 EVM 兼容的第 2 层 (L2) 区块链网络&#xff0c;旨在通过原生收益产生收益。该项目由匿名联合创始人 PacmanBlur 领导&#xff0c;并已成功从 Paradigm 和 Standard Crypto 等知名投资…

计算机网络面试TCP篇之TCP三次握手与四次挥手

TCP 三次握手与四次挥手面试题 任 TCP 虐我千百遍&#xff0c;我仍待 TCP 如初恋。 巨巨巨巨长的提纲&#xff0c;发车&#xff01;发车&#xff01; PS&#xff1a;本次文章不涉及 TCP 流量控制、拥塞控制、可靠性传输等方面知识&#xff0c;这些知识在这篇&#xff1a; TCP …

【编译原理】绪论

1.计算机程序语言以及编译 编译是对高级语言的翻译 源程序是句子的集合&#xff0c;树可以较好的反应句子的结构 编译程序是一种翻译程序 2.编号器在语言处理系统中的位置 可重定位&#xff1a;在内存中存放的起始位置不是固定的 加载器&#xff1a;修改可重定位地址&#x…

Element 页面滚动表头置顶

在开发后台管理系统时&#xff0c;表格是最常用的一个组件&#xff0c;为了看数据方便&#xff0c;时常需要固定表头。 如果页面基本只有一个表格区域&#xff0c;我们可以根据屏幕的高度动态的计算出一个值&#xff0c;给表格设定一个固定高度&#xff0c;这样表头就可以固定…

File类和IO流

File类和IO流 文章目录 File类和IO流[TOC](文章目录)前言一、java.io.File类&IO流原理及流的分类1.1 File类及其API1.2 IO流原理及分类 二、节点流的介绍&#xff08;字符/字节&#xff09;2.1 Reader\Writer--字符IO抽象基类2.2 FileReader\FileWriter--字符IO节点流2.3 I…

[leetcode]assign-cookies. 分发饼干

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(), g.end());sort(s.begin(), s.end());int m g.size(), n s.size();int count 0;for (int i 0, j 0; i…

代码随想录算法训练营第50天(py)| 动态规划 | 1143.最长公共子序列、1035.不相交的线、53. 最大子序和、392.判断子序列

1143.最长公共子序列 力扣链接 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列&#xff08;未必连续&#xff09; 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 思路 确定dp含义 dp[i][j]&#xff1a;长度为[0,i-1]和[0,j-1]的最长公…

Redis-实战篇-缓存雪崩

文章目录 1、缓存雪崩2、解决方案&#xff1a; 1、缓存雪崩 缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机&#xff0c;导致大量请求到达数据库&#xff0c;带来巨大压力。 2、解决方案&#xff1a; 给不同的key的TTL添加随机值利用Redis集群提高服务的可用性…

0.7 模拟电视标准 PAL 简介

0.7 模拟电视标准PAL PAL 是一种用于模拟电视的彩色编码系统&#xff0c;全名为逐行倒相&#xff08;Phase Alternating Line&#xff09;。它是三大模拟彩色电视标准之一&#xff0c;另外两个标准是 NTSC 和 SECAM。“逐行倒相”的意思是每行扫描线的彩色信号会跟上一行倒相&…

Axure 教程 | 雅虎新闻焦点

主要内容 在雅虎首页&#xff0c;新闻焦点大图和焦点小图同步切换轮播&#xff0c;本课程我们来学习如何实现这个效果。 交互说明 1.页面载入后&#xff0c;切换当前屏幕显示的5张焦点图&#xff0c;小图标处以横线提示当前焦点图。 2.鼠标移入焦点大图&#xff0c;新闻标题显示…

用两个钟,我又在VMWARE上搞了一套内部网配置

最近要学es&#xff0c;所以打算自己用虚拟机搞个NAT&#xff0c;又搞了两个钟。为了不再费劲尝试&#xff0c;也为了造福大众&#xff0c;所以选择搞一份NAT笔记&#xff01;&#xff01;&#xff01;&#xff01; 1.初始化网关和DNS 我们给网关配置一个地址192.168.96.1&…

发包真香之:scapy工具

scapy – python 可自由组包 参考学习&#xff1a;初识Scapy–Python的Scapy/Kamene模块学习之路 scapy 介绍 Scapy是基于Python语言的网络报文处理程序&#xff0c;它可以让用户发送、嗅探、解析、以及伪造网络报文&#xff0c;运用Scapy可以进行网路侦测、端口扫描、路由追…

【手眼标定】使用kalibr对imu和双目摄像头进行联合标定

使用kalibr对imu和双目摄像头进行联合标定 前言一、IMU标定二、双目摄像头标定三、手眼标定&#xff08;imu和双目摄像头的联合标定&#xff09; 前言 由于本文的imu、双目摄像头都是在ros2环境下开发&#xff0c;数据传输自然也是在ros2中。 但想要使用kalibr进行标定&#x…

Power BI 插件 DAX Studio 安装配置

1&#xff0c;dax studio 下载地址 DAX Studio | DAX Studio 2&#xff0c;安装配置&#xff08;几乎是默认&#xff09; 3&#xff0c;使用方法 打开DAX studio 默认支持Power povit, PBI/SSDT ,Tabular server。先打开PBI再打开DAX studio &#xff0c;不然如果只打开Dax …

ios18开发者预览,Beta 2升级新增镜像等功能

近日&#xff0c;苹果发布了 iOS 18 开发者预览版 Beta 2 升级&#xff0c;为 iPhone 用户带来了多项新功能。据了解&#xff0c;这些新功能包括 iPhone 镜像和 SharePlay 屏幕共享&#xff0c;以及其他新增功能。 据了解&#xff0c;iPhone镜像可以让Mac用户将iPhone屏幕镜像…

IPFoxy Tips:匿名海外代理IP的使用方法及注意事项

在互联网上&#xff0c;隐私和安全问题一直备受关注。为了保护个人隐私和数据安全&#xff0c;使用匿名代理IP是一种常用的方法。匿名代理IP可以隐藏用户的真实IP地址&#xff0c;使用户在访问网站时更加隐秘和安全。 本文将介绍匿名代理IP的基本原理和核心功能。 基本原则 匿…