基于Linux下,通过c语言、链表、结构体下实现——贪吃蛇小项目

    • 一、需要用的头文件以及Linux图形库函数、数据初始化
      • (1)关于curses.h图形库函数
    • 二、地图制作
    • 三、蛇身链表的初始化生成
    • 四、关于贪吃蛇移动,身体操作
    • ==总结:==
      • **无论贪吃蛇朝着那个方向移动,都是头节点删除,尾巴节点添加,从而达到身体移动的目的**
    • 五、关于贪吃蛇的食物解析
    • 六、控制贪吃蛇移动的方向位置
      • **标注:**
        • 线程创建格式:
    • 七、主函数
    • 八、代码实现
  • 哪里不好,有待提高的地方还望大佬指出,共同进步!感谢你的留言!

一、需要用的头文件以及Linux图形库函数、数据初始化

#include<stdio.h>
#include<curses.h>
#include<stdlib.h>// 用于调整蛇移动方向,防止蛇移动不合理
#define UP    1
#define DOWN -1
#define LEFT -2
#define RIGHT 2
struct Snake{int hang; //行int lie;  //列struct Snake *next; //节点指针};
struct Snake *head = NULL;  //头节点
struct Snake *wei = NULL;      //尾巴节点
int direction;  // 方向
int key;    // 接受方向键的指令
struct Snake food;  //控制食物
int cnt =0;    //进食分数
(1)关于curses.h图形库函数

1.初始化界面

void initcurses()
{initscr();keypad(stdscr,1);noecho();
}
  • initscr() :curses程式必备先呼叫函数,作用是系统将根据终端机的形态并启动 curses模式
  • keypad(stdscr,1) :第一个参数stdscr为标准输出荧幕,第二个参数为1(TRUE)/ 0(False),使用keypad目的是为了使用方向键指令
  • noecho() : 防止界面产生乱码,图形界面破坏的情况

2.相关函数使用

  1. getch() :用于从键盘读取一个字元,原理和getchar相似
  2. endwin() :** 用于结束程式,关闭上述的curses模式
  3. move(x,y) : 用于在贪吃蛇吃完食物 / 死亡 需要将地图重新生成并且覆盖旧地图,而不是换行重新打印一张新地图
  4. refresh():用于刷新界面函数,并输出到屏幕

3.使用到curses中的宏建

  • KEY_UP 0403 ↑
  • KEY_DOWN 0402 ↓
  • KEY_LEFT 0404 ←
  • KEY_RIGHT 0405 →

二、地图制作

//该地图是20行20列地图
void Map()
{int hang;int lie;move(0,0);    //刷新地图,覆盖旧地图for(hang=0 ; hang<20 ; hang++){if(hang==0){for(lie=0 ;lie<20;lie++){printw("--");}printw("\n");}else if(hang>0 && hang <19){for(lie=0 ;lie<=20;lie++){if(lie ==0 || lie==20){printw("|");}else if(calcSnake(hang,lie)) //生成蛇的身体{printw("[]");}else if(Eatfood(hang,lie) ) //生成蛇的食物{printw("$$");}else{printw("  ");}}printw("\n");  }else{for(lie=0 ; lie<20 ; lie++){printw("--");}// 调试信息如下,可以设计添加其他printw("\n");printw("The Map is by LiuZheng sir make\n"); // 地图制作者printw("The food hang = %d,food lie = %d\n",food.hang,food.lie); //记录蛇食物坐标printw("Alway eat food score = %d\n",cnt); // 记录蛇吃了多少食物}}
}

三、蛇身链表的初始化生成

//用于在initsnake中指定方向生成贪吃蛇身体
int  calcSnake(int h,int l)
{struct Snake *p;p = head;while(p != NULL){if(p->hang ==h &&p->lie == l){return 1;}p = p->next;}return 0;}
//贪吃蛇身体初始化
void initsnake()
{struct Snake *p;direction = RIGHT;    //规定刚开始蛇朝着右方向移动if(head !=NULL)  //用于清除蛇死亡后残留的数据,清理内存{p = head;head = head->next;free(p);}createfood(); //生成食物head = (struct Snake*)malloc(sizeof(struct Snake));head->hang = 2;head->lie = 2;head->next = NULL;wei = head;//生成蛇的身子AddNode();AddNode();
}

四、关于贪吃蛇移动,身体操作

//贪吃蛇身子节点的添加
void AddNode()
{struct Snake *new;new = (struct Snake*)malloc(sizeof(struct Snake));switch(direction)//控制方向上移动{case DOWN:new->hang = wei->hang+1;new->lie  = wei->lie;break;case UP:new->hang = wei->hang-1;new->lie  = wei->lie;break;case LEFT:new->hang = wei->hang;new->lie  = wei->lie-1;break;case RIGHT:new->hang = wei->hang;new->lie  = wei->lie+1;break;}//让新的节点代替之前的尾巴,成为新的尾巴new->next = NULL;wei->next = new;wei = new;
}
//删除贪吃蛇身体节点
void DeleteNode()
{struct Snake *p =head;head = head->next;free(p);
}
//控制贪吃蛇移动的函数
void moveSnake()
{AddNode();if(Eatfood(wei->hang,wei->lie) == 1) //如果吃到食物,就重新生成新的食物{createfood();cnt++; //统计贪吃蛇进食分数情况}else{DeleteNode();}if(ifsnakedeath()) //检查移动中贪吃蛇是否撞墙或者自己吃自己,导致死亡{initsnake(); //死亡之后需要重新生成贪吃蛇cnt=0;}
}
//查看贪吃蛇是否撞墙死亡 / 自己吃自己
int ifsnakedeath()
{struct Snake *p =head;if(wei->hang == 0||wei->lie ==0||wei->hang ==19||wei->lie== 19) //检查撞墙{return 1;}while(p->next != NULL){if(p->hang == wei->hang && p->lie ==wei->lie) // 检查是否自杀{return 1;}p = p->next;}return 0;
}

总结:

无论贪吃蛇朝着那个方向移动,都是头节点删除,尾巴节点添加,从而达到身体移动的目的

五、关于贪吃蛇的食物解析

//用于确定在随机生成的食物坐标中,在地图上打印该食物
int Eatfood(int h,int l)
{if(food.hang == h && food.lie ==l){return 1;}return 0;
}
void createfood()
{int x = rand()%20; //使用rand()函数随机生成一个坐标值int y = rand()%20; //使用rand()函数随机生成一个坐标值if(x==0 || x==19 || y==0 || y==19) //防止食物生成到地图边缘或者离开地图{x = rand()%20;y = rand()%20;}food.hang = x;food.lie  = y;
}

六、控制贪吃蛇移动的方向位置

标注:

由于需要地图的刷新,贪吃蛇方向的移动和改变、食物的生成,系统一个线程是忙不过来的,因此我们需要引进线程的概念,创建多个线程来分布执行这些命令操作

线程创建格式:

//创建线程 t1、t2pthread_t t1;pthread_t t2;pthread_create(&t1,NULL,refreshSnake,NULL);     //t1进程实现贪吃蛇移动pthread_create(&t2,NULL,Changedirection,NULL);    //t2进程实现贪吃蛇改变方向位置
//用该进程进行贪吃蛇移动
void refreshSnake()
{while(1){moveSnake();Map();refresh(); //刷新界面usleep(40000); //控制贪吃蛇移动速度,这里是微秒单位}
}
//防止贪吃蛇位置移动不合理
void Turndirection(int dir)
{if(abs(direction) != abs(dir)){direction = dir;}
}
void Changedirection()
{while(1){key = getch();//获取方向键控制贪吃蛇移动指令switch(key) //发送贪吃蛇方向移动指令{case KEY_DOWN: //向上Turndirection(DOWN);break;case KEY_UP: //向下Turndirection(UP);break;case KEY_LEFT: //向左Turndirection(LEFT);break;case KEY_RIGHT: //向右Turndirection(RIGHT);break;}}
}

七、主函数

int main()
{pthread_t t1;  //建立线程t1pthread_t t2;   //建立线程t2initcurses();initsnake();Map();pthread_create(&t1,NULL,refreshSnake,NULL);pthread_create(&t2,NULL,Changedirection,NULL);while(1);        //防止该进程不退出getch();endwin();return 0;
}

八、代码实现

#include<stdio.h>
#include<curses.h>
#include<stdlib.h>#define UP    1
#define DOWN -1
#define LEFT -2
#define RIGHT 2void initcurses()
{initscr();keypad(stdscr,1);noecho();}struct Snake{int hang;int lie;struct Snake *next;};struct Snake *head = NULL;
struct Snake *wei = NULL;
int direction;
int key;
struct Snake food;
int cnt =0;int  calcSnake(int h,int l)
{struct Snake *p;p = head;while(p != NULL){if(p->hang ==h &&p->lie == l){return 1;}p = p->next;}return 0;}int Eatfood(int h,int l)
{if(food.hang == h && food.lie ==l){return 1;}return 0;
}void createfood()
{int x = rand()%20;int y = rand()%20;if(x==0 || x==19 || y==0 || y==19){x = rand()%20;y = rand()%20;}food.hang = x;food.lie  = y;
}void Map()
{int hang;int lie;move(0,0);for(hang=0 ; hang<20 ; hang++){if(hang==0){for(lie=0 ;lie<20;lie++){printw("--");}printw("\n");}else if(hang>0 && hang <19){for(lie=0 ;lie<=20;lie++){if(lie ==0 || lie==20){printw("|");}else if(calcSnake(hang,lie)){printw("[]");}else if(Eatfood(hang,lie) ){printw("$$");}else{printw("  ");}}printw("\n");   }else{for(lie=0 ; lie<20 ; lie++){printw("--");}printw("\n");printw("The Map is by LiuZheng sir make\n");printw("The food hang = %d,food lie = %d\n",food.hang,food.lie);printw("Alway eat food score = %d\n",cnt);}}
}void AddNode()
{struct Snake *new;new = (struct Snake*)malloc(sizeof(struct Snake));switch(direction){case DOWN:new->hang = wei->hang+1;new->lie  = wei->lie;break;case UP:new->hang = wei->hang-1;new->lie  = wei->lie;break;case LEFT:new->hang = wei->hang;new->lie  = wei->lie-1;break;case RIGHT:new->hang = wei->hang;new->lie  = wei->lie+1;break;}new->next = NULL;wei->next = new;wei = new;
}void DeleteNode()
{struct Snake *p =head;head = head->next;free(p);
}void initsnake()
{struct Snake *p;direction = RIGHT;    if(head !=NULL){p = head;head = head->next;free(p);}createfood();head = (struct Snake*)malloc(sizeof(struct Snake));head->hang = 2;head->lie = 2;head->next = NULL;wei = head;AddNode();AddNode();
}void moveSnake()
{AddNode();if(Eatfood(wei->hang,wei->lie) == 1){createfood();cnt++;   }else{DeleteNode();}if(ifsnakedeath()){initsnake();cnt=0;}
}int ifsnakedeath()
{struct Snake *p =head;if(wei->hang == 0||wei->lie ==0||wei->hang ==19||wei->lie== 19){return 1;}while(p->next != NULL){if(p->hang == wei->hang && p->lie ==wei->lie){return 1;}p = p->next;}return 0;
}void refreshSnake()
{while(1){moveSnake();Map();refresh();usleep(40000);}
}
void Turndirection(int dir)
{if(abs(direction) != abs(dir)){direction = dir;}
}
void Changedirection()
{while(1){key = getch();switch(key){case KEY_DOWN:Turndirection(DOWN);break;case KEY_UP:Turndirection(UP);break;case KEY_LEFT:Turndirection(LEFT);break;case KEY_RIGHT:Turndirection(RIGHT);break;}}
}
int main()
{pthread_t t1;pthread_t t2;initcurses();initsnake();Map();pthread_create(&t1,NULL,refreshSnake,NULL);pthread_create(&t2,NULL,Changedirection,NULL);while(1);        getch();endwin();return 0;
}

哪里不好,有待提高的地方还望大佬指出,共同进步!感谢你的留言!

Linux学习篇——基于C语言使用结构体、链表实现贪吃蛇相关推荐

  1. [光速QA][linux学习篇]基于韦东山I.MX6ULL pro开发板的学习笔记

    #前言: CSDN上已经有了太多的教程,我决定使用一种很新的方式记录自己的学习过程,如果对你有帮助就点个赞吧!一篇博文但是会长期更新(争取). 光速QA,希望面试官和面试者都可以给我这里找到灵感,如果 ...

  2. 一起学习C语言:结构体(二)

    上一篇<一起学习C语言:结构体(一)> 中,我们了解了结构体的概念与定义形式,以及结构体变量初始化赋值.本章节,我们分析结构体成员访问形式,以及结构数组使用的场景. 章节预览: 4. 结构 ...

  3. go var type 互转_Go语言学习笔记(第九章) 结构体

    Go语言基础之结构体 Go语言中没有"类"的概念,也不支持"类"的继承等面向对象的概念.Go 通过类型别名(alias types)和结构体的形式支持用户自定义 ...

  4. c语言指针变量输出不了共用体,瘋子C语言札记(结构体/共用体/枚举篇)

    瘋子C语言笔记(结构体/共用体/枚举篇) (一)结构体类型 1.简介: 例: struct date { int month; int day; int year; }; struct student ...

  5. c语言结构体成员变量私有化,C语言中结构体变量私有化详解

    C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...

  6. 基于C语言Ncurse库和链表的简单贪吃蛇小游戏

    参考:基于C语言Ncurse库和链表的简单贪吃蛇小游戏 作者:三速何时sub20 发布时间:2020-09-29 10:23:51 网址:https://blog.csdn.net/weixin_44 ...

  7. C语言之结构体和共用体

    C语言之结构体和共用体 算上这篇笔记加上之前的四篇笔记,C语言基础我们也就告一段落了,对于刚刚接触c语言的童鞋们来说,这些以及足够了,稍后我会发布数据结构,对于想要深入学习的童鞋可以继续关注.本人也算 ...

  8. 【Golang第8章:面向对象编程】Go语言的结构体是什么,怎么声明;Golang方法的调用和声明;go语言面向对象实例,go语言工厂模式;golang面向对象的三大特性:继承、封装、多态

    介绍 这个是在B站上看边看视频边做的笔记,这一章是Glang面向对象编程 这一章内容较多,内容有Go语言的结构体是什么,怎么声明:Golang方法的调用和声明:go语言面向对象实例,go语言工厂模式: ...

  9. Go语言中结构体打Tag是什么意思?

    前言 哈喽,大家好,我是asong.今天想与大家分享Go语言中结构体标签是怎么使用的,以及怎样定制自己的结构体标签解析. 大多数初学者在看公司的项目代码时,看到的一些结构体定义会是这样的: type ...

最新文章

  1. Laravel7中Redis队列的使用
  2. RabbitMQ中RPC的实现及其通信机制
  3. Monte Carlo概率模型进行分子动力学模拟并计算苯甲醚键值
  4. python自动复制输出_python 深浅拷贝集合
  5. 在字符串中附加格式化的字符串
  6. 图像梯度增强_使用梯度增强机在R中进行分类
  7. redis分片_Redis分片
  8. 等待正确的时刻–集成测试
  9. 关于在nw里使用require('printer')和nw.require('printer')报错的问题
  10. sqlrowset 转化为json_Python 操作 JSON 的 9 个示例
  11. javascript 保存原函数_前端工程师必须掌握的几个JavaScript设计模式及场景应用
  12. LinkedHashMap入门
  13. 工作总结-虚拟机参数
  14. VS2013注册串口active控件mscomm32.ocx
  15. [4G5G专题-34]:物理层-浅谈m序列的原理以及在NR PSS中的应用
  16. 每日作业-品优购详情页
  17. 【斯科德C200立式访客机】
  18. 01背包问题解法及优化
  19. Reactor3 Mono
  20. java游戏魔界村_魔界村(附秘籍)游戏下载-魔界村游戏最新版v2.0-爱单机

热门文章

  1. 南方科技大学计算机学科评估,全国第四轮学科评估结果公布 我校7个学科进入B类...
  2. 软件测试 | 测试开发 | RPC接口测试技术-Tcp 协议的接口测试
  3. EOS系列 - EOSIO WEB IDE
  4. 单目三维运动重建(sfm算法)
  5. python openpyxl 设置表格列宽的自动适应_Python的openpyxl列宽调整大小
  6. 跳伞求生服务器未响应,绝地求生跳伞就未响应 | 手游网游页游攻略大全
  7. 全球与中国银铟合金市场运营形势及投资方向分析报告2022~2027年
  8. 真的,Kafka 入门一篇文章就够了
  9. 公众号如何跳转到页面php,图文详解微信公众号开发自定义菜单跳转页面并获取用户信息实例...
  10. 研究生小论文怎么发?