废话少说,先上代码!
#include <curses.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> //使用多线程思想实现位移与按键的双运行
int key; //用于存放用户输入的方向键的数码
int dir; //用于赋值数值
#define UP 1
#define DOWN -1
#define RIGHT 2
#define LEFT -2
void initnurses(){
initscr(); //ncurses库初始化
keypad(stdscr,1);
noecho(); //告诉curses不要把输入回显到屏幕上
}
struct snake{ //结构体蛇模块
int hang;
int lie;
struct snake *next;
};
struct snake *head=NULL; //使用动态链表方式实现尾节点插入,这里设置为头结点
struct snake *tail=NULL; //使用动态链表方式实现尾节点插入,这里设置为尾结点
struct snake food; // 结构体表示食物模块
void initfood(){ //食物初始化
int x=rand()%20; //rand()函数初始化食物x坐标
int y=rand()%20; //rand()函数初始化食物y坐标
food.hang = x;
food.lie = y;
}
int hasfood(int i,int j){ //用于判断食物位置是否与尾结点重合
if(food.hang==i && food.lie==j){
return 1;
}
else{
return 0;
}
}
int snake_line(int x,int y){ //判断蛇模块长度判断
struct snake *p;
p = head;
while(p !=NULL){
if(p->hang==x && p->lie==y){
return 1;
}
p=p->next;
}
return 0;
}
void mapbuilt(){ //地图绘制与食物绘制以及蛇模块绘制
int hang,lie;
move(0,0); //保证更新不会出现新地图
for(lie=0;lie<=20;lie++){
if(lie==0 || lie==20){
for(hang=0;hang<20;hang++){
printw("--");
}
}
else{
for(hang=0;hang<=20;hang++)
{
if(hang==0 || hang == 20){
printw("|");
}
else if(snake_line(hang,lie)){
printw("[]");
}
else if(hasfood(hang,lie)){
printw("##");
}
else{
printw(" ");
}
}
}
printw("\n");
}
printw("make by lhy==food.hang:%d,food.lie:%d\n",food.hang,food.lie); //显示食物坐标位置
}
void add_snake(){ //增加蛇模块,此外还可以控制蛇的左右上下移动
struct snake *new;
new=(struct snake *)malloc(sizeof(struct snake)); //malloc函数开辟新空间
switch(dir){
case UP:
new->hang = tail->hang;
new->lie = tail->lie-1;
break;
case DOWN:
new->hang =tail->hang;
new->lie = tail->lie+1;
break;
case RIGHT:
new->hang = tail->hang+1;
new->lie = tail->lie;
break;
case LEFT:
new->hang = tail->hang-1;
new->lie = tail->lie;
break;
}
new->next =NULL;
tail->next = new;
tail = new;
}
void init_snake(){ //初始化蛇模块,表示蛇模块为x=2,y=2.
struct snake *p;
while(head != NULL){// 当蛇死亡,重新生成新的蛇,应当及时清理之前的链表,防止时间一长导致内存泄露
p=head;
head = head->next;
free(p);
}
initfood();
head =(struct snake *)malloc(sizeof(struct snake)); //开始内存,先形成头结点,不够使用的是尾插法
head->hang=2;
head->lie=2;
head->next=NULL;
tail=head;
dir=RIGHT;//start go right
add_snake();
add_snake();
add_snake();
add_snake();
}
void delar_snake(){ // 删除蛇的长度,保证陕西中医药大学移动长度一样
struct snake *p;
p=head;
head = head->next;
free(p);
}
void movesnake(){ //实现碰壁死亡,与吃的食物蛇长度增长
add_snake();
if(hasfood(tail->hang,tail->lie) ){
// if(tail->hang==food.hang && tail->lie==food.lie ){
initfood();
}else{
delar_snake();
}
if(tail->hang==0 || tail->lie==0 || tail->hang==20 || tail->lie==20){
init_snake();
}
}
void turn(int dirction){ //绝对值设置,防止蛇可以通知左右移动(那不然会很酷)
if(abs(dir) != abs(dirction)){
dir = dirction;
}
}
void* choosewhere(){ //赋值ncurses库的上下左右移动的按键数码
while(1){
key=getch();
switch(key){
case KEY_DOWN:
turn(DOWN);
break;
case KEY_UP:
turn(UP);
break;
case KEY_RIGHT:
turn(RIGHT);
break;
case KEY_LEFT:
turn(LEFT);
break;
}
}
}
void* refreadsnake(){ //蛇移动,在Linux系统下 usleep可以控制蛇速度,单位为us,sleep()单位为s
while(1){
movesnake();
mapbuilt();
refresh(); //更新
usleep(100000); //0.1s
}
}
int main(){
initnurses();
init_snake();
pthread_t th1;
pthread_t th2;
mapbuilt();
pthread_create(&th1, NULL, choosewhere, NULL); // 线程1创立 ,表示方向选择
pthread_create(&th2, NULL, refreadsnake, NULL);// 线程2创立 ,表示蛇移动
while(1); //保证线程一直运行
getch(); //防止程序退出
endwin();
return 0;
}