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

C语言——贪吃蛇

一. 游戏效果


贪吃蛇


二. 游戏背景

贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。
贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》,后移植到各种平台上。具体如下:
起源。1977年,投币式墙壁游戏生产商Gremlin推出了经典的街机游戏《Blockade》,两名玩家要分别控制角色移动,角色会不停长大,而且走过的地方会变成围栏,谁先碰到围栏或碰到自己的身体就算输。
贪吃蛇最初的版本是像素版本,后来又衍生出3D版本、多人对战版本等2 3。
 

三、游戏开发日志

四、知识准备 

本次实现贪吃蛇会使⽤到的⼀些Win32 API知识,那么就学习⼀下

4.1 Win32 API

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

4.2 控制台程序

平常我们运⾏起来的⿊框程序其实就是控制台程序。
我们可以使⽤cmd命令来设置控制台窗⼝的⻓宽,也可以通过命令设置控制台窗⼝的名字:
设置控制台窗⼝的⼤⼩,30⾏,100列,设置控制台窗⼝的名字。
//控制台窗口设置
system("mode con cols=100 lines=35");
system("title 贪吃蛇");

4.3  控制台屏幕上的坐标COORD

COORD 是Windows API中定义的⼀种结构,表⽰⼀个字符在控制台屏幕上的坐标

typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;

4.4  GetStdHandle

GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

4.5 GetConsoleCursorInfo

检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息

4.5.1  CONSOLE_CURSOR_INFO

这个结构体,包含有关控制台游标的信息
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
(1) dwSize,由光标填充的字符单元格的百分⽐。 此值介于1到100之间。 光标外观会变化,范围从完全填充单元格到单元底部的⽔平线条。
(2)  bVisible,游标的可⻅性。 如果光标可⻅,则此成员为 TRUE。
CursorInfo.bVisible = false; //隐藏控制台光标

5.6  SetConsoleCursorInfo

设置指定控制台屏幕缓冲区的光标的⼤⼩和可⻅性。

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态

5.7  SetConsoleCursorPosition

设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调 ⽤SetConsoleCursorPosition函数将光标位置设置到指定的位置。

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

这里我们可以将SetPos:封装⼀个设置光标位置的函数

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

5.8 GetAsyncKeyState

获取按键情况,将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。
返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果 返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。
如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1.
我们这里定义一个宏:
 #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

5.9 宽字符打印

在游戏地图上,我们打印墙体使⽤宽字符:□,打印蛇使⽤宽字符●,打印⻝物使⽤宽字符■
普通的字符是占⼀个字节的,这类宽字符是俩个字节。

5.9.1  setlocale函数

char* setlocale (int category, const char* locale);

setlocale 函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项。 setlocale 的第⼀个参数如果是LC_ALL,就会影响所有的类项。

C标准给第⼆个参数仅定义了2种可能取值:"C"和"  "。
在任意程序执⾏开始,都会隐藏式执⾏调⽤:
 setlocale(LC_ALL, "C");

当地区设置为"C"时,库函数按正常⽅式执⾏.

当地区设置为"  "时,这种模式下程序会适应本地环境。⽐如:切换到我们的本地模式后就⽀
持宽字符(汉字)的输出等。
setlocale(LC_ALL, " ");//切换到本地环境

宽字符的打印如下:

#include <stdio.h>
#include<locale.h>
int main() {
setlocale(LC_ALL, "");
wchar_t ch1 = L'●';
wprintf(L"%c\n", ch1);
return 0;
}

五、游戏实现

5.1 游戏逻辑主体

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"
#include<locale.h>
#include<stdio.h>
int main()
{char ch;setlocale(LC_ALL, "");//切换到本地环境,支持宽字符srand((unsigned int)time(NULL));do{Snake snake = { 0 };GameInit(&snake);GameRun(&snake);GameOver(&snake);printf("小垃圾还要再来吗?是:Y,否:N\n");ch = getchar();getchar();} while (ch == 'y' || ch == 'Y');return 0;
}

5.2  游戏初始化实现

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"#define  WALL  L'□'
#define  BODY  L'●'
#define  FOOD  L'█'
void SetPos(short x, short y)
{COORD pos = { x, y };HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);
}
void  WelcomeToGame()
{SetPos(40, 13);printf("欢迎来到贪吃蛇小游戏");SetPos(42, 22);system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步system("cls");SetPos(25, 12);printf("↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");SetPos(42, 22);system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步system("cls");/*getchar();*/}
void CreateMap()
{SetPos(0,0);int i = 0;for(i=0;i<58;i=i+2){wprintf(L"%c", WALL);}SetPos(0, 26);for (i = 0; i < 58; i = i + 2){wprintf(L"%c", WALL);}for (i = 1; i <26; i++){SetPos(0, i);wprintf(L"%c", WALL);}for (i = 1; i < 26; i++){SetPos(56, i);wprintf(L"%c", WALL);}/*getchar();*/
}void InitSnake(Snake* snake)
{//初始化蛇身for (int i = 0; i < 5; i++){SnakeNode* node = (SnakeNode*)malloc(sizeof(SnakeNode));node->x = 24 + 2 * i;node->y = 15;node->next = NULL;if (snake->pSnake== NULL){snake->pSnake= node;}else{node->next = snake->pSnake;snake->pSnake = node;}}SnakeNode* cur = snake->pSnake;while (cur){int x = cur->x;int y = cur->y;SetPos(x, y);wprintf(L"%c", BODY);cur = cur->next;}snake->status = RUN;snake->dir = RIGHT;snake->FoodWeight = 10;snake->pFood = NULL;snake->score = 0;snake->SleepTime = 200;
}
void CreateFood(Snake* snake)
{int x = 0;int y = 0;again:do{x = rand() % 53 + 2;y = rand() % 24 + 1;} while (x % 2 != 0);SnakeNode* cur = snake->pSnake;do{if (x == cur->x && y == cur->y){goto again;}cur = cur->next;} while (cur);SnakeNode* food = (SnakeNode*)malloc(sizeof(SnakeNode));food->x = x;food->y = y;snake->pFood = food;SetPos(x, y);wprintf(L"%c", FOOD);/*getchar();*/}void  GameInit(Snake* snake)
{//控制台窗口设置system("mode con cols=100 lines=35");system("title 贪吃蛇");//隐藏光标HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态//打印欢迎界面WelcomeToGame();//创建地图CreateMap();//初始化贪吃蛇InitSnake(snake);//创建食物CreateFood(snake);
}

5.3 游戏运行实现

void PrintHelpInfo()
{SetPos(60, 13);printf("1. 不能穿墙不能咬到自己\n");SetPos(60, 14);printf("2.↑.↓.←.→分别控制蛇的移动\n");SetPos(60, 15);printf("3. F3为加速,F4为减速\n");SetPos(60, 16);printf("4. ESC-退出,空格-暂停\n");
}void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE) == 1){break;}}}
void EatFood(Snake* snake, SnakeNode* snakenext)
{snakenext->next = snake->pSnake;snake->pSnake = snakenext;SnakeNode* cur = snake->pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}free(snake->pFood);snake->pFood = NULL;CreateFood(snake);}
void NoEatFood(Snake* snake, SnakeNode* snakenext)
{snakenext->next = snake->pSnake;snake->pSnake = snakenext;SnakeNode* cur = snake->pSnake;while (cur->next->next){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);printf("  ");free(cur->next);cur->next = NULL;
}void SnakeMove(Snake* snake)
{SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));if (snake->dir == UP){snakenext->x = snake->pSnake->x;snakenext->y = snake->pSnake->y -1;snakenext->next = NULL;}else if (snake->dir == DOWN){snakenext->x = snake->pSnake->x;snakenext->y = snake->pSnake->y +1;snakenext->next = NULL;}if (snake->dir == LEFT){snakenext->x = snake->pSnake->x-2;snakenext->y = snake->pSnake->y ;snakenext->next = NULL;}if (snake->dir == RIGHT){snakenext->x = snake->pSnake->x + 2;snakenext->y = snake->pSnake->y;snakenext->next = NULL;}//判断下一个节点是否为食物if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y){EatFood(snake,snakenext);//吃食物snake->score += snake->FoodWeight;}else{NoEatFood(snake,snakenext);//不吃食物}//碰撞检测if (snake->pSnake->x == 0 || snake->pSnake->x == 56 || snake->pSnake->y == 0 || snake->pSnake->y == 26){snake->status = KILL_BY_WALL;}SnakeNode* cur = snake->pSnake->next;while (cur){if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y){snake->status = KILL_BY_SELF;}cur = cur->next;}
}void GameRun(Snake* snake)
{//打印帮助信息PrintHelpInfo();do{SetPos(60, 8);printf("游戏总得分:%5d ", snake->score);SetPos(60, 9);printf("每个食物的分数:%2d ", snake->FoodWeight);if (KEY_PRESS(VK_UP) == 1&&snake->dir!=DOWN){snake->dir = UP;}else if (KEY_PRESS(VK_DOWN) == 1 && snake->dir != UP){snake->dir = DOWN;}else if (KEY_PRESS(VK_RIGHT) == 1 && snake->dir != LEFT){snake->dir = RIGHT;}else if (KEY_PRESS(VK_LEFT) == 1 && snake->dir != RIGHT){snake->dir =LEFT;}else if (KEY_PRESS(VK_F3) == 1){if (snake->SleepTime>=80){snake->SleepTime -= 30;snake->FoodWeight += 2;}}else if (KEY_PRESS(VK_F4) == 1){if (snake->SleepTime<=320){snake->SleepTime += 30;snake->FoodWeight -= 2;}}else if (KEY_PRESS(VK_ESCAPE) == 1){snake->status = OVER;break;}else if (KEY_PRESS(VK_SPACE) == 1){Pause();}SnakeMove(snake);Sleep(snake->SleepTime);//每一帧停0.2s} while (snake->status==RUN);
}

5.4 游戏结束实现

void GameOver(Snake* snake)
{switch (snake->status){case KILL_BY_WALL:SetPos(20, 15);printf("你已经撞墙了,小垃圾!\n");break;case KILL_BY_SELF:SetPos(20, 15);printf("你已经自杀了,小垃圾!\n");break;case  OVER:SetPos(20, 15);printf("你退出游戏了,小垃圾!\n");break;}SetPos(0, 29);}

六、 完整代码

6.1 snake.h

#define _CRT_SECURE_NO_WARNINGS
#include<stdbool.h>
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
enum direction{UP = 1,  DOWN, LEFT, RIGHT};//蛇的方向
enum game_status{RUN,KILL_BY_WALL,KILL_BY_SELF,OVER};typedef struct  SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode;typedef struct Snake
{SnakeNode* pSnake;//指向贪吃蛇头节点SnakeNode* pFood;//指向食物的节点int  score;int FoodWeight;int SleepTime;enum direction dir;//蛇的方向enum  game_status status;//游戏状态
}Snake;
void  GameInit(Snake*snake);
void  WelcomeToGame();
void CreateMap();
void InitSnake(Snake* snake);
void CreateFood(Snake* snake);
void GameRun(Snake* snake);
void PrintHelpInfo();
void Pause();
void SnakeMove(Snake* snake);void EatFood(Snake* snake,SnakeNode*snakenext);
void NoEatFood(Snake* snake, SnakeNode* snakenext);
void GameOver(Snake* snake);

6.2 snake.c

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"#define  WALL  L'□'
#define  BODY  L'●'
#define  FOOD  L'█'
void SetPos(short x, short y)
{COORD pos = { x, y };HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);
}
void  WelcomeToGame()
{SetPos(40, 13);printf("欢迎来到贪吃蛇小游戏");SetPos(42, 22);system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步system("cls");SetPos(25, 12);printf("↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");SetPos(42, 22);system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步system("cls");/*getchar();*/}
void CreateMap()
{SetPos(0,0);int i = 0;for(i=0;i<58;i=i+2){wprintf(L"%c", WALL);}SetPos(0, 26);for (i = 0; i < 58; i = i + 2){wprintf(L"%c", WALL);}for (i = 1; i <26; i++){SetPos(0, i);wprintf(L"%c", WALL);}for (i = 1; i < 26; i++){SetPos(56, i);wprintf(L"%c", WALL);}/*getchar();*/
}void InitSnake(Snake* snake)
{//初始化蛇身for (int i = 0; i < 5; i++){SnakeNode* node = (SnakeNode*)malloc(sizeof(SnakeNode));node->x = 24 + 2 * i;node->y = 15;node->next = NULL;if (snake->pSnake== NULL){snake->pSnake= node;}else{node->next = snake->pSnake;snake->pSnake = node;}}SnakeNode* cur = snake->pSnake;while (cur){int x = cur->x;int y = cur->y;SetPos(x, y);wprintf(L"%c", BODY);cur = cur->next;}snake->status = RUN;snake->dir = RIGHT;snake->FoodWeight = 10;snake->pFood = NULL;snake->score = 0;snake->SleepTime = 200;
}
void CreateFood(Snake* snake)
{int x = 0;int y = 0;again:do{x = rand() % 53 + 2;y = rand() % 24 + 1;} while (x % 2 != 0);SnakeNode* cur = snake->pSnake;do{if (x == cur->x && y == cur->y){goto again;}cur = cur->next;} while (cur);SnakeNode* food = (SnakeNode*)malloc(sizeof(SnakeNode));food->x = x;food->y = y;snake->pFood = food;SetPos(x, y);wprintf(L"%c", FOOD);/*getchar();*/}void  GameInit(Snake* snake)
{//控制台窗口设置system("mode con cols=100 lines=35");system("title 贪吃蛇");//隐藏光标HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态//打印欢迎界面WelcomeToGame();//创建地图CreateMap();//初始化贪吃蛇InitSnake(snake);//创建食物CreateFood(snake);
}void PrintHelpInfo()
{SetPos(60, 13);printf("1. 不能穿墙不能咬到自己\n");SetPos(60, 14);printf("2.↑.↓.←.→分别控制蛇的移动\n");SetPos(60, 15);printf("3. F3为加速,F4为减速\n");SetPos(60, 16);printf("4. ESC-退出,空格-暂停\n");
}void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE) == 1){break;}}}
void EatFood(Snake* snake, SnakeNode* snakenext)
{snakenext->next = snake->pSnake;snake->pSnake = snakenext;SnakeNode* cur = snake->pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}free(snake->pFood);snake->pFood = NULL;CreateFood(snake);}
void NoEatFood(Snake* snake, SnakeNode* snakenext)
{snakenext->next = snake->pSnake;snake->pSnake = snakenext;SnakeNode* cur = snake->pSnake;while (cur->next->next){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);printf("  ");free(cur->next);cur->next = NULL;
}void SnakeMove(Snake* snake)
{SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));if (snake->dir == UP){snakenext->x = snake->pSnake->x;snakenext->y = snake->pSnake->y -1;snakenext->next = NULL;}else if (snake->dir == DOWN){snakenext->x = snake->pSnake->x;snakenext->y = snake->pSnake->y +1;snakenext->next = NULL;}if (snake->dir == LEFT){snakenext->x = snake->pSnake->x-2;snakenext->y = snake->pSnake->y ;snakenext->next = NULL;}if (snake->dir == RIGHT){snakenext->x = snake->pSnake->x + 2;snakenext->y = snake->pSnake->y;snakenext->next = NULL;}//判断下一个节点是否为食物if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y){EatFood(snake,snakenext);//吃食物snake->score += snake->FoodWeight;}else{NoEatFood(snake,snakenext);//不吃食物}//碰撞检测if (snake->pSnake->x == 0 || snake->pSnake->x == 56 || snake->pSnake->y == 0 || snake->pSnake->y == 26){snake->status = KILL_BY_WALL;}SnakeNode* cur = snake->pSnake->next;while (cur){if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y){snake->status = KILL_BY_SELF;}cur = cur->next;}
}void GameRun(Snake* snake)
{//打印帮助信息PrintHelpInfo();do{SetPos(60, 8);printf("游戏总得分:%5d ", snake->score);SetPos(60, 9);printf("每个食物的分数:%2d ", snake->FoodWeight);if (KEY_PRESS(VK_UP) == 1&&snake->dir!=DOWN){snake->dir = UP;}else if (KEY_PRESS(VK_DOWN) == 1 && snake->dir != UP){snake->dir = DOWN;}else if (KEY_PRESS(VK_RIGHT) == 1 && snake->dir != LEFT){snake->dir = RIGHT;}else if (KEY_PRESS(VK_LEFT) == 1 && snake->dir != RIGHT){snake->dir =LEFT;}else if (KEY_PRESS(VK_F3) == 1){if (snake->SleepTime>=80){snake->SleepTime -= 30;snake->FoodWeight += 2;}}else if (KEY_PRESS(VK_F4) == 1){if (snake->SleepTime<=320){snake->SleepTime += 30;snake->FoodWeight -= 2;}}else if (KEY_PRESS(VK_ESCAPE) == 1){snake->status = OVER;break;}else if (KEY_PRESS(VK_SPACE) == 1){Pause();}SnakeMove(snake);Sleep(snake->SleepTime);//每一帧停0.2s} while (snake->status==RUN);
}void GameOver(Snake* snake)
{switch (snake->status){case KILL_BY_WALL:SetPos(20, 15);printf("你已经撞墙了,小垃圾!\n");break;case KILL_BY_SELF:SetPos(20, 15);printf("你已经自杀了,小垃圾!\n");break;case  OVER:SetPos(20, 15);printf("你退出游戏了,小垃圾!\n");break;}SetPos(0, 29);}

6.3 text.c

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"
#include<locale.h>
#include<stdio.h>
int main()
{char ch;setlocale(LC_ALL, "");//切换到本地环境,支持宽字符srand((unsigned int)time(NULL));do{Snake snake = { 0 };GameInit(&snake);GameRun(&snake);GameOver(&snake);printf("小垃圾还要再来吗?是:Y,否:N\n");ch = getchar();getchar();} while (ch == 'y' || ch == 'Y');return 0;
}

相关文章:

C语言——贪吃蛇

一. 游戏效果 贪吃蛇 二. 游戏背景 贪吃蛇是久负盛名的游戏&#xff0c;它也和俄罗斯⽅块&#xff0c;扫雷等游戏位列经典游戏的⾏列。 贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》&#xff0c;后移植到各种平台上。具体如下&#xff1a; 起源。1977年&#xff0c;投币式…...

Android sqlite 使用简介

进行Android应用开发时经常会用到数据库。Android系统支持sqlite数据库&#xff0c;在app开发过程中很容易通过SQLiteOpenHelper使用数据库&#xff0c;SQLiteOpenHelper依赖于Context对象&#xff0c;但是基于uiatomator1.0和Java程序等无法获取Context的应用如何使用数据库呢…...

UE地形系统材质混合实现和Shader生成分析(UE5 5.2)

前言 随着电脑和手机硬件性能越来越高&#xff0c;游戏越来越追求大世界&#xff0c;而大世界非常核心的一环是地形系统&#xff0c;地形系统两大构成因素&#xff1a;高度和多材质混合&#xff0c;此篇文章介绍下UE4/UE5 地形的材质混合方案----基于WeightMap混合。 材质层 …...

Git分支与Git标签的介绍及其场景应用

目录 一、Git分支 1.1 定义 1.2 基本概念 1.3 特点与优势 1.4 Git分支操作命令 1.4.1 查看分支 1.4.2 创建分支 1.4.3 删除分支 1.4.4 切换分支 1.4.5 创建并切换到新建分支 1.5 场景应用 1.5.1 前期准备 1.5.2 具体操作 二、Git标签 2.1 定义 2.2 类型 2.3 标…...

Three.js——基于原生WebGL封装运行的三维引擎

文章目录 前言一、什么是WebGL&#xff1f;二、Three.js 特性 前言 Three.js中文官网 Three.js是基于原生WebGL封装运行的三维引擎&#xff0c;在所有WebGL引擎中&#xff0c;Three.js是国内文资料最多、使用最广泛的三维引擎。既然Threejs是一款WebGL三维引擎&#xff0c;那么…...

第八章认识Express框架

目录 Express模块化路由 基本概述 基本使用 基本构建 案例项目 Express接收请求参数 基本概述 基本类别 Express接收GET请求参数 Express接收POST请求参数 Express接收路由参数 Express模块化路由 基本概述 在Express中&#xff0c;路由是指确定应用程序如何响应对…...

【K8s集群离线安装-kubeadm】

1、kubeadm概述 kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具。这个工具能通过两条指令快速完成一个kubernetes集群的部署。 2、环境准备 2.1 软件环境 软件版本操作系统CentOS 7Docker19.03.13K8s1.23 2.2 服务器 最小硬件配置&#xff1a;2核CPU、2G内存…...

python工具CISCO ASA设备任意文件读取

​python漏洞利用 构造payload&#xff1a; /CSCOT/translation-table?typemst&textdomain/%2bCSCOE%2b/portal_inc.lua&default-language&lang../漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&#xff0c;万分感谢。 免…...

TCP关闭的两种方法概述

一个TCP需要经过四次挥手才可以关闭连接&#xff0c;能够开启四次挥手的函数有两个&#xff1a; int close(int sockfd) int shutdown(int sockfd,int howto) 接下来就分别讲解一下这两个函数。 close()函数 函数原型 #include<unistd.h> int close(int sockfd)这个函…...

Git的Hooks机制

参考文章&#xff1a;详解如何在项目中使用git Hooks&#xff08;husky、yorkie&#xff09; git hooks钩子 git hooks是一些自定义的脚本&#xff0c;用于控制git工作的流程&#xff0c;分为客户端钩子和服务端钩子。  ~/work/step-time/ [master*] ll .git/hooks total…...

代码随想录算法训练营第四十九天|121. 买卖股票的最佳时机、122. 买卖股票的最佳时机 II

第九章 动态规划part10 121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最…...

Rust教程6:并发编程和线程通信

文章目录 线程初步join方法线程通信 Rust系列&#xff1a;初步⚙所有权⚙结构体和枚举类⚙函数进阶⚙泛型和特征 线程初步 在Rust中&#xff0c;开启多线程进行并发编程&#xff0c;只需调用thread::spawn&#xff0c;但这里有一个坑点&#xff0c;即spawn函数只有一个传入参…...

JVM在线分析-监控工具(jps, jstat, jstatd)

参考官方文档&#xff08;jdk11&#xff09; https://docs.oracle.com/en/java/javase/11/tools/troubleshooting-tools-and-commands.html#GUID-CB44BFBA-E5F9-4D80-8EE8-28E9F16BC451 1. 监控工具(jps, jstat, jstatd) jps -q Suppresses the output of the class name, J…...

Console LDAP 配置解密

之前通过短视频向大家介绍了 Console 如何集成 LDAP&#xff0c;但很多小伙伴反映按照视频里的配置后不成功。今天就结合小伙伴们反映的问题来跟大家详细介绍一下。 Console LDAP 完整的配置参数如下&#xff1a; 名称类型说明hoststringLDAP 服务器地址portintLDAP 服务器端口…...

node插件MongoDB(三)—— 库mongoose 的使用和数据类型(一)

前言 提示&#xff1a;使用mongoose 的前提是你安装了node和 MongoDB。 mongoose 官网文档&#xff1a;http://mongoosejs.net/docs/index.html 文章目录 前言一、安装二、基本使用1. 打开bin目录的mongod.exe文件2. 基本使用的代码&#xff08;连接mongodb 服务&#xff09;3.…...

基础(二)

基础&#xff08;二&#xff09; 字符串型 C风格&#xff1a;char 变量名[] “字符串值”&#xff1b; C风格&#xff1a;string 变量名 “字符串值” #include <iostream> using namespace std; #include <string>int main() {// C风格char str1[] "h…...

思维模型 目标效应

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。明确目标&#xff0c;激发内在动机。 1 目标效应的应用 1.1 目标效应在教育领域的应用-棉花糖实验 美国斯坦福大学心理学系的教授米歇尔&#xff08;Walter Mischel&#xff09;曾经进行了…...

【从0到1设计一个网关】性能优化---Netty线程数配置与JVM参数配置

文章目录 Netty线程介绍Netty实战配置JVM参数与ZGCJVM与ZGC调优Netty线程介绍 在Netty中有两个比较重要的线程概念,一个是BOSS线程,一个是Woker线程。 Boss线程组: Boss线程组通常负责处理接受客户端连接的工作,即处理ServerSocketChannel的连接事件。 Boss线程会监听并接…...

node插件MongoDB(五)—— 库mongoose 的模块化(五)

文章目录 一、使用mongoose 模块化的原因二、准备工作2. 启动mongo.exe 和mongod.exe 两个程序连接数据库 三、基本模块的拆分1、基本逻辑2、代码3、代码图示说明 四、在index.js 中进一步的拆分1.拆分原因2.新建model文件夹存储文档的结构对象3.代码4.代码实际演示和注意点 一…...

Windows server 2008 R2 IIS搭建ASP网站教程

一、安装应用程序服务器 提示安装成功 二、添加角色服务asp 三、asp网站配置 放入源码 设置网站首页为index.asp: 设置应用程序池 四、设置网站目录属性 五、access数据库连接配置 Cd c:\Windows\System32\inetsrv appcmd list apppool /xml | appcmd set apppool /…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...