当前位置: 首页 > news >正文

CC++:贪吃蛇小游戏教程

❀创作不易,关注作者不迷路❀😀😀

目录

😀贪吃蛇简介

😃贪吃蛇的实现

🐍生成地图

🐍生成蛇模块

 ❀定义蛇的结构体

❀初始化蛇的相关信息

❀初始化食物的相关信息

🐍光标定位和隐藏

❀如何隐藏光标

❀如何定位光标

🐍蛇的移动

❀Sleep()函数:一个让程序暂停的函数

❀删除轨迹

🐍控制键盘改变蛇的移动方向

🐍吃食物获得积分

🐍蛇死亡,结束游戏

😀完整代码

😀拓展 


😀贪吃蛇简介

贪吃蛇是一款经典的小游戏,通过控制蛇头方向吃食物,使得蛇🐍变长,从而获得积分,通过上下左右键控制蛇的移动方向,寻找吃的东西,每吃到一口就能得到一定的积分,而且蛇的身子会越来越长,难度也越来越大,不能碰墙,也不能咬到自己的身体和尾巴,否则游戏结束,总体来说这款小游戏既简单又耐玩,至今仍是一款风靡全球的小游戏,也是编程入门学习的热门小游戏,今天将带领大家实现这款小游戏

😃贪吃蛇的实现

🐍生成地图

首先生成一张长为60,宽为20的地图

生成地图,只有在边界时输出“+”,其余地方输出“  ”

#define H 20
#define W 60void show_wall()
{for (int i = 0; i <= H; i++){for (int j = 0; j <= W; j++){if (i == H || j == W)printf("+");else printf(" ");}puts("");}}

🐍生成蛇模块

 ❀定义蛇的结构体
typedef struct body {//记录坐标int x; int y;
}BODY;typedef struct snake {int size;//蛇的长度BODY list[W * H];//蛇的位置,最大可以铺满整个墙	BODY food;//定义BODY类型的food变量,存储食物的位置信息COORD coord;//光标相关的结构体,不需要自己写,是本来就有的int dx;//x轴移动方向 int dy;//y轴移动方向 int score;//分数 BODY tail;//记录尾巴的位置,后续蛇的移动需要
}SNAKE;
❀初始化蛇的相关信息

初始化时蛇的长度为2,并且在地图最中间生成蛇🐍

void  init_snake(SNAKE* snake)
{snake->size = 2;//初始化蛇的长度为2,头和尾长度为2//使蛇🐍在地图最中间生成snake->list[0].x = W / 2; snake->list[1].x = W / 2 - 1;snake->list[0].y = H / 2; snake->list[1].y = H / 2;snake->score = 0;//初始分数为0snake->dx = 1; snake->dy = 0;//初始移动方向:向右移动init_food(&(snake->food));//初始化食物
}
❀初始化食物的相关信息

食物在地图内随机生成,因此要调用随机数生成函数rand()

    所需头文件

#include<time.h>
void init_food(BODY* food)
{srand(time(NULL));food->x = rand() % W;food->y = rand() % H;while (food->x == 0 || food->y == 0){food->x = rand() % W;food->y = rand() % H;}
}

生成的食物x轴范围在(0,W-1],y轴范围在(0,H-1],但仅仅对W和H取模是有可能生成在边界(x==0或y==0)的食物,因此生成时不满足条件则再次生成食物

🐍光标定位和隐藏

打印地图之后,我们看到光标在“按任意键关闭此窗口...”这里,而且在不停的闪烁,光标在地图中闪烁并不美观,所以我们需要加以隐藏光标,同时,还需要定位光标到指定位置,比如后续的蛇的移动,食物的生成都需要光标定位

❀如何隐藏光标

头文件

#include<Windows.h>
void hide_cur()//隐藏光标,里面是windows自带的函数,不需要刻意去记,也不需要自己去写,拿来就用
{CONSOLE_CURSOR_INFO  cci;cci.dwSize = sizeof(cci);cci.bVisible = FALSE;SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}

上面的函数是Windows自带的函数,用于隐藏光标,在不同的系统中不一样,Linux系统就跟这个不一样,因此要用的时候查找资料就好

❀如何定位光标

地图已经有了,我们发现打印完地图后,光标位置在地图之外,而蛇的初始位置是在地图中间,那么怎么办?使用光标定位,让光标定位到地图中间,然后打印蛇🐍

void show_ui(SNAKE* snake)
{for (int i = 0; i < snake->size; i++){	//定位光标位置,windows自带函数snake->coord.X = snake->list[i].x; snake->coord.Y = snake->list[i].y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);if (i == 0)printf("@");//蛇头用@表示else printf("*");//蛇的身体用*表示}snake->coord.X = snake->food.x; snake->coord.Y = snake->food.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf("#");//食物用#表示snake->coord.X = snake->tail.x; snake->coord.Y = snake->tail.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf(" ");
}

每一次定位光标都需要写一遍这份代码


snake->coord.X = snake->list[i].x; snake->coord.Y = snake->list[i].y;//光标x,y轴分别指向的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);

定位光标还需要用到系统自带结构体

COORD coord;

 OK,我们运行调试一下:

成功的使光标定位在想要的位置,显示出食物和蛇🐍,但目前蛇并不能移动,我们需要让蛇🐍动起来,因此我们下一步的目标便是让蛇移动

🐍蛇的移动

对于蛇的移动,我们可以将蛇头往前移一个单位,然后蛇的身体跟着蛇头向前移动

void move_snake(SNAKE* snake)
{snake->tail.x = snake->list[snake->size - 1].x;snake->tail.y = snake->list[snake->size - 1].y;//蛇的移动,倒过来赋值for (int i = snake->size - 1; i > 0; i--){snake->list[i].x = snake->list[i - 1].x;snake->list[i].y = snake->list[i - 1].y;}//蛇头的移动单独赋值snake->list[0].x += snake->dx;snake->list[0].y += snake->dy;
}

这里有一个小技巧,就是赋值的时候要倒着赋值,否则如果正向赋值,即蛇头的位置前进1个单位,这时候在赋值给蛇身体时,只能赋值到蛇头的位置,而其他的位置则被覆盖了,倒过来赋值,则不会出现这样的问题

此时运行结果如图,这里有两个问题,打开控制台就是一连串的*和@,因为程序的运行是很快的,在几毫秒就执行完成了,我们观察不了它如何移动的,其次,一连串的*是由于前面打印出来的*没有删除而残留下来的。接下来我们来解决这两个问题

❀Sleep()函数:一个让程序暂停的函数

程序执行打印*号是很快的,我们不想让它那么快打印,我们应该让它打印一次就停顿一小会,然后继续打印

void start_game(SNAKE* snake)
{while (snake->list[0].x >= 0 && snake->list[0].x <= W - 1 && snake->list[0].y >= 0 && snake->list[0].y <= H - 1){show_ui(snake);control_move(snake);eat_food(snake);move_snake(snake);eat_snake_body(snake);Sleep(200);//让程序暂停200ms后再运行}game_over(snake);
}

运行结果

这一阶段,实现了打印的停顿,有了一个动态的效果,但是每次移动前面的*号没有删除,因此要删除轨迹

❀删除轨迹

如何删除轨迹,可以每一次打印*号后,光标移动到蛇尾,在蛇尾的位置打印空格,用于清除轨迹

snake->coord.X = snake->tail.x; snake->coord.Y = snake->tail.y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
printf(" ");

运行结果

清除了轨迹之后,蛇的移动效果便制作出来了,目前移动的方向是向右,实际还可以向上下左右移动,下一步我们就开始实现用键盘控制改变移动方向

🐍控制键盘改变蛇的移动方向

通过键盘按键改变移动方向,我们设定w(向上),s(向下),a(向左),d(向右)

void control_move(SNAKE* snake)
{char key = 0;while (_kbhit()){key = _getch();}switch (key){case 'd':snake->dx = 1;snake->dy = 0;break;case 's':snake->dx = 0;snake->dy = 1;break;case 'a':snake->dx = -1;snake->dy = 0;break;case 'w':snake->dx = 0;snake->dy = -1;break;}
}

获取键盘按键有专门的函数_kbhit()和_getch(),当_kbhit()感应到键盘按下时,通过_getch()将获取键盘按下的值传给key

所需头文件

#include<conio.h>

然后根据方向,通过switch,case语句修改dx,dy,从而做到改变方向

🐍吃食物获得积分

吃到食物加10分,身体长度加1,然后通过随机函数再次生成新的食物

void eat_food(SNAKE* snake)
{if (snake->food.x == snake->list[0].x && snake->food.y == snake->list[0].y){snake->size++;snake->score += 10;init_food(&snake->food);}
}

🐍蛇死亡,结束游戏

在本游戏案例中,结束游戏有两种情况:①蛇撞到墙②蛇吃到身体

蛇没撞到墙时,一直在while()循环内,撞到墙则退出循环,游戏结束

void start_game(SNAKE* snake)
{while (snake->list[0].x >= 0 && snake->list[0].x <= W - 1 && snake->list[0].y >= 0 && snake->list[0].y <= H - 1){show_ui(snake);control_move(snake);eat_food(snake);move_snake(snake);eat_snake_body(snake);Sleep(1000);}game_over(snake);//蛇撞到墙,游戏结束
}

蛇吃到自己身体,游戏结束

蛇头的坐标和身体部位的坐标相同时代表吃到身体,通过for循环遍历寻找是否符合吃到身体这一情况

void eat_snake_body(SNAKE* snake)
{for (int i = 1; i < snake->size; i++){if (snake->list[0].x == snake->list[i].x && snake->list[0].y == snake->list[i].y){game_over(snake);exit(0);}}
}

😀完整代码

#include<stdio.h>
#include<Windows.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<time.h>
#define H 20
#define W 60
typedef struct body {int x; int y;
}BODY;typedef struct snake {int size;//蛇的长度BODY list[W * H];//蛇的位置,最大可以铺满整个墙	BODY food;COORD coord;int dx;//x轴移动方向 int dy;//y轴移动方向 int score;//分数 BODY tail;
}SNAKE;
//展示界面 
void show_wall()
{for (int i = 0; i <= H; i++){for (int j = 0; j <= W; j++){if (i == H || j == W)printf("+");else printf(" ");}puts("");}}
void init_food(BODY* food)
{srand(time(NULL));food->x = rand() % W;food->y = rand() % H;while (food->x == 0 || food->y == 0){food->x = rand() % W;food->y = rand() % H;}
}
void  init_snake(SNAKE* snake)
{snake->size = 2;snake->list[0].x = W / 2; snake->list[1].x = W / 2 - 1;snake->list[0].y = H / 2; snake->list[1].y = H / 2;snake->score = 0;snake->dx = 1; snake->dy = 0;init_food(&(snake->food));
}
void hide_cur()//隐藏光标,里面是windows特有的函数,不需要刻意去记,拿来就用
{CONSOLE_CURSOR_INFO  cci;cci.dwSize = sizeof(cci);cci.bVisible = FALSE;SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}
void show_ui(SNAKE* snake)
{for (int i = 0; i < snake->size; i++){	//定位光标位置,windows自带函数snake->coord.X = snake->list[i].x; snake->coord.Y = snake->list[i].y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);if (i == 0)printf("@");else printf("*");}snake->coord.X = snake->food.x; snake->coord.Y = snake->food.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf("#");snake->coord.X = snake->tail.x; snake->coord.Y = snake->tail.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf(" ");
}
void move_snake(SNAKE* snake)
{snake->tail.x = snake->list[snake->size - 1].x;snake->tail.y = snake->list[snake->size - 1].y;for (int i = snake->size - 1; i > 0; i--){snake->list[i].x = snake->list[i - 1].x;snake->list[i].y = snake->list[i - 1].y;}snake->list[0].x += snake->dx;snake->list[0].y += snake->dy;
}
void control_move(SNAKE* snake)
{char key = 0;while (_kbhit()){key = _getch();}switch (key){case 'd':snake->dx = 1;snake->dy = 0;break;case 's':snake->dx = 0;snake->dy = 1;break;case 'a':snake->dx = -1;snake->dy = 0;break;case 'w':snake->dx = 0;snake->dy = -1;break;}
}
void eat_food(SNAKE* snake)
{if (snake->food.x == snake->list[0].x && snake->food.y == snake->list[0].y){snake->size++;snake->score += 10;init_food(&snake->food);}
}
void game_over(SNAKE* snake)
{snake->coord.X = 30; snake->coord.Y = 25;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf("游戏结束!!! 得分:%d", snake->score);system("pause");
}
void eat_snake_body(SNAKE* snake)
{for (int i = 1; i < snake->size; i++){if (snake->list[0].x == snake->list[i].x && snake->list[0].y == snake->list[i].y){game_over(snake);exit(0);}}
}
void start_game(SNAKE* snake)
{while (snake->list[0].x >= 0 && snake->list[0].x <= W - 1 && snake->list[0].y >= 0 && snake->list[0].y <= H - 1){show_ui(snake);control_move(snake);eat_food(snake);move_snake(snake);eat_snake_body(snake);Sleep(300);}game_over(snake);
}int main()
{hide_cur();SNAKE* snake = (SNAKE*)malloc(sizeof(SNAKE));init_snake(snake);show_wall();show_ui(snake);start_game(snake);free(snake);system("pause");return 0;
}

😀拓展 

可以实现障碍物,新增关卡等等,以及图形化界面,提升难度,下列代码展示了增加障碍物


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<Windows.h>
#include<conio.h>/*
注意:
w:上移
s:下移
a:左移
d:右移
不可以用getchar()来进行控制,getchar()之后要有回车才行,而我们只希望通过wsad这些按键进行操作
但有专门的按键操作函数
#include<conio.h>
char key;//key要给初始值,否则key没值,进不了循环,但初始值也不能是wasd等
while(_kbhit())//判断是否按下按键,按下不等于0
{key=_getch();
}
*/char temp;
//1.设置地图边界
#define W 60
#define H 20//2.设置贪吃蛇结构体
typedef struct _body {int x; //坐标xint y; //坐标y
}BODY;typedef struct snake{BODY list[W * H];//贪吃蛇最大占满整个地图int size;//实际身体个数,蛇头(@)和蛇身蛇尾(*)BODY food;//食物,#COORD coord;//(定位光标)的坐标,显示int dx;//移动方向int dy;//移动方向BODY tail;//记录蛇尾,用于清除蛇尾痕迹 int score;//分数BODY disability;
}SNAKE;//3.实现显示地图,初始化蛇函数,初始化食物函数void test_ui()
{for (int i = 0; i < H; i++){for (int j = 0; j < W; j++)printf("=");printf("\n");}
}
void disability_snake(BODY* disability)
{Sleep(5);//设置障碍物坐标disability->x = rand() % W;disability->y = rand() % H;while (disability->x == 0 || disability->x == W - 1 || disability->y == 0 || disability->y == H - 1){disability->x = rand() % W;disability->y = rand() % H;}}
void init_food(BODY* food)
{//设置随机数种子srand(time(NULL));//设置食物坐标food->x = rand()% W;//[0,W-1],注意%的操作很巧妙food->y = rand() % H;//[0,H-1]while(food->x == 0 || food->x == W - 1 || food->y == 0 || food->y == H - 1){food->x = rand() % W;food->y = rand() % H;}}
void init_snake(SNAKE* snake)//初始化
{snake->list[0].x = W / 2;snake->list[0].y = H / 2;snake->list[1].x = W / 2 - 1;snake->list[1].y = H / 2;//这里老师写成H/2-1应该是错的snake->size = 2;//初始时蛇的长度为2,因为有头有尾//设置移动方向snake->dx = 1;//默认移动方向向右snake->dy = 0;//默认移动方向向左snake->score = 0;init_food(&snake->food);disability_snake(&snake->disability);while (snake->food.x == snake->disability.x && snake->food.y == snake->disability.y){init_food(&snake->food);disability_snake(&snake->disability);}
};void show_ui(SNAKE* snake)
{//显示蛇for (int i = 0; i < snake->size; i++){   snake->coord.X = snake->list[i].x;//这个函数是在显示地图后执行的,画完地图后光标是在地图之外的,用这个函数可以重置光标位置,让光标放到我们想要的地方snake->coord.Y = snake->list[i].y;//定位光标位置,windows自带函数SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);if (i == 0) {//显示蛇头printf("@");}else{//显示蛇身和蛇尾printf("*");}}//显示食物snake->coord.X = snake->food.x;snake->coord.Y = snake->food.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf("#");//显示障碍物snake->coord.X = snake->disability.x;snake->coord.Y = snake->disability.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf("?");//清除蛇尾的痕迹,否则一连串的*snake->coord.X = snake->tail.x;snake->coord.Y = snake->tail.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf(" ");
}
void show_wall()//展示墙
{for (int i = 0; i <=H; i++){for (int j = 0; j <=W; j++){if (i == H || j == W)printf("+");else printf(" ");}puts("");}
}void hide_cur()//隐藏光标,里面是windows特有的函数,不需要刻意去记,拿来就用
{CONSOLE_CURSOR_INFO  cci;cci.dwSize = sizeof(cci);cci.bVisible = FALSE;SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}void move_snake(SNAKE* snake)
{   //记录蛇尾,清除痕迹snake->tail = snake->list[snake->size - 1];//蛇身的移动,算法逻辑从后往前赋值//蛇头的移动,单独赋值for (int i = snake->size - 1; i > 0; i--){snake->list[i] = snake->list[i - 1];}snake->list[0].x += snake->dx;snake->list[0].y += snake->dy;
}
void control_snake(SNAKE* snake)
{char key = 0;while (_kbhit())//检测到按下按键{if (temp == 'w' && _kbhit() == 's')key = temp;else if (temp == 's' && _kbhit() == 'w')key = temp;else if (temp == 'a' && _kbhit() == 'd')key = temp;else if (temp == 'd' && _kbhit() == 'a')key = temp;else key = _getch();}//循环之外,抬起按下动作,或没有按下动作//根据按键,修改移动方向temp = key;switch (key){case 'w':snake->dy = -1;snake->dx = 0;break;case 's':snake->dy = 1;snake->dx = 0;break;case 'a':snake->dy = 0;snake->dx = -1;break;case 'd':snake->dy = 0;snake->dx = 1;}}void snake_eat(SNAKE* snake)
{//判断是否吃到食物if (snake->list[0].x == snake->food.x && snake->list[0].y == snake->food.y){//吃到食物,身体加长,食物消失,重新生成新的食物snake->size++;//食物消失也不用重新写,因为一旦生成了食物原来的地方就消失了snake->coord.X = snake->disability.x;snake->coord.Y = snake->disability.y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf(" ");init_food(&(snake->food));		disability_snake(&snake->disability);printf(" ");while (snake->food.x == snake->disability.x && snake->food.y == snake->disability.y){init_food(&snake->food);disability_snake(&snake->disability);}snake->score += 10;}}
void game_over(SNAKE* snake)//游戏结束,指定到具体位置打印游戏结束
{snake->coord.X = 40;snake->coord.Y = 25;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);printf("游戏结束  总分数:%d", snake->score);system("pause");
}
void snake_eat_body(SNAKE* snake)
{for (int i = 1; i < snake->size; i++){if (snake->list[0].x == snake->list[i].x && snake->list[0].y == snake->list[i].y){game_over(snake);//吃到身体;游戏结束exit(0);}}
}
void snake_push_disability(SNAKE* snake)
{if (snake->disability.x == snake->list[0].x && snake->disability.y == snake->list[0].y){game_over(snake);exit(0);}
}
void start_game(SNAKE* snake)
{while (snake->list[0].x >=0 && snake->list[0].x < W &&snake->list[0].y>=0 && snake->list[0].y < H)//在范围内移动{   //显示蛇和食物show_ui(snake);//控制移动方向control_snake(snake);//蛇吃到食物snake_eat(snake);//蛇吃到身体snake_eat_body(snake);//蛇撞到障碍物snake_push_disability(snake);//移动蛇move_snake(snake);//延迟300msSleep(100);}game_over(snake);//碰到墙壁,游戏结束
}int main(int argc,char *argv[])
{hide_cur();//隐藏光标SNAKE* snake = (SNAKE*)malloc(sizeof(SNAKE));//创建空间init_snake(snake);//显示地图边界show_wall();//显示蛇和食物show_ui(snake);//启动游戏start_game(snake);free(snake);//释放空间//while (1);//先不让程序结束,就暂时不显示程序结束的那段字return 0;
}

 

相关文章:

CC++:贪吃蛇小游戏教程

❀创作不易&#xff0c;关注作者不迷路❀&#x1f600;&#x1f600; 目录 &#x1f600;贪吃蛇简介 &#x1f603;贪吃蛇的实现 &#x1f40d;生成地图 &#x1f40d;生成蛇模块 ❀定义蛇的结构体 ❀初始化蛇的相关信息 ❀初始化食物的相关信息 &#x1f40d;光标定位和…...

C#中投影运算的深入解析与实例应用

文章目录 1、投影运算的基本语法2、投影运算的高级用法3、投影运算在向量空间中的运用4、投影运算在数据库和XML中的实际应用5、投影运算能用于哪些实际场景&#xff1f;6、结论 在C#编程中&#xff0c;投影运算是一种常用的数据操作技术&#xff0c;它可以将一个数据集合转换成…...

HTML+CSS練習---空隙產生記錄

1.第一層和第二層之間的間隙&#xff1a;以為導航欄超過高度朝下擠下來了 2.第2層兩個div中的空隙 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title><style>font-face {f…...

【leetcode】相同的树、另一棵树的子树、翻转二叉树(利用深度优先遍历)

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构、LeetCode专栏 &#x1f4da;本系…...

Linux系统窗口水印难点分析

给应用程序加水印是保护数据的一种方式&#xff0c;window上可以通过给进程通过注入的方法给进程的窗口创建一个同大小的副窗口&#xff0c;在副窗口上绘制水印内容&#xff0c;同时设置副窗口透明同时透传事件&#xff0c;这样就可以达到在源窗口上显示水印的效果且不影响程序…...

LabVIEW与CANopen实现自动化生产线的设备控制与数据采集

在某工厂的自动化生产线上&#xff0c;多个设备通过CANopen网络进行通信和控制。这些设备包括传感器、执行器和PLC&#xff0c;它们共同负责监测和控制生产过程中的关键参数&#xff0c;如温度、压力、速度等。为了实现对整个生产线的集中监控和管理&#xff0c;工厂决定使用La…...

吃惊!这个Windows双系统方法逆天了|UEFI篇

前言 最近小白在折腾别的系统教程&#xff0c;偶然间发现居然有一个很nice的Windows双系统教程。于是于是&#xff0c;果断尝试了一下&#xff0c;发现真的很可行&#xff01; 这个双系统的办法并不需要使用到WinPE系统&#xff0c;因此并不需要使用到U盘&#xff0c;只需要在…...

【C语言基础】C语言试题复习

1. 执行下面的程序段后&#xff0c;k 的值是_______。 int k1,n325; do { k*n%10;n/10;}while(n); 解析&#xff1a; 给定 n 325 和初始 k 1&#xff0c;代码中的循环将会进行如下操作&#xff1a; 第一次循环:n % 10 得到 5&#xff0c;因此 k * 5&#xff0c;即 k 1 * 5 …...

一拖三无线充底座-带给你极致的便利生活

随着科技的不断进步&#xff0c;无线充电技术已经逐渐渗透到我们日常生活的方方面面&#xff0c;一拖三无线充底座作为其中的佼佼者&#xff0c;以其高效、便捷的特点受到广大用户的青睐。本文将从电磁感应原理、多线圈设计、频率匹配、电能传输、功率分配以及充电管理六个方面…...

探索 Electron:打造深度书籍挖掘机的搜索体验

Electron是一个开源的桌面应用程序开发框架&#xff0c;它允许开发者使用Web技术&#xff08;如 HTML、CSS 和 JavaScript&#xff09;构建跨平台的桌面应用程序&#xff0c;它的出现极大地简化了桌面应用程序的开发流程&#xff0c;让更多的开发者能够利用已有的 Web 开发技能…...

tomato靶场

扫描网址端口 访问一下8888 我们用kali扫描一下目录 访问这个目录 产看iofo.php源码&#xff0c;发现里面有文件包含漏洞 访问/etc/passwd/发现确实有文件包含漏洞 远程连接2211端口 利用报错&#xff0c;向日志文件注入木马&#xff0c;利用文件包含漏洞访问日志文件 http:/…...

【Vue】computed计算对象不生效问题?

问题描述 最近使用vuex来管理全局状态&#xff0c;遇到了computed计算state中数据却不生效的问题。 原因分析&#xff1a; 先看vue官网示例&#xff1a; computed接收的是一个getter函数&#xff0c;但是这个getter函数是懒加载并且有缓存的&#xff0c;当计算属性最终计算…...

算法小白的进阶之路(力扣9~12)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…...

DOCKER容器中安装JDK1. 8 详细步骤

1.通过查找JDK8的远程镜像 docker search jdk 2.选择一个远程镜像下载到本地仓库 #拉取镜像 docker pull kdvolder/jdk8#查看镜像 docker images 可以看到REPOSITORY列下面出现了kdvolder/jdk8 3.在docker容器中运行jdk8的镜像 docker run -di --namejdk1.8 kdvolder/jdk…...

计算机毕业设计Python+Tensorflow股票推荐系统 股票预测系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

1、用pycharm打开项目&#xff0c;一定要打开包含manage.py文件所在文件夹 2、配置解释器&#xff1a;建议使用Anaconda(Python 3.8(base))&#xff0c;低于3.8版本的&#xff0c;页面会不兼容 3、安装依赖库&#xff1a;打开pycharm的终端&#xff0c;输入&#xff1a; pip in…...

深度学习常见的卷积和注意力机制文章集锦(持续更新)

卷积 友好链接1 卷积原理&#xff1a;几种常用的卷积&#xff08;标准卷积、深度卷积、组卷积、扩展卷积、反卷积&#xff09; 友好链接2 一文看尽深度学习中的20种卷积&#xff08;附源码整理和论文解读&#xff09; 友好链接3 深度学习中组卷积(Group convolution)、深度卷积…...

如何在立创EDA的PCB电路板导入logo图案

1、首先制作好logo图案&#xff0c;一般为公司logo图标&#xff0c;如下图 2、打开立创EDA的PCB文件&#xff0c;如下图 3、将PCB的图层切换到丝印层&#xff1a; 4、然后选择EDA菜单栏的放置---图片&#xff1a; 5、进入后点击选择图片&#xff0c;将logo图片导入&#xff0c;…...

springboot集成canal

目录 一、打开mysql的binlog1.1 打开 MySQL 配置文件 my.cnf&#xff08;通常位于 /etc/mysql/my.cnf 或 /etc/my.cnf&#xff09;并添加或修改以下设置&#xff1a;1.2 重启mysql服务1.3 验证是否生效 二、 部署canal 服务端&#xff08;docker&#xff09;2.1 下载启动脚本(可…...

leetcode数论(2447. 最大公因数等于 K 的子数组数目)

前言 经过前期的数据结构和算法学习&#xff0c;开始以OD机考题作为练习题&#xff0c;继续加强下熟练程度。 描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 nums 的子数组中元素的最大公因数等于 k 的子数组数目。 子数组 是数组中一个连续的非空序列…...

实现数组扁平化的几种方式

目标: 实现数组扁平化[1,[2,[3,4,5]]] > [1,2,3,4,5] 我们有几种方法可以实现,分别为: 1、递归 function flatten(list){return list.reduce((tar, cur) > {if(Array.isArray(cur)){tar tar.concat(flatten(cur));} else {tar.push(cur);}return tar;}, []); } flatt…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...