C从零开始实现贪吃蛇大作战
个人主页:星纭-CSDN博客
系列文章专栏 : C语言
踏上取经路,比抵达灵山更重要!一起努力一起进步!
有关Win32API的知识点在上一篇文章:
目录
一.地图
1.控制台基本介绍
2.宽字符
1.本地化
2.类项
3.setlocale函数
4.打印宽字符
3.地图坐标
二.游戏的结构设计
1.基础结构
2.游戏流程(未完成)
3.核心逻辑实现
1.游戏开始
1.控制台设置
2.欢迎界面
3.创建地图
4.初始化蛇
5.创建食物
4.游戏运行
1.打印信息
2.判断按键
3.蛇的移动
5.游戏结束
一.地图
这个游戏中,我们是通过控制台来完成的。首先就是需要完成这个地图。
1.控制台基本介绍
接下来介绍有关控制台窗口的一些知识点,当运行程序,需要在控制台上输出信息,打印的时候,第一个字符是在控制台最左上角打印的。我们将这个位置的坐标当作(0,0).
横向的坐标轴称为x轴,从左向右依次增长,纵向的坐标轴是y轴,从上到下依次增长。
2.宽字符
普通的字符是占一个字节的,宽字符是占用两个字节的。
打印字符,不难发现,两个英文字符的宽度是等于一个中文字符的宽度的。 而且一个英文字符的高大概是其宽的两倍。
1.<locale.h>本地化
<locale.h>提供的函数用于控制C标准库中对于不同的地区会产生不一样行为的部分。
在标准中,以来地区的部分有以下几项:
- 数字量的格式
- 货币量的格式
- 字符集
- 日期和时间的表示形式
2.类项
通过修改地区,程序可以改变它的⾏为来适应世界的不同区域。但地区的改变可能会影响库的许多部 分,其中⼀部分可能是我们不希望修改的。所以C语⾔⽀持针对不同的类项进⾏修改,下⾯的⼀个宏, 指定⼀个类项:
- • LC_COLLATE:影响字符串⽐较函数 strcoll() 和 strxfrm() 。
- • LC_CTYPE:影响字符处理函数的⾏为。
- • LC_MONETARY:影响货币格式。
- • LC_NUMERIC:影响 printf() 的数字格式。
- • LC_TIME:影响时间格式 strftime() 和 wcsftime() 。
- • LC_ALL-针对所有类项修改,将以上所有类别设置为给定的语⾔环境。
参考:setlocale,_wsetlocale | Microsoft Learn
3.setlocale函数
char *setlocale(int category,const char *locale
);
这个函数用于修改当前地区,可针对一个类项修改,也可以针对所有类型。
第一个参数是前面说明的类项目中的一个,那么每次都只会影响一个类项,如果第一个参数是LC_ALL就会影响所有的类项。
C标准给第二个参数仅仅定义了两种取值:“C”正常模式和“”本地模式
在任意程序开始执行之前,都会隐藏执行调用:
setlocale(LC_ALL, "C");
当地区设置为"C"时,库函数按正常⽅式执⾏,⼩数点是⼀个点。 当程序运⾏起来后想改变地区,就只能显⽰调⽤setlocale函数。⽤""作为第2个参数,调⽤setlocale 函数就可以切换到本地模式,这种模式下程序会适应本地环境。 ⽐如:切换到我们的本地模式后就⽀持宽字符(汉字)的输出等。
setlocale(LC_ALL, " ");//切换到本地环境
4.打印宽字符
如果想要在屏幕上打印宽字符,那么该如何打印呢?
为了区分宽字符与普通字符,宽字符的字面量前面必须加上前缀 L ,否则C语言会把字面量当作窄字符类型来处理。
同时还需要另一个函数wprintf函数来打印宽字符,用法与printf一样。宽字符的占位符为%lc,宽字符串的占位符为%ls.
setlocale(LC_ALL, "");wprintf(L"%lc\n", L'□');wprintf(L"%lc\n", L'●');wprintf(L"%lc\n", L'★');
打印一个宽字符选哟占用两个字符的位置,那么我们在贪吃蛇中使用宽字符,就需要处理好地图上坐标的位置的计算。
3.地图坐标
我们假设实现一个三十行六十列的地图,在围绕地图画出墙。
#define WALL L'□' //墙
#define BODY L'●' //蛇身
#define FOOD L'★' //食物
需要打印的东西总共有三个分别是墙,蛇身,食物。为了方便,我们define。
1.蛇身与食物
初始化状态,假设蛇的其实长度是5,蛇的每一个节点都是BODY.并且在一个固定的位置开始生成。
从该图不难发现,蛇与食物的每一个节点的坐标都应该是偶数,不能是技术,否则就就不对其了,而且会出现身体一半在墙体之内,一半在墙体之外的现象。
二.游戏的结构设计
1.基础结构
在游戏运行过程中,蛇每次吃一个食物,蛇的身体就会变长一节,如果我们使用链表来储存蛇的信息,那么蛇的每一个节点其实就是链表的每一个节点,每一个节点就需要记录好蛇身节点的位置,以及下一个节点的位置。
typedef struct SnakeNode {int x;int y;struct SnakeNode* next;
}SnakeNode,*pSnakeNode;
为了方便管理这个游戏,我们在封装一个Snake的结构来维护整个贪吃蛇。
//蛇的运动方向:上下左右
enum DIRECTION { UP = 1, DOWN, RIGHT, LEFT };
//游戏运行状态:正常运行,撞墙,撞自己,非正常结束。
//非正常结束:比如按Esc退出游戏。
enum GAME_STATUS { OK, KILL_BY_WALL, KILL_BY_SELF, END_NORMAL };typedef struct GreedySnake {pSnakeNode _pSnake;pSnakeNode _pFood;enum DIRECTION _Dir;enum GAME_STATUS _Status;int _Score;int _FoodWeight;int _SleepTime;//可以理解为蛇的运行速度。
}GSnake,*pGSnake;
2.游戏流程(未完成)
3.核心逻辑实现
程序开始就设置程序⽀持本地模式,然后进⼊游戏的主逻辑。 主逻辑分为3个过程:
- • 游戏开始(GameStart)完成游戏的初始化
- • 游戏运⾏(GameRun)完成游戏运⾏逻辑的实现
- • 游戏结束(GameEnd)完成游戏结束的说明,实现资源释放
1.游戏开始
这个模块需要完成游戏的初始化任务。
- 控制台的设置
- 欢迎界面
1.控制台设置
//一.设置控制台以及光标//设置控制台窗口的大小system("mode con cols=100 lines=30");//设置控制台窗口的名字system("title 贪吃蛇");//获得标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//定义一个光标信息的结构体CONSOLE_CURSOR_INFO cursor_info = { 0 };//获取和houput句柄相关的控制台上的光标的信息,存放在cursor_info中GetConsoleCursorInfo(houtput, &cursor_info);//修改光标信息cursor_info.bVisible = false;//可见度//设置和houtput句柄相关的控制台上的光标的信息SetConsoleCursorInfo(houtput, &cursor_info);
在这里需要更改控制台窗口的名字,以及将光标不可见。
2.欢迎界面
1.首先需要完成坐标定位函数,这样方便我们在特定的位置打印信息
void SetPos(int x, int y) {HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);COORD pos = { x, y };SetConsoleCursorPosition(houtput, pos);}
2.然后就是欢迎界面以及游戏规则的讲解
void WelcomeToGame() {SetPos(36,13);printf("欢迎来到星纭的贪吃蛇小游戏");SetPos(40,25);system("pause");system("cls");SetPos(15,10);printf("游戏规则介绍:");SetPos(24,13);wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");SetPos(36,16);printf("加速可以获得更更高的分数");SetPos(40,25);system("pause");system("cls");
}
3.创建地图
创建地图就是将地图打印出来,因为是宽字符打印,所以使用wprintf函数进行打印。
void CreateMap() {int i = 0;//上面的墙for (i = 0; i < 60; i += 2) {wprintf(L"%lc",WALL);}//左边的墙for (i = 1; i <= 30; i++) {SetPos(0,i);wprintf(L"%lc", WALL);}//右边的墙for (i = 1; i <= 30; i++) {SetPos(58,i);wprintf(L"%lc", WALL);}//下面的墙for (i = 2; i < 57; i += 2) {SetPos(i,30);wprintf(L"%lc", WALL);}SetPos(0, 33);
}
4.初始化蛇
蛇最开始⻓度为5节,每节对应链表的⼀个节点,蛇⾝的每⼀个节点都有⾃⼰的坐标。 创建5个节点,然后将每个节点存放在链表中进⾏管理。创建完蛇⾝后,将蛇的每⼀节打印在屏幕上。
- • 蛇的初始位置从(10,5)开始。 再设置当前游戏的状态,蛇移动的速度,默认的⽅向,初始成绩,每个⻝物的分数。
- • 游戏状态是:OK
- • 蛇的移动速度:200毫秒
- • 蛇的默认⽅向:RIGHT
- • 初始成绩:0
- • 每个⻝物的分数:10
void InitSnake(pGSnake ps) {//创建五个蛇节点,并完成头插pSnakeNode cur = NULL;int i = 0;for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));cur->next = NULL;cur->x = POS_X - i * 2;cur->y = POS_Y;if (ps->_pSnake == NULL) {ps->_pSnake = cur;}else {cur->next = ps->_pSnake;ps->_pSnake = cur;}}//打印蛇cur = ps->_pSnake;while (cur) {SetPos(cur->x,cur->y);wprintf(L"%lc",BODY);cur = cur->next;}//初始化游戏ps->_SleepTime = 200;ps->_Score = 0;ps->_Dir = RIGHT;ps->_Status = OK;ps->_FoodWeight = 10;
}
5.创建食物
void CreateFood(pGSnake ps) {int x = 0;int y = 0;again:do {x = rand() % 55 + 2;y = rand() % 29 + 1;} while (x % 2 != 0);pSnakeNode cur = ps->_pSnake;while (cur) {if (cur->x == x && cur->y == y) {goto again;}cur = cur->next;}pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));pFood->x = x;pFood->y = y;SetPos(x, y);wprintf(L"%lc",FOOD);ps->_pFood = pFood;
};
4.游戏运行
游戏运行期间,右侧打印帮助信息,提示玩家,坐标开始位置(64,15)
根据游戏状态检测游戏是否继续,如果状态时OK,游戏继续,其他状态游戏结束。
并且根据游戏的过程中,按键的情况来确定蛇的下一步方向,或者是否加速减速,暂停或者退出游戏。
- • 上:VK_UP
- • 下:VK_DOWN
- • 左:VK_LEFT
- • 右:VK_RIGHT
- • 空格:VK_SPACE
- • ESC:VK_ESCAPE
- • F3:VK_F3
- • F4:VK_F4
这是所需的虚拟按键
1.打印信息
void PrintHelpInfo()
{SetPos(60,10);wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动方向");SetPos(70,12);wprintf(L"按F3加速,F4减速");SetPos(66,14);printf("加速可以获得更更高的分数");
}
在控制台窗口中,打印游戏规则以及分数。
2.判断按键
#define KEY_PRESS(vk) ((GetAsyncKeyState(vk) & 1) ? 1 : 0)
3.蛇的移动
先创建下⼀个节点,根据移动⽅向和蛇头的坐标,蛇移动到下⼀个位置的坐标。 确定了下⼀个位置后,看下⼀个位置是否是⻝物(NextIsFood),是⻝物就做吃⻝物处理 (EatFood),如果不是⻝物则做前进⼀步的处理(NoFood)。 蛇⾝移动后,判断此次移动是否会造成撞墙(KillByWall)或者撞上⾃⼰蛇⾝(KillBySelf),从⽽影 响游戏的状态。
int NextisFood(pSnakeNode pNextNode, pGSnake ps) {if (ps->_pFood->x == pNextNode->x && ps->_pFood->y == pNextNode->y) {return 1;}return 0;
}
void EatFood(pSnakeNode pNextNode, pGSnake ps) {ps->_pFood->next = ps->_pSnake;ps->_pSnake = ps->_pFood;free(pNextNode);pSnakeNode cur = ps->_pSnake;while (cur) {SetPos(cur->x, cur->y);wprintf(L"%lc", L'●');cur = cur->next;}ps->_Score += ps->_FoodWeight;CreateFood(ps);}
void NoFood(pSnakeNode pNextNode, pGSnake ps) {pNextNode->next = ps->_pSnake;ps->_pSnake = pNextNode;pSnakeNode cur = ps->_pSnake;while (cur->next->next){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}SetPos(cur->next->x, cur->next->y);printf(" ");free(cur->next);cur->next = NULL;
}void KillByWall(pGSnake ps) {if ((ps->_pSnake->x == 0) ||(ps->_pSnake->x == 58) ||(ps->_pSnake->y == 0) ||(ps->_pSnake->y == 29)) {ps->_Status = KILL_BY_WALL;return 1;}return 0;
}
void KillBySelf(pGSnake ps) {pSnakeNode cur = ps->_pSnake->next;while (cur) {if (cur->x == ps->_pSnake->x && cur->y == ps->_pSnake->y) {ps->_pSnake = KILL_BY_SELF;break;}cur = cur->next;}}
void SnakeMove(pGSnake ps) {pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));switch (ps->_Dir) {case UP:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y - 1;break;case DOWN:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y + 1;break;case LEFT:pNextNode->x = ps->_pSnake->x - 2;pNextNode->y = ps->_pSnake->y;break;case RIGHT:pNextNode->x = ps->_pSnake->x + 2;pNextNode->y = ps->_pSnake->y;break;}if (NextisFood(pNextNode,ps)) {EatFood(pNextNode, ps);}else {NoFood(pNextNode, ps);}KillByWall(ps);KillBySelf(ps);
}
5.游戏结束
游戏状态不再是OK(游戏继续)的时候,要告知游戏结束的原因,并且释放蛇⾝节点。
void GameEnd(pGSnake ps) {system("cls");SetPos(32, 12);switch (ps->_Status) {case END_NORMAL:printf("游戏已结束。");break;case KILL_BY_WALL:printf("蛇撞墙!游戏结束。");break;case KILL_BY_SELF:printf("蛇撞到自己!游戏结束。");break;}printf("总得分:%d", ps->_Score);//pSnakeNode cur = ps->_pSnake;while (cur) {pSnakeNode del = cur;cur = cur->next;free(del);}SetPos(0, 26);}
三.代码
greedysnake.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<stdbool.h>
#include<locale.h>
#include<time.h>
#define WALL L'□' //墙
#define BODY L'●' //蛇
#define FOOD L'★' //食物typedef struct SnakeNode {int x;int y;struct SnakeNode* next;
}SnakeNode, * pSnakeNode;
//蛇的运动方向:上下左右
enum DIRECTION { UP = 1, DOWN, RIGHT, LEFT };
//游戏运行状态:正常运行,撞墙,撞自己,非正常结束。
//非正常结束:比如按Esc退出游戏。
enum GAME_STATUS { OK, KILL_BY_WALL, KILL_BY_SELF, END_NORMAL };typedef struct GreedySnake {pSnakeNode _pSnake;pSnakeNode _pFood;enum DIRECTION _Dir;enum GAME_STATUS _Status;int _Score;int _FoodWeight;int _SleepTime;//可以理解为蛇的运行速度。
}GSnake,*pGSnake;#define POS_X 10 //起始位置x
#define POS_Y 5 //起始位置y//游戏开始
void GameStart(pGSnake ps);void WelcomeToGame();
void CreateMap();
void InitSnake(pGSnake ps);
void CreateFood(pGSnake ps);//游戏运行
void GameRun(pGSnake ps); void PrintHelpInfo();
#define KEY_PRESS(vk) ((GetAsyncKeyState(vk) & 1) ? 1 : 0)
void SnakeMove(pGSnake ps);
int NextisFood(pSnakeNode pNextNode, pGSnake ps);
void EatFood(pSnakeNode pNextNode, pGSnake ps);
void NoFood(pSnakeNode pNextNode, pGSnake ps);
void KillByWall(pGSnake ps);
void KillBySelf(pGSnake ps);void GameEnd(pGSnake ps);
greedysnake.c
#define _CRT_SECURE_NO_WARNINGS
#include"greedysnake.h"void SetPos(int x, int y) {HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);COORD pos = { x, y };SetConsoleCursorPosition(houtput, pos);}
void WelcomeToGame() {SetPos(36, 13);printf("欢迎来到星纭的贪吃蛇小游戏");SetPos(40, 25);system("pause");system("cls");SetPos(15, 10);printf("游戏规则介绍:");SetPos(24, 13);wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");SetPos(36, 16);printf("加速可以获得更更高的分数");SetPos(40, 25);system("pause");system("cls");
}
void CreateMap() {int i = 0;//上面的墙for (i = 0; i < 60; i += 2) {wprintf(L"%lc", WALL);}//左边的墙for (i = 1; i <= 30; i++) {SetPos(0, i);wprintf(L"%lc", WALL);}//右边的墙for (i = 1; i <= 30; i++) {SetPos(58, i);wprintf(L"%lc", WALL);}//下面的墙for (i = 2; i < 57; i += 2) {SetPos(i, 30);wprintf(L"%lc", WALL);}}
void InitSnake(pGSnake ps) {//创建五个蛇节点,并完成头插pSnakeNode cur = NULL;int i = 0;for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));cur->next = NULL;cur->x = POS_X + i * 2;cur->y = POS_Y;if (ps->_pSnake == NULL) {ps->_pSnake = cur;}else {cur->next = ps->_pSnake;ps->_pSnake = cur;}}//打印蛇cur = ps->_pSnake;while (cur) {SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//初始化游戏ps->_SleepTime = 200;ps->_Score = 0;ps->_Dir = RIGHT;ps->_Status = OK;ps->_FoodWeight = 10;
}
void CreateFood(pGSnake ps) {int x = 0;int y = 0;
again:do {x = rand() % 47 + 6;y = rand() % 25 + 3;} while (x % 2 != 0);pSnakeNode cur = ps->_pSnake;while (cur) {if (cur->x == x && cur->y == y) {goto again;}cur = cur->next;}pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));pFood->x = x;pFood->y = y;SetPos(x, y);wprintf(L"%lc", FOOD);ps->_pFood = pFood;
};void GameStart(pGSnake ps) {//一.设置控制台以及光标//设置控制台窗口的大小system("mode con cols=100 lines=36");//设置控制台窗口的名字system("title 贪吃蛇");//获得标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//定义一个光标信息的结构体CONSOLE_CURSOR_INFO cursor_info = { 0 };//获取和houput句柄相关的控制台上的光标的信息,存放在cursor_info中GetConsoleCursorInfo(houtput, &cursor_info);//修改光标信息cursor_info.bVisible = false;//可见度//设置和houtput句柄相关的控制台上的光标的信息SetConsoleCursorInfo(houtput, &cursor_info);//二.打印欢迎界面WelcomeToGame();//三.创建地图CreateMap();//四.初始化蛇InitSnake(ps);//五.随机生成食物CreateFood(ps);};void PrintHelpInfo()
{SetPos(60, 10);wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动方向");SetPos(70, 12);wprintf(L"按F3加速,F4减速");SetPos(66, 14);printf("加速可以获得更更高的分数");
}
void pause() {while (1) {Sleep(1);if (KEY_PRESS(VK_SPACE)) {break;}}}
int NextisFood(pSnakeNode pNextNode, pGSnake ps) {if (ps->_pFood->x == pNextNode->x && ps->_pFood->y == pNextNode->y) {return 1;}return 0;
}
void EatFood(pSnakeNode pNextNode, pGSnake ps) {ps->_pFood->next = ps->_pSnake;ps->_pSnake = ps->_pFood;free(pNextNode);pSnakeNode cur = ps->_pSnake;while (cur) {SetPos(cur->x, cur->y);wprintf(L"%lc", L'●');cur = cur->next;}ps->_Score += ps->_FoodWeight;CreateFood(ps);}
void NoFood(pSnakeNode pNextNode, pGSnake ps) {pNextNode->next = ps->_pSnake;ps->_pSnake = pNextNode;pSnakeNode cur = ps->_pSnake;while (cur->next->next){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}SetPos(cur->next->x, cur->next->y);printf(" ");free(cur->next);cur->next = NULL;
}void KillByWall(pGSnake ps) {if ((ps->_pSnake->x == 0) ||(ps->_pSnake->x == 58) ||(ps->_pSnake->y == 0) ||(ps->_pSnake->y == 29)) {ps->_Status = KILL_BY_WALL;return 1;}return 0;
}
void KillBySelf(pGSnake ps) {pSnakeNode cur = ps->_pSnake->next;while (cur) {if (cur->x == ps->_pSnake->x && cur->y == ps->_pSnake->y) {ps->_Status = KILL_BY_SELF;break;}cur = cur->next;}}
void SnakeMove(pGSnake ps) {pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));switch (ps->_Dir) {case UP:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y - 1;break;case DOWN:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y + 1;break;case LEFT:pNextNode->x = ps->_pSnake->x - 2;pNextNode->y = ps->_pSnake->y;break;case RIGHT:pNextNode->x = ps->_pSnake->x + 2;pNextNode->y = ps->_pSnake->y;break;}if (NextisFood(pNextNode, ps)) {EatFood(pNextNode, ps);}else{NoFood(pNextNode, ps);}KillByWall(ps);KillBySelf(ps);
}
void GameRun(pGSnake ps) {//打印帮助信息PrintHelpInfo();//循环do {SetPos(66, 8);printf("游戏得分:%4d", ps->_Score);printf("食物重量:%4d", ps->_FoodWeight);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_SPACE)) {pause();}else if (KEY_PRESS(VK_ESCAPE)) {ps->_Status = END_NORMAL;break;}else if (KEY_PRESS(VK_F3)) {if (ps->_SleepTime > 80) {ps->_SleepTime -= 30;ps->_FoodWeight += 2;}}else if (KEY_PRESS(VK_F4)) {if (ps->_SleepTime < 320) {ps->_SleepTime += 30;ps->_FoodWeight -= 2;}}Sleep(ps->_SleepTime);SnakeMove(ps);} while (ps->_Status == OK);}void GameEnd(pGSnake ps) {system("cls");SetPos(32, 12);switch (ps->_Status) {case END_NORMAL:printf("游戏已结束。");break;case KILL_BY_WALL:printf("蛇撞墙!游戏结束。");break;case KILL_BY_SELF:printf("蛇撞到自己!游戏结束。");break;}printf("总得分:%d", ps->_Score);pSnakeNode cur = ps->_pSnake;while (cur) {pSnakeNode del = cur;cur = cur->next;free(del);}SetPos(0, 26);}
源.c
#define _CRT_SECURE_NO_WARNINGS
#include"greedysnake.h"int main()
{srand((unsigned int)time(NULL));setlocale(LC_ALL, "");GSnake snake = { 0 };//游戏初始化GameStart(&snake);//游戏运行中GameRun(&snake);GameEnd(&snake);SetPos(0, 33);system("pause");return 0;
}
相关文章:

C从零开始实现贪吃蛇大作战
个人主页:星纭-CSDN博客 系列文章专栏 : C语言 踏上取经路,比抵达灵山更重要!一起努力一起进步! 有关Win32API的知识点在上一篇文章: 目录 一.地图 1.控制台基本介绍 2.宽字符 1.本地化 2.类项 3.setlocale函…...
国内外相机在LabVIEW图像处理的对比
概述 本文对比国内外相机在LabVIEW进行图像处理的区别,探讨各自的特点。国内相机如大恒和海康威视,具有较高性价比和本地化支持;国外品牌如Basler和FLIR则以高性能和稳定性著称。两者在驱动兼容性、图像质量和技术支持方面各有优势。 详细对…...
第四十五天 | 322.零钱兑换
题目:322.零钱兑换 尝试解答: 1.确定dp[j]含义:装满容量为j的背包所需要放的硬币个数为dp[j]; 2.动态转移方程:dp[j] dp[j - coins[i]] 1; 3.遍历顺序:本题应该为组合类题目,不考虑装入的顺序&#x…...

3D 生成重建011-LucidDreamer 优化SDS过平滑结果的一种探索
3D 生成重建011-LucidDreamer 优化SDS过平滑结果的一种探索 文章目录 0论文工作1论文方法2 效果 0论文工作 文本到3D生成的最新进展标志着生成模型的一个重要里程碑,为在各种现实场景中创建富有想象力的3D资产打开了新的可能性。虽然最近在文本到3D生成方面的进展…...
ES6 笔记04
01 异步函数的使用 es6推出了一种按照顺序执行的异步函数的方法 async 异步函数 async异步函数可以解决promise封装异步代码,调用时一直then链式编程时比较麻烦的问题 定义异步函数: async function 函数名(){ await 表达式1或者函数的调用1 await 表达式2或者函数的调用2 ...…...

中间件-------RabbitMQ
同步和异步 异步调用 MQ MQ优势:①服务解耦 ②异步调用 ③流量削峰 结构 消息模型 RabbitMQ入门案例,实现消息发送和消息接收 生产者: public class PublisherTest {Testpublic void testSendMessage() throws IOException, TimeoutExce…...
flink Data Source数据源
flink Data Source数据源 Source 并行度 非并行:并行度只能为1 并行 基于集合的Source fromElements package com.pxj.sx.flink; import org.apache.flink.configuration.Configuration; import org.apache.flink.configuration.RestOptions; import org.ap…...
网络七层模型与云计算中的网络服务
网络七层模型,也称为OSI(Open System Interconnection)模型,是由国际标准化组织(ISO)制定的一个概念性框架,用于描述网络通信过程中信息是如何被封装、传输和解封装的。这一模型将复杂的网络通信…...

word一按空格就换行怎么办?word文本之间添加空格就换行怎么办?
如上图,无法在Connection和con之间添加空格,一按空格就会自动换行。 第一步:选中文本,打开段落。 第二步:点击中文版式,勾选允许西文在单词中间换行。 确定之后就解决一按空格就自动换行啦!...
Python 遍历字典的方法,你都掌握了吗
Python中的字典是一种非常灵活的数据结构,它允许通过键来存储和访问值。在处理字典时,经常需要遍历字典中的元素,以下是几种常见的遍历字典的方法。 1. 使用 for 循环直接遍历字典的键 字典的键是唯一的,可以直接通过 for 循环来…...

MySQL 8.4.0 LTS 变更解析:I_S 表、权限、关键字和客户端
↑ 关注“少安事务所”公众号,欢迎⭐收藏,不错过精彩内容~ MySQL 8.4.0 LTS 已经发布 ,作为发版模型变更后的第一个长期支持版本,注定要承担未来生产环境的重任,那么这个版本都有哪些新特性、变更,接下来少…...

LeetCode 124 —— 二叉树中的最大路径和
阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 二叉树的问题首先我们要想想是否能用递归来解决,本题也不例外,而递归的关键是找到子问题。 我们首先来看看一棵最简单的树,也就是示例 1。这样的一棵树总共有六条路径…...

美甲店会员预约系统管理小程序的作用是什么
女性爱美体现在方方面面,美丽好看的指甲也不能少,市场中美甲店、小摊不少,也跑出了不少连锁品牌,70后到00后,每个层级都有不少潜在客户,商家需要获取和完善转化路径,不断提高品牌影响力与自身内…...

..堆..
堆 堆是完全二叉树,即除了最后一列之外,上面的每一层都是满的(左右严格对称且每个节点都满子节点) 最后一列从左向右排序。 默认大根堆:每一个节点都大于其左右儿子,根节点就是整个数据结构的最大值 pr…...

【LLM多模态】综述Visual Instruction Tuning towards General-Purpose Multimodal Model
note 文章目录 note论文1. 论文试图解决什么问题2. 这是否是一个新的问题3. 这篇文章要验证一个什么科学假设4. 有哪些相关研究?如何归类?谁是这一课题在领域内值得关注的研究员?5. 论文中提到的解决方案之关键是什么?6. 论文中的…...
探索Linux中的神奇工具:重定向符的妙用
探索Linux中的神奇工具:重定向符的妙用 在Linux系统中,重定向符是一个强大的工具,用于控制命令的输入和输出,实现数据流的定向。本文将详细介绍重定向符的基本用法和一些实用技巧,帮助读者更好地理解和运用这个功能。…...
Kubernetes 文档 / 概念 / 工作负载 / 工作负载管理 / Job
Kubernetes 文档 / 概念 / 工作负载 / 工作负载管理 / Job 此文档从 Kubernetes 官网摘录 中文地址 英文地址 Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止。 随着 Pod 成功结束,Job 跟踪记录成功完成的…...

办公自动化-Python如何提取Word标题并保存到Excel中?
办公自动化-Python如何提取Word标题并保存到Excel中? 应用场景需求分析实现思路实现过程安装依赖库打开需求文件获取word中所有标题去除不需要的标题创建工作簿和工作表分割标题功能名称存入测试对象GN-TC需求标识符存入测试项标识存入需求标识符 完整源码实现效果学…...

基于Java、SpringBoot和uniapp在线考试系统安卓APP和微信小程序
摘要 基于Java、SpringBoot和uniapp的在线考试系统安卓APP微信小程序是一种结合了现代Web开发技术和移动应用技术的解决方案,旨在为教育机构提供一个方便、高效和灵活的在线考试平台。该系统采用Java语言进行后端开发,使用SpringBoot框架简化企业级应用…...
抖音a-bogus加密解析(三)
要补的环境我给提示,大家自行操作,出了问题就是因为缺环境,没补好 window global; // reading _u未定义 window.requestAnimationFrame function () {} // XMLHttpRequest 未定义 window.XMLHttpRequest function () {} window.onwheelx …...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...

Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...
用鸿蒙HarmonyOS5实现国际象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的国际象棋小游戏的完整实现代码,使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├── …...