《数据结构与算法分析》课程设计——贪吃蛇问题
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了《数据结构与算法分析》课程设计——贪吃蛇问题,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含14693字,纯文字阅读大概需要21分钟。
内容图文
中国矿业大学信控学院
/*文献参考*/
https://blog.csdn.net/Fdog_/article/details/102625969
https://blog.csdn.net/DY_1024/article/details/78841757
一、问题描述
以数据结构思想设计实现贪吃蛇小游戏。
二、需求分析
首先需要考虑如何设计一个win运行窗口来实时显示结果
然后考虑到蛇的身子是一节一节的,此时最容易联想到的数据结构就是顺序表,链表,如果把蛇比做顺序表或者链表,在之后吃到食物的时候,身子肯定会变长,这就涉及到插入的操作,所以为了更高的效率,我们用链表实现我们的蛇的部分,最初我们把蛇身子按照四个结点打印在屏幕。
对于蛇的移动,在屏幕上面蛇的移动看起来是整个身子向前方平移一个单位,但是其原理是我们在屏幕的另一个地方把蛇从新打印一遍,又把之前的蛇身子去除掉。
对于食物的产生,随机的在地图中产生一个节点,在蛇的头坐标和食物的坐标重复的时候,食物消失,蛇的身子加长,也就是蛇的节点数增加一个。
蛇在其中的几种状态,正常状态:蛇头节点的坐标没有和墙的坐标以及自己身子的坐标重合,
被自己杀死:蛇头的坐标和蛇身子的坐标重合,
撞墙:蛇头的坐标和墙的坐标重合。
三、算法设计
1.相关变量。
1
1
.相关变量。
2
int JudgeSum = 0; //判断是否加快3int Pause = 200000000; //暂停速度(移动速度)4int * PJ = &JudgeDirection; //用指针传值判断移动方向5 nakebody *end = NULL; //尾节点
2.创建链表 ,贪吃蛇的身体如何保存是游戏的核心,所以我们需要用到链表来保存蛇的身体,这样就可以随时知道蛇身数据。
1 typedef struct Snakebody
2{
3int x, y; //蛇身的坐标4struct Snakebody *next;//保存下一个蛇身的地址5 }Snakebody; //通过typedef将 Snakebody 替代 struct Snakebody
3.记录食物出现的坐标。
1 typedef struct Snakexy
2{
3int x;
4int y;
5 }Snakexy; //记录食物坐标
4.绘制初始界面和游戏地图,如图所示。
1 #include<Windows.h>
2#define HEIGHT 20 //设置地图高度 3#define WIDTH 40 //设置地图宽度 4#define PRINTF printf("■");
5#define LINE printf("\n");
6#define EMPTY printf(" "); //因为这三个语句经常用,所以我就定义成了宏 7void Front(); //绘制初始界面 8void DeawMap(); //绘制地图 910void Front()
11{
12 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);//设置红色和蓝色相加13 MoveCursor(18, 15);
14 printf("请等待......");
15for (int i = 0; i <= 3000000000; i++) {}
16 system("cls");//清屏处理17}
18void DeawMap()
19{
20for (int i = 0; i < WIDTH; i++)PRINTF LINE //打印上边框21for (int i = 1; i < HEIGHT - 1; i++) //打印左右边框22 {
23for (int j = 0; j < WIDTH; j++)
24 {
25if (j == 0 || j == WIDTH - 1 || j == WIDTH - 10)
26 {
27 PRINTF
28if (j == WIDTH - 1)LINE
29 }
30else EMPTY
31 }
32 }
33for (int i = 0; i < WIDTH; i++)PRINTF LINE //打印下边框34 }
SetConsoleTextAttribute()函数是一个API设置字体颜色和背景色的函数。参数表中使用两个属性(属性之间用,隔开),不同于system(),SetConsoleTextAttribute()可以改变界面多种颜色,而system()只能修改为一种!。
5. 初始化蛇身,刚开始蛇不应该只要一个头,所以我们必须创建几个身体。
1 Snakebody *Phead = NULL; //存储着整个蛇身 不可更改 2 Snakebody *Phead_1 = NULL; //指向蛇身 3 Snakebody *Pbady = NULL; //创建节点 4void ISnake(); //初始化蛇身 5void ISnake()
6{
7for (int i = 0; i < 5; i++)//初始化蛇身拥有五个长度 8 {
9 Pbady = (Snakebody*)malloc(sizeof(Snakebody));//创建节点10 Pbady->x = 5 - i;
11 Pbady->y = 5;
12if (Phead == NULL)
13 {
14 Phead = Pbady;
15 }
16else17 {
18 end->next = Pbady;
19 }
20 Pbady->next = NULL;
21 end = Pbady;
22 }
23 Phead_1 = Phead;
24while (Phead_1->next != NULL)//打印蛇身25 {
26 MoveCursor(Phead_1->x, Phead_1->y);
27 PRINTF
28 Phead_1 = Phead_1->next;
29 }
30 }
6.产生食物,随机产生食物,如果和蛇身体重合则再次随机产生食物。
1 #include<time.h>
2int sum = 0; //计算得分 3 Snakexy * Food = NULL; //保存食物位置 4void FoodRand(); //生成食物 5void FoodRand()
6{
7 srand((int)time(0));
8int x = rand() % 27 + 2;//生成随机数 9int y = rand() % 17 + 2;
10 Phead_1 = Phead;
11for (int i = 0; i <= 200; i++)
12 {
13if (Phead_1->x == x && Phead_1->y == y)
14 {
15 x = rand() % 27 + 2;
16 y = rand() % 17 + 2;
17 }
18else19 {
20 Phead_1 = Phead_1->next;
21 }
22if (Phead_1->next == NULL)
23 {
24break;
25 }
26 }
27 MoveCursor(x, y);
28 PRINTF
29 Food = (Snakexy*)malloc(sizeof(Snakexy));
30 Food->x = x;
31 Food->y = y;
32 MoveCursor(33, 5);
33 printf("");
34 Showf();
35 sum++;
36 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);// 蓝37 }
rand函数功能为获取一个伪随机数,如要产生[m,n]范围内的随机数num,可用int num=rand()%(n-m+1)+m;
7.游戏刷新和暂停 ,按回车可暂停游戏。
1
int JudgeDirection = 4; //判断方向 2void ControlMove(); //控制移动和暂停 3void ControlMove()
4{
5if (GetAsyncKeyState(VK_UP) && 0x8000)
6 {
7if (JudgeDirection == 2)
8 {
9 }
10else11 {
12 JudgeDirection = 1;
13 }
14 }
15if (GetAsyncKeyState(VK_DOWN) && 0x8000)
16 {
17if (JudgeDirection == 1)
18 {
19 }
20else21 {
22 JudgeDirection = 2;
23 }
24 }
25if (GetAsyncKeyState(VK_RIGHT) && 0x8000)
26 {
27if (JudgeDirection == 3)
28 {
29 }
30else31 {
32 JudgeDirection = 4;
33 }
34 }
35if (GetAsyncKeyState(VK_LEFT) && 0x8000)
36 {
37if (JudgeDirection == 4)
38 {
39 }
40else41 {
42 JudgeDirection = 3;
43 }
44 }
45if (GetAsyncKeyState(VK_RETURN) && 0x0D)//判断回车46 {
47while (1)
48 {
49if (GetAsyncKeyState(VK_RETURN) && 0x0D)//再次回车退出死循环50 {
51break;
52 }
53 }
54 }
55 }
GetAsyncKeyState()确定用户当前是否按下了键盘上的一个键
8.显示分数和难度,更新分数和难度。
1
int sum = 0; //计算得分 2int Hard = 0; //计算难度 3void Showf(); //显分数以及难度 4void Showf()
5{
6 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE);// 蓝 7 MoveCursor(33, 5);
8 printf("得分:%d", sum);
9 MoveCursor(33, 6);
10 printf("难度:%d", Hard);
11 }
9.移动光标 ,游戏不闪的原因就是我们只绘制一次地图 然后用光标定点刷新目标点。
1
void MoveCursor(int x, int y); //移动光标2void MoveCursor(int x, int y)//设置光标位置(就是输出显示的开始位置)3{
4 COORD pos = { x * 2,y };
5 HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出的句柄 6 SetConsoleCursorPosition(output, pos); //设置光标位置7 }
COORD是Windows API中定义的一种结构体
10.检测,检测是否吃到食物,是否撞墙,是否撞到自己。
1
void Jfood(); //检测是否吃到食物 2void Jwall(); //检测蛇头是否撞墙 3void Jsnake(); //检测蛇头是否撞到蛇身 4void Jfood()
5{
6 Phead_1 = Phead;
7if (Phead_1->x == Food->x&&Phead_1->y == Food->y)
8 {
9 FoodRand();
10 JudgeSum += 1;
11if (JudgeSum == 5)
12 {
13 JudgeSum = 0;//如果JudgeSum等于5则从新判断14 Hard += 1;
15 Pause -= 20000000;//每成立一次循环减少2000000016 }
17while (Phead_1->next != NULL)
18 {
19 Phead_1 = Phead_1->next;
20 }
21 Snakebody *S = (Snakebody*)malloc(sizeof(Snakebody));
22 S->x = Food->x;
23 S->y = Food->y;
24 S->next = NULL;
25 Phead_1->next = S;
26 ControlMove();
27 MoveCursor(Phead_1->x, Phead_1->y);
28 PRINTF
29 }
30//获取食物的坐标和蛇头做对比31}
32void Jwall()
33{
34if (Phead->x == 0 || Phead->x == 29 || Phead->y == 0 || Phead->y == 19)
35 {
36 MoveCursor(10, 20);
37 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色38 printf("抱歉,你撞到了自己,游戏结束! ");
39 system("pause>nul");
40 exit(0);
41 }
42}
43void Jsnake()
44{
45 Phead_1 = Phead->next;
46while (Phead_1->next != NULL)
47 {
48if ((Phead->x == Phead_1->x) && (Phead->y == Phead_1->y))
49 {
50 MoveCursor(10, 20);
51 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色52 printf("抱歉,你撞到了自己,游戏结束! ");
53 system("pause>nul");
54 exit(0);
55 }
56 Phead_1 = Phead_1->next;
57 }
58 }
11.游戏循环
1
void Move(); //游戏运行 2void Move()
3{
4while (1)
5 {
6 Phead_1 = Phead;
7while (Phead_1->next->next != NULL)
8 {
9 Phead_1 = Phead_1->next;
10 }
11 Phead_1->next = NULL;
12for (int i = 0; i < Pause; i++) {}
13 ControlMove();
14 MoveCursor(Phead_1->x, Phead_1->y);
15 EMPTY
16//上面为消除尾部17 Snakebody *Phead_2 = (Snakebody*)malloc(sizeof(Snakebody));
18if (*PJ == 1)
19 {
20 Phead_2->x = Phead->x;
21 Phead_2->y = Phead->y - 1;
22 }
23if (*PJ == 2)
24 {
25 Phead_2->x = Phead->x;
26 Phead_2->y = Phead->y + 1;
27 }
28if (*PJ == 3)
29 {
30 Phead_2->x = Phead->x - 1;
31 Phead_2->y = Phead->y;
32 }
33if (*PJ == 4)
34 {
35 Phead_2->x = Phead->x + 1;
36 Phead_2->y = Phead->y;
37 }
38 Phead_2->next = Phead;
39 Phead = Phead_2;
40 MoveCursor(Phead_2->x, Phead_2->y);
41 PRINTF
42 Jfood();
43 Jwall();
44 Jsnake();
45 MoveCursor(40, 20);
46 }
47 }
12.释放内存
1
void Free(); //释放内存 2void Free()
3{
4while (Phead->next != NULL)
5 {
6 Phead = Phead->next;
7free(Phead);
8 }
9free(Phead);
10 }
附录:完整代码
1 #include<stdio.h>
2 #include<time.h>
3 #include<Windows.h>
4#define HEIGHT 20 //设置地图高度 5#define WIDTH 40 //设置地图宽度 6#define PRINTF printf("■");
7#define LINE printf("\n");
8#define EMPTY printf(" ");
9 typedef struct Snakebody
10{
11int x, y;//身体的坐标 12struct Snakebody *next;//结构指针 13 }Snakebody;//先来创建保持身体的链表,贪吃蛇的核心代码就是该如何保存蛇的身体 14 typedef struct Snakexy
15{
16int x;
17int y;
18 }Snakexy; //记录食物坐标 19int sum = 0; //计算得分 20int JudgeSum = 0; //判断是否加快 21int Hard = 0; //计算难度 22int Pause = 200000000; //暂停速度(移动速度) 23int JudgeDirection = 4; //判断方向 24int * PJ = &JudgeDirection; //用指针传值判断移动方向 25 Snakebody *Phead = NULL; //存储着整个蛇身 不可更改 26 Snakebody *Phead_1 = NULL; //指向蛇身 27 Snakebody *Pbady = NULL; //创建节点 28 Snakebody *end = NULL; //尾节点 29 Snakexy * Food = NULL; //保存食物位置 30void Front(); //游戏开始页面1 31void Jfood(); //检测是否吃到食物1 32void Jwall(); //检测蛇头是否撞墙1 33void Jsnake(); //检测蛇头是否撞到蛇身1 34void ISnake(); //初始化蛇身1 35void DeawMap(); //绘制地图1 36void FoodRand(); //生成食物1 37void ControlMove(); //控制移动和暂停1 38void MoveCursor(int x, int y); //移动光标1 39void Move(); //游戏运行1 40void Showf(); //显分数以及难度1 41void Free(); //释放内存 42int main()
43{
44 Front();
45 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);//绿 46 DeawMap();
47 Showf();
48 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);// 暗白 49 MoveCursor(34, 10);
50 printf("↑");
51 MoveCursor(31, 11);
52 printf("使用←↓→来控制");
53 MoveCursor(31, 12);
54 printf("蛇的移动,撞墙游");
55 MoveCursor(31, 13);
56 printf("戏结束,每5分增 ");
57 MoveCursor(31, 14);
58 printf("一个难度(速度)");
59 ISnake();
60 FoodRand();
61 MoveCursor(40, 20);
62 Move();
63return0;
64}
65void Front()
66{
67 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);//设置红色和蓝色相加 68 MoveCursor(18, 15);
69 printf("请等待......");
70for (int i = 0; i <= 3000000000; i++) {}
71 system("cls");
72}
73void DeawMap()
74{
75for (int i = 0; i < WIDTH; i++)PRINTF LINE //上边框 76for (int i = 1; i < HEIGHT - 1; i++) //打印左右边框 77 {
78for (int j = 0; j < WIDTH; j++)
79 {
80if (j == 0 || j == WIDTH - 1 || j == WIDTH - 10)
81 {
82 PRINTF
83if (j == WIDTH - 1)LINE
84 }
85else EMPTY
86 }
87 }
88for (int i = 0; i < WIDTH; i++)PRINTF LINE //下边框 89}
90void MoveCursor(int x, int y)//设置光标位置(就是输出显示的开始位置) 91{
92/* COORD是Windows API中定义的一种结构体
93 * typedef struct _COORD
94 * {
95 * SHORT X;
96 * SHORT Y;
97 * } COORD;
98 * */ 99 COORD pos = { x * 2,y };
100 HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);//获得 标准输出的句柄 101 SetConsoleCursorPosition(output, pos); //设置控制台光标位置102}
103void FoodRand()
104{
105 srand((int)time(0));
106int x = rand() % 27 + 2;
107int y = rand() % 17 + 2;
108 Phead_1 = Phead;
109for (int i = 0; i <= 200; i++)
110 {
111if (Phead_1->x == x && Phead_1->y == y)
112 {
113 x = rand() % 27 + 2;
114 y = rand() % 17 + 2;
115 }
116else117 {
118 Phead_1 = Phead_1->next;
119 }
120if (Phead_1->next == NULL)
121 {
122break;
123 }
124 }
125 MoveCursor(x, y);
126 PRINTF
127 Food = (Snakexy*)malloc(sizeof(Snakexy));
128 Food->x = x;
129 Food->y = y;
130 MoveCursor(33, 5);
131 printf("");
132 Showf();
133 sum++;
134 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);// 蓝135}
136void ControlMove()
137{
138if (GetAsyncKeyState(VK_UP) && 0x8000)
139 {
140if (JudgeDirection == 2)
141 {
142 }
143else144 {
145 JudgeDirection = 1;
146 }
147 }
148if (GetAsyncKeyState(VK_DOWN) && 0x8000)
149 {
150if (JudgeDirection == 1)
151 {
152 }
153else154 {
155 JudgeDirection = 2;
156 }
157 }
158if (GetAsyncKeyState(VK_RIGHT) && 0x8000)
159 {
160if (JudgeDirection == 3)
161 {
162 }
163else164 {
165 JudgeDirection = 4;
166 }
167 }
168if (GetAsyncKeyState(VK_LEFT) && 0x8000)
169 {
170if (JudgeDirection == 4)
171 {
172 }
173else174 {
175 JudgeDirection = 3;
176 }
177 }
178if (GetAsyncKeyState(VK_RETURN) && 0x0D)
179 {
180while (1)
181 {
182if (GetAsyncKeyState(VK_RETURN) && 0x0D)
183 {
184break;
185 }
186 }
187 }
188}
189void ISnake()
190{
191for (int i = 0; i < 5; i++)
192 {
193 Pbady = (Snakebody*)malloc(sizeof(Snakebody));
194 Pbady->x = 5 - i;
195 Pbady->y = 5;
196if (Phead == NULL)
197 {
198 Phead = Pbady;
199 }
200else201 {
202 end->next = Pbady;
203 }
204 Pbady->next = NULL;
205 end = Pbady;
206 }
207 Phead_1 = Phead;
208while (Phead_1->next != NULL)
209 {
210 MoveCursor(Phead_1->x, Phead_1->y);
211 PRINTF
212 Phead_1 = Phead_1->next;
213 }
214}
215void Move()
216{
217while (1)
218 {
219 Phead_1 = Phead;
220while (Phead_1->next->next != NULL)
221 {
222 Phead_1 = Phead_1->next;
223 }
224 Phead_1->next = NULL;
225for (int i = 0; i < Pause; i++) {}
226 ControlMove();
227 MoveCursor(Phead_1->x, Phead_1->y);
228 EMPTY
229//上面为消除尾部230 Snakebody *Phead_2 = (Snakebody*)malloc(sizeof(Snakebody));
231if (*PJ == 1)
232 {
233 Phead_2->x = Phead->x;
234 Phead_2->y = Phead->y - 1;
235 }
236if (*PJ == 2)
237 {
238 Phead_2->x = Phead->x;
239 Phead_2->y = Phead->y + 1;
240 }
241if (*PJ == 3)
242 {
243 Phead_2->x = Phead->x - 1;
244 Phead_2->y = Phead->y;
245 }
246if (*PJ == 4)
247 {
248 Phead_2->x = Phead->x + 1;
249 Phead_2->y = Phead->y;
250 }
251 Phead_2->next = Phead;
252 Phead = Phead_2;
253 MoveCursor(Phead_2->x, Phead_2->y);
254 PRINTF
255 Jfood();
256 Jwall();
257 Jsnake();
258 MoveCursor(40, 20);
259 }
260}
261void Jfood()
262{
263 Phead_1 = Phead;
264if (Phead_1->x == Food->x&&Phead_1->y == Food->y)
265 {
266 FoodRand();
267 JudgeSum += 1;
268if (JudgeSum == 5)
269 {
270 JudgeSum = 0;
271 Hard += 1;
272 Pause -= 20000000;
273 }
274while (Phead_1->next != NULL)
275 {
276 Phead_1 = Phead_1->next;
277 }
278 Snakebody *S = (Snakebody*)malloc(sizeof(Snakebody));
279 S->x = Food->x;
280 S->y = Food->y;
281 S->next = NULL;
282 Phead_1->next = S;
283 ControlMove();
284 MoveCursor(Phead_1->x, Phead_1->y);
285 PRINTF
286 }
287//获取食物的坐标和蛇头做对比288}
289void Jwall()
290{
291if (Phead->x == 0 || Phead->x == 29 || Phead->y == 0 || Phead->y == 19)
292 {
293 MoveCursor(10, 20);
294 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色295 printf("抱歉,你撞到了自己,游戏结束! ");
296 system("pause>nul");
297 exit(0);
298 }
299}
300void Jsnake()
301{
302 Phead_1 = Phead->next;
303while (Phead_1->next != NULL)
304 {
305if ((Phead->x == Phead_1->x) && (Phead->y == Phead_1->y))
306 {
307 MoveCursor(10, 20);
308 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色309 printf("抱歉,你撞到了自己,游戏结束! ");
310 system("pause>nul");
311 exit(0);
312 }
313 Phead_1 = Phead_1->next;
314 }
315}
316void Showf()
317{
318 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE);// 蓝319 MoveCursor(33, 5);
320 printf("得分:%d", sum);
321 MoveCursor(33, 6);
322 printf("难度:%d", Hard);
323}
324void Free()
325{
326while (Phead->next != NULL)
327 {
328 Phead = Phead->next;
329free(Phead);
330 }
331free(Phead);
332 }
原文:https://www.cnblogs.com/zhangzhangzhang624531420/p/12181744.html
内容总结
以上是互联网集市为您收集整理的《数据结构与算法分析》课程设计——贪吃蛇问题全部内容,希望文章能够帮你解决《数据结构与算法分析》课程设计——贪吃蛇问题所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。