当前位置:网站首页>c语言(循环链表)实现贪吃蛇的基本功能
c语言(循环链表)实现贪吃蛇的基本功能
2020-11-09 12:58:00 【osc_0tqqardd】
总体思想
利用循环链表将一条蛇的坐标进行存储,然后利用gotoxy()函数(可以将光标定位到指定的位置),此时根据蛇的坐标进行输出“@”,输出多几个既可以产生一条蛇。通过遍历循环链表进行蛇的移动,对循环链表的插入元素,产生蛇变长的效果。下面为各功能实现的函数
1.贪吃蛇地图函数map()
2.蛇的移动move(),up(),left()等函数
3.产生食物food()和吃到食物eat_food()
4.蛇吃到食物时产生的变长效果snake_link()函数
5.判断蛇的死亡,分别为撞墙hit_wall()和自杀suicide()
1.贪吃蛇地图函数map()
游戏地图采用的是应该封闭的区域,采用一个数组a[25][50],将此数组初始化为0,将游戏墙的边缘赋值为1,当数组为0,输出" ",数组为1,输出“#”,产生一个地图。
代码如下:
void map() //创建蛇的地图
{
int a[25][50] = {
0};
int i,j;
for(i = 0; i < 50; i++)
{
a[0][i] = 1;
a[24][i] =1;
}
for(i = 0; i < 25; i++)
{
a[i][0] = 1;
a[i][49] =1;
}
for(i = 0; i < 25; i++)
for(j = 0; j < 50; j++)
{
if(j%50 == 0)
printf("\n");
if(a[i][j] == 0)
{
printf(" ");
}
else
{
printf("#");
}
}
}
2.蛇的移动move(),up(),left()等函数
move()函数主要对蛇的上下左右进行更改在此采用switch函数进行解决(下面代码中ch为全局变量)
代码如下
void move(struct snake *p) //蛇的移动函数
{
while(1)
{
ch = getch();
switch(ch)
{
case 'W':p = up(p);break;
case 'A':p = left(p);break;
case 'D':p = right(p);break;
case 'S':p = down(p);break;
}
}
}
让蛇动起来的即我们主要对蛇的坐标进行更改,此时蛇头移动一次我们就利用gotoxy()函数进行输出“@”,然后在蛇尾输出“ ”,循环往复就可以产生蛇移动的效果,蛇的上下左右则只需在移动一个方向的时候对单一的坐标x或y进行更改,然后对更改的坐标保存进循环链表即可。移动函数则主要有up(),left()等,因为做法差不多,在此只对up()函数进行展示
代码如下
struct snake *up(struct snake *p) //向上移动
{
int x;
int y;
x = p->pre->x; //将蛇头坐标赋值给x,y
y = p->pre->y;
while(p) //对循环链表的遍历,即蛇的遍历
{
Sleep(SNAKE_SPEED); //蛇移动的速度
y--; //向上移动则只需将纵坐标进行减,就可以实现蛇向上移动的效果
gotoxy(p->x,p->y); //定位到蛇尾,输出“ ”即蛇尾消失
printf(" ");
gotoxy(x, y); //定位到蛇头输出,"@",结合上面的蛇尾消失又进行蛇头打印,产生蛇移动的效果
printf("@");
suicide(p,x,y); //判断蛇头是否撞到蛇身
p = p->next; //将蛇头的坐标变为下一个
p->pre->x = x; //此时将前一个蛇头变成蛇尾,通过不断的遍历产生不断移动的效果
p->pre->y = y;
food(); //产生食物
eat_food(p,x,y); //判断是否吃到食物
hit_wall(y); //判断是否撞墙
if(kbhit()) break; //判断是否有按键输入,有就进行蛇移动方向的改变
}
return p;
}
3.产生食物food()和吃到食物eat_food()
食物和吃到食物,产生食物则采用了产生随机数,产生一个食物的x,y坐标分别存放在全局变量food_xy[2]数组里面,最后利用gotoxy(food_xy[0],food_xy[1])随机产生食物
代码如下
void food() //产生食物
{
int i;
if(!flag) //根据flag的值来判断地图上是否有食物
{
srand( (unsigned)time( NULL ) );
for( i = 0; i < 2; i++ ) //对food_(x,y)来随机赋值
{
food_xy[i] = rand()%24+2;
while(food_xy[0] == 1 || food_xy[0] == 25) //这两个while为了防止食物
food_xy[0] = rand()%24+2; //的坐标与地图的边缘重叠
while(food_xy[1] >= 49 || food_xy[1] == 1)
food_xy[1] =rand()%24+2;
}
gotoxy(food_xy[0],food_xy[1]); //打印食物
printf("*");
flag = 1;
}
}
吃到食物eat_food(),则我们只需判断蛇头是否和食物的坐标重叠,若重叠则表明蛇吃到了食物
代码如下
void eat_food(struct snake *p,int x, int y) //蛇吃到食物,即主要是对蛇头的x,y坐标和
{
//food_xy的坐标进行匹配对比,若相同即调
if(x == food_xy[0] && y == food_xy[1]) //snake_link函数即可
{
p = snake_link(p);
flag = 0; //表明食物被吃,准备重新产生食物
printSnake(p);
gotoxy(8,0);
score = score + 1; //得分
printf("%d",score);
}
}
4.蛇吃到食物时产生的变长效果snake_link()函数
蛇的变长,当蛇吃到食物的时候,此时我们将食物的坐标变成蛇头,然后进行重新的打印蛇,即可以有蛇变成的效果产生,实质为对循环链表进行元素的插入。
即通过这样将食物的坐标插进去循环链表,达到蛇变成的效果
代码如下
struct snake *snake_link(struct snake *p) //蛇的连接
{
struct snake *q;
q = (struct snake *)malloc(sizeof(struct snake)); //即主要是实现了对循环链表的插入元素,再
q->x = food_xy[0]; //进行打印蛇,即可有吃到食物蛇变长的结果
q->y = food_xy[1];
q->pre = p->pre;
p->pre->next = q;
p->pre = q;
q->next = p;
return p;
}
5.判断蛇的死亡,分别为撞墙hit_wall()和自杀suicide()
撞墙,则只需判断蛇头的单一坐标x轴或者y轴是否与墙壁的坐标是否相等,若相等则说明蛇撞墙了
代码如下
void hit_wall(int n) //判断蛇是否撞墙,即对蛇的单一坐标x或者y进行判断,若等于墙壁的值,即游戏结束
{
if(ch == 'W'|| ch == 'S' )
if(n == 1 || n == 25) //墙壁的坐标值
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
if(ch == 'A'|| ch == 'D' )
if(n == 0 || n == 49)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
}
自杀suicide()即蛇头是否有撞到了蛇身,做法是把蛇头的坐标拿出来,与蛇身的坐标进行对比如果相等,说明蛇头撞到了蛇身,本质上是循环链表的值进行匹配,遍历
代码如下
void suicide(struct snake *p, int x, int y) //自杀,即撞到自己本身的时候游戏结束
{
struct snake *q; //把蛇头坐标传递进来,然后与其自己身体坐标做对比若有相等则表明,蛇头撞到了蛇身
q = p;
while(q != p->next) //即对循环链表的遍历匹配
{
if(p->x == x && p->y == y)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
else
p = p->next;
}
}
到此蛇的基本功能已经讲完,以下是全部代码。
全部代码如下
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#define SNAKE_SPEED 200 //蛇移动的速度
int score = 0; //成绩得分
int flag = 0; //用于判断地图上是否存在食物,0为不存在食物
int food_xy[2]; //定位食物的位置
char ch; //用来决定蛇的移动方向
struct snake //定义一条循环链表的蛇
{
int x;
int y;
struct snake *next;
struct snake *pre;
};
void HideCursor()//把蛇移动的时候产生的光标进行隐藏,隐藏光标函数
{
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = sizeof(cursor);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(handle, &cursor);
}
void gotoxy(int x, int y) //定位光标函数,用来实现蛇的移动,和食物的出现(传送x,y可以将光标定位到x,y)
{
HideCursor();
COORD coord = {
x,y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void map() //创建蛇的地图
{
int a[25][50] = {
0};
int i,j;
for(i = 0; i < 50; i++)
{
a[0][i] = 1;
a[24][i] =1;
}
for(i = 0; i < 25; i++)
{
a[i][0] = 1;
a[i][49] =1;
}
for(i = 0; i < 25; i++)
for(j = 0; j < 50; j++)
{
if(j%50 == 0)
printf("\n");
if(a[i][j] == 0)
{
printf(" ");
}
else
{
printf("#");
}
}
}
struct snake *createSnake() //给蛇进行初始化,构建一条蛇,本质为循环链表
{
int i;
struct snake *head,*p,*q;
p = q = (struct snake *)malloc(sizeof(struct snake));
head = NULL;
head = p;
head->pre = NULL;
for( i = 0; i < 5; i++)
{
p->x = 25 - i;
p->y = 13;
p->pre = head->pre;
head->pre = p;
q->next = p;
q = p;
p = (struct snake *)malloc(sizeof(struct snake));
}
q->next = head;
return head;
}
void printSnake(struct snake *p) //打印蛇,利用gotoxy()来对蛇进行打印,只需遍历一次循环链表即可将坐标可视化为一条蛇
{
struct snake *q;
q = p;
while(q != p->next) //循环链表的遍历
{
gotoxy(p->x,p->y); //根据坐标和定位光标函数来打@,实现输出蛇
printf("@");
p = p->next;
}
gotoxy(p->x,p->y);
printf("@");
gotoxy(0,0);
printf("你的得分:"); //初始化得分
}
void food() //产生食物
{
int i;
if(!flag) //根据flag的值来判断地图上是否有食物
{
srand( (unsigned)time( NULL ) );
for( i = 0; i < 2; i++ ) //对food_(x,y)来随机赋值
{
food_xy[i] = rand()%24+2;
while(food_xy[0] == 1 || food_xy[0] == 25) //这两个while为了防止食物的坐标与地图的边缘重叠
food_xy[0] = rand()%24+2;
while(food_xy[1] >= 49 || food_xy[1] == 1)
food_xy[1] =rand()%24+2;
}
gotoxy(food_xy[0],food_xy[1]); //打印食物
printf("*");
flag = 1;
}
}
struct snake *snake_link(struct snake *p) //蛇的连接
{
struct snake *q;
q = (struct snake *)malloc(sizeof(struct snake)); //即主要是实现了对循环链表的插入元素,再进行打印蛇,即可有吃到食物蛇变长的结果
q->x = food_xy[0];
q->y = food_xy[1];
q->pre = p->pre;
p->pre->next = q;
p->pre = q;
q->next = p;
return p;
}
void eat_food(struct snake *p,int x, int y) //蛇吃到食物,即主要是对蛇头的x,y坐标和food_xy的坐标进行匹配对比,若相同即调用snake_link函数即可
{
if(x == food_xy[0] && y == food_xy[1])
{
p = snake_link(p);
flag = 0;
printSnake(p);
gotoxy(8,0);
score = score + 1;
printf("%d",score);
}
}
void hit_wall(int n) //判断蛇是否撞墙,即对蛇的单一坐标x或者y进行判断,若等于墙壁的值,即游戏结束
{
if(ch == 'W'|| ch == 'S' )
if(n == 1 || n == 25)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
if(ch == 'A'|| ch == 'D' )
if(n == 0 || n == 49)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
}
void suicide(struct snake *p, int x, int y) //自杀,即撞到自己本身的时候游戏结束
{
struct snake *q; //把蛇头坐标传递进来,然后与其自己身体坐标做对比若有相等则表明,蛇头撞到了蛇身
q = p;
while(q != p->next) //即对循环链表的遍历匹配
{
if(p->x == x && p->y == y)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
else
p = p->next;
}
}
struct snake *up(struct snake *p) //向上移动
{
int x;
int y;
x = p->pre->x; //将蛇头坐标赋值给x,y
y = p->pre->y;
while(p) //对循环链表的遍历,即蛇的遍历
{
Sleep(SNAKE_SPEED); //蛇移动的速度
y--; //向上移动则只需将纵坐标进行减,就可以实现蛇向上移动的效果
gotoxy(p->x,p->y); //定位到蛇尾,输出“ ”即蛇尾消失
printf(" ");
gotoxy(x, y); //定位到蛇头输出,"@",结合上面的蛇尾消失又进行蛇头打印,产生蛇移动的效果
printf("@");
suicide(p,x,y); //判断蛇头是否撞到蛇身
p = p->next; //将蛇头的坐标变为下一个
p->pre->x = x; //此时将前一个蛇头变成蛇尾,通过不断的遍历产生不断移动的效果
p->pre->y = y;
food(); //产生食物
eat_food(p,x,y); //判断是否吃到食物
hit_wall(y); //判断是否撞墙
if(kbhit()) break; //判断是否有按键输入,有就进行蛇移动方向的改变
}
return p;
}
struct snake *left(struct snake *p) //向左移动
{
int x;
int y;
x = p->pre->x;
y = p->pre->y;
while(p)
{
Sleep(SNAKE_SPEED);
x--;
gotoxy(p->x,p->y);
printf(" ");
gotoxy(x, y);
printf("@");
suicide(p,x,y);
p = p->next;
p->pre->x = x;
p->pre->y = y;
food();
eat_food(p,x,y);
hit_wall(x);
if(kbhit()) break;
}
return p;
}
struct snake *down(struct snake *p) //向下移动
{
int x;
int y;
x = p->pre->x;
y = p->pre->y;
while(p)
{
Sleep(SNAKE_SPEED);
y++;
gotoxy(p->x,p->y);
printf(" ");
gotoxy(x, y);
printf("@");
suicide(p,x,y);
p = p->next;
p->pre->x = x;
p->pre->y = y;
food();
eat_food(p,x,y);
hit_wall(y);
if(kbhit()) break;
}
return p;
}
struct snake *right(struct snake *p) //向右移动
{
int x;
int y;
x = p->pre->x;
y = p->pre->y;
while(p)
{
Sleep(SNAKE_SPEED);
x++;
gotoxy(p->x,p->y);
printf(" ");
gotoxy(x, y);
printf("@");
suicide(p,x,y);
p = p->next;
p->pre->x = x;
p->pre->y = y;
food();
eat_food(p,x,y);
hit_wall(x);
if(kbhit()) break;
}
return p;
}
void move(struct snake *p) //蛇的移动函数
{
while(1)
{
ch = getch();
switch(ch)
{
case 'W':p = up(p);break;
case 'A':p = left(p);break;
case 'D':p = right(p);break;
case 'S':p = down(p);break;
}
}
}
int main()
{
struct snake *p;
map(); //产生地图
p = createSnake(); // 初始化蛇
printSnake(p); // 打印蛇
move(p); //移动蛇
return 0;
}
版权声明
本文为[osc_0tqqardd]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4263437/blog/4709418
边栏推荐
- 导师制Processing网课 双十一优惠进行中
- 苏宁基于知识图谱的大规模告警收敛和根因定位实践
- Using stream to read and write files to process large files
- 彩虹排序 | 荷兰旗问题
- The use of Android studio Aidl
- Learn with me. NETCORE EF core practical introduction, a look will
- Reading design patterns adapter patterns
- Android NDK development and actual combat WeChat official account 2-D code detection
- Interface tests how to pass files in post requests
- Introduction to zero based im development (4): what is message timing consistency in IM systems?
猜你喜欢
随机推荐
嗯,查询滑动窗口最大值的这4种方法不错...
Open source ERP recruitment
服务应用 ClockService安卓实现闹钟
A simple way to realize terminal text paste board
Gather in Beijing! Openi / O 2020 Qizhi Developer Conference enters countdown
Visual Studio (MAC) installation process notes
Explain Python input() function: get user input string
移动安全加固助力 App 实现全面、有效的安全防护
Well, the four ways to query the maximum value of sliding window are good
Viewing PDB files from the angle of assembly
Tutorial system unity online course double 11 preferential registration is in progress
JVM学习(四)-垃圾回收器和内存分配
Rainbow sorting | Dutch flag problem
Configure switch trunk interface traffic local priority forwarding (cluster / stack)
块级元素和行内元素
AndroidStudio导入定制化的framework classess.jar AS 4.0.1版本亲测有效
Setting up a proxy for the WGet command
“开源软件供应链点亮计划 - 暑期 2020”公布结果 基于 ChubaoFS 开发的项目获得最佳质量奖
IDEA rest-client,会了它我还没打开过postman
Flink 系例 之 Reduce