当前位置:网站首页>C语言贪吃蛇-链表和指针练习
C语言贪吃蛇-链表和指针练习
2022-07-26 13:56:00 【闪耀大叔】
一个简单的控制台小游戏,用链表实现贪吃蛇。代码不到两百行,压缩一下可以在100行以内。
很多同学刚学C语言,不知道能干嘛。其实C语言什么都能干,只不过可能比较复杂,但深入学习C语言,对于底层数据结构和算法原理学习极有好处。
以后再学习其他语言,学习速度跟坐飞机一样。
比如这个贪吃蛇小程序,实现方式有很多,数组也行,这里用链表,主要是为了练习链表和指针的使用。

一、控制光标
想让控制台成为游戏画面,printf作为输出,得先实现指定位置printf
头文件#include <conio.h>
代码:
COORD coord;
HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
//获取控制台缓冲区句柄
coord.X = x;
coord.Y = y;
//设置光标位置
SetConsoleCursorPosition(ConsoleHandle, coord);
printf("*");使用以上代码就可以在(x,y)位置输出,控制台左上角坐标为(0,0).
二、定时
贪吃蛇每走一步,需要间隔一段时间,所以需要定时。
curTime = GetTickCount();
if (curTime - lastTime > 300)
{
if (move(dire, &head, food, &tail) == -1)
break;
lastTime = curTime;
}move函数是贪吃蛇的移动函数,GetTickCount()获取当前时间,当前时间和上次时间只差大于300ms就移动一次。
你也可以用一个宏定义,或者从键盘输出控制间隔时间也就是控制速度(难度)。
三、获取方向
头文件:#include <conio.h>
代码:
if (_kbhit())
{
switch (_getch())
{
case 'w':
dire = 'w'; break;
case 's':
dire = 's'; break;
case 'a':
dire = 'a'; break;
case 'd':
dire = 'd'; break;
default:break;
}
}_kbhit()函数检测键盘是否有按下,有则返回1,无则返回0;_getch()函数获取键盘值。
我们用w,s,a,d分别表示上,下,左,右。
四、构造贪吃蛇
typedef struct {
int x;
int y;
}POS;
typedef struct BODY {
POS pos;
struct BODY* next;
}BODY; BODY* head = malloc(sizeof(BODY));
BODY* body = malloc(sizeof(BODY));
BODY* tail = malloc(sizeof(BODY));
BODY* food = malloc(sizeof(BODY));
int lastTime;
int curTime;
head->pos.x = w_max / 2;
head->pos.y = h_max / 2;
body->pos.x = w_max / 2 + 1;
body->pos.y = h_max / 2;
tail->pos.x = w_max / 2 + 2;
tail->pos.y = h_max / 2;
head->next = body;
body->next = tail;
tail->next = NULL;每一节身体,都有两部分内容,pos坐标,next指针,指向下一节的位置。初始化贪吃蛇为三节,head头,body身体,tail尾巴。
五、移动
没有吃到食物的移动:
移动位置根据方向确定。
首先检测新的位置在不在身体上,也就是链表的遍历,在这个遍历过程中,我们把尾巴的前一个位置pretail记录下来。
移动过程其实就是把尾巴变成新的头,尾巴的前一节身体变成尾巴,新的位置变为头,原来的头变成头的下一节。
吃到食物的移动:
其实就是食物的位置变成了头结点。
六、完整代码
如果编译不通过,只要将 malloc(sizeof(BODY))改为(BODY*)malloc(sizeof(BODY))。
自己可以加一下界面,比如开始和gameover,以及速度选择,地图大小选择。
tips:如果要做失败从头再来的功能记得释放malloc出来的空间。
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
#define H 52//长
#define W 102//宽
#define h_max (H-1)
#define w_max (W-1)
#define h_min 1
#define w_min 1
typedef struct {
int x;
int y;
}POS;
typedef struct BODY {
POS pos;
struct BODY* next;
}BODY;
void produceFood(BODY* food)
{
food->pos.x = rand() % (W - 2) + 1;
food->pos.y = rand() % (H - 2) + 1;
show_point(food->pos.x, food->pos.y);
}
int show_point(int x, int y)
{
COORD coord;
HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
coord.X = x;
coord.Y = y; //设置光标位置
SetConsoleCursorPosition(ConsoleHandle, coord);
printf("*");
return 0;
}
int clear_point(int x, int y)
{
COORD coord;
HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); //获取控制台缓冲区句柄
coord.X = x;
coord.Y = y; //设置光标位置
SetConsoleCursorPosition(ConsoleHandle, coord);
printf(" ");
return 0;
}
int move(char dire, BODY** head, BODY* food, BODY** tail)
{
BODY newhead;
BODY* search;
BODY* pretail;
pretail = NULL;
int pretail_flag = 0;
newhead.pos.x = (*head)->pos.x;
newhead.pos.y = (*head)->pos.y;
switch (dire)
{
case 'w':newhead.pos.y--; break;
case 's':newhead.pos.y++; break;
case 'a':newhead.pos.x--; break;
case 'd':newhead.pos.x++; break;
default:break;
}
if (newhead.pos.y >= h_max || newhead.pos.y < h_min || newhead.pos.x < w_min || newhead.pos.x >= w_max)//越界则退出
return -1;
if (newhead.pos.x == food->pos.x && newhead.pos.y == food->pos.y) //吃到食物
{
BODY* newHead = malloc(sizeof(BODY));//新申请一个空间并加入贪吃蛇头部
newHead->pos.x = newhead.pos.x;
newHead->pos.y = newhead.pos.y;
newHead->next = *head;
*head = newHead;
produceFood(food);//吃了食物要产生一个新的食物
return 0;
}
else//没吃到食物则按方向前进(其实就是尾巴变成新的头部,尾巴的前一个变尾巴),同时需看新的位置是否在身体上
{
search = *head;
pretail_flag = 0;
while (1)
{
if(pretail_flag==0)
{
pretail = search;
if ((pretail->next)->next == NULL)
pretail_flag = 1;
}
if (search->pos.x == newhead.pos.x && search->pos.y == newhead.pos.y)
return -1;
if (search->next == NULL)
break;
search = search->next;
}
clear_point((*tail)->pos.x, (*tail)->pos.y);
show_point(newhead.pos.x, newhead.pos.y);
//没有返回-1说明未碰撞,尾巴变新的头,pretail变新尾巴
pretail->next = NULL;
(*tail)->next = *head;
(*tail)->pos.x = newhead.pos.x;
(*tail)->pos.y = newhead.pos.y;
*head = *tail;
*tail = pretail;
return 0;
}
}
void show()//画出背景
{
COORD coord;
//获取控制台缓冲区句柄
HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
//设置光标位置
for (int i = 0; i < W; i++)
{
coord.X = i;
coord.Y = 0;
SetConsoleCursorPosition(ConsoleHandle, coord);
printf("#");
coord.Y = H - 1;
SetConsoleCursorPosition(ConsoleHandle, coord);
printf("#");
}
for (int i = 0; i < H; i++)
{
coord.X = 0;
coord.Y = i;
SetConsoleCursorPosition(ConsoleHandle, coord);
printf("#");
coord.X = W - 1;
SetConsoleCursorPosition(ConsoleHandle, coord);
printf("#");
}
}
int main()
{
srand((unsigned)time(NULL));
//初始化
BODY* head = malloc(sizeof(BODY));
BODY* body = malloc(sizeof(BODY));
BODY* tail = malloc(sizeof(BODY));
BODY* food = malloc(sizeof(BODY));
int lastTime;
int curTime;
head->pos.x = w_max / 2;
head->pos.y = h_max / 2;
body->pos.x = w_max / 2 + 1;
body->pos.y = h_max / 2;
tail->pos.x = w_max / 2 + 2;
tail->pos.y = h_max / 2;
head->next = body;
body->next = tail;
tail->next = NULL;
lastTime = GetTickCount();
//
char dire;//0,1,2,3,上下左右
dire = 'w';
show();
show_point(head->pos.x, head->pos.y);
show_point(body->pos.x, body->pos.y);
show_point(tail->pos.x, tail->pos.y);
produceFood(food);
while (1)
{
if (_kbhit())
{
switch (_getch())
{
case 'w':
dire = 'w'; break;
case 's':
dire = 's'; break;
case 'a':
dire = 'a'; break;
case 'd':
dire = 'd'; break;
default:break;
}
}
curTime = GetTickCount();
if (curTime - lastTime > 300)
{
if (move(dire, &head, food, &tail) == -1)
break;
lastTime = curTime;
}
}
return 0;
}
边栏推荐
- See you tomorrow at the industrial session of cloud intelligence technology forum!
- Familiarize you with the "phone book" of cloud network: DNS
- 循环队列(c语言实现)
- POM file details
- Frisbee, 2022 "black red" top stream
- Propagation of transactions
- .net6 encounter with the League of heroes - create a game assistant according to the official LCU API
- My meeting of OA project
- 数据泄漏、删除事件频发,企业应如何构建安全防线?
- 【论文阅读】GRAW+:A Two-View Graph Propagation Method With Word Coupling for Readability Assessment
猜你喜欢

基于多特征的技术融合关系预测及其价值评估

【论文阅读】GRAW+:A Two-View Graph Propagation Method With Word Coupling for Readability Assessment

Docker swarm cluster builds highly available MySQL active and standby
![[oauth2] v. oauth2loginauthenticationfilter](/img/54/3c3f02511e30c301a5cea6f6ddd4c2.png)
[oauth2] v. oauth2loginauthenticationfilter

【着色器实现Overlay重新覆盖变装效果_Shader效果第九篇】

Jenkins 中 shell 脚本执行失败却不自行退出

12437 words, take you to explore the principle of RPC communication

Concept and handling of exceptions

LCL three-phase PWM rectifier (inverter)

Pytorch学习笔记(三)模型的使用、修改、训练(CPU/GPU)及验证
随机推荐
.net6 encounter with the League of heroes - create a game assistant according to the official LCU API
redis学习笔记
Native JS get transform value x y z and rotate rotation angle
JS, e.pagex, pagey modal box drag
C语言_结构体和数组的结合
天翼云Web应用防火墙(边缘云版)支持检测和拦截Apache Spark shell命令注入漏洞
My meeting of OA project
WPS凭什么拒绝广告?
How to write the introduction of GIS method journals and papers?
12437 words, take you to explore the principle of RPC communication
基于多任务深度学习的实体和事件联合抽取模型
【数学建模】常用基本模型总结
消息的订阅和发布
JS download files, filesaver.js export txt and Excel files
Sequence traversal of binary tree (implemented in C language)
[oauth2] VII. Wechat oauth2 authorized login
最新战报:十项认证,五项最佳实践
Digital collections accelerate the breaking of the circle and help the industry find new opportunities
[shaders realize overlay to re cover cross dressing effect _shader effect Chapter 9]
[oauth2] v. oauth2loginauthenticationfilter