最后我们做小的机制优化,蛇咬到自己后会导致游戏结束,重置。
我们通过循环整个蛇身,判断蛇头(链表尾指针)是否和蛇身中的某一处坐标相同,如果相同,那么游戏结束。注意,需要蛇头和除了蛇身的位置去作比较,否则会导致每次都判断通过。
#include"curses.h"
#include "stdlib.h"
#include "pthread.h"
#include "time.h"
#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2
struct Snake
{
int row;
int col;
struct Snake* next;
};
struct Snake food;
int key; // user input
int dir;
struct Snake* head = NULL;
struct Snake* tail = NULL;
void addNode();
void mapinit();
void cursesinit()
{
initscr();
keypad(stdscr,1);
// noecho();
}
void snakeinit()
{
// init food
foodinit();
// dir init
dir = RIGHT;
// free
struct Snake* p;
while(head != NULL)
{
p = head;
head = head->next;
free(p);
}
// create node
head = (struct Snake*)malloc(sizeof(struct Snake));
head->row = 2;
head->col = 2;
head->next = NULL;
tail = head;
addNode();
addNode();
}
void foodinit()
{
// 使用当前时间作为种子
srand(time(NULL));
// 生成[1, 19)区间的随机数
int x = rand() % 18 + 1;
int y = rand() % 18 + 1;
food.row = x;
food.col = y;
x += 2;
y += 2;
}
void addNode()
{
struct Snake* node = (struct Snake*)malloc(sizeof(struct Snake));
node->next = NULL;
switch(dir)
{
case RIGHT:
node->row = tail->row;
node->col = tail->col + 1;
break;
case LEFT:
node->row = tail->row;
node->col = tail->col - 1;
break;
case DOWN:
node->row = tail->row + 1;
node->col = tail->col;
break;
case UP:
node->row = tail->row - 1;
node->col = tail->col;
break;
}
tail->next = node;
tail = node;
}
void deleteNode()
{
struct Snake* p;
p = head;
head = head->next;
free(p);
}
int isSnakeDie()
{
if(tail->row == 0 || tail->col == 0 || tail->row >= 20 || tail->col >= 19)
return 1;
struct Snake* p;
p = head;
while(p->next != NULL)
{
if(p->row == tail->row && p->col == tail->col)
return 1;
p = p->next;
}
return 0;
}
void moveSnake()
{
addNode();
// if there have food
if(hasFood(tail->row,tail->col))
foodinit();
else
deleteNode();
// if snake is die
if(isSnakeDie())
snakeinit();
}
int hasSnake(int row,int col)
{
struct Snake* p = head;
while(p!=NULL)
{
if(row == p->row && col == p->col)
return 1;
p = p->next;
}
return 0;
}
int hasFood(int row,int col)
{
if(row==food.row && col==food.col)
return 1;
return 0;
}
void mapinit()
{
int row;
int col;
move(0,0);
for(row = 0;row < 20;row++)
{
// one
if(row == 0 || row == 19)
{
for(col = 0;col < 19;col++)
printw("--");
}
// two
else
{
for(col = 0;col < 20;col++)
{
if(col == 0 || col == 19 ) printw("|");
else if(hasSnake(row,col))
{
printw("[]");
}
else if(hasFood(row,col))
{
printw("##");
}
else
{
printw(" ");
}
}
}
printw("\n");
}
printw("By hongzhe food:(%d,%d)\n",food.row,food.col);
}
void refreshScreen()
{
while(1)
{
moveSnake(); // snake forward
mapinit(); // fresh map
refresh(); // fresh screen
usleep(100000); // sleep(0.5)
}
return;
}
void turnDir(int direction)
{
if(abs(dir) != abs(direction))
dir = direction;
}
void changeDir()
{
while(1)
{
key = getch();
switch(key)
{
case KEY_DOWN:
printw("\rDOWN\t");
turnDir(DOWN);
break;
case KEY_RIGHT:
printw("\rRIGHT\t");
turnDir(RIGHT);
break;
case KEY_LEFT:
printw("\rLEFT\t");
turnDir(LEFT);
break;
case KEY_UP:
printw("\rUP\t");
turnDir(UP);
break;
}
}
return;
}
int main()
{
pthread_t t1;
pthread_t t2;
cursesinit();
snakeinit();
mapinit();
pthread_create(&t1,NULL,refreshScreen,NULL);
pthread_create(&t2,NULL,changeDir,NULL);
while(1); // zu se main thread
getch();
endwin();
return 0;
}