1 #include <stdio.h>
2 #include <conio.h>
3 #include <stdlib.h>
4 #include <windows.h>
5 #include <time.h>
6 #define MAX__X 23
7 #define MAX__Y 50
8 #define MAX_FOOD 50
9 #define ESC 27
10 #define SPACE 32
11
12 typedef struct Node
13 {
14 int x;
15 int y;
16 struct Node *next;
17 } Node,*LinkList;
18
19 typedef struct
20 {
21 LinkList front;
22 LinkList rear;
23 int length;
24 } Queue;
25
26 Queue snake;
27
28 void gotoxy(int x,int y)//坐标定位
29 {
30 COORD loc;
31 loc.X = y;
32 loc.Y = x;
33 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), loc);
34 }
35
36 void help_info()//显示帮助信息
37 {
38 gotoxy(8,55);
39 puts("按ESC键退出,空格键暂停:");
40 gotoxy(10,55);
41 puts("上,下,左,右:w,s,a,d");
42 gotoxy(12,55);
43 puts("蛇越长,速度也会越快:");
44 gotoxy(14,55);
45 puts("如无法控制蛇,请关闭");
46 gotoxy(15,56);
47 puts("大写键盘锁定状态:");
48 }
49
50 void game_info()//显示游戏信息
51 {
52 gotoxy(3,60);
53 printf("当前蛇长度: %d",snake.length);
54 gotoxy(5,60);
55 printf(" ");
56 gotoxy(5,60);
57 printf("离胜利还差: %d",MAX_FOOD-snake.length);
58 }
59
60 void enqueue(int x,int y)//入队
61 {
62 LinkList p;
63 p = (LinkList)malloc(sizeof(Node));
64 p->x = x;
65 p->y = y;
66 snake.rear->next = p;
67 snake.rear = p;
68 p->next = NULL;
69 snake.length++;
70 }
71
72 void dequeue()//出队
73 {
74 LinkList p = snake.front;
75 //保存食物位置
76 p->next->x = p->x;
77 p->next->y = p->y;
78 snake.front = snake.front->next;
79 snake.length--;
80 free(p);
81 }
82
83 void destroy_queue()//销毁队列
84 {
85 LinkList p;
86 while(p = snake.front)
87 {
88 snake.front = snake.front->next;
89 free(p);
90 }
91 }
92
93 void snake_init()//初始化蛇,rear指向蛇头,front指向食物,front->next指向蛇尾
94 {
95 int i;
96 snake.rear = snake.front = (LinkList)malloc(sizeof(Node));
97 snake.rear->next = NULL;
98 snake.length = 0;
99 for(i = 0; i < 3; i++)
100 {
101 enqueue(1,i + 1);
102 }
103 }
104
105 void show_food()//随机化食物位置
106 {
107 LinkList p;
108 srand(time(NULL));//初始化随机种子
109 while(1)
110 {
111 snake.front->x = rand() % (MAX__X-1) + 1;
112 snake.front->y = rand() % (MAX__Y-1) + 1;
113 p = snake.front->next;
114 //防止食物出现在蛇内部
115 while(p)
116 {
117 if(snake.front->x == p->x && snake.front->y == p->y)
118 {
119 break;
120 }
121 else
122 {
123 p = p->next;
124 }
125 }
126 if(!p)
127 {
128 break;
129 }
130 }
131 gotoxy(snake.front->x,snake.front->y);
132 putchar('@');//食物
133 }
134
135 int judge()//判断失败与否
136 {
137 LinkList p;
138 if(snake.length >= MAX_FOOD)
139 {
140 system("cls");
141 gotoxy(4,20);
142 puts("恭喜你,赢了!!!");
143 exit(0);
144 }
145 //碰到自身
146 p = snake.front->next;
147 while(snake.rear != p)
148 {
149 if(snake.rear->x == p->x && snake.rear->y == p->y)
150 {
151 break;
152 }
153 else
154 {
155 p = p->next;
156 }
157 }
158 if(snake.rear == p)
159 {
160 //碰到边界
161 if(snake.rear->x >= 1 && snake.rear->y >= 1 && snake.rear->x < MAX__X && snake.rear->y < MAX__Y)
162 {
163 return 1;
164 }
165 }
166 system("cls");
167 gotoxy(4,20);
168 puts("GAME OVER!!!");
169 destroy_queue();
170 getch();
171 exit(0);
172 }
173
174 void drow_wall()//画墙
175 {
176 int i;
177 for(i = 0; i <= MAX__Y; i++)
178 {
179 gotoxy(0,i);
180 putchar('W');
181 gotoxy(MAX__X,i);
182 putchar('M');
183 if(i <= MAX__X)
184 {
185 gotoxy(i,0);
186 putchar('I');
187 gotoxy(i,MAX__Y);
188 putchar('I');
189 }
190 }
191 }
192
193 void drow_snake(int i)//0表示画蛇头,1表示画蛇身
194 {
195 LinkList p;
196 p = snake.rear;
197 gotoxy(p->x,p->y);
198 if(i)
199 {
200 putchar('*'); //蛇身
201 }
202 else
203 {
204 putchar('%'); //蛇头
205 }
206 }
207
208 void clear_snake_tail()
209 {
210 LinkList p = snake.front->next;
211 gotoxy(p->x,p->y);
212 putchar(' ');//清除旧蛇尾
213 p = p->next;
214 gotoxy(p->x,p->y);
215 putchar('~');//添加新蛇尾
216 }
217
218 void snake_auto_move(char temp)//实现蛇的自动移动
219 {
220 int x,y,speed;
221 do
222 {
223 clear_snake_tail();
224 drow_snake(1);//画蛇身
225 x = snake.rear->x;
226 y = snake.rear->y;
227 switch(temp)
228 {
229 case 'w':
230 x--;
231 break;
232 case 's':
233 x++;
234 break;
235 case 'a':
236 y--;
237 break;
238 case 'd':
239 y++;
240 }
241 enqueue(x,y);//新蛇头入队
242 if(snake.front->x == x && snake.front->y == y) //蛇捕捉到食物后,食物重新随机化
243 {
244 game_info();
245 show_food();
246 }
247 else
248 {
249 dequeue(); //旧蛇尾出队
250 }
251 drow_snake(0);//画蛇头
252 speed = -2.3 * snake.length + 157;
253 Sleep(speed);//程序暂停speed个单位毫秒
254 }
255 while(!_kbhit() && judge()); //_kbhit为检测键盘输入
256 }
257
258 void snake_move()//实现玩家控制蛇的移动
259 {
260 char c,pause;
261 static char temp = 0;//静态局部变量
262 pause = 0;
263 if(!temp) //一开始的时候让蛇先自动移动
264 {
265 temp = 'd';
266 snake_auto_move(temp);
267 }
268 while(1)
269 {
270 c = getch();
271 if(c == ESC) //退出
272 {
273 system("cls");
274 puts("游戏退出成功!");
275 system("pause");
276 destroy_queue();
277 exit(0);
278 }
279 if(pause == SPACE)
280 {
281 if(c == SPACE) //再按下空格键继续游戏
282 {
283 pause = 0;
284 gotoxy(6,20);
285 printf(" ");//消除~~Pause~~:
286 snake_auto_move(temp);
287 }
288 continue;
289 }
290 if(c == SPACE) //按空格键暂停游戏
291 {
292 pause = SPACE;
293 gotoxy(6,20);
294 printf("~~Pause~~:");
295 continue;
296 }
297 if(c == 'w' || c == 'a' || c == 's' || c == 'd')
298 {
299 if((temp == 'w' && c == 's') || (temp == 's' && c == 'w') || (temp == 'd' && c == 'a') || (temp == 'a' && c == 'd')) //不允许连续的两次内按相反的键
300 {
301 snake_auto_move(temp);
302 continue;
303 }
304 break;
305 }
306 snake_auto_move(temp);
307 }
308 temp = c;
309 snake_auto_move(temp);
310 }
311
312 int main()
313 {
314 help_info();
315 snake_init();
316 show_food();
317 drow_wall();
318 game_info();
319 while(judge())
320 {
321 snake_move();
322 }
323 return 0;
324 }