当前位置: 首页 > 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 /…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...

xmind转换为markdown

文章目录 解锁思维导图新姿势&#xff1a;将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件&#xff08;ZIP处理&#xff09;2.解析JSON数据结构3&#xff1a;递归转换树形结构4&#xff1a;Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

写一个shell脚本&#xff0c;把局域网内&#xff0c;把能ping通的IP和不能ping通的IP分类&#xff0c;并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...