贪吃蛇的简单实现(c语言)

news/2024/5/18 17:12:37

前言:学完了C语言的基础语法,和一点数据结构的知识,拿贪吃蛇来练练手,并熟悉以前的知识。写完之后,有一种成就感,为以后的学习饱满激情。

注意这里的讲解是由部分到整体的思路。

目录

控制台不能是终端:

mode和title命令

GetStdHandle函数

隐藏光标函数(HideCurso)的实现:

GetConsoleCursorInfo函数

SetConsoleCursorInfo函数

综上,可以利用以上函数分装成一个函数隐藏光标HideCurso:

在窗口内任意位置打印(SetPos)的函数的实习:

SetCursorPostion函数:

SetPos函数的实现:

实现KEY_PRESS来检测按键被按的情况

按键检测函数GetAsynckeyState

KEY_PRESS的实现:

setlocale函数

游戏实现的大体框架:

游戏开始GameStart实现

1.欢迎界面WelcomeGame的实现

2.创建地图CreateMap的实现

3.CreateSnake创建蛇

3.1蛇身体节点的定义

3.2 蛇的定义

3.3创建蛇CreateSnake的实现

3.4创建食物并打印,CreateFood函数的实现

3.4将上面的函数分装进函数IniteSnake

4.打印蛇,PrintSnake函数的实现

5.最后一步将上述的函数分装进GameStart函数

游戏运行GameRun函数的实现 

GameRun 中需要实现的逻辑

PrintHelpInfo打印帮助信息函数的实现:

PrintScore的实现

SnakeMove的实现

Pause暂停函数的实现:

SnakeNext蛇走一步函数的实现:

接下来说一下NextIsFood函数的实现:

IsKill函数的实现:

游戏结束GameEnd函数的实现:

整个游戏逻辑的运行逻辑的实现:

整个游戏的源码(有感兴趣的可以自取):


这里先放一张最后的成果图和一段视频来展示效果

 

贪吃蛇游戏

这里先讲一些可能需要用到的windows的控制台函数和一些系统操作。

控制台不能是终端:

终端的控制台:

修改过程:

 

mode和title命令

	system("title 贪吃蛇");system("mode con cols=100 lines=30");

mode改变控制台窗口的大小,cols表示行,lines表示列。

title就是改变控制台的名称。

效果展示:

GetStdHandle函数

其返回值类型是HANDLE(是一个指针),获得一个句柄。

//获得一个句柄
HANDLE hOutPut = GetStdHandle(STD_OUTPUT_HANDLE);

CONSOLE_CURSOR_INFO CursorInfo;//CONSOLE_CURSOR_INFO是控制台光标标的结构体类型
//CursorInfo是我们创建的变量

CONSOLE_CURSOR_INFO是一个结构体其中有两个成员,dwSize 和 dVisible ,dwSize 表示光标占一个单位光标高度的百分比,比如下图。

 dVisiable 表示光标是否可见,将光标的信息为不可见:

CursorInfo.bVisible = false;

隐藏光标函数(HideCurso)的实现:

GetConsoleCursorInfo函数

获取控制台的光标信息:

	CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutPut, &CursorInfo);//将光标信息放入CursorInfo这个变量中

SetConsoleCursorInfo函数

设置控制台光标的信息:

将光标的信息设置为不可见。

CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutPut, &CursorInfo);
CursorInfo.bVisible = false;
SetConsoleCursorInfo(hOutPut, &CursorInfo);//将CursorInfo中的数据设置为控制台的光标的信息。

综上,可以利用以上函数分装成一个函数隐藏光标HideCurso:

void HideCursor()
{HANDLE hOutPut = NULL;hOutPut = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutPut, &CursorInfo);CursorInfo.bVisible = false;SetConsoleCursorInfo(hOutPut, &CursorInfo);
}

效果:

上图看不见光标。

在窗口内任意位置打印(SetPos)的函数的实习:

SetCursorPostion函数:

他有两个参数一个是句柄Ll类型为HANDLE,另一个类型为COORD这是一个结构体类型。

typedef sruct COORD
{short x;short y;
}COORD;

定位光标的位置,说到位置这里就不得不聊聊控制台的坐标系的定义

这里注意:一个单位的x不等于一个的单位的y,两个单位的x才等于一个单位的y。

SetPos函数的实现:

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

调用函数SetPos可以直接将光标定位到你给的坐标处。

实现KEY_PRESS来检测按键被按的情况

按键检测函数GetAsynckeyState

short GetAsyncKeyState(int vKey);


他的返回值是short,如果按下了一个间他会返回一个二进制形势下最低位为1的数,否则为0。

 虚拟键码:这里会用到的比如,

上:VK_UP

下:VK_DOWN

左:VK_LEFT

右:VK_RIGHT

f3(加速):VK_F3

f4(减速):VK_F4

空格暂停:SPACE

esc退出:ESCAE

KEY_PRESS的实现:

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

如果vk这个虚拟键位代表的按键被按过,则返回1,否则返回0。

setlocale函数

setlocale(LC_ALL, "");//可以将模式改为当前所在地区的模式,可以打印一些特殊的字符
int main()
{char* ret =  setlocale(LC_ALL, "");printf("%s\n", ret);return 0;
}

宽字符:

一个宽字符是两个字符的大小。

	setlocale(LC_ALL, "");printf("ab\n");wprintf(L"%lc", L'我');

将C改为当前地区的模式时,可以打印宽字符。

宽字符打印与普通字符打印的区别

宽字符普通字符
使用函数wprintfprintf
换位符%lc  %ls%c %s
使用

wprintf(L"%ls",L"helloworld");

wprintf(L"%lc",L'a');

printf("%s","helloworld");

printf("%c",'a');

游戏实现的大体框架:

 游戏大揽

 


游戏开始GameStart实现

1.欢迎界面WelcomeGame的实现

void WelcomeGame()
{system("mode con cols=100 lines=30");system("title 贪吃蛇");HideCursor();SetPos(35, 15);wprintf(L"%ls", L"欢迎来到贪吃蛇小游戏");SetPos(36, 22);system("pause");system("cls");SetPos(30, 12);wprintf(L"%ls", L"你可以用↑.↓.←.→来控制蛇的移动");SetPos(30, 13);wprintf(L"%ls", L"F3加速,F4减速");SetPos(36, 22);system("pause");system("cls");
}

这里实现的结果就是大揽里的前两周照片,SetPos,HideCurso两个函数再前面已经实现完了这里就不讲了。

2.创建地图CreateMap的实现

#define WALL L'□'
void CreateMap()
{for (int i = 1; i <= 29; i++){wprintf(L"%lc", WALL);}SetPos(0, 26);for (int i = 1; i <= 29; i++){wprintf(L"%lc", WALL);}for (int i = 1; i <= 26; i++){SetPos(0, i);wprintf(L"%lc", WALL);}for (int i = 1; i <= 26; i++){SetPos(56, i);wprintf(L"%lc", WALL);}
}

注意:system("mode con cols=100 lines=30");这是已开设我们设置的窗口大小,这里我们的地图大小为 (58,27)坐标从零开始并且2x=y并且宽字符的宽度为两个x,所以一行打印29个墙就可以了。

还有一点需要注意,以上代码打印出的墙的x坐标的值都为偶数,所以在后面代码中蛇的节点的坐标和食物的坐标的x值也应为偶数,若为偶数,那么蛇再装到上面墙的是时候总是撞在墙与墙之间的空隙中,影响也不大,但必须保证蛇的x坐标与食物的x坐标都为奇数或都为偶数,否则吃不到食物。

表示墙的这个字符可以再输入法中找到, 

3.CreateSnake创建蛇

蛇的身体是用链表的一个一个的节点组成的来的。

3.1蛇身体节点的定义

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

其中的x,y表示这个节点在控制台中的坐标。

这里食物的定义与蛇的节点的定义一样。

3.2 蛇的定义

enum DIRECTION
{UP = 1,//上DOWN,//下RIGHT,//左LEFT//右
};
enum STATUS
{OK = 1,//状态正常KILL_BY_WALL,//撞墙死亡KILL_BY_SELF,//自己要到自己死亡END_NORMAL//按esc退出
};
typedef struct Snake
{pSnakeNode _psnake;//指向蛇的头节点的指针int sleep_time;//Sleep(sleep_time)来控制蛇的速度enum DIRECTION dir;//蛇的方向pSnakeNode _pfood;//一个指向食物的指针int food_score;//一个食物的分数int score;//总分enum STATUS status;//蛇当前的装态
}Snake,* pSnake;

3.3创建蛇CreateSnake的实现

void CreateSnake(pSnake ps)
{ps->_psnake = NULL;for (int i = 0; i < 5; i++){pSnakeNode tmp = (pSnakeNode)malloc(sizeof(SnakeNode));if (tmp == NULL){perror("CreateSnake():malloc:");return;}tmp->next = NULL;if (ps->_psnake == NULL){tmp->x = 10;tmp->y = 4;ps->_psnake = tmp;}else{tmp->x = 10 + 2 * i;tmp->y = 4;tmp->next = ps->_psnake;ps->_psnake = tmp;}}
}

运用for循环创建5个节点作为蛇的身体,注意这五个节点每两个节点的坐标应该相邻,确保蛇的身体是连续的。还有蛇的节点坐标别等于墙的坐标。

注意:这里生成的蛇的节点的坐标都是偶数,那么食物的x坐标必须为偶数,否则蛇的头一半吃到食物另一半吃不到食物,就等于永远吃不到食物,就是一个bug了。

3.4创建食物并打印,CreateFood函数的实现

//注意rand的使用需要有srand((unsigned)time(NULL))这一句,这里没有是因为在源码的main函数中
void RandPos(pSnakeNode* tmp)
{int x1 = 0;int y1 = 0;do{x1 = rand() % 53 + 2;y1 = rand() % 25 + 1;} while (x1%2);//保证食物的x坐标为偶数tmp->x = x1;tmp->y = y1;
}
#define FOOD L'★'
void CreateFood(pSnake ps)
{pSnakeNode tmp = (pSnakeNode)malloc(sizeof(SnakeNode));if (tmp == NULL){perror("CreateFood():malloc:");return;}again:RandPos(tmp);pSnakeNode cur = ps->_psnake;//生成的食物的坐标不能与蛇的节点的坐标一样while (cur){if (tmp->x == cur->x && tmp->y == cur->y)goto again;cur = cur->next;}ps->_pfood = tmp;SetPos(tmp->x, tmp->y);//打印食物wprintf(L"%lc", FOOD);return;
}

RandPos函数是随机生成一个坐标,这里需要注意的是生成的坐标的范围,因为我想要的地图的大小为58(x)*27(y)去除墙的所以x的范围为[2,54],y的范围为[1,25],注意这里生成的食物x坐标的奇偶性要与蛇的节点的x保持一致。

注意:生成的食物的坐标不能与蛇的节点的坐标一样。

3.4将上面的函数分装进函数IniteSnake

void IniteSnake(pSnake ps)
{CreateSnake(ps);CreateFood(ps);//以下的为其他初始化蛇的信息ps->dir = RIGHT;ps->status = OK;ps->sleep_time = 200;ps->food_score = 10;ps->score = 0;
}

4.打印蛇,PrintSnake函数的实现

上面已经初始化完了蛇的节点,那么就可以着手打印了。

void PrintSnake(pSnake ps)
{pSnakeNode cur = ps->_psnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}
}

 初始化完了节点,打印就很简单了,定位光标位置直接按链表的顺序直接打印就完了。

5.最后一步将上述的函数分装进GameStart函数

void GameStart(pSnake ps)
{WelcomeGame();CreateMap();IniteSnake(ps);PrintSnake(ps);//getchar();可以用getchar函数来观察打印的效果}

辛苦了这么久看一下打印效果:

游戏运行GameRun函数的实现 

这里采用总分的方式来挨个实现:

GameRun 中需要实现的逻辑

void GameRun(pSnake ps)
{PrintHelpInfo();//打印游戏提示信息do{PrintScore(ps);//打印游戏分数SnakeMove(ps);//蛇的移动IsKill(ps);//判断蛇的状态并修改蛇的状态Sleep(ps->sleep_time);} while (ps->status==OK);//蛇为其他状态时,跳出循环return;
}

简单的一句话总结就是,蛇每走一步判断一下状态并更新一下分数。

PrintHelpInfo打印帮助信息函数的实现:

void PrintHelpInfo()
{SetPos(60, 20);wprintf(L"%ls", L"你可以用↑.↓.←.→来控制蛇的移动");SetPos(60, 21);wprintf(L"%ls", L"F3加速,得分增加;F4减速,得分减少");SetPos(60, 22);wprintf(L"%ls", L"空格是暂停");SetPos(60, 23);wprintf(L"%ls", L"ESC是退出游戏");
}

这里比较简单,需要注意的就是找个合适的位置打印。

PrintScore的实现

void PrintScore(pSnake ps)
{SetPos(60, 5);printf("食物分数:%2d 总分数:%d", ps->food_score, ps->score);
}

每次打印时都会覆盖上次打印的数据。

SnakeMove的实现

这里比较重要,也比较难一些。

void SnakeMove(pSnake 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_F3)){//f3是加速,将系统休眠时间改小就可以了,别忘了每个食物的加分,并限制一下,不能一直加速if (ps->sleep_time > 100){ps->sleep_time -= 20;ps->food_score += 2;}}else if (KEY_PRESS(VK_F4)){//f4跟f3一样if (ps->sleep_time < 300&&ps->food_score>10){ps->sleep_time += 20;ps->food_score -= 2;}}else if (KEY_PRESS(VK_SPACE)){Pause();//这个函数实现暂停}else if (KEY_PRESS(VK_ESCAPE)){//只需要改变蛇状态就可以了ps->status = END_NORMAL;}SnakeNext(ps);//蛇走下一步
}

注意: 蛇现在的运动方向为下,那么我们根据以前玩贪吃蛇的知识知道,按上时不改变蛇的方向

Pause暂停函数的实现:

void Pause()
{while (1){if (KEY_PRESS(VK_SPACE))break;Sleep(200);}
}

实现思路:让系统一致Sleep就可以了,当再次检测到你按下空格时,则跳出循环。

SnakeNext蛇走一步函数的实现:

void SnakeNext(pSnake ps)
{//创建一个新节点,这个新节点可以理解为新的蛇头pSnakeNode movenext = (pSnakeNode)malloc(sizeof(SnakeNode));if (movenext == NULL){perror("SnakeNext():malloc:");return;}//基于蛇头的坐标和蛇移动的方向,确定新节点的坐标if (ps->dir == UP){movenext->x = ps->_psnake->x;movenext->y = ps->_psnake->y-1;}else if (ps->dir == DOWN){movenext->x = ps->_psnake->x;movenext->y = ps->_psnake->y + 1;}else if (ps->dir == LEFT){movenext->x = ps->_psnake->x-2;movenext->y = ps->_psnake->y;}else if (ps->dir == RIGHT){movenext->x = ps->_psnake->x+2;movenext->y = ps->_psnake->y;}//判断蛇的下一步是否是食物,如果是食物那么,就将食物的这个节点改为新的蛇头,并释放掉movenextif (NextIsFood(ps, movenext)){SetPos(ps->_pfood->x, ps->_pfood->y);//将食物的位置覆盖式打印为蛇的身体,表示被吃掉wprintf(L"%lc", BODY);ps->_pfood->next = ps->_psnake;ps->_psnake = ps->_pfood;//总分增加ps->score += ps->food_score;free(movenext);//食物被吃掉,这在重新创建一个新的食物。CreateFood(ps);}else{   //下一步没有吃到食物,则将movenext节点头插到蛇的链表中movenext->next = ps->_psnake;ps->_psnake = movenext;pSnakeNode cur = ps->_psnake;//循环打印蛇身,注意跳出循环的条件,当cur指向倒数第二个节点时跳出while (cur->next->next != NULL){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//打印倒数第二个节点SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);//将原来最后一节身体被覆盖打印成空格,因为这里是没有吃到食物身体没有变长SetPos(cur->next->x, cur->next->y);wprintf(L"  ");//一定要释放最后一个节点,因为加上了一个节点movenextfree(cur->next);//现在cur指向尾结点,将尾结点的next置为NULLcur->next = NULL;}
}

思路:根据创建一个新的节点,这个节点是由蛇的方向和头结点的坐标确定的;然后,如果movenext的坐标与食物一样,表示吃到食物,直接将食物的节点头插进蛇的链表;如果movenext与食物的坐标没重合,那么就将movenext头插进链表,并将原链表的尾结点释放。

接下来说一下NextIsFood函数的实现:
int NextIsFood(pSnake ps, pSnakeNode movenext)
{if (ps->_pfood->x == movenext->x && ps->_pfood->y == movenext->y)return 1;elsereturn 0;
}

如果与食物坐标重合就返回1,否则返回0.不用怕,这个函数就是很简单。

IsKill函数的实现:

void IsKill(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;}//判断是否要到自己else{//要从蛇头的下一个节点开始,遍历链表pSnakeNode cur = ps->_psnake->next;while (cur){if (ps->_psnake->x == cur->x && ps->_psnake->y == cur->y){ps->status = KILL_BY_SELF;return;}cur = cur->next;}}return;
}

思路:判断是否撞墙,是否要咬自己,如果为真则改变蛇的相应状态,并跳出函数。

这里说一些为什么在判断是否咬到自己这种情况时,不能从蛇头开始遍历,如果是这样,则cur和ps->_psnake都指向蛇头,坐标重合,状态被修改,结果就是一进游戏你就咬到自己,所从蛇头的下一个节点开始遍历。


游戏结束GameEnd函数的实现:

这里实现逻辑比较简单,直接上代码:

void GameEnd(pSnake ps)
{SetPos(30, 14);//根据蛇的状态打印信息if (ps->status== END_NORMAL){printf("正常退出\n");}else if (ps->status == KILL_BY_SELF){printf("咬到自己,死亡\n");}else if (ps->status == KILL_BY_WALL){printf("撞到了墙,死亡\n");}//将开辟的空间释放pSnakeNode cur = ps->_psnake;pSnakeNode prev = cur;while (cur){prev = cur;cur = cur->next;free(prev);}free(ps->_pfood);
}

注意:释放链表的方式,使用的是前后指针的方法,如果不太懂可以看我双链表的博客。


整个游戏逻辑的运行逻辑的实现:

void test()
{char op;do{Snake s;GameStart(&s);GameRun(&s);GameEnd(&s);SetPos(30, 15);wprintf(L"%ls",L"是否再来一局?(Y/N):");scanf(" %c", &op);} while (op == 'y' || op == 'Y');
}
int main()
{setlocale(LC_ALL, "");test();return 0;
}

这里就不多说了哈,主要一点就是加入了,游戏结束你是否还要再来一局。

整个游戏的源码(有感兴趣的可以自取):

    里面也有单向链表,和双向链表的源码。

     这里是我的gitee仓库的链接,项目的名称为Snake追风逐梦又一天/newer_C - 码云 - 开源中国 (gitee.com)icon-default.png?t=N7T8https://gitee.com/small-bit-big-dream/newer_-c

到这里就结束了,拜拜!


http://www.mrgr.cn/p/43537275

相关文章

UE4网络图片加载库(带内存缓存和磁盘缓存)

UE4网络图片加载库,带内存缓存和磁盘缓存,支持自定义缓存大小,支持蓝图和C++代码调用 1、调用示例 2、对外暴露函数 3、源代码-网络模块 KeImageNet.h // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreM…

BERT-CRF 微调中文 NER 模型

文章目录 数据集模型定义数据集预处理BIO 标签转换自定义Dataset拆分训练、测试集 训练验证、测试指标计算推理其它相关参数CRF 模块 数据集 CLUE-NER数据集&#xff1a;https://github.com/CLUEbenchmark/CLUENER2020/blob/master/pytorch_version/README.md 模型定义 imp…

vulfocus靶场couchdb 权限绕过 (CVE-2017-12635)

Apache CouchDB是一个开源数据库&#xff0c;专注于易用性和成为"完全拥抱web的数据库"。它是一个使用JSON作为存储格式&#xff0c;JavaScript作为查询语言&#xff0c;MapReduce和HTTP作为API的NoSQL数据库。应用广泛&#xff0c;如BBC用在其动态内容展示平台&…

WDS+MDT网络启动自动部署windows(七)添加驱动

简介: 以前的ghost,是封装万能驱动。 现在安装原版ISO,是手动安装驱动。 那么WDS+MDT,怎么装驱动更方便呢? 本来是轻接触,lite touch,通过设置rules,bootstrap,可以达到只选择一下任务序列即可。 那么也要自动安装驱动。 WDS也可以注入驱动,但是是在使用原版安装镜像…

【嵌入式AI部署神经网络】STM32CubeIDE上部署神经网络之指纹识别(Pytorch)——篇一|环境搭建与模型初步部署篇

前言&#xff1a;本篇主要讲解搭建所需环境&#xff0c;以及基于pytorch框架在stm32cubeide上部署神经网络&#xff0c;部署神经网络到STM32单片机&#xff0c;本篇实现初步部署模型&#xff0c;没有加入训练集与验证集&#xff0c;将在第二篇加入。篇二详细讲解STM32CubeIDE上…

4.19作业

1、总结二进制信号量和计数型信号量的区别&#xff0c;以及他们的使用场景。 二进制信号量&#xff1a;信号量的数值只能是0和1&#xff0c;用于共享资源的访问 计数型信号量&#xff1a;信号量的值都是大于或者等于2&#xff0c;实现生产者和消费者模型 2、使用技术型信号量…

手撕netty源码(一)- NioEventLoopGroup

文章目录 前言一、NIO 与 netty二、NioEventLoopGroup 对象的创建过程2.1 创建流程图 前言 本文是手撕netty源码系列的开篇文章&#xff0c;会先介绍一下netty对NIO关键代码的封装位置&#xff0c;主要介绍 NioEventLoopGroup 对象的创建过程&#xff0c;看看new一个对象可以做…

快速新建springboot项目

一、初始化 1.打开IDEA&#xff0c;在Spring initializer这里按照下图项目进行配置。注意&#xff1a;如果jdk是1.8建议将Server URL这里替换为图中的阿里云服务器&#xff0c;否则容易找不到对应的java8&#xff0c;然后点击next 2.在这里提前配置一些需要使用的依赖&#xf…

软考 系统架构设计师系列知识点之大数据设计理论与实践(13)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之大数据设计理论与实践&#xff08;12&#xff09; 所属章节&#xff1a; 第19章. 大数据架构设计理论与实践 第4节 Kappa架构 19.4.2 Kappa架构介绍 Kappa架构由Jay Kreps提出&#xff08;Lambda由Storm之父Nayhan M…

react引入iconfont的svg图标

react引入iconfont的svg图标 本文目录 react引入iconfont的svg图标普通图标通过link引入css组件内引入css使用 svg图标通过script引入js组件内引入js使用 通过封装组件自定义封装组件中调用 通过antd封装使用 普通图标 通过link引入css <link rel"stylesheet" h…

C语言 字符类型

下面 我们来说字符类型 我们来看这个 保险单 金额 和 总额 都可以用数字类型 而性别则需要字符型 字符数据的存储 – ASCI码 字符类型 char 就是专为存储字符(如字母&#xff0c;标点和数字)而设计的类型。 使用单引号包含单个字符或转义字符去表示一个 char 类型的常量。 …

【QT学习】9.绘图,三种贴图,贴图的转换,不规则贴图(透明泡泡)

一。绘图的解释 Qt 中提供了强大的 2D 绘图系统&#xff0c;可以使用相同的 API 在屏幕和绘图设备上进行绘制&#xff0c;它主要基于QPainter、QPaintDevice 和 QPaintEngine 这三个类。 QPainter 用于执行绘图操作&#xff0c;其提供的 API 在 GUI 或 QImage、QOpenGLPaintDev…

ZYNQ--PL读写PS端DDR数据

PL 和PS的高效交互是zynq 7000 soc开发的重中之重&#xff0c;我们常常需要将PL端的大量数 据实时送到PS端处理&#xff0c;或者将PS端处理结果实时送到PL端处理&#xff0c;常规我们会想到使用DMA 的方式来进行&#xff0c;但是各种协议非常麻烦&#xff0c;灵活性也比较差&am…

CDN、边缘计算与云计算:构建现代网络的核心技术

在数字化时代&#xff0c;数据的快速传输和处理是保持竞争力的关键。内容分发网络&#xff08;CDN&#xff09;、边缘计算和云计算共同构成了现代互联网基础架构的核心&#xff0c;使内容快速、安全地到达用户手中。本文将探讨这三种技术的功能、相互关系以及未来的发展趋势。 …

网络 (基础概念, OSI 七层模型, TCP/IP 五层模型)

网络互连 网络互连: 将多台计算机连接在一起, 完成数据共享 数据共享的本质是网络数据传输, 即计算机之间通过网络来传输数, 也叫做网络通信 根据网络互连的规模不同, 将网络划分为局域网和广域网 注意: 局域网和广域网是相对的概念 局域网LAN 又称内网, 局域网和局域网之间在没…

【快速入门 LVGL】-- 5、Gui Guider界面移植到STM32工程

上篇&#xff0c;我们已学习&#xff1a;【快速入门 LVGL】-- 4、显示中文 工程中添加了两个按钮作示范。运行效果如图&#xff1a; 本篇&#xff1a;把Gui Guider设计好的界面&#xff0c;移植到STM32工程。 特别地&#xff1a; 在使用Gui Guider进行界面设计时&#xff0c;应…

读天才与算法:人脑与AI的数学思维笔记08_生物的创造力

读天才与算法:人脑与AI的数学思维笔记08_生物的创造力1. 生物的创造力 1.1. 在进化树中是否有其他的物种已经具有与我们人类相当的创造力水平 1.2. 20世纪50年代中期,动物学家德斯蒙德莫里斯(Desmond Morris)在伦敦动物园做了这样一个试验 1.2.1. …

[转帖]18--k8s之Nginx ingress

https://www.cnblogs.com/caodan01/p/15142709.html 目录一、介绍 二、安装nginx ingress 三、http部署1.编写一个service准备实验 2.编写http的ingress 3.部署四、https部署 五、常用配置 一、介绍 ingress为kubernetes集群中的服务提供了入口,可以提供负载均衡,ssl终止和基…

基于Vue+ElementPlus自定义带历史记录的搜索框组件

前言 基于Vue2.5ElementPlus实现的一个自定义带历史记录的搜索框组件 效果如图&#xff1a; 基本样式&#xff1a; 获取焦点后&#xff1a; 这里的历史记录默认最大存储10条&#xff0c;同时右侧的清空按钮可以清空所有历史记录。 同时搜索记录也支持点击搜索&#xff0c;按…

SpringCloud系列(11)--将微服务注册进Eureka集群

前言&#xff1a;在上一章节中我们介绍并成功搭建了Eureka集群&#xff0c;本章节则介绍如何把微服务注册进Eureka集群&#xff0c;使服务达到高可用的目的 Eureka架构原理图 1、分别修改consumer-order80模块和provider-payment8001模块的application.yml文件&#xff0c;使这…