一、判断蛇咬到身子死亡问题
二、边界问题
#include <curses.h>//不是标准库 1.sudo apt-get install libncurses5-dev 2.vi /usr/include/crses.h 3.gcc my_snake,c -lcurses
#include <stdio.h>
#include <stdlib.h>//malloc
#include <pthread.h>//Linux线程
#include <unistd.h>//睡眠时间函数usleep()与sleep()类似,用于延迟挂起进程。进程被挂起放到ready queue。
//提供对 POSIX 操作系统(可移植系统)接口 API 的访问功能的头文件的名称,是一组定义了UNIX-like操作系统接口标准的规范,旨在增加移植性和兼容性。
#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2
//定义贪吃蛇节点结构体
struct Snake
{
int hang;
int lie;
struct Snake *next;
};
struct Snake *head = NULL;//定义蛇尾(链表头)
struct Snake *tail = NULL;//定义蛇头(链表尾)
int key;//记录键入的值 changeDirection()函数中使用到
int dir;//记录方向的值 addNode()函数中使用到
struct Snake food;//定义结构体变量食物
//函数封装初始化Ncurse界面
void initNcurse()
{
initscr();//ncurse界面的初始化函数
keypad(stdscr,1);//从标准stdscr中接受功能键,TRUE代表是否接收
noecho();//大多数的交互式应用程序在初始化时会调用noecho()函数,用于在进行控制操作时不显示输入的控制字符。
}
//随机食物生成
void initFood()
{
int x = rand()%20;
int y = rand()%20;
food.hang = x;
food.lie = y;
}
//判断地图上的点是否有食物
int judgeFood(int i,int j)
{
if(food.hang == i && food.lie == j){
return 1;
}
return 0;
}
//判断地图上的点是否是蛇身节点
int judgeSnakeNode(int i,int j)
{
struct Snake *p;
p=head;
while (p!=NULL){
if(p->hang==i && p->lie==j){
return 1;
}
p=p->next;
}
return 0;
}
//打印输出游戏界面
void gamePic()
{
int hang;
int lie;
move(0,0);//将光标定位到0行0列 ncurses的性质
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(judgeSnakeNode(hang,lie)){
printw("[]");
}else if(judgeFood(hang,lie)){//判断食物节点,打印食物
printw("##");
}else{
printw(" ");
}
}
printw("\n");
}
if(hang==19)
{
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
}
printw("by tanyang!food hang node = %d,food lie node = %d\n",food.hang,food.lie);
}
//增加新节点(通过方向判断加在哪)
void addNode()
{
struct Snake *new = (struct Snake *)malloc(sizeof(struct Snake));
switch (dir){//根据键入的值来增加节点,修改tail所指结点中hang,lie并将修改后的值赋值给新节点
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 initSnake()
{
struct Snake *p;
dir = RIGHT;//蛇头初始方向为RIGHT
while (head!=NULL)//判断蛇是否为空,清理内存
{
p=head;
head=head->next;
free(p);
}
initFood();//随机食物生成
head=(struct Snake *)malloc(sizeof(struct Snake));
head->hang=4;
head->lie=4;
head->next=NULL;
tail=head;//初始时尾指针指向头
addNode();
addNode();
addNode();//增加3节点,设置初始蛇身长度
}
//删除蛇尾(头结点)
void deleteNode()
{
struct Snake *p;
p = head;
head = head->next;
free(p);//释放p=head原先头节点
}
int judgeSnakeDeath()
{
struct Snake *p;
p = head;
if(tail->hang < 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 21){//当tail节点中数据到达最大边界return 1
return 1;
}
while(p->next != NULL){
if(p->hang == tail->hang && p->lie == tail->lie){//当tail节点中数据与蛇身一致时return 1
return 1;
}
p = p->next;
}
return 0;
}
//蛇的移动(蛇头增加新节点,删除蛇尾节点)
void moveSnake()
{
addNode();//增加新节点
if(judgeFood(tail->hang,tail->lie)){
initFood();//随机食物生成
}else{
deleteNode();//删除蛇尾(头结点)
}
if(judgeSnakeDeath()){
initSnake();//死亡,重新初始化蛇身,游戏重新开始
}
}
//界面刷新
void* refreshInterface()
{
while(1){
moveSnake();//移动
gamePic();//打印输出
refresh();//更新终端屏幕
usleep(200000);//控制蛇的运动速度,以微秒为单位,100毫秒睡眠一次,执行挂起不动
}
}
//通过绝对值判断相反方向不触发
void turn(int direction)
{
if(abs(dir) != abs(direction)){//绝对值函数abs();
dir = direction;
}
}
//扫描键入的值判断方向
void* changeDirection()
{
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();
gamePic();
pthread_create(&t1, NULL, refreshInterface, NULL);
pthread_create(&t2, NULL, changeDirection, NULL);
while(1);
getch();//获取用户的输入
endwin();//没有会破坏show的界面
return 0;
}