简易贪吃蛇(c语言实现)
#include<ncurses.h>//读取键盘输入的库
#include<stdlib.h>//malloc 动态分配的库
#include<locale.h>//显示汉字的库
#include<unistd.h>//usleep延时函数库
#include<pthread.h>//多线程的库
#define UP 1//宏定义
#define DOWN -1
#define LEFT 2
#define RIGHT -2
void add();
void dtshe();
void cshshiwu();
int flag=0;//赵的标记全局变量
int key;//方向标记位
int dir;//控制蛇的方向
struct da//定义结构体,创建链表
{
int hang;
int lie;
struct da *next;
};
struct da *head=NULL;
struct da *tail=NULL;
struct da food;
void chushihua()//贪吃蛇初始化函数
{
initscr();
keypad(stdscr,1);//ncurses初始化
noecho();//防止显示功能键导致乱码
dtshe();//初始化一条蛇
cshshiwu();
}
int pdd(struct da *she)//判断蛇的死亡函数
{
struct da *p=(struct da*)malloc(sizeof(struct da));
p=she;
while(p->next!=NULL)
{
if(p->hang==tail->hang&&p->lie==tail->lie)//如果撞到自己则回到开始的状态
{
return 1;
}
if(tail->hang==0||tail->hang==20||tail->lie==0||tail->lie==20)//如果撞墙则初始化,回到刚开始的状态
{
return 1;
}
p=p->next;//移动到下一个节点
}
return 0;
}
void cshshiwu()//初始化食物
{
int x=rand()%20;//静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。
int y=rand()%20;
food.hang=x;
food.lie=y;
}
int sw(int hang,int lie)//输出食物函数
{
if(hang==food.hang&&lie==food.lie)
{
return 1;
}
}
int tcs(int hang,int lie,struct da *she)//显示函数,如果传入的行列与she对应的相等,首先输出赵,然后一直输出皮
{
struct da *p=(struct da*)malloc(sizeof(struct da));
p=she;
while(p!=NULL)
{
if(hang==p->hang&&lie==p->lie)
{
if(flag==0)//第一次进入返回2,后面一直返回1
{
flag=1;
return 2;
}
else
{
return 1;
}
}
p=p->next;//移动到下一个节点
}
}
void dtshe()//初始化贪吃蛇函数
{
dir=LEFT;//初始化蛇的方向
while(head!=NULL)//如果不是第一次调用这个函数,则释放掉之前建立的蛇
{
struct da *sf;
sf=head;
head=head->next;
free(sf);
}
head=(struct da*)malloc(sizeof(struct da));
head->hang=1;
head->lie=19;
head->next=NULL;
tail=head;//开始时,头节点和尾节点内存地址是一个地址,然后tail后面接节点就在这个地址后面接,所以连上了
add();//增加蛇身子节点
add();
add();
add();
}
void add()//控制蛇的移动方向以及增加蛇身子函数
{
struct da *new=(struct da*)malloc(sizeof(struct da));
new->next=NULL;
switch(dir)
{
case RIGHT:
new->hang=tail->hang;
new->lie=tail->lie+1;
break;
case LEFT:
new->hang=tail->hang;
new->lie=tail->lie-1;
break;
case UP:
new->hang=tail->hang-1;
new->lie=tail->lie;
break;
case DOWN:
new->hang=tail->hang+1;
new->lie=tail->lie;
break;
}
tail->next=new;
tail=new;//尾节点等于新节点
}
void shuchu()//输出函数
{
move(0,0);//初始化光标位置
int hang;
int lie;
for(hang=0;hang<=20;hang++)
{
for(lie=0;lie<=20;lie++)
{
if(hang==0&&(lie!=0&&lie!=20)||hang==20&&(lie!=0&&lie!=20))//打印地图
{
printw("[]");
}
else if(lie==0||lie==20)
{
printw("[]");
}
if(hang!=0&&hang!=20&&lie!=0&&lie!=20)
{
if(tcs(hang,lie,head)==2)//这里不能调换位置,调换位置之后tcs第二次调用返回1会影响结果
{
printw("赵");
}
else if(tcs(hang,lie,head)==1)
{
printw("皮");
}
else if(sw(hang,lie)==1)
{
printw("皮");
}
else
{
printw(" ");
}
}
if(lie==20)
{
printw("\n");
}
}
}
printw("作者:赵皮皮\n");
printw("欢迎加入电子设计工作室\n");
}
void delete()//头节点向后移动
{
head=head->next;
}
void youyd()//改变蛇移动方向的函数
{
add();//增加一个新节点
if(sw(tail->hang,tail->lie)==1)
{
cshshiwu();
}
else
{
delete();//删除一个旧节点
}
if(pdd(head))//如果撞墙或者撞到自己则初始化,回到刚开始的状态
{
dtshe();
}
}
void* yidong()//移动函数,每隔100微秒重新打印地图
{
while(1)
{
youyd();//改变蛇的方向
flag=0;//每次执行,让标记置0,目的输出赵
shuchu();//打印地图函数
refresh();//刷新函数
usleep(100000);//延迟函数,100微秒
}
}
void turn(int direction)//防止反向移动函数
{
if(abs(dir)!=abs(direction))
{
dir=direction;
}
}
void* shuru()//读入键盘数值,确定移动方向函数
{
while(1)
{
key=getch();//读入键盘输入,确定方向
switch(key)
{
case KEY_RIGHT:
turn(RIGHT);
break;
case KEY_LEFT:
turn(LEFT);
break;
case KEY_UP:
turn(UP);
break;
case KEY_DOWN:
turn(DOWN);
break;
}
}
}
int main()
{
setlocale(LC_ALL,"");//显示中文
pthread_t th1;//定义多线程
pthread_t th2;
chushihua();//调用初始化函数
pthread_create(&th1,NULL,shuru,NULL);
pthread_create(&th2,NULL,yidong,NULL);
while(1);
endwin();//结束函数
return 0;
}
//总体思路:采用多线程的方式,让键盘输入函数和打印整个贪吃蛇游戏的函数同时进行,当键盘读入数值时通过方向标记变量结合移动函数使蛇移动