C语言——贪吃蛇小游戏
目录
一、ncurse
1.1 为什么需要用ncurse:
1.2 ncurse的输入输出:
1.2.1 如何使用ncurse:
1.2.2 编译ncurse的程序:
1.2.3 测试输入一个按键ncurse的响应速度:
1.3 ncurse上下左右键获取:
1.3.1 如何查看宏定义的.h文件:
1.3.2 ncurse上下左右键获取:
二、地图规划
2.1 地图规划算法显示第一行:
2.2 实现贪吃蛇完整地图:
2.3 优化贪吃蛇地图:
三、显示贪吃蛇身子
3.1 显示贪吃蛇身子的一个节点:
3.2 显示贪吃蛇完整身子:
3.3 显示贪吃蛇完整身子改进:
四、贪吃蛇移动
4.1 按下▶贪吃蛇向右移动:
4.2 贪吃蛇撞墙重新开始:
4.3 贪吃蛇脱缰自由向右行走
五、Linux线程引入
5.1 贪吃蛇方向移动和刷新界面一起实现面临的问题:
5.2 线程的基本用法:
5.3 线程demo案例:
5.4 使用线程解决贪吃蛇方向移动和刷新界面一起实现面临的问题:
六、贪吃蛇跑起来
6.1 实现贪吃蛇四方向的风骚走位:
6.2 用绝对值方式来解决不合理的走位:
6.3 贪吃蛇吃饭了(食物的位置是随机的):
七、项目代码
-
项目运行环境:Linux,基于Ncurse图形库的C语言小游戏
-
项目的目的和意义:起到承上启下的作用,对于前面学的C语言的基础和数据结构链表做一个比较好的巩固,对于后面的Linux系统编程的开发做铺垫
-
项目基础要求:C语言基础、Linux基本操作
/*项目步骤*/ (1)选择ncurses库的原因 在进行贪吃蛇游戏时,贪吃蛇的行进方向需要你按下上下左右键进行操控,如果使用C语言自带的函数,例如:scanf或者getchar之类的,需要你按下回车键,程序才能进行响应,而这显然是十分不方便的,但是ncurses库就很好的解决了这个问题。ncurses库自带的函数getch就能实现迅速便捷的贪吃蛇方向响应。(2)ncurses库的基本入门 对于该项目而言,ncurses库我们不需要进行过于深入的学习,只需要知道一些基本的函数使用即可。下列程序中的函数,就是一个基于ncurses库的基本代码框架。 #include <curses.h>int main() {initscr();//ncurse界面的初始化函数printw("this is a curses window\n");//在ncurse模式下的printfgetch();//等待用户的输入,如果没有这句话,程序就退出了,看不到运行的结果,也就是无法看到上面那句话endwin();//程序退出,恢复shell终端的显示,如果没有这句话,shell终端字乱码,坏掉return 0; }(3)贪吃蛇地图的整体规划 整个贪吃蛇地图的大小将它设置成一个20*20的近似正方形,使用"|"来表示左右边框,使用"--"来表示上下边框。(4)实现贪吃蛇第一个节点的显示(5)显示贪吃蛇的完整身子 注意,在这里,我们设置两个全局变量,struct Snake *head和struct Snake *tail,一个指向贪吃蛇的头,一个指向贪吃蛇的尾。在将第一个节点打印完后,将尾指向头,即:head = tail。每一次节点的添加,我们调用一个单独的函数去执行,并其使用尾插法实现。(6)实现贪吃蛇的右移 贪吃蛇的移动,整体来说就是链表节点的删除与添加。我们首先实现贪吃蛇的右移,每当按键按下时,贪吃蛇右移一格,即左侧的头结点删除head = head->next,右侧再次添加一个新的节点。新节点的坐标应该是行不变,列加一。注意:不要忘记清楚垃圾节点。(7)实现贪吃蛇的撞墙死亡 将贪吃蛇的尾节点坐标进行判断,判断其是否达到边界坐标。满足条件时,将贪吃蛇重新初始化。注意:不要忘记清楚垃圾节点。(8)实现贪吃蛇的自由行走 在这里,我们发现了一个问题,地图需要实时刷新进行贪吃蛇位置的变更,这是一个while(1)的死循环,而获取键值也是一个实时读取的操作,因此也是一个while(1)死循环,代码执行逻辑上出现了问题,所以我们引入了线程的概念。(9)了解什么是线程(10)用线程解决上述问题,实现贪吃蛇的分骚走位 开辟两个线程,一个用来执行地图刷新操作,一个用来获取键值。pthread_create(&t1,NULL,refreshScreen,NULL);pthread_create(&t2,NULL,changeDir,NULL);(11)解决贪吃蛇的不合理走位 在这里,我们使用绝对值法来解决问题,abs函数的作用便是取绝对值,我们将上下左右键,两两对应,宏定义为1,-1,2,-2之类的数就能成功解决问题。(12)实现贪吃蛇食物的打印(13)实现食物的随机出现 取随机数,C语言有一个自带的函数可以解决这个问题,rand()函数可以实现随机取数,我们只要再对它进行取余操作,便可以防止食物出现在地图以外的位置。(14)实现贪吃蛇咬到自己结束游戏,重新开始的操作 当贪吃蛇的尾节点与自身除尾巴节点以外的其他节点进行比较后,若行列数相同,则初始化整个贪吃蛇,注意:不要忘记垃圾节点的清除(我们可以在每次贪吃蛇初始化之前进行这个操作)。
一、ncurse
1.1 为什么需要用ncurse:
-
因为的按键响应牛逼哄哄
-
1.2 ncurse的输入输出:
-
ncurse用的最多的地方是在Linux内核编译之前的内核配置
-
1.2.1 如何使用ncurse:
1.2.2 编译ncurse的程序:
1.2.3 测试输入一个按键ncurse的响应速度:
1 #include <curses.h>2 3 int main()4 {5 char c;6 7 initscr();8 c = getch();9 printw("you Input :%c\n",c);10 getch();11 endwin();12 return 0;13 }
-
使用ncurse的好处是:按下一个按键不需要按下回车,直接就可以输出c的值,和我们C语言的其他输入函数好用
1.3 ncurse上下左右键获取:
1.3.1 如何查看宏定义的.h文件:
vi /usr/include/curses.h //查看宏定义.h文件的指令
:q //退出查看
1.3.2 ncurse上下左右键获取:
1 #include <curses.h>2 3 int main()4 {5 int key;6 7 initscr();8 keypad(stdscr,1); //这个函数允许使用功能键,例如:F1、F2、方向键等功能键。几乎所有的交互式程序都需要使用功能 键,因为绝大多数用户界面主要用方向键进行操作。使用keypad(stdscr,TURE)就为“标准屏幕”(stdscr)激活了功能键。9 10 while(1){11 key = getch();12 switch(key){13 case KEY_DOWN:14 printw("DOWN\n");15 break;16 case KEY_UP:17 printw("up\n");18 break;19 case KEY_LEFT:20 printw("LEFT\n");21 break;22 case KEY_RIGHT:23 printw("RIGHT\n");24 break;25 }26 27 28 }29 endwin();30 return 0;31 }
-
我们按下上下左右▲▼◀▶之后,可以获取到上下左右的打印信息
二、地图规划
2.1 地图规划算法显示第一行:
#include <curses.h>void initNcurse()
{initscr();keypad(stdscr,1);
}void gamPic()
{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 == 20){printw("|");}else{printw(" ");}}}}
}int main()
{initNcurse(); //初始化NcursegamPic(); //地图规划显示第一行getch();endwin();return 0;
}
2.2 实现贪吃蛇完整地图:
#include <curses.h>void initNcurse()
{initscr();keypad(stdscr,1);
}void gamPic()
{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 == 20){printw("|");}else{printw(" ");}}printw("\n");}if(hang>0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}int main()
{initNcurse(); //初始化NcursegamPic(); //实现贪吃蛇地图getch();endwin();return 0;
}
2.3 优化贪吃蛇地图:
#include <curses.h>void initNcurse()
{initscr();keypad(stdscr,1);
}void gamPic()
{int hang;int lie;for(hang=0; hang<20; hang++){if(hang == 0){ //第0行打“--”for(lie=0; lie<20; lie++){printw("--");}printw("\n");}if(hang>=0 && hang<=19) { //第0行-19行的第0列和第20列打“|”for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else{printw(" ");}}printw("\n");}if(hang == 19){ //第19行打“--”for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n"); //作者}}
}int main()
{initNcurse();gamPic();getch();endwin();return 0;
}
//实现的贪吃蛇地图和上面一样,只不过是优化了一下代码
三、显示贪吃蛇身子
3.1 显示贪吃蛇身子的一个节点:
#include <curses.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake node1 = {2,2,NULL};void initNcurse()
{initscr();keypad(stdscr,1);
}void gamPic()
{int hang;int lie;for(hang=0; hang<20; hang++){if(hang == 0){for(lie=0; lie<20; lie++){printw("--");}printw("\n");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(node1.hang == hang && node1.lie == lie){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}int main()
{initNcurse();gamPic();getch();endwin();return 0;
}
3.2 显示贪吃蛇完整身子:
#include <curses.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake node1 = {2,2,NULL};
struct Snake node2 = {2,3,NULL};
struct Snake node3 = {2,4,NULL};
struct Snake node4 = {2,5,NULL};void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = &node1;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{int hang;int lie;for(hang=0; hang<20; hang++){if(hang == 0){for(lie=0; lie<20; lie++){printw("--");}printw("\n");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}int main()
{initNcurse();node1.next = &node2;node2.next = &node3;node3.next = &node4;gamPic();getch();endwin();return 0;
}
3.3 显示贪吃蛇完整身子改进:
#include <curses.h>
#include <stdlib.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL; //指向链表头
struct Snake *tail = NULL; //指向链表尾void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic() //地图规划
{int hang;int lie;for(hang=0; hang<20; hang++){if(hang == 0){for(lie=0; lie<20; lie++){printw("--");}printw("\n");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake)); //创建新节点if(new == NULL){printw("malloc error\n");}new->hang = tail->hang; //新节点的行等于链表尾的行new->lie = tail->lie+1; //新节点的行等于链表尾的列+1new->next = NULL;tail->next = new; //从链表尾部插入新节点tail = new; //新节点当作尾部
}void initSnake()
{head = (struct Snake *)malloc(sizeof(struct Snake)); //创建链表头if(head == NULL){printw("malloc error\n");}head->hang = 2; head->lie = 2;head->next = NULL;tail = head; //第一个节点链表头和链表尾是一样的addNode(); //调用一次代表增加一个节点addNode();addNode();
}int main()
{initNcurse();initSnake();gamPic();getch();endwin();return 0;
}
四、贪吃蛇移动
4.1 按下▶贪吃蛇向右移动:
#include <curses.h>
#include <stdlib.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;tail->next = new;tail = new;
}void initSnake()
{head = (struct Snake *)malloc(sizeof(struct Snake));if(head == NULL){printw("malloc error\n");}head->hang = 2;head->lie = 2;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode(); //增加一个节点deletNode(); //删除头节点
}int main()
{int con;initNcurse();initSnake();gamPic();while(1){con = getch(); //con获取键值if(con == KEY_RIGHT){ //如果是右键moveSnake(); //向右移动gamPic(); //必须刷新一下界面,否则看不到🐍移动} }getch();endwin();return 0;}
4.2 贪吃蛇撞墙重新开始:
#include <curses.h>
#include <stdlib.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));if(new == NULL){printw("malloc error\n");}new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;tail->next = new;tail = new;
}void initSnake()
{struct Snake *p;while(head != NULL){ 判断蛇是否为空,清理内存 p = head;head = head->next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));if(head == NULL){printw("malloc error\n");}head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode();deletNode();//判断蛇的尾巴碰到上下左右的四个边框后就重新开始if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){initSnake();}
}int main()
{int con;initNcurse();initSnake();gamPic();while(1){con = getch();if(con == KEY_RIGHT){moveSnake();gamPic();} }getch();endwin();return 0;}
4.3 贪吃蛇脱缰自由向右行走
#include <curses.h>
#include <stdlib.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));if(new == NULL){printw("malloc error\n");}new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;tail->next = new;tail = new;
}void initSnake()
{struct Snake *p;while(head != NULL){p = head;head = head->next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));if(head == NULL){printw("malloc error\n");}head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode();deletNode();if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){initSnake();}
}int main()
{int con;initNcurse();initSnake();gamPic();while(1){ //之前受方向键控制,现在自由行走moveSnake(); gamPic(); refresh(); //刷新界面usleep(100000); //延时100ms}getch();endwin();return 0;}
五、Linux线程引入
5.1 贪吃蛇方向移动和刷新界面一起实现面临的问题:
#include <curses.h>
#include <stdlib.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!\n");}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));if(new == NULL){printw("malloc error\n");}new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;tail->next = new;tail = new;
}void initSnake()
{struct Snake *p;while(head != NULL){p = head;head = head->next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));if(head == NULL){printw("malloc error\n");}head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode();deletNode();if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){initSnake();}
}int main()
{int key;initNcurse();initSnake();gamPic();while(1){moveSnake();gamPic();refresh();usleep(100000);}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:printw("RIGHT\n");break;}} getch();endwin();return 0;}
-
在上面的程序中main函数中有两个while(1)循环,这样就会出现问题,程序运行的现象是:获取按键值的这个while循环根本不会执行,那该如何解决?于是引入“Linux线程”!
-
在贪吃蛇运动过程中,我们需要改变蛇的移动方向,这是就需要不停扫描键盘输入的值来判断方向,同时还需要不停的刷新界面,为了多个while循环并存这里需要引入linux线程。
5.2 线程的基本用法:
#include <pthread.h> // 头文件pthread_t:当前Linux中可理解为:typedef unsigned long int pthread_t;
如:pthread_t t1; //多线程定义pthread_create(&t1,NULL,refreshInterface,NULL);
参数1:传出参数,保存系统为我们分配好的线程ID
参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
参数4:线程主函数执行期间所使用的参数,如要传多个参数, 可以用结构封装。使用多线程的函数必须返回指针型,如void *refreshInterface()注:gcc xxx.c -lcurses -lpthead //编译需要连接pthead库
5.3 线程demo案例:
/*在这个程序当中只有func1一个函数会被执行,func2函数根本不会执行想要解决这个问题就需要引入Linux的线程
*/
#include <stdio.h>void pfunc1()
{while(1){printf("this is a pfunc1\n");sleep(1);}
}void pfunc2()
{while(1){printf("this is a pfunc2\n");sleep(1);}
}int main()
{pfunc1();pfunc2();return 0;
}
/*引入Linux线程修改代码,func1和func2两个函数都可以执行
*/
#include <stdio.h>
#include <pthread.h> //线程头文件void* func1()
{while(1){printf("this is a func1\n");sleep(1);}}void* func2()
{while(1){printf("this is a func2\n");sleep(1);}
}int main()
{pthread_t th1; //定义一个th1线程pthread_t th2; //定义一个th2线程pthread_create(&th1, NULL, func1, NULL);pthread_create(&th2, NULL, func2, NULL);while(1);return 0;
}
5.4 使用线程解决贪吃蛇方向移动和刷新界面一起实现面临的问题:
#include <curses.h>
#include <stdlib.h>struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;int key;void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!key = %d\n",key);}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;tail->next = new;tail = new;
}void initSnake()
{struct Snake *p;while(head != NULL){p = head;head = head->next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode();deletNode();if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){initSnake();}
}void* refreshJieMian()
{while(1){moveSnake();gamPic();refresh();usleep(100000);}
}void* changeDir()
{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:printw("RIGHT\n");break;}}
}int main()
{initNcurse();initSnake();//注意:线程创建要放在初始化后面,不然就会导致程序段错误(答疑老师解决)pthread_t t1;pthread_t t2;pthread_create(&t1, NULL, refreshJieMian, NULL);pthread_create(&t2, NULL, changeDir, NULL);gamPic();while(1);getch();endwin();return 0;}
-
蛇在向右移动的同时也可以按方向键,这就是引入线程之后的牛逼之处!
六、贪吃蛇跑起来
6.1 实现贪吃蛇四方向的风骚走位:
#include <curses.h>
#include <stdlib.h>
#include <pthread.h>#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;int key;
int dir;void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");:}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!key = %d\n",key);}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;switch(dir){case UP: new->hang = tail->hang-1;new->lie = tail->lie;break;case DOWN: new->hang = tail->hang+1;new->lie = tail->lie;break;case LEFT: new->hang = tail->hang;new->lie = tail->lie-1;break;case RIGHT: new->hang = tail->hang;new->lie = tail->lie+1;break;}tail->next = new;tail = new;
}void initSnake()
{struct Snake *p;dir = RIGHT;while(head != NULL){p = head;head = head->next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode();deletNode();if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){initSnake();}
}void* refreshJieMian()
{while(1){moveSnake();gamPic();refresh();usleep(100000);}
}void* changeDir()
{while(1){key = getch();switch(key){case KEY_DOWN:dir = DOWN;break; case KEY_UP:dir = UP;break;case KEY_LEFT:dir = LEFT;break;case KEY_RIGHT:dir = RIGHT;break;}}
}int main()
{pthread_t t1;pthread_t t2;initNcurse();initSnake();gamPic();pthread_create(&t1, NULL, refreshJieMian, NULL);pthread_create(&t2, NULL, changeDir, NULL);while(1);getch();endwin();return 0;}
6.2 用绝对值方式来解决不合理的走位:
#include <curses.h>
#include <stdlib.h>#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;int key;
int dir;void initNcurse()
{initscr();keypad(stdscr,1);noecho();
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao!key = %d\n",key);}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;switch(dir){case UP: new->hang = tail->hang-1;new->lie = tail->lie;break;case DOWN: new->hang = tail->hang+1;new->lie = tail->lie;break;case LEFT: new->hang = tail->hang;new->lie = tail->lie-1;break;case RIGHT: new->hang = tail->hang;new->lie = tail->lie+1;break;}tail->next = new;tail = new;
}void initSnake()
{struct Snake *p;dir = RIGHT;while(head != NULL){p = head;head = head->next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode();deletNode();if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){initSnake();}
}void refreshJieMian()
{while(1){moveSnake();gamPic();refresh();usleep(100000);}
}void turn(int direction) 通过绝对值判断相反方向不触发
{if(abs(dir) != abs(direction)){dir = direction;}
}void changeDir()
{while(1){key = getch();switch(key){case KEY_DOWN:turn(DOWN);break; case KEY_UP:turn(UP);break;case KEY_LEFT:turn(LEFT);break;case KEY_RIGHT:turn(RIGHT);break;}}
}int main()
{pthread_t t1;pthread_t t2;initNcurse();initSnake();gamPic();pthread_create(&t1, NULL, refreshJieMian, NULL);pthread_create(&t2, NULL, changeDir, NULL);while(1);getch();endwin();return 0;}
6.3 贪吃蛇吃饭了(食物的位置是随机的):
#include <curses.h>
#include <stdlib.h>
#include <pthread.h>#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2struct Snake
{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;int key;
int dir;struct Snake food;void initFood()
{int x = rand()%20;int y = rand()%20;food.hang = x;food.lie = y;
}void initNcurse()
{initscr();keypad(stdscr,1);noecho();
}int hasSnakeNode(int i, int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}int hasFood(int i, int j)
{if(food.hang == i && food.lie == j){return 1;}return 0;
}void gamPic()
{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");}if(hang>=0 && hang<=19) {for(lie=0; lie<=20; lie++){if(lie == 0 || lie == 20){printw("|");}else if(hasSnakeNode(hang,lie)){printw("[]");}else if(hasFood(hang,lie)){printw("##");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0; lie<20; lie++){printw("--");}printw("\n");printw("By ShiYaHao! food.hang = %d,food.lie = %d\n",food.hang,food.lie);}}
}void addNode()
{struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));new->hang = tail->hang;new->lie = tail->lie+1;new->next = NULL;switch(dir){case UP: new->hang = tail->hang-1;new->lie = tail->lie;break;case DOWN: new->hang = tail->hang+1;new->lie = tail->lie;break;case LEFT: new->hang = tail->hang;new->lie = tail->lie-1;break;case RIGHT: new->hang = tail->hang;new->lie = tail->lie+1;break;}tail->next = new;tail = new;
}void initSnake()
{struct Snake *p;dir = RIGHT;while(head != NULL){p = head;head = head->next;free(p);}initFood();head = (struct Snake *)malloc(sizeof(struct Snake));head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deletNode()
{struct Snake *p;p = head;head = head->next;free(p);
}void moveSnake()
{addNode();if(hasFood(tail->hang,tail->lie)){initFood();}else{ deletNode();}if(tail->hang < 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){initSnake();}
}void* refreshJieMian()
{while(1){moveSnake();gamPic();refresh();usleep(100000);}
}void turn(int direction)
{if(abs(dir) != abs(direction)){dir = direction;}
}void* changeDir()
{while(1){key = getch();switch(key){case KEY_DOWN:turn(DOWN);break; case KEY_UP:turn(UP);break;case KEY_LEFT:turn(LEFT);break;case KEY_RIGHT:turn(RIGHT);break;}}
}int main()
{pthread_t t1;pthread_t t2;initNcurse();initSnake();gamPic();pthread_create(&t1, NULL, refreshJieMian, NULL);pthread_create(&t2, NULL, changeDir, NULL);while(1);getch();endwin();return 0;}
七、项目代码
#include <curses.h>
#include <stdlib.h>
#include <pthread.h>#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2struct Snake{int hang;int lie;struct Snake *next;
};struct Snake *head = NULL;
struct Snake *tail = NULL;
struct Snake food;
int key;
int dir;void addNode(); /*从尾部插入新节点*///void initNcurses(); /*ncurses库的初始化函数*/
//void gameMap(); /*贪吃蛇地图的初始化*/
//int printSnakeNode(int i,int j); /*在地图上打印贪吃蛇的节点*/
//void initSnake(); /*初始化贪吃蛇*///void deletNode(); /*删除头结点*/
//void moveSnake(); /*实现贪吃蛇的移动*/
//void *refreshScreen(); /*线程实现图像刷新*/
//void *changeDir(); /*线程实现贪吃蛇方向的改变*/
//void turn(int direction); /*防止出现不合理走位*/
//void creatFood(); /*随机出现食物*/
//int hasFood(int i,int j); /*打印食物*/
//int ifSnakeDie(); /*判断贪吃蛇是否死亡*//*随机出现食物*/
void creatFood()
{int x = rand()%20;int y = rand()%19+1;food.hang = x;food.lie = y;
}int hasFood(int i,int j)
{if(food.hang == i && food.lie == j){return 1;}return 0;
}/*ncurses库的初始化函数*/
void initNcurses()
{initscr();//ncurse界面的初始化函数keypad(stdscr,1);//使用keypad函数,才可以使用键盘功能键noecho();//防止打印无关键值
}/*贪吃蛇地图的初始化*/
void gameMap()
{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");}if(hang>=0 && hang<=19){for(lie=0;lie<=20;lie++){if(lie == 0 || lie == 20){printw("|");}else if(printSnakeNode(hang,lie)){printw("[]");}else if(hasFood(hang,lie)){printw("##");}else{printw(" ");}}printw("\n");}if(hang == 19){for(lie=0;lie<20;lie++){printw("--");}printw("\n");}}printw("By ShiYaHao!,food.hang = %d,food.lie = %d\n",food.hang,food.lie);
}/*在地图上打印贪吃蛇的节点*/
int printSnakeNode(int i,int j)
{struct Snake *p = head;while(p != NULL){if(p->hang == i && p->lie == j){return 1;}p = p->next;}return 0;
}/*初始化贪吃蛇*/
void initSnake()
{ struct Snake *p = NULL;if(head != NULL){ //当贪吃蛇死亡后,把多余节点释放p = head;head = head->next; free(p);}creatFood();dir = RIGHT;head = (struct Snake *)malloc(sizeof(struct Snake));head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();
}/*从尾部插入新节点*/
void addNode()
{struct Snake *new = (struct Snake *)malloc(sizeof(struct Snake));switch(dir){case UP:new->hang = tail->hang-1;new->lie = tail->lie;break;case DOWN:new->hang = tail->hang+1;new->lie = tail->lie;break;case LEFT:new->hang = tail->hang;new->lie = tail->lie-1;break;case RIGHT:new->hang = tail->hang;new->lie = tail->lie+1;break;}new->next = NULL;tail->next = new;tail = new;}/*删除头结点*/
void deletNode()
{struct Snake *p = head;head = head->next;free(p);
}/*判断贪吃蛇是否死亡*/
int ifSnakeDie()
{struct Snake *p;p = head;if(tail->hang < 0 || tail->hang == 20 || tail->lie == 0 || tail->lie == 20){return 1;}while(p->next != NULL){if(p->hang == tail->hang && p->lie == tail->lie){return 1;}p = p->next;}return 0;}/*实现贪吃蛇的移动*/
void moveSnake()
{addNode();if(hasFood(tail->hang,tail->lie)){creatFood();}else{deletNode();}if(ifSnakeDie()){initSnake();}}/*线程实现图像刷新*/
void *refreshScreen()
{usleep(100000);while(1){moveSnake();gameMap();//刷新地图 refresh();//界面刷新函数usleep(100000);}
}
/*防止不合理走位*/
void turn(int direction)
{if(abs(dir) != abs(direction)){dir = direction;}
}/*线程实现贪吃蛇方向的改变*/
void *changeDir()
{while(1){key = getch();switch(key){case KEY_UP:turn(UP);break;case KEY_DOWN:turn(DOWN);break;case KEY_LEFT:turn(LEFT);break;case KEY_RIGHT:turn(RIGHT);break;}}
}int main()
{pthread_t t1;pthread_t t2;initNcurses();initSnake();gameMap();pthread_create(&t1,NULL,refreshScreen,NULL);pthread_create(&t2,NULL,changeDir,NULL);while(1);getch();//等待用户的输入,如果没有这句话,程序就退出了,看不到运行的结果,也就是无法看到上面那句话endwin();//程序退出,恢复shell终端的显示,如果没有这句话,shell终端字乱码,坏掉return 0;
}
相关文章:

C语言——贪吃蛇小游戏
目录 一、ncurse 1.1 为什么需要用ncurse: 1.2 ncurse的输入输出: 1.2.1 如何使用ncurse: 1.2.2 编译ncurse的程序: 1.2.3 测试输入一个按键ncurse的响应速度: 1.3 ncurse上下左右键获取: 1.3.1 如…...

PHP8中获取并删除数组中第一个元素-PHP8知识详解
我在上一节关于数组的教程,讲的是在php8中获取并删除数组中最后一个元素,今天分享的是相反的:PHP8中获取并删除数组中第一个元素。 回顾一下昨天的知识,array_pop()函数将返回数组的最后一个元素,今天学习的是使用arr…...

EtherCAT 总线型 4 轴电机控制卡解决方案
技术特点 支持标准 100M/s 带宽全双工 EtherCAT 总线网络接口及 CoE 通信协议一 进一出(RJ45 接口),支持多组动态 PDO 分组和对象字典的自动映射,支持站 号 ID 的自动设置与保存,支持 SDO 的电机参数设置与…...

Upload-labs十六和十七关
目录 第十六关第十七关 第十六关 直接上传php文件判断限制方式: 同第十五关白名单限制 第十六关源码: 代码逻辑判断了后缀名、content-type,以及利用imagecreatefromgif判断是否为gif图片,最后再做了一次二次渲染 第71行检测…...

软件包的管理
概念 在早期Linux系统中,要想在Linux系统中安装软件只能采取编译源码包的方式进行安装,所以早期安装软件是一件非常困难、耗费耐心的事情,而且大多数服务程序仅提供源代码,还需要运维人员编译后自行解决软件之间的依赖关系。所以…...

常见入门级进销存系统合集
进销存系统是企业管理中不可或缺的一环,它们可以帮助企业有效管理库存、销售和采购等关键业务。然而,对于初创企业和小型企业来说,选择一个合适的进销存系统可能是一项挑战。在这篇文章中,我们将探讨入门级和资深级进销存系统之间…...

爬虫逆向实战(32)-某号店登录(RSA、补环境、混淆)
一、数据接口分析 主页地址:某号店 1、抓包 通过抓包可以发现登录接口是/publicPassport/login.do 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”模块可以发现,有三个加密参数:username、password、captchaTok…...

正则表达式学习和高级用法
以下所有的验证都在 在线验证 1. 起始符 / 正则表达式的起始符2. 限定符 匹配前面的子表达式**1次或多次**。例如,zo 能匹配 "zo" 以及"zoo",但不能匹配 "z"。等价于 {1,}。 ? 匹配前面的子表达式**0次或1次**。例如…...

C# Onnx Yolov8 Fire Detect 火焰识别,火灾检测
效果 项目 代码 using Microsoft.ML.OnnxRuntime.Tensors; using Microsoft.ML.OnnxRuntime; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using Syste…...

线程安全问题
目录 一、线程安全 二、线程安全问题 三、线程安全 1.同步代码块 2.同步方法 3.Lock锁 3.1常用方法: 3.2 死锁 3.3 练习: 四、生产者和消费者(线程通信问题) 一、线程安全 如果有多个线程在同时运行,而这些…...

【力扣每日一题】2023.9.18 打家劫舍Ⅲ
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 今天是打家劫舍3,明天估计就是打家劫舍4了。 今天的打家劫舍不太一样,改成二叉树了,不过规则没有变&…...

Docker基础学习
Docker 学习目标: 掌握Docker基础知识,能够理解Docker镜像与容器的概念 完成Docker安装与启动 掌握Docker镜像与容器相关命令 掌握Tomcat Nginx 等软件的常用应用的安装 掌握docker迁移与备份相关命令 能够运用Dockerfile编写创建容器的脚本 能够…...
esbuild中文文档-路径解析配置项(Path resolution - Alias、Conditions)
文章目录 路径解析配置项 Path resolution别名 Alias条件解析 Conditionsconditions是如何工作的 结语 哈喽,大家好!我是「励志前端小黑哥」,我带着最新发布的文章又来了! 老规矩,小手动起来~点赞关注不迷路࿰…...
您的应用存在隐藏最近任务列表名称的行为,不符合华为应用市场审核标准
最近各家应用市场,唯独华为审核被拒了。。理由是您的应用存在隐藏最近任务列表名称的行为,不符合华为应用市场审核标准。 根据华为给出的视频,app在任务队列(也就是俗称的安卓多任务管理后台)不显示应用名。因为我们ap…...

Spring的 webFlux 和 webMVC
看到一个测评文章,并发在300的时候webMVC 和 webFlux的处理能力不相上下, 当并发达到3000的时候, webFlux明显优于webMVC, 有图有真相, 我信了. webMVC 是 one-request-one thread 堵塞模式, flux是非阻塞模式, 是spring家族系列…...

【洛谷算法题】P5706-再分肥宅水【入门1顺序结构】
👨💻博客主页:花无缺 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5706-再分肥宅水【入门1顺序结构】🌏题目描述🌏输入格式…...
android studio环境搭建让你的开发之旅更加简单
示例示例Android Studio环境搭建:下载并安装Android Studio:从官网下载Android Studio,然后双击安装文件,按照提示进行安装,安装完成之后,可以在桌面上找到Android Studio的快捷方式。 Android Studio环境…...

Java面试_并发编程_线程基础
Java面试_并发编程_线程基础 线程基础线程和进程的区别(出现频率: 3⭐)并行和并发的区别(出现频率: 2⭐)线程的创建(出现频率: 4⭐)线程的状态(出现频率: 4⭐)让线程按顺序执行(出现频率: 3⭐)notify()和notifyAll()有什么区别(出现频率: 2⭐)wait方法和sleep方法的区别(出现频…...

基于Java的高校实习管理系统设计与实现(亮点:实习记录、实习打分、实习作业,功能新颖、老师没见过、当场唬住!)
高校实习管理系统 一、前言二、我的优势2.1 自己的网站2.2 自己的小程序(小蔡coding)2.3 有保障的售后2.4 福利 三、开发环境与技术3.1 MySQL数据库3.2 Vue前端技术3.3 Spring Boot框架3.4 微信小程序 四、功能设计4.1 主要功能描述 五、系统主要功能5.1…...
傅里叶变换
傅里叶变换常用于缺陷检测项目,对于一些背景偏暗,对比度不明显的场景,傅里叶变换可以起到提升对比度的效果。傅里叶变换从频域角度来处理,对于一些图像像素尺寸大的图像,算法时间往往时间达到1s以上,对于一…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...