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以上,对于一…...
Vue Grid Layout -️ 适用Vue.js的栅格布局系统,在vue3+上使用
文章目录 1、官网简介2、在vue3中使用1)、需要导入vue3支持的版本插件2)、在mian.js里引入:3)、在组件中使用 3、layout布局的计算逻辑4、 gridLayout 的属性 该栅格系统目前对 vue2 的支持是最好的,vue3 是需要用插件支持的,会在小节详细讲解…...
Electron(v26.2.1)无法加载React Developer Tools(v4.28.0)
一开始按照electron官网上的 开发者工具扩展 教程设置React Developer Tools时,重启项目后并没有按照预期成功加载React Developer Tools,而且控制台报错: Permission scripting is unknown or URL pattern is malformed.查了下原因是因为Re…...
网站降权的康复办法(详解百度SEO数据分析)
随着搜索引擎算法的不断升级,很多网站在SEO优化过程中遭遇到降权的情况。如果您的网站也遭遇到了类似的问题,不必惊慌失措。本文将为您详细介绍网站降权恢复的方法,包括百度SEO数据分析、网站收录少的5个原因、网站被降权的6个因素以及百度SE…...
非对称加密、解密原理及openssl中的RSA示例代码
一、【原理简介】非对称加密 非对称加密,也被称为公钥加密,其中使用一对相关的密钥:一个公钥和一个私钥。公钥用于加密数据,私钥用于解密数据。公钥可以公开分享,而私钥必须保密。 密钥生成: 当一个用户或设备希望使用…...
基于springboot漫画管理系统springboot001
摘 要 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代&…...
【探索C++】string类详解
(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮࿰…...
python 第一次作业
1.使用turtle换一个五环 2.设计这样一个程序:输入一个数字 判断它是不是一个质数 使用turtle换一个五环: >>> import turtle #导入模块 >>> turtle.width(10) #设置圆圈宽度 >>> turtle.color("blue&qu…...
个人博客网站一揽子:Docker建站(Nginx、Wordpress、MySql)
前言 既然安装了Docker,那就不妨建立一个自己的博客网站。实现内外网隔离网站部署,更安全。 1.创建Docker子网络 首先创建一个Docker虚拟子网: sudo docker network create wpnt检查是否建立成功: sudo docker network ls最后…...
Unity 课时 4 : No.4 模拟面试题
课时 4 : No.4 模拟面试题 C# 1. 请说明字符串中 string str null string str “” string str string.Empty 三者的区别 第一个未作初始化没有值, 第二个为空字符串, 答案: str null 在堆中没有分配内存地址 str "" 和 string.Empty 一样都是…...
Golang 基础面试题 01
Golang 面试题合集.png 背景 在之前的文章中分享了 k8s 相关的面试题,本文我们重点来讨论和 k8s 密切相关的 Go 语言面试题。 这几年随着云原生的兴起,大部分后端开发者,特别是 Java 开发者都或多或少的想学习一些 Go 相关的技能,…...
做视频的软件模板下载网站有哪些内容/优化设计四年级上册语文答案
近日,由深度学习技术及应用国家工程实验室与百度联合发起的 AICA|首席 AI 架构师培养计划第五期正式结业。经过为期半年的学习,最终来自中国石油、中国四维测绘、中国石化、霍尼韦尔、中国海油、法国电信、中国东方航空、中国铁塔等企业的57位…...
做调研的网站有哪些/搜索引擎优化的方式有哪些
zx-image-view 图片预览插件,支持图片切换、旋转、缩放、移动... 浏览器支持:IE10, (IE9不支持旋转功能) 效果预览:https://capricorncd.github.io... 源码地址:https://github.com/capricornc... 默认键盘操作 方向键:…...
ui界面设计app/今日头条seo
网游数据收集 1.投资风险加大 数据显示, 2009年上线的国内自主研发客户端网游数量为321款,其中进入公测的仅64款; 2010年上线网游356款,截止2010年8月,仅公测41款。 业内人士估算,国内至少有1000个团队…...
政府网站建设指标/微信引流推广怎么找平台
Javascript作用域经常接触Context这个词语,对这个词语越来越模糊,书中一般翻译为上下文! 作用域应该是一个范围,什么范围呢,就是一个环境执行的时候所属的范围,环境中定义的所有变量和函数都保存在其中,那么…...
多语种网站制作/平台软件定制开发
一、压缩与解压缩1、compress [-rcv] 文件或目录 <压缩uncompress 文件.Z <解压缩-r:可以连同目录下的文件也同时进行压缩-c:将压缩数据输出成standard output(输出到屏幕)-v:可以显示出压缩后的文件信息以及压缩过程中的一些文件名变化(这个命令是非常老旧的一款)2、gzi…...
dede 门户网站/推广产品的方法和步骤
共回答了13个问题采纳率:84.6%172.19.52.128/26代表该网段为172.19.52.128-172.19.52.191,段内2^8/2^(26-3*8)64个IP地址,划分为两个16IP地址的子网,一个32IP地址的子网,三个子网分别为172.19.52.128/28、172.19.52.14…...