Linux下C语言实现贪吃蛇

简单记录下贪吃蛇小游戏。

以下是源码:

  1 #include <curses.h>
  2 #include <stdlib.h>
  3 #include <pthread.h>
  4 #define  UP     1
  5 #define  DOWN  -1
  6 #define  LEFT   2
  7 #define  RIGHT -2
  8 
  9 /*蛇和食物的结构体*/
 10 struct Snake
 11 {
 12     int hang;
 13     int lie;
 14     struct Snake *next;
 15 };
 16 
 17 struct Snake *head = NULL;      //链表头
 18 struct Snake *tail = NULL;        //链表尾
 19 struct Snake food;              //食物
 20 int key;                        //记录键盘输入值
 21 int dir;                        //记录输入的方向键
 22 
 23 /*输入横坐标和纵坐标值,判断是否存在蛇的链表节点*/
 24 int hasSnakeNode(int i,int j)
 25 {
 26     struct Snake *p;            //临时变量,用于记录蛇的链表表头
 27     p = head;
 28     
 29     while(p != NULL)            //当链表头不为空时,进入循环
 30     {
 31         if(p->hang == i && p->lie == j)
 32         {
 33             return 1;           //输入的行纵坐标存在于蛇的链表中时返回1
 34         }
 35         p = p->next;            //链表头指向下一个节点
 36     }
 37     return 0;                   //输入的横纵坐标不存在蛇的链表中时返回0
 38 }
 39 
 40 /*食物初始化*/
 41 void initFoodnode()
 42 { 
 43     int x;                     //定义横坐标临时变量
 44     int y;                     //定义纵坐标临时变量
 45     x = rand()%20;             //在[0-20]范围内随机获取横坐标值
 46     y = rand()%20;             //在[0-20]范围内随机获取纵坐标值
 47     
 48     if(y == 0)
 49     {
 50         y = rand()%20;          //当纵坐标取值为0时,重新取值
 51     }
 52 
 53     food.hang = x;             //将前面获取到的横坐标赋值为食物的横坐标
 54     food.lie = y;               //将前面获取到的纵坐标复制为食物的纵坐标
 55 }
 56 
 57 /*输入横纵坐标判断是否存在食物,用于地图刷新*/
 58 int hasFoodnode(int i,int j)
 59 {
 60     if((food.hang == i)&&(food.lie == j))
 61     {
 62         return 1;               //当输入横纵坐标为食物的横纵坐标时,返回1
 63     }
 64     return 0;                   //当输入横纵坐标不是食物的横纵坐标时,返回0
 65 }
 66 
 67 /*地图绘制*/
 68 void gamePic()
 69 {
 70     int hang,lie;              //行列临时变量
 71     move(0,0);                 //每次界面刷新都将界面光标移动到(0,0)的位置
 72     for(hang=0;hang<20;hang++) //历遍行
 73     {
 74         if(hang==0)
 75         {
 76             for(lie=0;lie<20;lie++)
 77             {
 78                 printw("--");  //判断为第0行时,绘制‘--’边界符号
 79             }
 80             printw("\n");
 81         }
 82         if(hang>=0 || hang<=19)
 83         {
 84             for(lie=0;lie<=20;lie++)
 85             {
 86                 if(lie==0 || lie==20)
 87                 {
 88                     printw("|");//第0和19列绘制‘|’边界符号
 89                 }
 90                 else if(hasSnakeNode(hang,lie))
 91                 {
 92                     printw("[]");//行列值满足蛇的节点坐标时,绘制‘[]’符号                
 93                 }
 94                 else if(hasFoodnode(hang,lie))
 95                 {
 96                     printw("##");//行列之满足食物节点坐标时,绘制‘##’符号
 97                 }
 98                 else
 99                 {
100                     printw("  ");//地图上空闲位置绘制‘  ’空格符号
101                 }
102             }
103             printw("\n");        //每绘制完一行,该处添加一处换行符
104         }
105         if(hang==19)
106         {
107             for(lie=0;lie<20;lie++)
108             {
109                 printw("--");   //判断为第19行时,绘制‘--’边界符号
110             }
111             printw("\n");
112             printw("By chenguanxiong\n");
113             printw("%d",key);
114         }
115     }
116 }
117 
118 /*添加蛇身节点*/
119 void addNode()
120 {
121     struct Snake *new;         //新节点变量
122     new = (struct Snake *)malloc(sizeof(struct Snake));//为新节点开辟内存空间
123 
124     switch(dir)                //方向键判断
125     {
126         case UP:
127             new->hang = tail->hang - 1;  //向上,行减1,上移
128             new->lie = tail->lie;        //列保持
129             break;
130         case DOWN:
131             new->hang = tail->hang + 1;  //向下,行加1,下移
132             new->lie = tail->lie;        //列保持不变
133             break;
134         case LEFT:
135             new->hang = tail->hang;      //行保持不变
136             new->lie = tail->lie - 1;    //向左,列减1,左移
137             break;
138         case RIGHT:
139             new->hang = tail->hang;      //行保持不变
140             new->lie = tail->lie + 1;    //向右,列加1,右移
141             break;
142         default:
143             break;
144 
145     }
146 
147     new->next = NULL;           //新节点的下一个节点指向为NULL
148     tail->next = new;           //尾部的下一个节点指向新节点
149     tail = new;                 //新节点复制给尾部节点
150 }
151 
152 /*初始化蛇*/
153 void initSnake()
154 {
155     struct Snake *p;            //临时变量,指向蛇的链表头
156     dir = RIGHT;                //运动方向初始化为向右
157     while(head != NULL)         //当链表头不为空时进入,用于释放蛇当前的链表占用内存空间
158     {
159         p = head;               //p指向链表头      
160         head = head->next;      //链表头指向下一个节点
161         free(p);                //释放链表头内存
162     }    
163     
164     initFoodnode();             //初始化食物
165     head = (struct Snake *)malloc(sizeof(struct Snake)); //为链表头开辟新的内存空间
166     head->hang = 2;             //链表头行初始值为2
167     head->lie = 2;              //链表头列初始值为2
168     head->next = NULL;          //链表头的下一个节点指向为NULL
169     tail = head;                //链表尾指向链表头
170 
171     addNode();                  //为链表添加新节点
172     addNode();
173     addNode();
174     addNode();
175 }
176  
177 /*节点删除*/
178 void deleteNode()
179 {
180     struct Snake *p;            //创建临时节点
181     p = head;                    //节点指向链表头
182     head = head->next;          //链表头指向下一个节点
183     free(p);                    //释放p的空间(原链表头)
184 }
185 
186 /*判断蛇是否越界或自残*/
187 int ifSnakedie()
188 {
189     struct Snake *p;            //创建临时节点
190     p = head;                   //指向链表头
191 
192     if(tail->hang<0 | tail->lie==0 | tail->hang==20 | tail->lie==20)
193     {
194         return 1;               //当蛇链表的尾部坐标等于边界值时,返回1
195     }
196 
197     while(p->next != NULL)
198     {
199         if((p->hang==tail->hang)&&(p->lie==tail->lie))
200         {
201             return 1;           //当蛇链表其它的节点与尾部节点坐标相同,返回1
202         }
203         p = p->next;
204     }
205 
206     return 0;                   //无越界,无自残,返回0
207 }
208 
209 /*蛇移动*/
210 void moveSnake()
211 {
212     addNode();                  //添加新节点
213     if(hasFoodnode(tail->hang,tail->lie))
214     {
215         initFoodnode();         //当蛇链表尾节点坐标值和食物坐标值一样,刷新食物位置
216     }
217     else
218     {
219         deleteNode();           //否则,删除蛇链表中的头节点
220     }
221 
222     if(ifSnakedie())
223     {
224         initSnake();            //如果满足越界或者自残条件,重新初始化蛇链表
225     }
226 }
227 
228 /*地图界面刷新线程函数*/
229 void* refreshjiemian()
230 {
231     while(1)
232     {
233         moveSnake();           //蛇链表移动
234         gamePic();             //地图刷新
235         refresh();             //执行刷新
236         usleep(150000);           //线程休眠函数,150ms
237     }
238 }
239 
240 /*方向函数*/
241 void turn(int direction)
242 {
243     if(abs(dir) != abs(direction))
244     {
245         dir = direction;        //方向取绝对值比较,当左右运动时只有上下输入才生效
246     }
247 }
248 
249 /*键盘方向输入监测线程函数*/
250 void* changeDir()
251 {
252     while(1)
253     {
254         key = getch();          //获取键盘输入
255         switch(key)
256         {
257             case KEY_UP:
258                 turn(UP);       //
259                 break;
260             case KEY_DOWN:
261                 turn(DOWN);     //
262                 break;
263             case KEY_LEFT:
264                 turn(LEFT);     //
265                 break;
266             case KEY_RIGHT:
267                 turn(RIGHT);    //
268                 break;
269             default:
270                 break;        
271         }
272     }
273 } 
274 
275 int main()
276 {
277     pthread_t t1;               //创建线程变量t1
278     pthread_t t2;               //创建线程变量t2
279 
280     initscr();                  //Ncurses初始化
281     keypad(stdscr,1);           //在std中接受键盘的功能键
282     noecho();                   //控制键盘输入进来的字符
283 
284     initSnake();                //初始化蛇列表
285     gamePic();                  //地图初始化
286 
287     pthread_create(&t1,NULL,refreshjiemian,NULL);  //创建界面刷新线程
288     pthread_create(&t2,NULL,changeDir,NULL);       //创建键盘方向输入监测线程
289 
290     while(1);
291 
292     getch();
293     endwin();
294 
295     return 0;
296 }

 

posted @ 2023-06-28 15:55  熊来闯一闯  阅读(390)  评论(0编辑  收藏  举报