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

【C语言】基于C语言实现的贪吃蛇游戏

【C语言】基于C语言实现的贪吃蛇游戏

🔥个人主页大白的编程日记

🔥专栏C语言学习之路


文章目录

  • 【C语言】基于C语言实现的贪吃蛇游戏
    • 前言
    • 一.最终实现效果
    • 一.Win32 API介绍
      • 1.1Win32 API
      • 1.2控制台程序
      • 1.3控制台屏幕上的坐标COORD
      • 1.4GetStdHandle
      • 1.5GetConsoleCursorInfo
      • 1.6SetConsoleCursorInfo
      • 1.7SetConsoleCursorPosition
      • 1.8GetAsyncKeyState
    • 二.C语言的国际化
      • 2.1国际化
      • 2.2<locale.h>本地化
      • 2.3类项
      • 2.4setlocale函数
      • 2.5宽字符的打印
    • 三.思路分析
    • 四.GameStar函数
      • 4.1设置控制台信息
      • 4.2欢迎界面的打印
      • 4.3地图的绘制
      • 4.4初始化贪吃蛇
    • 五.GameRun函数
      • 5.1提示信息函数
      • 5.2打印分数
      • 5.3检测键值
      • 5.4蛇的移动
      • 5.5检测是否撞墙
    • 六.GameEnd函数
    • 七.游戏主体设计
    • 八.源码
    • 后言

前言

哈喽,各位小伙伴大家好!今天给大家带来的是使用C语言实现的贪吃蛇小游戏。也是检验C语言是否学好的试金石。话不多说,咱们进入正题!向大厂冲锋!

一.最终实现效果

贪吃蛇实现视频

一.Win32 API介绍

本次实现贪吃蛇会使用到的⼀些Win32 API知识,接下来我们就学习⼀下什么是Win32 API。

1.1Win32 API

Windows 这个多作业系统除了协调应⽤程序的执行、分配内存、管理资源之外,
它同时也是⼀个很大的服务中心,调用这个服务中心的各种服务(每⼀种服务就是⼀个函数),可以帮应用程序达到开启视窗、描绘图形、使⽤周边设备等目的,由于这些函数服务的对象是应⽤程序(Application), 所以便称之为 Application Programming Interface,简称 API 函数。
WIN32 API也就是Microsoft Windows32位平台的应用程序编程接口。

1.2控制台程序


平常我们运行起来的黑框程序其实就是控制台程序。
那这个控制台的大小我们可不可设置呢?其实是能的。

  • 设置大小
    我们可以使用cmd命令来设置控制台窗口的长宽:设置控制台窗口的大小,30行,100列。
mode con cols=100 lines=30

我们要设置控制台的话就需要使用system函数,system函数可以用来执行系统命令。

int main()
{system("mode con cols=40 lines=40");return 0;
}


  • 设置名字
    控制台的名字也能修改,使用title命令即可
title 贪吃蛇
int main()
{system("mode con cols=100 lines=30");system("title 贪吃蛇");getchar();return 0;
}

  • 控制台设置
    我们平时的默认是控制台终端,但是它实现不了我们想要的效果,所以我们要修改一下。

    先点箭头后出现的设置

    之后找到默认终端程序应用,改为控制台主机即可。

1.3控制台屏幕上的坐标COORD

我们的贪吃蛇游戏里面有蛇,食物,墙等等。他们涉及到的位置是我们游戏中的关键信息,那我们再屏幕上也要定位他们的位置,那怎么定位呢?这就涉及到COORD了。
COORD是WindowsAPI中定义的⼀个结构体,表示一个字符在控制台屏幕幕缓冲区上的坐标,坐标系(0,0)的原点位于缓冲区的顶部左侧单元格。


COORD是一种结构体类型

  • 结构体类型
typedef struct _COORD {SHORT X;SHORT Y;
} COORD, *PCOORD;
  • 头文件
    使用COORD结构体需要包含windows.h的头文件

那现在我们定义一个坐标就可以这样写

	COORD pos = { 2,3 };COORD pos1 = { 5,6 };

1.4GetStdHandle

GetStdHandle是⼀个WindowsAPI函数。它用于从⼀个特定的标准设备(标准输入、标准输出或标准错误)中取得⼀个句柄(用来标识不同设备的数值),使用这个句柄可以操作设备。
我们在控制台窗口中进行光标隐藏等操作时,都需要先获得这个窗口。而GetStdHandle就可以获得一个对窗口操作的把手,也就是句柄。通过这个把手我们就可以对控制台窗口进行操作。

HANDLE GetStdHandle(DWORD nStdHandle);

  • 参数
    标准设备。 此参数的取值可为下列值之一。

那我们贪吃蛇进行蛇的移动,食物的绘制等都是在屏幕上输出信息。所以我们需要或许标准输出设备的句柄

	HANDLE houtput = NULL;houtput=GetStdHandle(STD_OUTPUT_HANDLE);

1.5GetConsoleCursorInfo

大家可以发现我们运行时窗口会有一个光标闪烁,那等下贪吃蛇运行时我们是不希望它闪烁的,有没有办法把它隐藏掉呢?那我们得先获取光标信息。
GetConsoleCursorInfo是检索有关指定控制台屏幕缓冲区的光标大小可见性的信息的函数

它的参数有两个:

  • 光标控制台句柄

第一个参数是一个跟光标关联的控制台窗口的句柄

 _In_  HANDLE               hConsoleOutput,
  • 光标信息
    第二个参数是指向光标信息结构体CONSOLE_CURSOR_INFO的指针
 _Out_ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
  • 光标信息结构体

dwSize,由光标填充的字符单元格的百分比。此值介于1到100之间。光标外观会变化,范围从完全填充单元格到单元底部的水平线条
bVisible,游标的可见性。如果光标可见,则此成员为TRUE。


那我们现在获取光标就可以这样写

HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值) 
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo={0};//光标信息结构体
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息 

现在我们输出一下光标的信息看一下

	//获取标准输出的句柄(⽤来标识不同设备的数值) HANDLE hOutput = NULL;hOutput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo = { 0 };//光标信息结构体GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息 printf("%d", CursorInfo.dwSize);


现在我们把光标大小设为50

HANDLE hOutput = NULL;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo = { 0 };//光标信息结构体
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息 
CursorInfo.dwSize = 50;


可是为什么光标大小没变呢?
这是因为我们只修改了光标的信息,我们还需要设置修改后光标信息。

1.6SetConsoleCursorInfo

SetConsoleCursorInfo是用来设置指定控制台屏幕缓冲区的光标的大小和可见性。

  • 参数
BOOL WINAPI SetConsoleCursorInfo(_In_       HANDLE              hConsoleOutput,_In_ const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);


它的参数和GetConsoleCursorInfo一样。
现在我们来设置光标信息

  • 修改光标大小
  • 隐藏光标

1.7SetConsoleCursorPosition

那我们如何让光标移动到指定位置呢?
设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的位置。

  • 参数

一个是控制台窗口的句柄 一个是光标位置的结构体

BOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD pos
);

那我们现在想定位光标到第10行,第5列就可以这样写。

COORD pos = { 10, 5};HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值) hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为pos SetConsoleCursorPosition(hOutput, pos);

为了方便我们后面游戏打印食物和移动蛇的位置,我们封装⼀个设置光标位置的函数

//设置光标的坐标 
void SetPos(short x, short y)
{COORD pos = { x, y };HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值) hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为pos SetConsoleCursorPosition(hOutput, pos);
}

1.8GetAsyncKeyState

我们贪吃蛇游戏需要根据键盘的的按键进行上下左右的移动。 那如何让程序获取我们的按键信息呢?

这时就需要用到GetAsyncKeyState函数

将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。
GetAsyncKeyState的返回值是short类型,在上⼀次调用GetAsyncKeyState 函数后,如果返回的16位的short数据中,最高 位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。 如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1.

  • 参数
    函数的参数是一个int类型,代表要检测按键的虚拟键值
SHORT GetAsyncKeyState([in] int vKey
);
  • 虚拟键值表

这样我们就可以定义一个宏来检测按键是否被按过,只需检测函数返回值的最低位即可。

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

二.C语言的国际化

在游戏地图上,我们打印墙体使⽤宽字符:□,打印蛇使⽤宽字符●,打印食物使用宽字符★ 普通的字符是占⼀个字节的,这类宽字符是占用2个字节。
这⾥再简单的讲⼀下C语言的国际化特性相关的知识,过去C语言并不适合非英语国家(地区)使用。C语言最初假定字符都是单字节的。但是这些假定并不是在世界的任何地方都适用。

2.1国际化

C语言字符默认是采⽤ASCII编码的,ASCII字符集采⽤的是单字节编码,且只使用了单字节中的低7 位,最高位是没有使用的,可表⽰为0xxxxxxxx;可以看到,ASCII字符集共包含128个字符,在英语国家中,128个字符是基本够用的,但是,在其他国家语言中,比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,⼀些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。

比如,法语中的é的编码为130(⼆进制10000010)。这样⼀来,这些欧洲国家使⽤的编码体系,可以表示最多256个符号。但是,这⾥又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码⽅式,代表的字母却不⼀样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字⺟Gimel在俄语编码中又会代表另⼀个符号。但是不管怎样,所有这些编码方式中,0–127表示的符号是⼀样的,不⼀样的只是128–255的这一段。

至于亚洲国家的文字,使⽤的符号就更多了,汉字就多达10万左右。⼀个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达⼀个符号。比如,简体中文常见的编码方式是GB2312,使用两个字节表示⼀个汉字,所以理论上最多可以表示256x25=65536个符号。

后来为了使C语言适应国际化,C语言的标准中不断加入了国际化的支持。比如:加入了宽字符的类型wchar_t 和宽字符的输⼊和输出函数,加⼊了<locale.h>头文件,其中提供了允许程序员针对特定地区(通常是国家或者说某种特定语⾔的地理区域)调整程序行为的函数。

2.2<locale.h>本地化

<locale.h>提供的函数用于控制C标准库中对于不同的地区会产生不⼀样行为的部分。
在标准中,依赖地区的部分有以下几项:

  • 数字量的格式
  • 货币量的格式
  • 字符集
  • 日期和时间的表示形式

2.3类项

通过修改地区,程序可以改变它的行为来适应世界的不同区域。但地区的改变可能会影响库的许多部分,其中⼀部分可能是我们不希望修改的。所以C语言支持针对不同的类项进行修改,下面的⼀个宏,指定⼀个类项:

  • LC_COLLATE:影响字符串比较函数 strcoll() 和 strxfrm()
  • LC_CTYPE:影响字符处理函数的行为。
  • LC_MONETARY:影响货币格式。
  • LC_NUMERIC:影响 printf() 的数字格式。
  • LC_TIME:影响时间格式 strftime() 和 wcsftime() 。
  • LC_ALL-针对所有类项修改,将以上所有类别设置为给定的语⾔环境。

2.4setlocale函数

setlocale函数⽤于修改当前地区,可以针对一个类项修改,也可以针对所有类项。setlocale的第⼀个参数可以是前⾯说明的类项中的⼀个,那么每次只会影响⼀个类项,如果第⼀个参数是LC_ALL,就会影响所有的类项。

C标准给第⼆个参数仅定义了2种可能取值:“C”(正常模式)和""(本地模式)。

  • 正常模式
    在任意程序执行开始,都会隐藏式执行调用:
setlocale(LC_ALL, "C");

地区设置为"C"时,库函数按正常方式执行,小数点是⼀个点

  • 本地模式
    当程序运行起来后想改变地区,就只能显示调用setlocale函数。⽤"作为第2个参数,调用setlocale函数就可以切换到本地模式,这种模式下程序会适应本地环境。
    比如:切换到我们的本地模式后就支持宽字符(汉字)的输出等。
setlocale(LC_ALL, " ");//切换到本地环境 

2.5宽字符的打印

那如果想在屏幕上打印宽字符,怎么打印呢?
宽字符的字面量必须加上前缀“L”,否则C语言会把字面量当作窄字符类型处理。前缀“L”在单引
号前面,表⽰宽字符,对应 wprintf() 的占位符为 %lc ;在双引号前⾯,表示宽字符串,对应
wprintf() 的占位符为 %ls 。

#include <stdio.h>
#include<locale.h>
int main() {setlocale(LC_ALL, "");wchar_t ch1 = L'●'; wchar_t ch2 = L'⽐';wchar_t ch3 = L'特';wchar_t ch4 = L'★';printf("%c%c\n", 'a', 'b');wprintf(L"%lc\n", ch1);wprintf(L"%lc\n", ch2);wprintf(L"%lc\n", ch3);wprintf(L"%lc\n", ch4);return 0;
}

三.思路分析

我们先把游戏分为三个大的模块。每个模块分别负责不同的功能。 每个模块具体实现又由多个小的函数模块合理设计拼接后组成。大体的思路如下:

  • GameStar函数
    GameStar函数负责进入窗口大小和名字的设置,光标的隐藏。
    欢迎界面的打印,地图的绘制。
    贪吃蛇的创建和初始化,食物的创建。

  • GameRun函数
    右侧打印帮助信息-PrintHelpInfo
    打印当前已获得分数和每个食物的分数以提示用户
    根据按键情况移动蛇-SnakeMove直到游戏是结束状态

  • SnakeMove
    根据蛇头的坐标和方向,计算下⼀个节点的坐标
    判断下⼀个节点是否是食物-NextIsFood
    是食物就吃掉-EatFood
    不是食物,吃掉食物,尾巴删除⼀节-NoFood
    判断是否撞墙-KillByWall
    判断是否撞上自己-KillBySelf

  • GameEnd
    告知游戏结束的原因
    释放蛇身节点

四.GameStar函数

为了方便阅读代码,这里先把我们定义好的宏给大家看

  • 实现效果


4.1设置控制台信息

首先我们需要设置控制台大小,名字,还要隐藏光标。
这些操作我们前面讲过的了。不再过多赘述了。

system("mode con cols=100 lines=30");//设置控制台窗口大小
system("title 贪吃蛇");//设置控制台名字
HANDLE houtput = NULL;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);
//定义一个光标信息的结构体
CONSOLE_CURSOR_INFO cursor_info ;
//获取和houtput句柄相关的控制台上的光标信息,存放在cursor_info中
GetConsoleCursorInfo(houtput, &cursor_info);
//修改光标(隐藏光标)
cursor_info.bVisible= false;
//设置和houtput句柄相关的控制台上的光标信息
SetConsoleCursorInfo(houtput, &cursor_info);

4.2欢迎界面的打印



这里我们把欢迎界面的打印封装为WelcomeToSnake函数
我们只需要将光标定位到指定位置,然后打印文字即可。
注意这里涉及到程序的暂停我们用system函数即可实现。
打印完切换下一个界面时,我们清理屏幕。这个用system函数也能实现
再定位打印文字。

void WelcomeToSnake()
{setpos(40, 14);//定位光标wprintf(L"欢迎来到贪吃蛇小游戏~\n");setpos(42, 20);//定位光标system("pause");//暂停程序system("cls");//清理屏幕setpos(25, 14);//定位光标wprintf(L"分别用↑.↓.←.→控制移动方向,F3加速,F4减速\n");setpos(25, 15);//定位光标wprintf(L"加速能够获得更高的分数\n");setpos(42, 20);//定位光标system("pause");//暂停程序system("cls");//清理屏幕
}

4.3地图的绘制

地图的绘制我们也单独封装为一个Greatmap()函数
假设我们要绘制一个27行 58列的地图,我们只需要关注好四个角落点的坐标,
然后用四层for循环打印即可。
在这里插入图片描述

void Greatmap()
{setpos(0, 0);//定位原点for (int i = 0; i < 29; i++)//打印第一行墙体{wprintf(L"%lc", WALL);}setpos(0, 26);//定位第二行起点for (int i = 0; i < 29; i++)//打印第二行墙体{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);}
}

这里大家要注意行的打印光标不需要移动,但是列的打印光标需要移动。

4.4初始化贪吃蛇

游戏中食物的信息,贪吃蛇的信息,蛇的移动方向, 游戏状态,食物分数,总得分,蛇的移动快慢(休眠时间), 食物信息。都是我们游戏过程中需要维护的信息。我们维护游戏其实就是维护这些信息。我们把他们用结构体包含,作为贪吃蛇,我们只需要维护这贪吃蛇即可。

  • 游戏状态
    四种游戏状态:正常游戏 撞墙 咬到自己 玩家主动结束。
    用枚举类型即可。
enum STATUS//游戏的状态
{ok = 1,kill_by_wall,kill_by_self,end
};
  • 蛇的移动方向
    四种移动状态:上 下 左 右。
    用枚举类型即可。
enum DIRECTION//枚举蛇的方向
{up = 1,down,left ,right
};
  • 蛇头
    蛇的维护我们只需要一个指向蛇头的指针即可。食物我们也可以看成蛇的节点。蛇的节点我们用链表来表示。
typedef struct SnakeNode //蛇身
{int x;int y;struct SnakeNode* next;
}Snakenode,* pSnakenode;
  • 其他信息
    食物分数 总分 休眠时间
    用int类型即可。
int fool_score;
int score;
int sleep_time;
  • 贪吃蛇信息
typedef struct Snake//游戏中贪吃蛇的信息
{pSnakenode shead;pSnakenode snakefool;enum DRIECTION dir;enum STATUS statu;int fool_score;int score;int sleep_time;
}Snake,*psnake;
  • 创建食物函数
    我们创建一个蛇的节点作为食物节点。再用rand函数生成横纵坐标。
    然后循环遍历区判断食物节点和和蛇身的每一个节点坐标是否有重合。
    重合就用goto语句继续生成坐标知道不重合为止。接着打印食物即可。
void GreatFool(psnake ps)
{pSnakenode pcur = ps->shead;pSnakenode fool = (pSnakenode)malloc(sizeof(Snakenode));//创建蛇的节点作为食物节点if (fool == NULL)//判空{perror("GreatFool:malloc");return;}int x, y;
again:do{x = rand() % 53 + 2;//生成横坐标y = rand() % 25 + 1;//纵坐标} while (x % 2 != 0);//保证横坐标为偶数while (pcur)//遍历蛇身{if (pcur->x == x && pcur->y == y)goto again;//食物和蛇身重叠重新生成pcur = pcur->next;}fool->x = x;//赋值横坐标fool->y = y;//赋值纵坐标fool->next = NULL;//置空setpos(fool->x, fool->y);//定位光标wprintf(L"%lc", FOOD);//打印食物ps->snakefool= fool;//存放食物节点
}

最后我们再循环创建五个初始的蛇身节点,初始化贪吃蛇信息,再创建食物即可。

void Initsnake(psnake ps)
{psnake pcur = ps;for (int i = 0; i < 5; i++)//创建五个蛇的节点{pSnakenode node = (pSnakenode)malloc(sizeof(Snakenode));//创建蛇的节点if (node == NULL)//判空{perror("Initsnake:malloc");return;}node->next = NULL;node->x = POS_X + 2 * i;//横坐标node->y = POS_Y;//纵坐标if (pcur->shead == NULL){pcur->shead = node;//蛇头节点(第一个节点)}else{node->next = pcur->shead;//头插法pcur->shead = node;}while (node)//遍历蛇身打印{setpos(node->x, node->y);//定位蛇身坐标wprintf(L"%lc", BODY);//打印node = node->next;//遍历下一个蛇身节点}}ps->dir = right;//默认移动方向为右ps->statu = ok;//游戏状态正常ps->fool_score = 10;//默认食物分数为10ps->score = 0;//总分为0ps->sleep_time = 200;//休眠时间默认为0GreatFool(ps);//创建食物
}

五.GameRun函数

5.1提示信息函数


在游戏时我们打印一下提示信息给玩家。封装PrintHelpInfo()

void PrintHelpInfo()//打印提示信息
{setpos(64, 15);wprintf(L"不能穿墙,不能咬到⾃⼰\n");setpos(64, 16);printf("分别用↑.↓.←.→分别控制蛇的移动\n");setpos(64, 17);wprintf(L"F3 为加速,F4 为减速\n");setpos(64, 18);wprintf(L"ESC :退出游戏.space:暂停游戏.");setpos(64, 19);wprintf(L"成杰MAKE");
}

5.2打印分数


游戏过程食物分数和总得分都需要更新
我们也要打印出来。

setpos(64, 10);//定位
printf("总分:%2d", ps->score);//打印信息
setpos(64, 11);//定位
printf("当前食物分数:%2d", ps->fool_score);//打印信息

5.3检测键值

游戏过程我们需要根据键盘输入进行相对的相应
蛇的移动,暂停 加速减速等。
我们前面已经定义了一个宏,直接使用即可

#define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )//检测虚拟键值
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))//检测ESC按键
{ps->statu = end;//设置退出游戏状态
}
else if (KEY_PRESS(VK_SPACE) )//检测space按键
{Pause();//暂停游戏
}
else if (KEY_PRESS(VK_F3))//检车f3加速按键
{if (ps->sleep_time > 120)//设置加速上限{ps->sleep_time -= 20;//减少休眠加快速度ps->fool_score += 2;//分数增加}
}
else if (KEY_PRESS(VK_F4))//检测f4减速按键
{if (ps->fool_score> 2)//设置减速上限{ps->sleep_time += 20;//增加休眠时间减慢速度ps->fool_score -= 2;//分数减少}
}

注意我们移动时不能与当前移动方向相反。
加速减速我们加减休眠时间即可。
暂停我们用pause函数即可,检测space按键,按过直接break跳出即可。
否则一直休眠。

void Pause()
{while (1){Sleep(200);//休眠if (KEY_PRESS(VK_SPACE))//检测是否再次按space按键{break;//继续游戏}}
}

检测完后我们再根据按键输入进行蛇的移动即可。
我们封装为Snakemove函数。
我们先创建一个节点作为下一个蛇头节点。
然后根据移动方向给节点横纵坐标赋值即可。

pSnakenode pcur = (pSnakenode)malloc(sizeof(Snakenode));//生成蛇头下一个位置的节点
if (pcur == NULL)//判空
{perror("Snakemove:malloc");return; 
}
switch (ps->dir)//检测蛇移动方向
{
case up:pcur->y=ps->shead->y -1;//赋值横坐标pcur->x = ps->shead->x;//赋值纵坐标break;
case down:pcur->y = ps->shead->y +1;//赋值横坐pcur->x = ps->shead->x; // 赋值纵坐标break;
case right:pcur->x = ps->shead->x +2;//赋值横坐pcur->y = ps->shead->y; // 赋值纵坐标break;
case left:pcur->x = ps->shead->x -2;//赋值横坐pcur->y = ps->shead->y; // 赋值纵坐标break;
}

5.4蛇的移动

蛇的移动分两种情况:

  • 吃食物移动
    若下一个位置是食物。
    我们释放开辟的节点,然后让食物节点成为新的蛇头节点
    然后遍历打印蛇身,再创建新的食物即可。同时更新得分。
void EatFood(pSnakenode pn, psnake ps)//吃食物
{ps->snakefool->next = ps->shead;//食物节点链接蛇头ps->shead = ps->snakefool;//食物节点成为蛇头free(pn);//释放新开辟的蛇头节点pn = NULL;pSnakenode cur = ps->shead;while (cur)//遍历打印蛇身{setpos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->score += ps->fool_score;//总分增加GreatFool(ps);//生成新的食物
}
  • 不吃食物移动
    让新开辟节点链接原来的蛇头,新开辟的节点成为新的蛇头。
    再遍历找到倒数第二个尾节点,释放尾巴节点,再让倒数第二个节点指向空封尾。同时记得打印空白覆盖掉蛇尾节点打印的信息。再遍历打印蛇身即可。
void NotFood(pSnakenode pn, psnake ps)
{pn->next = ps->shead;//让新的蛇头连接原来的蛇头ps->shead = pn;//让蛇下一个位置的节点成为新的蛇头pSnakenode pcur = ps->shead;while (pcur->next->next != NULL)//找到蛇尾倒数第二个节点{pcur = pcur->next;//移动}pSnakenode dle = pcur;setpos(pcur->next->x, pcur->next->y);//定位光标到最后的蛇尾printf("  ");//覆盖原来蛇尾打印的信息free(dle->next);//释放最后的蛇尾节点dle->next = NULL;pSnakenode cur = pn;while (cur){setpos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}
}

5.5检测是否撞墙

我们只需要检测横坐标是否为0或56
纵坐标是否为0或26。
再根据穿墙的横坐标或纵坐标不变,修改蛇头另一变化坐标即可。
最后即可设置游戏状态即可。
要实现穿墙我们再让蛇每次移动都刷新城墙即可。

void KillByWall(psnake ps)
{if (ps->shead->x == 56)//检测是否撞到第二列城墙{ps->shead->x = 0;//重新定位穿墙后的横坐标位置(第一列出)}else if (ps->shead->x == 0)//检测是否撞到第一列城墙{ps->shead->x = 56;//重新定位穿墙后的横坐标位置(第二列出)}else if (ps->shead->y == 0)//检测是否撞到第一行城墙{ps->shead->y = 26;//重新定位穿墙后的纵坐标位置(第一行出)}else if (ps->shead->y == 26)//检测是否撞到第二行城墙{ps->shead->y = 0;//重新定位穿墙后的纵坐标位置(第二行出)}
}
  • 检测是否咬到自己
    我们只需要判断当前蛇头坐标是否与其他蛇身坐标重合即可。
    用循环遍历蛇身在判断即可。最后即可设置游戏状态即可
void KillBySelf( psnake ps)
{pSnakenode pcur = ps->shead->next;//保存蛇头下一个节点while (pcur)//遍历蛇身{if (ps->shead->x == pcur->x && ps->shead->y == pcur->y)//蛇身与蛇头重合{ps->statu = kill_by_self;//设置游戏状态break;//结束循环}pcur = pcur->next;//移动}
}

每次移动后都检测撞墙和咬到自己。
判断游戏状态,正常则继续游戏。

六.GameEnd函数

游戏结束我们需要检测游戏状态再打印对应提示信息。
最后循环遍历销毁蛇身节点和食物节点即可

void GemaEnd(psnake ps)
{pSnakenode pcur = ps->shead;setpos(20, 12);//定位光标switch (ps->statu)//游戏状态{case kill_by_wall://撞墙wprintf(L"您撞到墙上,游戏结束!");break;case kill_by_self://咬到自己wprintf(L"您咬到自己,游戏结束!");break;case end://自己结束wprintf(L"您主动结束了游戏!");break;}setpos(0, 27);//定位光标while (pcur)//遍历蛇身销毁链表{pSnakenode del = pcur;//保存销毁节点pcur = pcur->next;//移动下一个销毁节点free(del);//销毁del = NULL;}free(ps->snakefool);//销毁食物ps->snakefool = NULL;
} 

七.游戏主体设计

最后我们调用三大模块函数即可,再用do_while循环给用户选择是否继续再来一局游戏的选择。注意使用宽字符要记得本地化。

setlocale(LC_ALL, "");
void test()
{char ch = 0;do{Snake snake = { 0 };GemeStar(&snake);GameRun(&snake);GemaEnd(&snake);setpos(20, 15);wprintf(L"再来一局吗?(Y/N):");ch = getchar();setpos(0, 27);} while (ch == 'Y' || ch == 'y');
}

八.源码

  • Snake.h
#pragma once
#include<Windows.h>
#include<stdlib.h>
#include<stdio.h> 
#include<stdbool.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 )//检测虚拟键值
enum DIRECTION//枚举蛇的方向
{up = 1,down,left ,right
};
enum STATUS//游戏的状态
{ok = 1,kill_by_wall,kill_by_self,end
};
typedef struct SnakeNode //蛇身
{int x;int y;struct SnakeNode* next;
}Snakenode,* pSnakenode;
typedef struct Snake//游戏中贪吃蛇的信息
{pSnakenode shead;pSnakenode snakefool;enum DRIECTION dir;enum STATUS statu;int fool_score;int score;int sleep_time;
}Snake,*psnake;
void setpos(short x,short y);
void GemeStar(psnake ps);
void Greatmap();
void Initsnake(psnake ps);
void GreatFool(psnake ps);
void GameRun(psnake ps);
void PrintHelpInfo();
void Pause();
void Snakemove(psnake ps);
int NextIsFood(pSnakenode pn, psnake ps);
void EatFood(pSnakenode pn, psnake ps);
void NotFood(pSnakenode pn, psnake ps);
void KillByWall(psnake ps);
void KillBySelf(psnake ps);
void GemaEnd(psnake ps);
  • Snake.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"snake.h"
void WelcomeToSnake()
{setpos(40, 14);//定位光标wprintf(L"欢迎来到贪吃蛇小游戏~\n");setpos(42, 20);//定位光标system("pause");//暂停程序system("cls");//清理屏幕setpos(25, 14);//定位光标wprintf(L"分别用↑.↓.←.→控制移动方向,F3加速,F4减速\n");setpos(25, 15);//定位光标wprintf(L"加速能够获得更高的分数\n");setpos(42, 20);//定位光标system("pause");//暂停程序system("cls");//清理屏幕
}
void GemeStar(psnake ps)
{system("mode con cols=100 lines=30");//设置控制台窗口大小system("title 贪吃蛇");//设置控制台名字HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//定义一个光标信息的结构体CONSOLE_CURSOR_INFO cursor_info ;//获取和houtput句柄相关的控制台上的光标信息,存放在cursor_info中GetConsoleCursorInfo(houtput, &cursor_info);//修改光标(隐藏光标)cursor_info.bVisible= false;//设置和houtput句柄相关的控制台上的光标信息SetConsoleCursorInfo(houtput, &cursor_info);WelcomeToSnake();//欢迎界面打印 Greatmap();//地图打印Initsnake(ps);//初始化贪吃蛇的信息
}
void Greatmap()
{setpos(0, 0);//定位原点for (int i = 0; i < 29; i++)//打印第一行墙体{wprintf(L"%lc", WALL);}setpos(0, 26);//定位第二行起点for (int i = 0; i < 29; i++)//打印第二行墙体{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 setpos(short x, short y)//定位坐标函数
{HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//创建句柄COORD pos = {x,y};//坐标的结构体SetConsoleCursorPosition(houtput, pos);//设置光标位置
}
void Initsnake(psnake ps)
{psnake pcur = ps;for (int i = 0; i < 5; i++)//创建五个蛇的节点{pSnakenode node = (pSnakenode)malloc(sizeof(Snakenode));//创建蛇的节点if (node == NULL)//判空{perror("Initsnake:malloc");return;}node->next = NULL;node->x = POS_X + 2 * i;//横坐标node->y = POS_Y;//纵坐标if (pcur->shead == NULL){pcur->shead = node;//蛇头节点(第一个节点)}else{node->next = pcur->shead;//头插法pcur->shead = node;}while (node)//遍历蛇身打印{setpos(node->x, node->y);//定位蛇身坐标wprintf(L"%lc", BODY);//打印node = node->next;//遍历下一个蛇身节点}}ps->dir = right;//默认移动方向为右ps->statu = ok;//游戏状态正常ps->fool_score = 10;//默认食物分数为10ps->score = 0;//总分为0ps->sleep_time = 200;//休眠时间默认为0GreatFool(ps);//创建食物
}
void GreatFool(psnake ps)
{pSnakenode pcur = ps->shead;pSnakenode fool = (pSnakenode)malloc(sizeof(Snakenode));//创建蛇的节点作为食物节点if (fool == NULL)//判空{perror("GreatFool:malloc");return;}int x, y;
again:do{x = rand() % 53 + 2;//生成横坐标y = rand() % 25 + 1;//纵坐标} while (x % 2 != 0);//保证横坐标为偶数while (pcur)//遍历蛇身{if (pcur->x == x && pcur->y == y)goto again;//食物和蛇身重叠重新生成pcur = pcur->next;}fool->x = x;//赋值横坐标fool->y = y;//赋值纵坐标fool->next = NULL;//置空setpos(fool->x, fool->y);//定位光标wprintf(L"%lc", FOOD);//打印食物ps->snakefool= fool;//存放食物节点
}
void PrintHelpInfo()//打印提示信息
{setpos(64, 15);wprintf(L"不能穿墙,不能咬到⾃⼰\n");setpos(64, 16);printf("分别用↑.↓.←.→分别控制蛇的移动\n");setpos(64, 17);wprintf(L"F3 为加速,F4 为减速\n");setpos(64, 18);wprintf(L"ESC :退出游戏.space:暂停游戏.");setpos(64, 19);wprintf(L"成杰MAKE");
}
void Pause()
{while (1){Sleep(200);//休眠if (KEY_PRESS(VK_SPACE))//检测是否再次按space按键{break;//继续游戏}}
}
int NextIsFood(pSnakenode pn, psnake ps)
{return (pn->x == ps->snakefool->x &&pn->y == ps->snakefool->y);//判断下一个节点是否是食物
}void Snakemove(psnake ps)
{pSnakenode pcur = (pSnakenode)malloc(sizeof(Snakenode));//生成蛇头下一个位置的节点if (pcur == NULL)//判空{perror("Snakemove:malloc");return; }switch (ps->dir)//检测蛇移动方向{case up:pcur->y=ps->shead->y -1;//赋值横坐标pcur->x = ps->shead->x;//赋值纵坐标break;case down:pcur->y = ps->shead->y +1;//赋值横坐pcur->x = ps->shead->x; // 赋值纵坐标break;case right:pcur->x = ps->shead->x +2;//赋值横坐pcur->y = ps->shead->y; // 赋值纵坐标break;case left:pcur->x = ps->shead->x -2;//赋值横坐pcur->y = ps->shead->y; // 赋值纵坐标break;}if (NextIsFood(pcur, ps))//判断下一个节点是否为食物{EatFood(pcur, ps);//吃食物的移动}else{NotFood(pcur,ps);//不吃食物的移动}
}
void GameRun(psnake ps)
{PrintHelpInfo();//打印提示信息do{setpos(64, 10);//定位printf("总分:%2d", ps->score);//打印信息setpos(64, 11);//定位printf("当前食物分数:%2d", ps->fool_score);//打印信息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))//检测ESC按键{ps->statu = end;//设置退出游戏状态}else if (KEY_PRESS(VK_SPACE) )//检测space按键{Pause();//暂停游戏}else if (KEY_PRESS(VK_F3))//检车f3加速按键{if (ps->sleep_time > 120)//设置加速上限{ps->sleep_time -= 20;//减少休眠加快速度ps->fool_score += 2;//分数增加}}else if (KEY_PRESS(VK_F4))//检测f4减速按键{if (ps->fool_score> 2)//设置减速上限{ps->sleep_time += 20;//增加休眠时间减慢速度ps->fool_score -= 2;//分数减少}}Snakemove(ps);//蛇移动Greatmap();//每次移动刷新城墙实现穿墙;Sleep(ps->sleep_time);//休眠KillByWall(ps);//检测是否撞墙KillBySelf(ps);//检测是否咬到自己} while (ps->statu == ok);//检测游戏状态
}
void EatFood(pSnakenode pn, psnake ps)//吃食物
{ps->snakefool->next = ps->shead;//食物节点链接蛇头ps->shead = ps->snakefool;//食物节点成为蛇头free(pn);//释放新开辟的蛇头节点pn = NULL;pSnakenode cur = ps->shead;while (cur)//遍历打印蛇身{setpos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->score += ps->fool_score;//总分增加GreatFool(ps);//生成新的食物
}
void NotFood(pSnakenode pn, psnake ps)
{pn->next = ps->shead;//让新的蛇头连接原来的蛇头ps->shead = pn;//让蛇下一个位置的节点成为新的蛇头pSnakenode pcur = ps->shead;while (pcur->next->next != NULL)//找到蛇尾倒数第二个节点{pcur = pcur->next;//移动}pSnakenode dle = pcur;setpos(pcur->next->x, pcur->next->y);//定位光标到最后的蛇尾printf("  ");//覆盖原来蛇尾打印的信息free(dle->next);//释放最后的蛇尾节点dle->next = NULL;pSnakenode cur = pn;while (cur){setpos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}
}
void KillByWall(psnake ps)
{if (ps->shead->x == 56)//检测是否撞到第二列城墙{ps->shead->x = 0;//重新定位穿墙后的横坐标位置(第一列出)}else if (ps->shead->x == 0)//检测是否撞到第一列城墙{ps->shead->x = 56;//重新定位穿墙后的横坐标位置(第二列出)}else if (ps->shead->y == 0)//检测是否撞到第一行城墙{ps->shead->y = 26;//重新定位穿墙后的纵坐标位置(第一行出)}else if (ps->shead->y == 26)//检测是否撞到第二行城墙{ps->shead->y = 0;//重新定位穿墙后的纵坐标位置(第二行出)}
}
void KillBySelf( psnake ps)
{pSnakenode pcur = ps->shead->next;//保存蛇头下一个节点while (pcur)//遍历蛇身{if (ps->shead->x == pcur->x && ps->shead->y == pcur->y)//蛇身与蛇头重合{ps->statu = kill_by_self;//设置游戏状态break;//结束循环}pcur = pcur->next;//移动}
}
void GemaEnd(psnake ps)
{pSnakenode pcur = ps->shead;setpos(20, 12);//定位光标switch (ps->statu)//游戏状态{case kill_by_wall://撞墙wprintf(L"您撞到墙上,游戏结束!");break;case kill_by_self://咬到自己wprintf(L"您咬到自己,游戏结束!");break;case end://自己结束wprintf(L"您主动结束了游戏!");break;}setpos(0, 27);//定位光标while (pcur)//遍历蛇身销毁链表{pSnakenode del = pcur;//保存销毁节点pcur = pcur->next;//移动下一个销毁节点free(del);//销毁del = NULL;}free(ps->snakefool);//销毁食物ps->snakefool = NULL;
} 
  • test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"snake.h"
void test()
{char ch = 0;do{Snake snake = { 0 };GemeStar(&snake);GameRun(&snake);GemaEnd(&snake);setpos(20, 15);wprintf(L"再来一局吗?(Y/N):");ch = getchar();setpos(0, 27);} while (ch == 'Y' || ch == 'y');
}
int main(){setlocale(LC_ALL, "");test();return 0;
}

后言

这就是用C语言写出来的贪吃蛇小游戏。这游戏基本使用到C语言所学的全部内容。也算是C语言的试金石吧!今天就分享到这里,感谢小伙伴的耐心垂阅!咱们下期见!拜拜~
在这里插入图片描述

相关文章:

【C语言】基于C语言实现的贪吃蛇游戏

【C语言】基于C语言实现的贪吃蛇游戏 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C语言学习之路 文章目录 【C语言】基于C语言实现的贪吃蛇游戏前言一.最终实现效果一.Win32 API介绍1.1Win32 API1.2控制台程序1.3控制台屏幕上的坐标COORD…...

代码审计(工具Fortify 、Seay审计系统安装及漏洞验证)

源代码审计 代码安全测试简介 代码安全测试是从安全的角度对代码进行的安全测试评估。&#xff08;白盒测试&#xff1b;可看到源代码&#xff09; 结合丰富的安全知识、编程经验、测试技术&#xff0c;利用静态分析和人工审核的方法寻找代码在架构和编码上的安全缺陷&#xf…...

cocos creator 3.x 手搓背包拖拽装备

项目背景&#xff1a; 游戏背包 需要手动 拖拽游戏装备到 装备卡槽中&#xff0c;看了下网上资料很少。手搓了一个下午搞定&#xff0c;现在来记录下实现步骤&#xff1b; 功能拆分&#xff1a; 一个完整需求&#xff0c;我们一般会把它拆分成 几个小步骤分别造零件。等都造好了…...

运维开发.Kubernetes探针与应用

运维系列 Kubernetes探针与应用 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263…...

Spring 框架:Java 企业级开发的基石

文章目录 序言Spring 框架的核心概念Spring 框架的主要模块Spring Boot&#xff1a;简化 Spring 开发Spring Cloud&#xff1a;构建微服务架构实际案例分析结论 序言 Spring 框架自 2002 年发布以来&#xff0c;已经成为 Java 企业级开发的标准之一。它通过提供全面的基础设施…...

在Docker中使用GPU

一、安装nvidia-container-toolkit 总之一句话&#xff1a;nvidia-docker和nvidia-docker2&#xff0c;nvidia-container-runtime 已经被英伟达迭代了&#xff0c;可以认为nvidia-container-toolkit是nvidia-docker和nvidia-docker2&#xff0c; nvidia-container-runtime 的替…...

vue3 前端实现导出下载pdf文件

这样的数据实现导出 yourArrayBufferOrByteArray 就是后端返回数据 // 创建Blob对象const blob new Blob([new Uint8Array(res)], { type: application/pdf })// 创建一个表示该Blob的URLconst url URL.createObjectURL(blob);// 创建一个a标签用于下载const a document.cr…...

AI智能体研发之路-模型篇(五):pytorch vs tensorflow框架DNN网络结构源码级对比

博客导读&#xff1a; 《AI—工程篇》 AI智能体研发之路-工程篇&#xff08;一&#xff09;&#xff1a;Docker助力AI智能体开发提效 AI智能体研发之路-工程篇&#xff08;二&#xff09;&#xff1a;Dify智能体开发平台一键部署 AI智能体研发之路-工程篇&#xff08;三&am…...

电商物流查询解决方案助力提升消费者体验

截至2023年12月&#xff0c;中国网络购物用户规模达9.15亿人&#xff0c;占网民整体的83.8%。这一庞大的数字不仅展现了电子商务的蓬勃发展&#xff0c;也标志着数字零售企业营销战略的转变——从以产品和流量为核心&#xff0c;到用户为王的新阶段。因此&#xff0c;提升消费者…...

【深度密码】神经网络算法在机器学习中的前沿探索

目录 &#x1f69d;前言 &#x1f68d;什么是机器学习 1. 基本概念 2. 类型 3. 关键算法 4. 应用领域 5. 工作流程 &#x1f68b;什么是神经网络 基本结构 &#x1f682;神经网络的工作原理 前向传播&#xff08;Forward Propagation&#xff09;&#xff1a; 损失函…...

搭载算能 BM1684 芯片,面向AI推理计算加速卡

搭载算能 BM1684 芯片&#xff0c;是面向AI推理的算力卡。可集成于服务器、工控机中&#xff0c;高效适配市场上所有AI算法&#xff0c;实现视频结构化、人脸识别、行为分析、状态监测等应用&#xff0c;为智慧城市、智慧交通、智慧能源、智慧金融、智慧电信、智慧工业等领域进…...

Python开发 我的世界 Painting-the-World: Minecraft 像素图片生成器

简介 Painting-the-World 是一款创新的工具&#xff0c;专为《我的世界》(Minecraft) 玩家及创作者设计&#xff0c;旨在将数字图片转变为游戏内的像素艺术。通过利用 RCON (Remote Console) 协议&#xff0c;本项目可以直接与《我的世界》服务器对话&#xff0c;根据输入的图…...

【经验分享】盘点“食用“的写文素材

一、构建框架 简介 1. 身份 擅长领域 2. 博客内容 3. 目前示例&#xff1a; 阿里云专家博主&#xff0c;华为云-云享专家&#xff0c;专注前、后端开发 博客内容&#xff1a;前后端实战教学、源码剖析、常见面试知识解析、算法题解与心得、日常考研总结等 目前正在备战考研&…...

实习碰到的问题w1

1.vueelementUI在输入框中按回车键会刷新页面 当一个 form 元素中只有一个输入框时&#xff0c;在该输入框中按下回车应提交该表单。如果希望阻止这一默认 行为&#xff0c;可以在 <el-form> 标签上添加 submit.native.prevent 。 参考&#xff1a;element-ui 表单 form …...

c#实现BPM系统网络传输接口,http协议,post

BPM通过http协议实现网络传输&#xff0c;语言使用.net(c#)&#xff0c;在这里只提供一个接口&#xff0c;具体代码如下,请参照&#xff1a; public string MakeRequest(string parameters) { ServicePointManager.ServerCertificateValidationCallback new Syst…...

如何修改开源项目中发现的bug?

如何修改开源项目中发现的bug&#xff1f; 目录 如何修改开源项目中发现的bug&#xff1f;第一步&#xff1a;找到开源项目并建立分支第二步&#xff1a;克隆分支到本地仓库第三步&#xff1a;在本地对项目进行修改第四步&#xff1a;依次使用命令行进行操作注意&#xff1a;Gi…...

结构设计模式 - 代理设计模式 - JAVA

代理设计模式 一. 介绍二. 代码示例2.1 定义 CommandExecutor 类2.2 定义 CommandExecutorProxy代理类2.3 模拟客户端2.4 测试结果 三. 结论 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子…...

企业了解这些cad图纸加密方法,再也不怕图纸被盗了!

在竞争激烈的商业环境中&#xff0c;企业的核心技术、设计图纸和创意是维持其市场地位和竞争优势的关键。CAD图纸作为产品设计的重要载体&#xff0c;其安全性自然成为企业关注的焦点。为了确保CAD图纸不被非法获取或盗用&#xff0c;企业需要采取一系列有效的加密方法。本文将…...

# 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项

为什么会突然想到写这么一个大杂烩的博文呢&#xff0c;必须要从笔者几年前的一次面试说起 当时的我年轻气盛&#xff0c;在简历上放了自己的博客地址&#xff0c;而面试官应该是翻了我的博客&#xff0c;好几道面试题都是围绕着我的博文来提问 其中一个问题&#xff0c;直接…...

神经网络与深度学习——第14章 深度强化学习

本文讨论的内容参考自《神经网络与深度学习》https://nndl.github.io/ 第14章 深度强化学习 深度强化学习 强化学习&#xff08;Reinforcement Learning&#xff0c;RL&#xff09;&#xff0c;也叫增强学习&#xff0c;是指一类从与环境交互中不断学习的问题以及解决这类问题…...

centOS 编译C/C++

安装C和C编译器 yum -y install gcc*查看CenterOS系统信息 cat /etc/system-releaseCentOS Linux release 8.2.2004 (Core)查看gcc版本 gcc --versiongcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) Copyright (C) 2018 Free Software Foundation, Inc. This is free software…...

java——网络原理初识

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 目录 1.网络通信概念初识1.1 IP地址1.2端口号1.3协议1.3.1协议分层协议分层带来的好处主要有两个方面 1.3.2 TCP/IP五层 (或四层模型)1.3.3 协议的层和层之间是怎么配合工作的 1.网络通信概念初识…...

js怎么判断是否为手机号?js格式校验方法

数据格式正确与否是表单填写不可避免的一个流程&#xff0c;现整理一些较为常用的信息格式校验方法。 判断是否为手机号码 // 判断是否为手机号码 function isPhoneNumber(phone) {return /^[1]\d{10}$/.test(phone) }判断是否为移动手机号 function isChinaMobilePhone(phon…...

深入理解Java中的方法重载:让代码更灵活的秘籍

关注微信公众号 “程序员小胖” 每日技术干货&#xff0c;第一时间送达&#xff01; 引言 在Java编程的世界里&#xff0c;重载(Overloading)是一项基础而强大的特性&#xff0c;它让我们的代码更加灵活、可读性强。对于追求高效、优雅编码的开发者而言&#xff0c;掌握方法重…...

鸿蒙ArkTS声明式开发:跨平台支持列表【显隐控制】 通用属性

显隐控制 控制组件是否可见。 说明&#xff1a; 开发前请熟悉鸿蒙开发指导文档&#xff1a; gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本…...

每日一题——Java编程练习题

题目&#xff1a; 键盘录入两个数字number1和number2表示一个范围&#xff0c;求这个范围之内的数字和。 我写的代码&#xff1a; public class Test {public static void main(String[] args) {Scanner sc new Scanner(System.in);System.out.print("输入第一个数:&q…...

java编辑器中如何调试程序?

目录 如何调试java程序? 待续、更新中 如何调试java程序? 1 看错误信息 2 相应位置输入输出信息: System.out.println("测试信息1 "); 以此查看哪条语句未进行输入 待续、更新中 1 顿号、: 先使用ctrl. &#xff0c;再使用一遍切回 2 下标: 21 2~1~ 3 上标: 2…...

第四范式Q1业务进展:驰而不息 用科技锻造不朽价值

5月28日&#xff0c;第四范式发布今年前三个月的核心业务进展&#xff0c;公司坚持科技创新&#xff0c;业务稳步拓展&#xff0c;用人工智能为千行万业贡献价值。 今年前三个月&#xff0c;公司总收入人民币8.3亿元&#xff0c;同比增长28.5%&#xff0c;毛利润人民币3.4亿元&…...

SpringBoot整合Kafka的快速使用教程

目录 一、引入Kafka的依赖 二、配置Kafka 三、创建主题 1、自动创建(不推荐) 2、手动动创建 四、生产者代码 五、消费者代码 六、常用的KafKa的命令 Kafka是一个高性能、分布式的消息发布-订阅系统&#xff0c;被广泛应用于大数据处理、实时日志分析等场景。Spring B…...

低边驱动与高边驱动

一.高边驱动和低边驱动 低边驱动(LSD): 在电路的接地端加了一个可控开关&#xff0c;低边驱动就是通过闭合地线来控制这个开关的开关。容易实现&#xff08;电路也比较简单&#xff0c;一般由MOS管加几个电阻、电容&#xff09;、适用电路简化和成本控制的情况。 高边驱动&am…...

【C++】入门(二):引用、内联、auto

书接上回&#xff1a;【C】入门&#xff08;一&#xff09;&#xff1a;命名空间、缺省参数、函数重载 文章目录 六、引用引用的概念引用的使用场景1. 引用做参数作用1&#xff1a;输出型参数作用2&#xff1a;对象比较大&#xff0c;减少拷贝&#xff0c;提高效率 2. 引用作为…...

编程学习 (C规划) 6 {24_4_18} 七 ( 简单扫雷游戏)

首先我们要清楚扫雷大概是如何实现的&#xff1a; 1.布置雷 2.扫雷&#xff08;排查雷&#xff09; &#xff08;1&#xff09;如果这个位置是雷就炸了&#xff0c;游戏结束 &#xff08;2&#xff09;如果不是雷&#xff0c;就告诉周围有几个雷 3.把所有不是雷的位置都找…...

【AI】llama-fs的 安装与运行

pip install -r .\requirements.txt Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved.Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows(venv) PS D:\XTRANS\pythonProject>...

Android NDK系列(五)内存监控

在日常的开发中&#xff0c;内存泄漏是一种比较比较棘手的问题&#xff0c;这是由于其具有隐蔽性&#xff0c;即使发生了泄漏&#xff0c;很难检测到并且不好定位到哪里导致的泄漏。如果程序在运行的过程中不断出现内存泄漏&#xff0c;那么越来越多的内存得不到释放&#xff0…...

软件设计师,下午题 ——试题六

模型图 简单工厂模式 工厂方法模式抽象工厂模式生成器模式原型模式适配器模式桥接模式组合模式装饰&#xff08;器&#xff09;模式亨元模式命令模式观察者模式状态模式策略模式访问者模式中介者模式 简单工厂模式 工厂方法模式 抽象工厂模式 生成器模式 原型模式 适配器模式 桥…...

《Kubernetes部署篇:基于麒麟V10+ARM64架构部署harbor v2.4.0镜像仓库》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;企业级K8s集群运维实战 一、环境信息 K8S版本 操作系统 CPU架构 服务版本 1.26.15 Kylin Linux Advanced Server V10 ARM64 harbor v2.4.0 二、部…...

远程工作/线上兼职网站整理(数字游民友好)

文章目录 国外线上兼职网站fiverrupwork 国内线上兼职网站甜薪工场猪八戒网云队友 国外线上兼职网站 fiverr https://www.fiverr.com/start_selling?sourcetop_nav upwork https://www.upwork.com/ 国内线上兼职网站 甜薪工场 https://www.txgc.com/ 猪八戒网 云队友 …...

elasticsearch7.15实现用户输入自动补全

Elasticsearch Completion Suggester&#xff08;补全建议&#xff09; Elasticsearch7.15安装 官方文档 补全建议器提供了根据输入自动补全/搜索的功能。这是一个导航功能&#xff0c;引导用户在输入时找到相关结果&#xff0c;提高搜索精度。 理想情况下&#xff0c;自动补…...

掌握正则表达式的力量:全方位解析PCRE的基础与进阶技能

Perl 兼容正则表达式&#xff08;PCRE&#xff09;是 Perl scripting language 中所使用的正则表达式语法标准。这些正则表达式在 Linux 命令行工具&#xff08;如 grep -P&#xff09;及其他编程语言和工具中也有广泛应用。以下是一些基础和进阶特性&#xff0c;帮你掌握和使用…...

FastFM库,一款强大神奇的Python系统分析预测的工具

FastFM库概述 在机器学习领域,Factorization Machines&#xff08;FM&#xff09;是处理稀疏数据集中特征间交互的重要工具.Python的fastFM库提供了高效的实现,特别适合用于推荐系统、评分预测等任务.本文将全面介绍fastFM的安装、特性、基本和高级功能,并结合实际应用场景展示…...

R语言绘图 --- 饼状图(Biorplot 开发日志 --- 2)

「写在前面」 在科研数据分析中我们会重复地绘制一些图形&#xff0c;如果代码管理不当经常就会忘记之前绘图的代码。于是我计划开发一个 R 包&#xff08;Biorplot&#xff09;&#xff0c;用来管理自己 R 语言绘图的代码。本系列文章用于记录 Biorplot 包开发日志。 相关链接…...

用于日常任务的实用 Python 脚本

Python 是一种多功能编程语言&#xff0c;以其简单易读而闻名。它广泛应用于从 Web 开发到数据分析等各个领域。Python 脚本&#xff0c;它们可以通过自动执行常见任务来使您的生活更轻松。 用于日常任务的实用 Python 脚本 1. 使用 Pandas 进行数据分析2. 使用 BeautifulSoup …...

7-Zip是什么呢

1. 简介 7-Zip 是一个功能强大、免费开源的文件压缩和解压缩工具&#xff0c;适用于个人用户和企业用户&#xff0c;可以在多种操作系统上进行使用&#xff0c;并且支持广泛的压缩格式和高级功能。 2. 特点与优势 开源免费&#xff1a;7-Zip 是免费的开源软件&#xff0c;可…...

Satellite Stereo Pipeline学习

1.在Anaconda某个环境中安装s2p pip install s2p 2.在Ubuntu系统中安装s2p源代码 git clone https://github.com/centreborelli/s2p.git --recursive cd s2p pip install -e ".[test]" 3.在s2p中进行make all处理 中间会有很多情况&#xff0c;基本上哪个包出问题…...

linux-gpio

在Linux shell中测试GPIO通信&#xff0c;通常需要使用GPIO的设备文件&#xff0c;这些文件通常位于/sys/class/gpio目录下。要使用特定的GPIO引脚&#xff0c;比如GPIO92&#xff0c;你需要执行以下步骤&#xff1a; 导出GPIO引脚&#xff1a;首先&#xff0c;需要确保GPIO92已…...

C# 代码配置的艺术

文章目录 1、代码配置的定义及其在软件工程中的作用2、C# 代码配置的基本概念和工具3、代码配置的实践步骤4、实现代码配置使用属性&#xff08;Properties&#xff09;使用配置文件&#xff08;Config Files&#xff09;使用依赖注入&#xff08;Dependency Injection&#xf…...

268 基于matlab的模拟双滑块连杆机构运动

基于matlab的模拟双滑块连杆机构运动&#xff0c;并绘制运动动画&#xff0c;连杆轨迹可视化输出&#xff0c;并输出杆件质心轨迹、角速度、速度变化曲线。可定义杆长、滑块速度&#xff0c;滑块初始位置等参数。程序已调通&#xff0c;可直接运行。 268 双滑块连杆机构运动 连…...

进口铝合金电动隔膜泵

进口铝合金电动隔膜泵是一种高效、可靠的工业泵&#xff0c;其特点、性能与应用广泛&#xff0c;以下是对其的详细分析&#xff1a; 特点 材质与结构&#xff1a; 采用铝合金材料制造&#xff0c;具有良好的耐腐蚀性和轻量化特点。铝合金材质使得泵体结构紧凑、轻便&#xff…...

G4 - 可控手势生成 CGAN

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目录 代码总结与心得 代码 关于CGAN的原理上节已经讲过&#xff0c;这次主要是编写代码加载上节训练后的模型来进行指定条件的生成 图像的生成其实只需要使用…...

使用 DuckDuckGo API 实现多种搜索功能

在日常生活中&#xff0c;我经常使用搜索引擎来查找信息&#xff0c;如谷歌和百度。然而&#xff0c;当我想通过 API 来实现这一功能时&#xff0c;会发现这些搜索引擎并没有提供足够的免费 API 服务。如果有这样的免费 API, 就能定时获取“关注实体”的相关内容&#xff0c;并…...