基于Linux的Ncurse库的贪吃蛇项目

贪吃蛇项目的意义

  • 承上启下:从C语言基础的学习:数据结构链表基础、C变量、流程控制、函数、指针、结构体等。过渡到Linux系统编程:文件编程、进程、线程、通信、第三方等。

Linux终端图形库curses

curses的名字起源于"cursor optimization",即光标优化。它最早由美国伯克利大学的Bill Joy和Ken Arnold编写的,用来处理一个游戏rogue的屏幕显示。后来贝尔实验室的Mark Horton在system III Unix中重新编写了curses。

现在几乎所有的Unix,Linux操作系统都带了curses函数库,curses也加入了对鼠标的支持,一些菜单和面板的处理。可以说,curses是Linux终端图形编程的不二选择。

#include <curses.h>int main()
{initscr();//ncurse界面的初始化函数printw("this is a curses window\n");//ncurse模式下的printfgetch();//等待用户输入,如果没有这句话,程序就退出了,看不到运行结果endwin();//程序退出,调用该函数来恢复shell终端的显示,如果没有这句话,shell终端字乱码,坏掉return 0;
}
  1. 绘制地图

    void init_map(struct snake_node s)
    {int hang;int lie;for(hang=0;hang<20;hang++){if(hang == 0 ){for(lie=0;lie<20;lie++){printw("--");}printw("\n");}for(lie=0;lie<20;lie++){if(lie == 0 || lie == 19){printw("|");}else{printw("  ");}}if(hang == 19 ){printw("\n");for(lie=0;lie<20;lie++){printw("--");}}}printw("This is Snaker");
    }                     
    

    效果:

    在这里插入图片描述

  2. 初始化贪吃蛇身体

    void add_node()//增加一个节点
    {struct snake_node *new = (struct snake_node *)malloc(sizeof(struct snake_node));new->hang = tail->hang;new->lie = tail->lie + 1;new->next = NULL;tail->next = new;tail = new;
    }
    void init_sanke()//初始化身体
    {head = (struct snake_node*)malloc(sizeof(struct snake_node));head->hang = 5;head->lie = 5;//初始化头部的位置head->next = NULL;tail = head;add_node();add_node();//初始化身体,想长一点就加一个节点
    }
    
  3. 贪吃蛇向右移动

    void delet_node()//删除一个节点
    {struct snake_node * p;p = head;head = head->next;free(p);//注意:删除节点需要free掉,所以创建一个p来承接原head的空间,避免内存泄漏
    }
    void move_snake()//删掉头,加一个尾
    {add_node();delet_node();
    }
    //主函数中判断按键
    while(1){dir = getch();switch(dir){case KEY_RIGHT://如果是右方向键move_snake();break;}init_map();//刷新地图,注意用:move(int x,int y)函数重置光标的位置}
  4. 贪吃蛇撞墙死掉

    void move_snake()
    {add_node();delet_node();
    //加入判断条件,判断tail的行和列,和墙体重合就死掉,重新生成if(tail->hang == 0 || tail->lie == 0 || tail->hang == 21 || tail->lie == 21){init_snake();}
    }
    void init_snake()
    {
    //加入判断条件,如果不是第一次创建蛇,把之前的蛇free掉,防止内存溢出struct snake_node *p;while(head != NULL){p = head;head = head->next;free(p);}head = (struct snake_node*)malloc(sizeof(struct snake_node));head->hang = 20;head->lie = 1;head->next = NULL;tail = head;add_node();add_node();
    }
  5. 双线程实现刷新界面和响应按键

    int main()
    {init_ncurse();init_snake();init_map();while(1){move_snake();init_map();refresh();usleep(200000);}while(1){key = getch();switch(key){case KEY_DOWN:printw("DOWN\n");break;case KEY_UP:printw("UP\n");break;case KEY_LEFT:printw("LEFT\n");break;case KEY_RIGHT:}}endwin();return 0;
    }
    

    上面main函数中存在两个while(1),常规方法无法实现该函数的功能,因此引入线程。

        #include <pthread.h>  // 头文件pthread_t:当前Linux中可理解为:typedef  unsigned long int  pthread_t;如:pthread_t t1;  //多线程定义pthread_create(&t1,NULL,fun,NULL);参数1:传出参数,保存系统为我们分配好的线程ID参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。参数4:线程主函数执行期间所使用的参数,如要传多个参数, 可以用结构封装。使用多线程的函数必须返回指针型,如void *fun()注:gcc xxx.c -lcurses -lpthread  //编译需要连接pthread库
  6. 线程demo

    #include <stdio.h>
    #include <pthread.h>void * fun1()
    {while(1){printf("this is fun1\n");usleep(300000);}
    }
    void * fun2()
    {while(1){printf("this is fun2\n");usleep(300000);}
    }
    int main()
    {pthread_t t1;//定义线程pthread_t t2;pthread_create(&t1,NULL,fun1,NULL);//创建线程pthread_create(&t2,NULL,fun2,NULL);while(1);return 0;
    }
    

    效果:

    在这里插入图片描述

  7. 双线程实现刷新屏幕和按键改变方向

    void* refresh_screen()//刷新屏幕的线程
    {while(1){move_snake();init_map();refresh();usleep(200000);}}
    void* change_dir()//响应按键改变方向的线程
    {while(1){dir = getch();switch(dir){case KEY_DOWN:printw("DOWN\n");break;case KEY_UP:printw("UP\n");break;case KEY_LEFT:printw("LEFT\n");break;case KEY_RIGHT:printw("RIGHT\n");break;}}
    }
    int main()
    {init_ncurse();init_snake();init_map();pthread_t t1;//定义两个线程pthread_t t2;pthread_create(&t1,NULL,refresh_screen,NULL);//启动这两个线程pthread_create(&t2,NULL,change_dir,NULL);while(1);//保证程序不退出endwin();return 0;
    }
    
  8. 贪吃蛇上下左右的移动

    void add_node()//实现贪吃蛇的上下左右移动
    {struct snake_node *new = (struct snake_node *)malloc(sizeof(struct snake_node));new->hang = tail->hang;switch(dir){case UP:new->hang = tail->hang - 1;new->lie = tail->lie;new->next = NULL;break;case DOWN:new->hang = tail->hang + 1;new->lie = tail->lie;new->next = NULL;break;case LEFT:new->hang = tail->hang;new->lie = tail->lie - 1;new->next = NULL;break;case RIGHT:new->hang = tail->hang ;new->lie = tail->lie + 1;new->next = NULL;break;}tail->next = new;tail = new;
    }
    void turn(int direction)//用绝对值来避免从上直接到下和从左直接到右的方向不合理转换
    {if(abs(dir) != abs(direction)){dir = direction;}
    }
    
  9. 实物的生成和吃食物变长

    void init_food()//随机生成食物
    {//1---20int x = rand()%20 + 1;int y = rand()%20 + 1;food.hang = x;food.lie = y;
    }
    void move_snake()
    {add_node();if(tail->hang == food.hang && tail->lie == food.lie){init_food();//如果吃掉食物,长度+1,同时刷新食物位置}else{delet_node();}if(tail->hang == 0 || tail->lie == 0 || tail->hang == 21 || tail->lie == 21){init_snake();}
    }
    
  10. 贪吃蛇死亡

    int snake_die()//贪吃蛇死亡的两种方式
    {struct snake_node *p;p = head;//撞墙死亡if(tail->hang == 0 || tail->lie == 0 || tail->hang == 21 || tail->lie == 21){return 1;}//自杀,撞到身体while(p->next != NULL){if(p->hang == tail->hang && p->lie == tail->lie){return 1;}p = p->next;}return 0;
    }
    void move_snake()
    {add_node();if(tail->hang == food.hang && tail->lie == food.lie){init_food();}else{delet_node();}if(snake_die()){//判断是否满足死亡条件init_snake();}
    }
    
  11. 最终效果

    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/3356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle Analytics BIEE 操作方法(五)仪表盘导出“区域”不换行也不合并居中的方法

1 分析 取消所有区域内列格式里面的换行 2 仪表盘 点击“工具” 打印和导出选项 设置固定列宽&#xff08;范围是&#xff1a;0-300&#xff09;

Day22 SSH远程管理服务

sshd服务&#xff0c;系统自带&#xff0c;默认开机自启运行 云/物理服务器的安全组和防火墙默认放行该端口 软件包&#xff1a;openssh-server&#xff08;服务端&#xff09;&#xff1b;openssh-client&#xff08;客户端&#xff09;&#xff1b; 格式&#xff1a;ssh I…

【学习笔记二十七】EWM存储类型控制

一、EWM存储类型控制概述 Storage control 是用来决定仓库产品移动时所需要的流程步骤。它的目的是用来处理基于仓库物理布局及仓库流程所要求的复杂的上架和下架流程步骤。 仓库里常见的操作步骤有:Picking、Packing、Staging、Loading、Putaway、Unloading、Counting、Quali…

Jetbrains Fleet这十个快捷键,效率提高50倍

当我们无法解决一段感情中的问题 就会选择解决这段感情 如果真诚不得到回应 那么再热情的人 也会沉默 很多人对你感兴趣 却没有人执着于你 我们知道任何一款牛批的IDE 都是有很多快捷键的&#xff0c;但是我们没有superpower &#xff0c;不能记住所有的快捷键。 所以下面…

成功密码期刊投稿简介

《成功密码》综合版是由国家新闻出版总署批准&#xff0c;江西省教育厅主管的正规期刊&#xff0c;"以培养担当民族复兴大任的时代新人为着眼点&#xff0c;强化教育引导、实践养成、制度保障"&#xff0c;倡导教育研究的学术水准&#xff0c;注重理论与实践的有机结…

Delphi 的Show和ShowModal

Show没有返回值是一个过程&#xff0c;焦点可以不在当前窗体&#xff1b; 用法新建一个子窗体&#xff1a; 主窗体&#xff1a; 调用&#xff0c;引用子窗体的单元 调用 showmodal是一个函数有返回值&#xff0c;窗体的处理结果&#xff0c;且只能聚焦到当前窗体 效果都能展示…

尺取法知识点讲解

一、固定长度的情况&#xff1a; 最小和(sum) 输入N个数的数列&#xff0c;所有相邻的M个数的和共有N-M1个&#xff0c;求其中的最小值。 输入格式 第1行&#xff0c;2个整数N&#xff0c;M&#xff0c;范围在[3…100000]&#xff0c;N>M。 第2行&#xff0c;有N个正…

C++多线程系列——std::future | std::promise

获得线程执行任务的结果 在 C 11 之前&#xff0c;想要从线程返回执行任务的结果&#xff0c;可以通过指针来完成。 void fun(int x, int y, int* ans, std::condition_variable &cv) {// 模拟求值之前的准备工作this_thread::sleep_for(3s);*ans x y;cv.notify_one();…

一文掌握Vue3:深度解读Vue3新特性、Vue2与Vue3核心差异以及Vue2到Vue3转型迭代迁移重点梳理与实战

每次技术革新均推动着应用性能与开发体验的提升。Vue3 的迭代进步体现在性能优化、API重构与增强型TypeScript支持等方面&#xff0c;从而实现更高效开发、更优运行表现&#xff0c;促使升级成为保持竞争力与跟进现代前端趋势的必然选择。本文深度解读Vue3 响应式数据data、生命…

蓝桥杯python考级整理

4_1:算术运算符 4_2:基本语法 4_3:基本语法 4_4:列表 4_5:函数 4_6:字符串 4_7:列表 4_8:逻辑运算符 4_9:字典 4_10:函数

MacOS通过命令行开启关闭向日葵远程控制的后台服务

categories: [Tips] tags: MacOS Tips 写在前面 经常有小伙伴问我电脑相关的问题, 而解决问题的一个重要途径就是远程了. 关于免费的远程工具我试过向日葵和 todesk, 并且主要使用向日葵, 虽然 MacOS 下要设置很多权限, 但是也不影响其丝滑的控制. 虽然用着舒服, 但是向日葵…

mysql的约束和表关系

根据查询的结果&#xff0c;复制出一个新表 create table newTable AS select * from oldTable; create table newPeople AS select * from day2_test.people; 约束 引入&#xff1a;如果某一列如id列&#xff0c;有重复的数据&#xff0c;无法准确定位&#xff0c;有的列有空…

人脸清晰修复神器CodeFormer

随着AI技术在图像处理领域大展身手&#xff0c;AI去马赛克相关的项目也屡见不鲜&#xff0c;比如在Github上开源免费、备受欢迎的 CodeFormer 。不得不说利用这款神奇的人脸修复工具&#xff0c;真的是让我大开眼界&#xff0c;竟然可以这样搞&#xff01; 不管面对的是多么模…

大模型+多模态实现

那么如何在预训练LLM的基础上引入跨模态的信息&#xff08;包括图像、语音、视频模态&#xff09;&#xff0c;让其变得更强大、更通用呢&#xff1f;本节将介绍“大模型多模态”的3种实现方法。 以LLM为核心&#xff0c;调用其他多模态组件 微软亚洲研究院&#xff08;MSRA&…

Java基础(运算符)

运算符 运算符和表达式 运算符&#xff1a;对字面量或者变量进行操作的符号 表达式&#xff1a;用运算符把字面量或者变量连接起来&#xff0c;符合java语法的式子就可以称为表达式&#xff1b;不同运算符连接的表达式体现的是不同类型的表达式。 算术运算符&#xff08;加…

Linux基础命令[24]-su

文章目录 1. su 命令说明2. su 命令语法3. su 命令示例3.1 不加参数3.2 -&#xff08;登录&#xff09;3.3 -c&#xff08;执行命令&#xff09; 4. 总结 1. su 命令说明 su&#xff1a;以用户身份执行命令&#xff0c;基本信息如下&#xff1a; Usage:su [options] [-] [USE…

数据结构四:线性表之带头结点的单向循环循环链表的设计

前面两篇介绍了线性表的顺序和链式存储结构&#xff0c;其中链式存储结构为单向链表&#xff08;即一个方向的有限长度、不循环的链表&#xff09;&#xff0c;对于单链表&#xff0c;由于每个节点只存储了向后的结点的地址&#xff0c;到了尾巴结点就停止了向后链的操作。也就…

架构师系列-消息中间件(九)- RocketMQ 进阶(三)-消费端消息保障

5.2 消费端保障 5.2.1 注意幂等性 应用程序在使用RocketMQ进行消息消费时必须支持幂等消费&#xff0c;即同一个消息被消费多次和消费一次的结果一样&#xff0c;这一点在使用RoketMQ或者分析RocketMQ源代码之前再怎么强调也不为过。 “至少一次送达”的消息交付策略&#xff…

Hive主要介绍

Hive介绍 hive是基于 Hadoop平台操作 HDFS 文件的插件工具 可以将结构化的数据文件映射为一张数据库表 可以将 HQL 语句转换为 MapReduce 程序 1.hive 是由驱动器组成&#xff0c;驱动器主要由4个组件组成&#xff08;解析器、编译器、优化器、执行器&#xff09; 2.hive本身不…

【安卓13-Framework】SystemUI定制之屏蔽下拉状态栏部分快捷按钮

1、需求 屏蔽下拉状态栏谷歌录屏、省电模式、二维码扫描器等快捷按钮。 2、修改路径 普及&#xff1a;安卓的SystemUI包提供了状态栏、导航栏、通知中心等重要的用户界面元素。 状态栏小部件UI显示修改路径&#xff1a;frameworks/base/packages/SystemUI/src/com/android/s…