C语言:在Linux系统下实现贪吃蛇

         此段代码是在Linux系统下实现的贪吃蛇项目,用到的工具为Ncurse,非常古老的一门技术,比他先进的有很多,目的旨在于强化个人的cyy基础,有兴趣的胖友可以参考实现以下。

        首先我来介绍一下这个思路的实现:

        1、首先贪吃蛇身体的实现是由许多个[]符号来实现的,这里用到了C语言的链表,灵活的连接每一个节点的前后关系。

        2、贪吃蛇的身体位置定位是由行和列组成的,共有20行,20列;

        3、大多数人认为贪吃蛇的移动实现,必然是“头”开始移动去吃食物,但这里我转变了思路:使用“尾节点”来带头,每移动一步,尾节点+1,这样必然会导致贪吃蛇越来越长,所以与此同时头节点后移(也就是删除)一位,并且释放空间(能够防止空间爆炸)。

#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>

#define UP		1		//进行宏定义,用于操控贪吃蛇的方向
#define DOWN	-1
#define LEFT	2
#define RIGHT	-2

typedef struct Snake{
	int row;
	int col;
	struct Snake *next;
}snake;					//此处,因为使用了typedef,所以snake可以直接表示 struct Student

snake *head=NULL;
snake *tail=NULL;
int key;
int dir;
snake food;

void initNcurse(){		//初始化ncurse界面的函数
	initscr();
	keypad(stdscr,1);
}

void initFood(){		//初始化食物函数
	int x=rand()%20,y=rand()%20;	//使用随机函数,初始化食物位置
	food.row=x;
	food.col=y;

}

void initSnake(){		//初始化贪吃蛇的身体
	dir=RIGHT;			//起始移动方向,向右前进
	snake* p;
	while(head!=NULL){	//当头节点不为空时,向后遍历每一个身体节点
		p=head;
		head=head->next;
		free(p);		//最后释放空闲空间
	}
	initFood();			//在初始化贪吃蛇时,也同时初始化食物的位置
	head=(snake*)malloc(sizeof(snake));
	head->row=0;
	head->col=1;
	head->next=NULL;
	tail=head;
	addNode();
	addNode();
	addNode();
	addNode();
}

int hasSnakeNode(int row,int col){	//
	snake *p=head;
	while(p!=NULL){
		if(p->row==row && p->col==col){
			return 1;
		}
		p=p->next;
	}
	return 0;
}

int hasFood(int i,int j){
	if(food.row==i && food.col==j) return 1;
	return 0;
}

void printTheBox(){		//打印贪吃蛇边框
	int row,col;
	move(0,0);			//调用移动函数,让贪吃蛇从0,0位置开始移动
	for(row=0;row<20;row++){
		if(row==0){
			for(col=0;col<20;col++){
				printw("--");
			}
			printw("\n");
		}
		if(row>=0 && row<=19){
			for(col=0;col<=20;col++){
				if(col==0 ||col==20){
					printw("|");
				}else if(hasSnakeNode(row,col)){
					//用于打印贪吃蛇的身体,在对应的位置,将空格替代
					printw("[]");	
				}else if(hasFood(row,col)){
					//打印食物的位置
					printw("**");
				}else{
					printw("  ");
				}
                        }
			printw("\n");
		}
		if(row==19){
			for(col=0;col<20;col++){
                                printw("--");
                        }
                        printw("\n");
			printw("Bye Bye!!!key=%d\n",key);
		}
		
	}
}

void addNode(){		//添加贪吃蛇身体节点函数,每执行一次,贪吃蛇增加1节
	snake *new=(snake*)malloc(sizeof(snake));
	new ->next=NULL;

	switch(dir){	//判断指令,下一步想着什么方向移动
		case UP:
			new->row=tail->row-1;
			new->col=tail->col;
			break;
		case DOWN:
			new->row=tail->row+1;
			new->col=tail->col;
			break;
		case LEFT:
			new->row=tail->row;
			new->col=tail->col-1;
			break;
		case RIGHT:
			new->row=tail->row;
			new->col=tail->col+1;
			break;
	}
	tail->next=new;
	tail=new;//update the tail's address
}

void deleteNode(){		//贪吃移动的实现,靠的是尾节点+1,头节点-1,此处实现删除头节点
	snake *p;
	p=head;
	head=head->next;//change the head
	free(p);
}

void moveSnake(){		//实现贪吃蛇的移动
	addNode();
	if(hasFood(tail->row,tail->col)){//如果吃到食物,刷新食物位置,仅此时不删除旧的头节点
		initFood();
	}else{
		deleteNode();	//没有吃到食物时,移动时头节点-1,尾节点+1
	}
	if(ifSnakeDie()){	//如果吃到了自己,或者碰壁,贪吃蛇重置刷新
		initSnake();
	}
}

int ifSnakeDie(){		//判断贪吃蛇是否死亡
	snake *p=head;
	if(tail->row<0 ||tail->col==0 ||tail->row==20 ||tail->col==20){
                return 1;
        }
	while(p->next!=NULL){
		if(p->row==tail->row && p->col==tail->col) return 1;
		p=p->next;
	}
	return 0;
}

void* refreshTheWin(){	//为实现贪吃蛇动态移动,要实现实时刷新地图
	
	while(1){
		moveSnake();
		printTheBox();
                refresh();
                usleep(300000);
	}
}

void turn(int direction){//防止贪吃蛇上下、左右冲突撞到自己
	if(abs(dir)!=abs(direction)){
		dir=direction;
	}
}

void* changeTheDir(){	//贪吃蛇转向函数
	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(){
	//create the thread;
        pthread_t th1;
        pthread_t th2;
	
	initNcurse();
	
	initSnake();

	printTheBox();
	
	pthread_create(&th1,NULL,refreshTheWin,NULL);
	pthread_create(&th1,NULL,changeTheDir,NULL);
	
	while(1);

	getch();  
	endwin();//exit the exe
	return 0;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值