服务器之家

服务器之家 > 正文

C语言循环链表实现贪吃蛇游戏

时间:2021-10-03 22:31     来源/作者:yzw丶

本文实例为大家分享了C语言表实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下

总体思想

利用循环链表将一条蛇的坐标进行存储,然后利用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,输出“#”,产生一个地图。

代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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为全局变量)
代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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()函数进行展示

代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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])随机产生食物
代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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(),则我们只需判断蛇头是否和食物的坐标重叠,若重叠则表明蛇吃到了食物

代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
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()函数

蛇的变长,当蛇吃到食物的时候,此时我们将食物的坐标变成蛇头,然后进行重新的打印蛇,即可以有蛇变成的效果产生,实质为对循环链表进行元素的插入。

C语言循环链表实现贪吃蛇游戏

即通过这样将食物的坐标插进去循环链表,达到蛇变成的效果
代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
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轴是否与墙壁的坐标是否相等,若相等则说明蛇撞墙了
代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()即蛇头是否有撞到了蛇身,做法是把蛇头的坐标拿出来,与蛇身的坐标进行对比如果相等,说明蛇头撞到了蛇身,本质上是循环链表的值进行匹配,遍历

代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
 }
}

到此蛇的基本功能已经讲完,以下是全部代码。

全部代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#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;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/weixin_46571879/article/details/109538169

标签:

相关文章

热门资讯

yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部