贪吃蛇的实现,基于windows操作系统

前言:

贪吃蛇从学习到真正实现花了9天实现,第一二天第一次学习,第三四五天第二次学习,第六七八天一边实现一边思考,才完成了贪吃蛇的代码。实现了贪吃蛇以后已经接近过年,我想自己再根据掌握的知识制作烟花燃烧绽放的场景。贪吃蛇的移动和烟花的移动原理是一样的,贪吃蛇的头插删尾,使我能够处理烟花消失的部分。在我花两天时间写完500行的烟花代码后,对贪吃蛇的实现原理也更加了解了。然后再写下这篇文章。

写作过程中遇到的问题:有很多,但最多的是,写着写着不知道当前要实现什么。思路不清晰。然后去看正确的代码。以及对指针的掌握不够,要使用的函数比较生疏,令人烦躁,静不下心去理解等等。之后通过各种途径一一克服了。

一、分析和规划贪吃蛇的思路

1.一个已经懂得贪吃蛇怎样写的人和一个从没写过贪吃蛇怎么写,第一次上手的思维是不一样的。但是第一部应该都需要了解自己要实现哪些功能。然后划分为不同阶段逐个完成。

2.根据想要制作的成品模样,画出草图和X-mind思维导图。

                                                          成图1,欢迎页面一

                                                        成图2,欢迎页面二

                                                      成图3,游戏页面

     根据贪吃蛇游戏框,绘出墙体食物和蛇。

接下来是X-mind思维导图,写出整个程序的脉络。然后一一落实。

二、落实想法

1.建立三个文件。snake.c  snake.h  test.c.

2.贪吃蛇有两个结构体。

一个是蛇身,它是由一个个结点组成。

这个结点里放蛇身的坐标和下一个结点的指针,记住下一个结点的位置。放坐标是因为蛇在移动的时候要打印蛇身,蛇身的位置是依靠坐标来确定的,这样打印的时候就能找到蛇身的位置了。

这个蛇身由单向不带头不循环链表----单链表构成。

创建一个结构体,以及一个指向结构体的指针并将它们重命名。

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

另一个用来维护蛇。如思维导图中写的思路所示。

typedef struct Snake
{
   pSnakeNode sn;  //指向蛇头的指针
   pSnakeNode pfood;//指向食物的指针,本质上和蛇身没什么区别,只是它是单个的,没有链。
   int score;   //分数,每次吃食物要涨粉
   int foodweight;//当前每吃一个食物增加的分数
   enum DIRECTION;//方向
   enum STATUS;//状态
   int sleeptime;//速度
}Snake,*psnake;//重命名

3.三个文件代码附上

snake.h

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#pragma once
#include <locale.h>
#include <windows.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <math.h>

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

//监测按键
#define KEY_STATE(vkey)   ((GetAsyncKeyState(vkey)&0x1)?(1):(0))
//蛇头方向
enum DIRICTION
{
	UP=1,
	DOWN,
	LEFT,
	RIGHT
};
//游戏状态
enum STATUS
{
	OK=1,
	KILL_BY_SELF,
	KILL_BY_WALL,
	ESC
};

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

//蛇的维护
typedef struct Snake
{
	pSnakeNode sn;//蛇身,是一个结构体指针
	pSnakeNode pfood;//也是一个结构体指针,它是一个坐标
	enum DIRICTION Dir;//蛇的方向
	enum STATUS Status;//蛇的状态
	int Score;//游戏当前得分
	int Foodweight;//食物的分数
	int Sleeptime;//走一步睡眠时间,和蛇速相关
}Snake,*pSnake;

//游戏开始前的准备工作
void GameStart(pSnake snake);

//玩游戏
void GameRun(pSnake snake);
//
游戏结束
//void GameEnd();

snake.c

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include "snake.h"

//把光标移动到想要的位置
void SetPos(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);
}

void Welcometogame()
{
	SetPos(38, 13);
	printf("欢迎来到贪吃蛇小游戏\n");
    
	SetPos(60, 25);
	system("pause");
	system("cls");
	//打印游戏说明
	SetPos(25, 12);
	printf("用↑.↓.←.→分别控制蛇的移动,F3为加速,F4为减速\n");
	SetPos(25, 13);
	printf("加速能得到更高的分数。\n");
	SetPos(60, 25);
	system("pause");
	system("cls");
}

//初始化蛇身
void InitSnake(pSnake snake)
{
	for (int i = 0; i < 5; i++)
	{
		pSnakeNode p = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (p == NULL)
		{
			perror("malloc failed!\n");
			exit(1);
		}
		p->x = 20+2*i;
		p->y = 6;
		p->next = NULL;

		//头插法
		if (snake->sn==NULL)
		{
			snake->sn = p;
		}
		else
		{
			p->next = snake->sn;
			snake->sn = p;
		}

		//打印蛇身,用循环
		/*if (p)
		{
			SetPos(p->x, p->y);
			wprintf(L"%lc", SNAKE);
		}*/
		while (p)
		{
			SetPos(p->x, p->y);
			wprintf(L"%lc", SNAKE);
			p = p->next;
		}
	}
	//其他信息初始化
	snake->Dir = RIGHT;
	snake->Foodweight = 10;
	snake->pfood = NULL;
	snake->Score = 0;
	snake->Sleeptime = 200;
	snake->Status = OK;
	
}

void CreatMap()
{
	int i = 0;
	for (i = 0; i < 57; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	
	for (i = 0; i <= 26; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc\n", WALL);
	}
	SetPos(0, 26);
	for (i = 0; i < 57; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, 1);
	for (i = 0; i <= 25; i++)
	{
		wprintf(L"%lc\n", WALL);
	}
}

void CreatFood(pSnake snake)
{
	int x = 0;
	int y = 0;
again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 24 + 1;
	} while (x % 2 != 0);

	//不能在蛇身上
	pSnakeNode cur = snake->sn;
	while (cur)
	{
		if (cur->x != x || cur->y != y)
		{
			cur = cur->next;
		}
		else
		{
			goto again;
		}
	}

	//申请食物的结点
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("malloc failed!\n");
		exit(1);
	}
	pFood->x = x;
	pFood->y = y;

	snake->pfood = pFood;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);

}
//游戏开始前的准备工作
void GameStart(pSnake snake)
{
	//设置一下控制台大小 
	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();
	//绘制地图
	CreatMap();
	//初始化蛇身
	InitSnake(snake);
	//打印食物
	CreatFood(snake);

}

void PrintHelpInfo()
{
	SetPos(61, 16);
	printf("1.不能撞墙,不能咬到自己\n");
	SetPos(61, 17);
	printf("2.用↑.↓.←.→分别控制蛇的移动\n");
	SetPos(61, 18);
	printf("3.F3为加速,F4为减速\n");
	SetPos(61, 19);
	printf("4.加速可以获得更多分数\n");
	SetPos(80, 22);
	printf("制作者:真白");
}

void EatFood(pSnake snake, pSnakeNode pnext)
{
	//吃食物,则头插
	pnext->next = snake->sn;//食物的下一个结点连接蛇头
	snake->sn = pnext;//把食物的结点给蛇头
	
	//打印蛇身
	pSnakeNode cur = snake->sn;//创建一个cur指针来循环
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", SNAKE);
		cur = cur->next;
	}
	//分数变化
	snake->Score += snake->Foodweight;
	//释放旧的食物结点
	free(snake->pfood);
	
	//创建新的食物结点
	CreatFood(snake);
}

void NotEatFood(pSnake snake,pSnakeNode pnext)
{
	//正常走,头插,删尾
	pnext->next = snake->sn;
	snake->sn = pnext;

	//删尾,创建一个指针循环
	pSnakeNode cur = snake->sn;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);//先设置坐标再打印
		wprintf(L"%lc", SNAKE);//打印蛇身
		cur = cur->next;
	}
	SetPos(cur->next->x, cur->next->y);//先设置坐标再打印尾处的空白
	printf("  ");
	free(cur->next);//释放尾结点
	cur->next = NULL;
}

void IsItFood(pSnake snake, pSnakeNode pnext)
{
	if (pnext->x == snake->pfood->x && pnext->y == snake->pfood->y)
	{
		//是食物,吃掉
		EatFood(snake,pnext);
	}
	else
	{
		//不是食物,不吃
		NotEatFood(snake,pnext);
	}
}

void KillByWall(pSnake snake, pSnakeNode pnext)
{
	//下一个结点的位置是不是墙的坐标
	if (pnext->x == 0 || pnext->y == 0 || pnext->x == 56 || pnext->y==26)
	{
		snake->Status = KILL_BY_WALL;
	}
}
void KillBySelf(pSnake snake, pSnakeNode pnext)
{
	//下一个结点是不是蛇身
	pSnakeNode cur = snake->sn->next;
	while (cur)
	{
		if (pnext->x != cur->x || pnext->y != cur->y)
		{
			cur = cur->next;
		}
		else 
		{
			snake->Status = KILL_BY_SELF;
			break;
		}
	}

}

void SleepTime(pSnake snake)
{
	Sleep(snake->Sleeptime);
}
void Snakemove(pSnake snake)
{
	//创建蛇的下一个位置的结点
	pSnakeNode pnext = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pnext == NULL)
	{
		perror("Snakemove:: malloc");
		return;
	}
	pnext->next = NULL;//只需要这个结点,不需要它下一个结点的信息

	//安排pnext的坐标
	switch (snake->Dir)
	{
	case UP: pnext->x = snake->sn->x;
		     pnext->y = snake->sn->y - 1;//如果按了上,下一个坐标的位置就在蛇头的上面
		break;
	case DOWN: pnext->x = snake->sn->x;
		       pnext->y = snake->sn->y + 1;//同上,下面同上
		break;
	case LEFT:pnext->x = snake->sn->x - 2;
		      pnext->y = snake->sn->y;
		break;
	case RIGHT:pnext->x = snake->sn->x + 2;
		       pnext->y = snake->sn->y;
		break;
	}

	//判断下一个结点是否是食物
	IsItFood(snake, pnext);

	//判断下一个节点是否撞墙
	KillByWall(snake,pnext);

	//判断下一个节点是否咬到自己
	KillBySelf(snake,pnext);
    
}
void Pause()
{
	while (1)
	{
		Sleep(200);
		if (KEY_STATE(VK_SPACE) == 1)
		{
			break;
		}
	}
}

void F3(pSnake snake)
{
	//休眠时间限制,5档 200,170,140,110,80
	if (snake->Sleeptime <= 200 && snake->Sleeptime >= 110)
	{
		snake->Sleeptime -= 30;
		snake->Foodweight += 2;
	}
}

void F4(pSnake snake)
{
	if (snake->Sleeptime >= 80 && snake->Sleeptime <= 170)
	{
		snake->Sleeptime += 30;
		if (snake->Foodweight >= 4)
		{
			snake->Foodweight -= 2;
		}
	}
}
//玩游戏
void GameRun(pSnake snake)
{
	//打印帮助信息
	PrintHelpInfo();

	do
	{
		//当前分数情况
		SetPos(60, 10);
		printf("得分:%d  ", snake->Score);
		printf("每个食物得分:%02d\n", snake->Foodweight);

		//监测当前按键情况
		
		if (KEY_STATE(VK_UP) == 1 && snake->Dir != DOWN)
		{
			snake->Dir = UP; 
		}
		else if(KEY_STATE(VK_DOWN) == 1&& snake->Dir != UP)
		{
			snake->Dir = DOWN;
		}
		else if (KEY_STATE(VK_LEFT) == 1&& snake->Dir != RIGHT)
		{
			snake->Dir = LEFT;
		}
		else if (KEY_STATE(VK_RIGHT) == 1&& snake->Dir != LEFT)
		{
			snake->Dir = RIGHT;
		}
		else if (KEY_STATE(VK_ESCAPE) == 1)
		{
			snake->Status = ESC;
			break;
		}
		else if (KEY_STATE(VK_SPACE) == 1)
		{
			Pause();
		}
		else if (KEY_STATE(VK_F3) == 1)
		{
			F3(snake);
		}
		else if (KEY_STATE(VK_F4) == 1)
		{
			F4(snake);
		}
		

		
		//蛇的移动
		Snakemove(snake);

		//移动一个位置,休眠一下
		SleepTime(snake);

	} while(snake->Status==OK);

}

void GameEnd(pSnake snake)
{
	SetPos(15, 12);
	switch (snake->Status)
	{
	case ESC:
		printf("主动退出游戏,正常退出\n");
		break;
	case KILL_BY_WALL:
		printf("很遗憾,你撞墙了,游戏结束\n");
		break;
	case KILL_BY_SELF:
		printf("很遗憾,你咬到自己了,游戏结束\n");
		break;
		}
	pSnakeNode cur = snake->sn;
	pSnakeNode del = NULL;

	while (cur)
	{
		del = cur;
		cur = cur->next;
		free(del);
	}

	free(snake->pfood);
	snake = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include "snake.h"


void test()
{
	int ch = 0;
	do
	{
		Snake s1 = { 0 };
		GameStart(&s1);
		GameRun(&s1);
		GameEnd(&s1);
		SetPos(15, 14);
		printf("再玩一把吗?Y/N :");
		ch = getchar();
		getchar();
	

	} while (ch == 'Y' || ch == 'y');
	
}

//
int main()
{
	setlocale(LC_ALL, "");//本地化,头文件<locale.h>
	test();
	
	
	SetPos(0, 27);
	return 0;

}




三、整个贪吃蛇实现的难点

1.windows系统提供的API的一些接口和功能。

在学C语言的时候没有接触,所以要了解一下需要掌握的函数用法。

如何修改控制台的大小?

通过包含windows.h的库函数,可以使用windows命令提示符的一些命令。来达到修改控制台大小的效果。在程序结束前,都是这个大小。system("mode con cols 100 lines 30")

同样的,修改控制台的标题也是利用windows命令提示符的一些命令来修改。

如何隐藏光标?

首先是要获得控制台的句柄。句柄就相当于控制台的钥匙,获取句柄,就是获取这个控制台的信息,(这些信息使得这个控制台与其他控制台相区别)我们得到的这个控制台的句柄,只能操作这个控制台的独特信息,不能修改其他控制台的独特信息。提供的函数是GetStdHandle,它有一个参数,但可以选择填入的参数有三个,为了获取句柄,填入的是STD_OUTPUT_HANDLE。这个函数返回的类型是HANDLE。因此也要创建一个HANDLE 类型的变量来接收返回的句柄。

    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 
    CONSOLE_CURSOR_INFO Cursorinfo;      创造一个光标的变量,前面是类型,后面是变量,这是在下一句获取光标信息要用到。提前创建一个变量。
    GetConsoleCursorInfo(handle, &Cursorinfo);    传本控制台的句柄和一个光标变量的地址。传入这两个变量以后,就能获取本控制台的光标信息。本控制台的光标信息,会被复制到Cursorinfo这个变量上。
    Cursorinfo.bVisible = false; 这个Cursorinfo是一个结构体变量,它有两个成员,一个是光标占一个坐标的比例(0-100)。第二个是是否可见。把bVisible设置为ture就是可见,false就是不可见。通过这一步,就把光标设置为隐藏。
    SetConsoleCursorInfo(handle, &Cursorinfo);这个函数是设置光标信息。传入本控制台的句柄,再把设置好的光标信息传进去。从而改变本控制台的光标。

如何设置坐标位置?

首先,什么是坐标?

以此图为例,x坐标是横坐标,从左向右延申,y坐标是纵坐标,从上至下延申,第一个位置是原点。

如何设置坐标位置:

void SetPos(int x, int y)  只要传入坐标的位置,就可以把光标移到想要的地方。把他封装成一个函数
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);    获取本控制台的句柄,因为把光标移到指定坐标(的函数)也需要本控制台的句柄(作为它的参数)。
    COORD pos = { x,y }; 这是一个坐标的结构体,COORD是一个结构体类型,里面是坐标的参数。这一步是设置pos作为一个结构体坐标变量,成员初始化为x,y。
    SetConsoleCursorPosition(handle, pos);这是一个设置光标位置的函数,需要传两个参数,一个是本控制台句柄,一个是指定的坐标信息。
}

通过这些代码就可以把光标移动到指定位置,然后在指定位置打印出想要的信息。

2.绘制地图

地图的墙是宽字符,打印宽字符要先本地化。使用的函数是wprintf,w表示wide的意思。

3.初始化蛇身

初始化蛇身需要做到申请蛇的结点,每个结点的坐标关系是怎样的,在于你想要蛇一开始在地图的哪个位置出现。蛇的结点之间的连接采用头插法。把蛇的结点都创建出来以后,还要打印一遍蛇身。最后再初始化蛇的状态、速度、食物分数、分数等信息。

4.打印食物

食物的特征,本质上是一个结点。坐标要随机生成,不能生成在墙上,x坐标得是2的倍数,因为和蛇对称,和墙也要对称。坐标不能在蛇的身上。设置好相关条件就可以创建结点了。然后把它初始化为已经生成的坐标。

5.蛇的移动

蛇是走一步移动一步,它要监测是否有按上下左右,如果按了,蛇头就要转变方向。蛇的移动本质上是下一个结点的位置在哪。所以要安排下一个结点的位置。下一个结点的位置有多种可能,撞墙,撞自己,吃食物和正常进行。

如果是吃食物,就是头插。

如果是正常走,那么就是头插以后再删尾,这个过程还要打印一遍蛇身。那么尾巴部分的结点被释放以后,在尾结点的原坐标上打印两个空格来代替。这个过程在地图上显示就是蛇走了一格。

蛇移动的速度越快,休眠的时间越短。所以速度方面设置休眠时间就可以了。这个休眠时间Sleep的函数也是包含windows的库函数来实现的。

撞墙和撞自己都需要修改游戏状态。修改的游戏状态就在于停止游戏。所以外面要套个循环。游戏只在状态是OK的时候进行,其他情况都分别打印出对应的信息。

6.暂停功能如何实现?

暂停的功能可以通过死循环,一直在睡眠。只有重新按了空格键,再跳出循环继续运行。

7.最后的收尾

收尾部分主要是游戏玩了一把game over以后,因为各种原因结束而打印不同信息。打印完了要把蛇的结点依次释放。然后再把食物释放,把传来的维护蛇的指针置为空。

如果想设置再来一把的消息,可以在test.c文件里进行。

要注意两个getchar。第一个getchar用来读取信息,通过一个变量来接收,用于判断玩家到底要不要开下一把。第二个getchar用来接收读取回车字符,但是没有变量接收它,也就是它不产生实际作用。因为它的目的只是用来吸收回车,使这个回车键不至于影响到下一次的输入判定。

8.贪吃蛇的结构体维护

贪吃蛇有两个结构体,第一个结构体是蛇身,第二个是蛇的各种信息,里面也包含了蛇身。

那么就是创建一条贪吃蛇的结构体,来玩这个贪吃蛇游戏。传的参数就是这个贪吃蛇的结构体的地址,因为传地址,才能改变贪吃蛇的值。这里的值包括状态,蛇的结点的指针,蛇的方向,当前分数等等。蛇的结点的头指针是常常需要改变的,因为它要不断移动。如果传的是结点指针,那么要传二级指针。但是本次情况中蛇的结点的头指针在贪吃蛇结构体里只是一个值,这里既然传了贪吃蛇的结构体地址,那么就能随便改变蛇的结点的头指针了。这个是要注意的关于指针的细节。以便在进行与贪吃蛇相似的项目中能够复用。

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

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

相关文章

leetcode 461. 汉明距离

比较简单的一题&#xff0c;先对两个整数进行异或操作&#xff0c;会将两个整数二进制形式中各个数字进行异或操作&#xff0c;不同的数字则为1&#xff0c;再通过移位操作统计得到的二进制数中为1的个数&#xff0c;即为所求。 Java代码如下&#xff1a; class Solution {pub…

STM32 STD/HAL库驱动W25Q64模块读写字库数据+OLED0.96显示例程

STM32 STD/HAL库驱动W25Q64 模块读写字库数据OLED0.96显示例程 &#x1f3ac;原创作者对W25Q64保存汉字字库演示&#xff1a; W25Q64保存汉字字库 &#x1f39e;测试字体显示效果&#xff1a; &#x1f4d1;功能实现说明 利用W25Q64保存汉字字库&#xff0c;OLED显示汉字的时…

SVD奇异值分解

一、奇异值 奇异值&#xff08;Singular Values&#xff09;是线性代数中矩阵的重要性质之一&#xff0c;与奇异值分解&#xff08;SVD&#xff09;密切相关。让我们来更详细地了解一下奇异值的概念&#xff1a; 定义&#xff1a; 对于一个矩阵 ( A )&#xff0c;它的奇异值是…

【Chrono Engine学习总结】4-vehicle-4.1-vehicle的基本概念

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 1、基本介绍 Vehicle Overview Vehicle Mannel Vehicle的官方demo 1.1 Vehicle的构型 一个车辆由许多子系统构成&#xff1a;悬挂、转向、轮子/履带、刹车/油门、动…

双场板功率GaN HEMT电容模型以精确模拟开关行为

标题&#xff1a;Capacitance Modeling in Dual Field-Plate Power GaN HEMT for Accurate Switching Behavior&#xff08;TED.16年&#xff09; 摘要 本文提出了一种基于表面电位的紧凑模型&#xff0c;用于模拟具有栅极和源极场板&#xff08;FP&#xff09;结构的AlGaN/G…

JMM(Java内存模型)

Java内存模型&#xff08;Java Memory Model&#xff0c;简称JMM&#xff09;是Java语言规范中定义的一个抽象概念&#xff0c;它描述了程序中各个变量&#xff08;包括实例字段、静态字段和构成数组对象的元素&#xff09;在并发环境下的访问规则和一致性保证。JMM的主要目标是…

python+flask+django医院预约挂号病历分时段管理系统snsj0

技术栈 后端&#xff1a;python 前端&#xff1a;vue.jselementui 框架&#xff1a;django/flask Python版本&#xff1a;python3.7 数据库&#xff1a;mysql5.7 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm . 第一&#xff0c;研究分析python技术&#xff0c…

点云标注工具

目录 3d手势识别 c 3d关键点&#xff0c;Bounding Box Labels Rectangle Labels KITTI 3D Ground Truth Annotator c标注工具 3d手势识别 GitHub - 99xtaewoo/Automated-Hand-3D-pose-annotation-Tool: Automated Hand 3D pose annotation Tool c 3d关键点&#xff0c;Bou…

【Django】Django文件上传

文件上传 1 定义&场景 定义&#xff1a;用户可以通过浏览器将图片等文件上传至网站。 场景&#xff1a; 用户上传头像。 上传流程性的文档[pdf&#xff0c;txt等] 2 上传规范-前端[html] 文件上传必须为POST提交方式 表单 <form> 中文件上传时必须带有 enctype…

电视上如何下载软件

电视上如何下载软件&#xff0c;告诉大家一个简单的方法&#xff0c;可以用DT浏览器下载软件&#xff0c;然后会自动安装这个软件&#xff0c;如有技术问题&#xff0c;可以免费解答

【初中生讲机器学习】8. KNN 算法原理 实践一篇讲清!

创建时间&#xff1a;2024-02-11 最后编辑时间&#xff1a;2024-02-12 作者&#xff1a;Geeker_LStar 你好呀~这里是 Geeker_LStar 的人工智能学习专栏&#xff0c;很高兴遇见你~ 我是 Geeker_LStar&#xff0c;一名初三学生&#xff0c;热爱计算机和数学&#xff0c;我们一起加…

从零开始学howtoheap:fastbins的house_of_spirit攻击3

how2heap是由shellphish团队制作的堆利用教程&#xff0c;介绍了多种堆利用技术&#xff0c;后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;优化pwn虚拟机配置支持libc等指…

Python:解析获取连续的重叠对pairwise

简介&#xff1a;pairwise函数&#xff0c;返回从输入迭代器获取的重叠对的迭代器&#xff0c;是Python 3.10 新特性&#xff0c;表示一个迭代器从对象中获取连续的重叠对&#xff0c;在某些场景中可以优化代码运行效率。pairwise 函数是一种用于处理列表中元素之间配对操作的通…

渗透专用虚拟机(公开版)

0x01 工具介绍 okfafu渗透虚拟机公开版。解压密码&#xff1a;Mrl64Miku&#xff0c;压缩包大小&#xff1a;15.5G&#xff0c;解压后大小&#xff1a;16.5G。安装的软件已分类并在桌面中体现&#xff0c;也可以使用everything进行查找。包含一些常用的渗透工具以及一些基本工…

腾讯云4核8G服务器多少钱?2024精准报价

腾讯云4核8G服务器S5和轻量应用服务器优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;标准型SA2服务器1444.8元一年&#xff0c;轻量应用服务器4核8G12M带宽一…

app逆向-android-studio安装使用教程

Android Studio 是谷歌推出的一个Android集成开发工具&#xff0c;基于IntelliJ IDEA. 类似 Eclipse ADT&#xff0c;Android Studio 提供了集成的 Android 开发工具用于开发和调试。 android-studio下载地址&#xff1a;https://developer.android.com/studio/archive androi…

【ES】--ES集成自定义分词库

目录 一、相关安装1、(window单机)elasticsearch安装2、安装Elasticvue插件3、ik分词器插件4、ES集成自定义词库 一、相关安装 1、(window单机)elasticsearch安装 Win10下下载ES组件&#xff0c;安装部署如下&#xff1a;JDK1.8、elasticsearch-7.3.2-windows-x86_64。 Elast…

【前端web入门第六天】01 CSS浮动

⭐️第六天目标 解决布局问题如多个div标签在同一行的问题 简单来说,就是可以两个标签,一个在左边,另一个在右边. &#x1f449;相关知识 标准流浮动flex布局❗️ ❗️ ❗️ 标准流是先导,浮动和flex布局都可以解决问题,但是浮动在目标开发领域较为落后,主流的解决办法是flex…

Linux第51步_移植ST公司的linux内核第3步_添加修改设备树

1、设备树文件的路径 1)、创建linux中的设备树头文件 在“my_linux/linux-5.4.31/arch/arm/boot/dts/”目录中&#xff0c;以“stm32mp15xx-edx.dtsi”为蓝本&#xff0c;复制一份&#xff0c;并命名为 “stm32mp157d-atk.dtsi”&#xff0c;这就是我们开发板的设备树头文件。…

车载诊断协议DoIP系列 —— 协议中术语解释和定义

车载诊断协议DoIP系列 —— 协议中术语解释和定义 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,…