C语言 实现贪吃蛇(纯) @美杜莎

C语言 实现贪吃蛇(纯) @美杜莎_第1张图片

main函数:对制作小蛇的过程做了大体的注释;

后面有作者自己遇到一些坑,可以参考 T.T ;

总之把能解释的都做了一定的注释,源码里see see;

@ 源码(可以先看main函数,就不会凌乱QAQ): 

#include 
#include 
#include 

#define UP    1   //注意宏定义时不能加分号";"
#define DOWN  -1  //反方向一正一负,方便后面abs()取绝对值,让蛇不能在一条直线原地掉头;
#define LEFT  2
#define RIGHT -2

struct Snake 
{
	int hang;
	int lie;
	struct Snake* next;	
};

struct Snake* head = NULL;
struct Snake* tail = NULL;
struct Snake food;

int direct;
int key;	//保存 getch()获取到的方向键返回值;便于后面打印实时方向 详见:gamePic();


void addSnake()
{
	struct Snake *new;
	struct Snake *p = tail;
	new = (struct Snake *)malloc(sizeof(struct Snake));
	new->next = NULL;
	switch(direct){
		case UP:
			new->hang = p->hang-1;
			new->lie = p->lie;
			break;
		case DOWN:
			new->hang = p->hang+1;
			new->lie = p->lie;
			break;
		case LEFT:
			new->hang = p->hang;
			new->lie = p->lie-1;
			break;			
		case RIGHT:
			new->hang = p->hang;
			new->lie = p->lie+1;	
			break;
	}
	tail->next = new;
	tail = new;
}


void testInitscr()
{
	initscr();
	keypad(stdscr,1);	
	noecho(); //吸收 getch()时特殊键位返回的多余的键值;
}


int haveSnake (int hang,int lie)
{
	struct Snake* p = head;
	while(p != NULL){		
		if(p->hang == hang && p->lie == lie){
			return 1;
		}
		p = p->next;
	}
	return 0;
}


void initFood()
{
	int x;
	int y;
	x = rand()%19+1;
	y = rand()%19+1;
	food.hang = x;
	food.lie = y;
}


int ifFood(int hang,int lie)
{
	if(hang == food.hang && lie == food.lie ){
		
		return 1;
	}
	
	return 0;
}


void lieIoI_Pic(int hang)
{
	int lie;
	for(lie=0;lie<=20;lie++){
		if(lie == 0 || lie ==20 ){
			printw("|");			
		} 
		else if(haveSnake(hang,lie)){
			printw("[]");
		}
		
		else if(ifFood(hang,lie)){
			printw("##");
		}
		
		else{
			printw("  ");
		}				
	}
	printw("\n");
}


void hangGang_Pic()
{
	int lie;
	for(lie=0;lie<20;lie++){
		printw("--");
	}
					
	
}


void gamePic()
{
	int hang;
	
	move(0,0); //下一次光标的初始位置;
	for(hang=0;hang<20;hang++){
		
		if(hang == 0){
			hangGang_Pic();	
			printw("\n");
		}
		
		if(hang >= 0 && hang <= 19){
			lieIoI_Pic(hang);
		}
		
		if(hang == 19){
			
			hangGang_Pic();		
		}
	}
	printw("\n");
	printw("by: TianYang10.0\n");
	switch(key){
		case 0403:
		printw("UP\n");
		break;
		case 0402:
		printw("DOWN\n");
		break;
		case 0404:
		printw("LEFT\n");
		break;
		case 0405:
		printw("RIGHT\n");
		break;
	}
}





void initSnake(){
	
	int i;
	struct Snake* p;
	
	direct = RIGHT; //复活时,默认方向为右,具体可看addSnake;
	
	//遍历蛇的链表,注意释放内存空间;
	while(head != NULL){
		
		p = head;
		head = head->next;
		free(p);
	}
	head = (struct Snake *)malloc(sizeof(struct Snake));
	head->hang = 2;
	head->lie = 1;
	head->next = NULL;
	tail = head;
	
	for(i=0;i<3;i++){
		addSnake();
	}
	

}


void delectSnakeHead()
{
	struct Snake *p = head;
	head = p->next;
	
	free(p);
}

int ifSnakeDie()
{
	struct Snake *p = head;
	
	//碰到边界就噶;
	if(tail->hang < 0||tail->lie == 0 ||tail->hang == 20||tail->lie == 20){
		return 1;
	}
	
	//碰到蛇身就噶;
	while(p->next != NULL){
		if(tail->hang == p->hang && tail->lie == p->lie){
			return 1;
		}
		p = p->next;
	}
	return 0;
}


void moveSnake()
{
	
	addSnake(); 		//增加一节尾节点;

	if(tail->hang == food.hang && tail->lie == food.lie){
		//addSnake();
		initFood();	
	}else{
		delectSnakeHead();	//把头节点删了;
	}
	//delectSnakeHead();
	//蛇死了,就初始化蛇;
	if(ifSnakeDie()){
		initSnake();
	}	
}

void * fereshJieMian()
{
	while(1){
		
		moveSnake(); 	//移动蛇的方向;
		gamePic();		//打印地图;
		usleep(100000);	//1 s = 10^6 us; 不睡会,你想挑战while(1)的循环速度嘛?怕是快到看不清奥;
		refresh();  	//刷新窗口;
		
	}	
}

void adsDirection(int num)
{
	if(abs(num) != abs(direct)){
		direct = num;		
	}

}


void * getDirect()
{
	while(1){
		key = getch();
		switch(key){
			case KEY_UP:
				adsDirection(UP);
				break;
			case KEY_DOWN:
				adsDirection(DOWN);
				break;
			case KEY_LEFT:
				adsDirection(LEFT);
				break;
			case KEY_RIGHT:
				adsDirection(RIGHT);
				break;
		}
	}
	
}

int main()
{	
	pthread_t t1;	//创建2个线程的标识码变量为 t1,t2;
	pthread_t t2;	//让它们和主线程同时运行
	
	//线程使用必要条件:
	//pthread_t1; --创建线程的标识码变量
	//pthread_create(&t1,NULL,&要执行的函数,NULL); --建立线程运行
	//注意:使用线程在ubuntu系统编译时,需要链库-lpthread 才能正常使用;
	
	//同样的:程序调用curses.h库,在编译时也要链库-lcurses;
	
	testInitscr();	//curses.h库运行需要的必备函数:initscr();keypad(stdscr,1);
	initSnake();  	//初始化蛇;
	initFood();		//初始化食物;
	
	gamePic();   	//打印首次的地图

	//线程t1:定义方向键的返回的int型a变量;
	//getch()获取键盘返回值给a变量;
	//while(1){判断方向键后,执行赋值等操作 并break退出无限循环;}
	pthread_create (&t1,NULL,getDirect,NULL);
	
	
	//线程t2:while(1){刷新界面;移动蛇;打印地图;sleep()一会让人能看见;refresh()刷新一下;};
	pthread_create(&t2,NULL,fereshJieMian,NULL);
	

	while(1);	//让主线程不会结束,和t1,t2一起无限循环下去,游戏才能正常玩;

	endwin();	
	//正常在调用curses.h库时,在后面必加endwin();
	//但是这个游戏程序被上面的while(1)拦住,所以不要也不影响贪吃蛇的运行;
	
	return 0;
}

博主遇到的坑:

No.1:在Ubuntu系统编译时,如果在for写循环条件时,直接int 定义变量是不行滴,会提示需要 -sdt=c99;可即使编译时加了 -std=c99,结果依旧编译不过!最后将int i  写在循环之外才得以飞升。。0_0;

// 失败的形状:
for(int i=0;i<3;i++){
    addSnake();
}
/*-------------------------------------------------------------------*/
// 成功的形状:
int i;
for(i=0;i<3;i++){
    addSnake();
}

No.2:在判断蛇吃到食物时,少写了一个" = " ,但此时编译时也不会报错,导致调整了半天才降伏了虚空跳跃蛇; :#大胆妖孽,还不赶快束手就擒!

void moveSnake()
{
	
	addSnake(); 		//增加一节尾节点;
    
    //        这里 ⬇ 少了一个 "=",导致蛇变成了虚空跳跃蛇;
	if(tail->hang = food.hang && tail->lie == food.lie){
		//addSnake();
		initFood();	
	}else{
		delectSnakeHead();	//把头节点删了;
	}
	//delectSnakeHead();
	//蛇死了,就初始化蛇;
	if(ifSnakeDie()){
		initSnake();
	}	
}

编译了:

虚空惊现:

C语言 实现贪吃蛇(纯) @美杜莎_第2张图片

99 81分钟,补上 "=" 号真言;

健康小蛇诞生:

C语言 实现贪吃蛇(纯) @美杜莎_第3张图片

你可能感兴趣的:(算法)