贪吃蛇
- 初始蛇身长为4,向右移动,每吃到一次食物身长加1
- 键盘上下左右键控制移动方向
- 碰到墙壁、障碍物或者吃到自身时死亡,游戏结束
#include <curses.h>
#include <stdlib.h>
#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2
struct Snake { //蛇身一段的坐标信息
int hang;
int lie;
struct Snake *next;
};
int key;
int dir;
struct Snake *head = NULL;//蛇头
struct Snake *tail = NULL;//蛇尾
struct Snake food; //食物
void initfood() {//初始化食物坐标
int x = rand() % 20;
int y = rand() % 20;//地图长宽为20
food.hang = x;
food.lie = y;
}
void initNcurse() {
initscr();
keypad(stdscr,1);
noecho();
}
int hasNode(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;
}//判断该坐标是否存在蛇身体
int hasfood(int i,int j) {
if (food.hang == i && food.lie == j){
return 1;
}
return 0;
}//判断该坐标是否存在食物
void gamePic() {//扫描全图,初始化并且判断地图,食物和蛇身体
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 (hasNode(hang,lie)) {
printw("[]");
}
else if(hasfood(hang,lie)) {
printw("##");
}
else {
printw(" ");
}
}
printw("\n");
}
if (hang == 20) {
for (lie = 0 ; lie < 20 ; lie++){
printw("--");
}
printw("\n");
}
}
printw("By xiaozhang,food.hang=%d,food.lie=%d\n",food.hang,food.lie);
}
void addsnake() {
struct Snake *new;
new = (struct Snake*)malloc(sizeof(struct Snake));
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;//刚开始蛇头和蛇尾重合
addsnake();
addsnake();
addsnake();//蛇尾添加新节点
}
void deleteNote() {//运动过程中,随着尾节点每运动一下,就删除一个原来的头节点
struct Snake *p;
p = head;
head = head->next;
free(p);
}
int ifsnakedie() {
struct Snake *p;
p = head;
if(tail->lie==0 || tail->lie==20 || tail->hang < 0 || tail->hang ==20) {
return 1;
}//触碰边界返回1
while (p->next != NULL) {
if (tail->hang == p->hang && tail->lie == p->lie) {
return 1;
}//触碰身体返回1
p = p->next;
}
return 0;
}
void movesnake() {
addsnake();//移动时尾部添加新节点
if (hasfood(tail->hang,tail->lie)) {
initfood();//吃到食物添加新节点
}else{
deleteNote();//没吃到食物,移动一次删除一次头节点
}
if(ifsnakedie()) {
initsnake();//无论碰到地图边界还是碰到自身,游戏重新开始
}
}
void refreshjiemian() {
while (1) {
movesnake();
gamePic();
refresh();
usleep(100000); //每100ms刷新一次界面
}
}
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;
initNcurse();
initsnake();
gamePic();
pthread_create(&t1,NULL,refreshjiemian,NULL);
pthread_create(&t2,NULL,changedir,NULL); //多线程操作,使得刷新界面和改变方向两个无限循环可以同时完成
while (1);//防止游戏结束
getch();
endwin();
return 0;
}
运行方法
-
打开命令行窗口,输入
gcc snake.c -lcurses -lpthread
进行编译 - ./a.out运行