天天看点

贪吃蛇(C语言)

首先,我们是用turboC来写的,因为turboC中有gotoxy();和bioskey();函数可以简单的去描绘图形。和判断键值;

此版贪吃蛇是这样的:

  1. 蛇是用数组装起来的,一共给了2000,因为turboC界面是80*25的。
  2. 蛇分为蛇头和蛇尾,蛇头用来在接受键值后控制方向和或改变蛇的状态(例如暂停、加速、吃食物),蛇尾负责移动以及增加蛇的长度。
  3. 蛇吃一个食物50分。
  4. 用0表示改地方没有显示任何东西、用1表示该地方是蛇的身体。而食物有给他另外的数组,它有自己产生食物的随机性。(一组五个食物,吃完一组再来一组),障碍有给他另外的数组,它有自己产生障碍的随机性。(一组十个,通过键值Z来增加),通过这个方法就可以表示出屏幕上每一个点的状态。这个面的状态要随时更新,这个更新极少,只有在产生新食物的时候更新食物位置对应下标的状态和蛇向前移动一步的时更新之前蛇尾的位置和现在蛇头的位置。但是在更新蛇头位置需要判断一下蛇头将要去的位置是否有障碍、食物、其他蛇等等需要判断状态、这时候这个数组的存在就对于这些的判断显极其简单。这时候只需要转化到对应下标,取得对应下标的状态进行判断。这里节省了时间。降低了时间复杂度。
  5. 蛇的位置的存储作为一个比较麻烦的事情,要存储蛇身体的每个点坐标,而且每个点的信息都在改变这是一个极其耗费时间的操作。综合考虑多个方面,最后决定通过循环数组的方式来实现蛇身体坐标的储存。虽然蛇在屏幕上给人的感觉是不停的在移动,但是实际上他改变的只有蛇头、蛇尾。
  6. 大框架如下

while (没死或者没退出) {

        获得键值

        if (延时没到) {

            if (要改变蛇头) {

                蛇头方向改变

            } else {

              继续延时

              方向没变继续按着以前方向走。

            }

        }

        延时重开

        if(还活着){

           移动身体

    }

#include <stdio.h>
#include <bios.h>
#include <stdlib.h>
#include <time.h> 

#define   KEY_UP                 	0
#define   KEY_DOWN              	1
#define   KEY_LEFT              	2
#define   KEY_RIGHT            		3
#define   FINISHED		        4				
#define   QUICK				12386           /*B			*/
#define   SLOW				12654		/*N			*
#define   STOP                	 	14624 		/*KEY_SPACE             */
#define   OBSTACLE                	11386 		/*Z                     */
#define   LIVE                   	1
#define   DIED                   	0 
#define   TURE                   	1
#define   FALSE                  	0 
#define   SNAKE                  	1
#define   WALL				2
#define   NO_SNAKE_NO_BORDER_WALL       0 
#define   NO_FOOD   			0 
#define   KEYVALUE_COUNT         	sizeof(keyValue)/sizeof(int)
#define	  TIME				SPEED
#define   SNAKE_LENGTH           	5

const int keyValue[] = {    
	18432,      /*KEY_UP    */
	20480,	    /*KEY_DOWN  */
	19200,	    /*KEY_LEFT  */
	19712,	    /*KEY_RIGHT */
	283,	    /*KEY_ESC	*/
}; 
//此两数组用数组下标相对应方法直接判断数组内容以及执行,省去ifelse多次判断。
const int move[] = {-80, +80, -1, +1};
const char dir[] = {'^','v','<','>'};
//速度
int SPEED = 3000;
int food[2000] = {0};
//蛇的分布
int doc[2000] = {0};
//蛇移动的数据存储
int snake[2000] = {0};
//障碍物
int Obstacles[2000] = {0};
int sign = 0;
typedef unsigned char Boolean;

int getKey(int oldkey);
int dealKeyConflict(int oldkey, int key);
int getSnakeKey(int oldkey);
Boolean setHeadDir(int key, int snake_head);
Boolean moveSnakeBody(int key, int *head, int *head_index, int *tail_index, int *len);
Boolean moreKey(int key);
Boolean ifDied(int head, int *LIFE, int key);
Boolean ifPrintAlldoc(int len, int head_index, int tail_index);
Boolean productFood ();
Boolean eatFood(int head, int *len, int *score);
void printBorderWall();
void printWord();
void productObstacles();
void dealEnd(int score);

void dealEnd(int score) {
	clrscr();
	gotoxy(35,11);
	printf("Game Over!");
	gotoxy(32,13);
	printf("your score is: %d",score);
	getch();
}

//用随机数和数组下标组合的处理,将产生的放入最后数组的位置上
void productObstacles() {
	int i;
	int m = 0;
	int tmp;
	int WALLTmp;
	int x = 2000;
	
	
	if(1 == sign) {
		sign = 0;
		for (i = 0; i < 2000; i++) {
			if(NO_SNAKE_NO_BORDER_WALL == doc[i] && NO_FOOD == !food[i]) {
				Obstacles[m++] = i;
			}
		}
		srand(time(NULL));
		for(i = 0; i < 10; i++) {
			tmp = rand()%(m + 1);
			WALLTmp = Obstacles[tmp];
			doc[WALLTmp] = 3;
			Obstacles[--x] = WALLTmp;
			Obstacles[tmp] = Obstacles[m--];
		}
		for(i = 0; i < 10; i++) {
			gotoxy(Obstacles[1999-i]%80+1, Obstacles[1999-i]/80+1);
			printf("w");
		}
	}
	
}

//打印结束语
void printWord() {
	gotoxy(37,10);
	printf("Snake-Greedy");
	gotoxy(38,12);
	printf("Start Game");
	gotoxy(42,16);
	printf("Any key to continue......");
	getch();
}

//边界墙
void printBorderWall() {
	int i;
	
	for (i = 0; i< 2000; i++) {
		if(i % 80 == 0 || i%80 == 79 || i <= 79 || i >= 1920){
			doc[i] = 2;
		if(i <= 79 && (i % 80 == 0 || i%80 == 79))
			doc[i] = 0;
		} else if(i >= 1920 && (i % 80 == 0 || i%80 == 79))	{
			doc[i] = 0;
		}	
	}
	for(i = 0; i < 1999; i++) {
		if(2 == doc[i]){
			gotoxy(i%80 + 1,i/80 +1);
			printf("#");
			 
		}
	}
	gotoxy(1,25);
	printf(" ");
}

//吃了食物后的处理以及一组吃完后再来一组的处理
Boolean eatFood(int head, int *len, int *score) {
	int i;
	int x = 0;
	
	for(i = 0; i < 5; i++) {
		if((head%80+1 == food[1999-i]%80+1) && (head/80+1 == food[1999-i]/80+1)) {
			*len += 2;
			*score += 50;
			food[1999-i] = 0;	
		}
	}
	for(i = 0; i < 5; i++) {
		if(0 == food[1999-i]){
			x++;
		}
	}
	if(5 == x) {
		productFood ();
	}
}

//产生食物,与产生障碍物思想一致
Boolean productFood () {
	int i;
	int m = 0;
	int tmp;
	int FOODTmp;
	int x = 2000;
	
	for (i = 0; i < 2000; i++) {
		if(NO_SNAKE_NO_BORDER_WALL == doc[i]) {
			food[m++] = i;
		}
	}
	srand(time(NULL));
	for(i = 0; i < 5; i++) {
		tmp = rand()%(m + 1);
		FOODTmp = food[tmp];
		food[--x] = FOODTmp;
		food[tmp] = food[m--];
	}
	for(i = 0; i < 5; i++) {
		gotoxy(food[1999-i]%80+1, food[1999-i]/80+1);
		printf("0");
	}
}

//此函数是重要代码,判断是否消掉尾巴,公式用头和尾和数组容量2000和长度对比,
Boolean ifPrintAlldoc(int len, int head_index, int tail_index) {
	if((2000 + head_index - tail_index) % 2000 + 1 == len){
		return TURE;
	} else {
		return FALSE;
	}
}

//判断是否死亡(撞墙死、撞到自己死、撞到障碍物死)
Boolean ifDied(int head, int *LIFE, int key) {
	if ((head)%80 == 0 || (head%80) == 79 || (head/80 + 1) <= 1 ||
	 (head/80 + 1) >= 25 || 1 == doc[head+ move[key]] || 3 == doc[head + move[key]]) {
		*LIFE = DIED;
	}
}

//功能性键值、速度、暂停、障碍物。
Boolean moreKey(int key) {
	if (key == QUICK && TIME != 200) {
		SPEED -= 100;
	}
	if (key == SLOW) {
		SPEED += 100;
	}
	if (key == STOP) {
		getch();
	}
	if (key == OBSTACLE && TIME != 500) {
		sign = 1;
	}
}

//次函数是大框架下的灵魂
Boolean moveSnakeBody(int key, int *head, int *head_index, int *tail_index, int *len) {
	//先覆盖头
	gotoxy(*head%80 + 1, *head/80 + 1);
	printf("*"); 
	doc[*head] = 1; 
	
        //看是否打印完
	if(ifPrintAlldoc(*len, *head_index, *tail_index)){  
		gotoxy(snake[*tail_index]%80 + 1, snake[*tail_index]/80 + 1);
		printf(" ");
		doc[snake[*tail_index]] = 0;
		++*tail_index;
	}
        //头总是要动的
	snake[*head_index] = *head;
	
	*head = *head + move[key];
	++*head_index;
		
        //循环数组处理
	*tail_index = *tail_index % 2000;
	*head_index = *head_index % 2000;
           
        //打印头
	gotoxy(*head%80 + 1, *head/80 + 1);
	printf("%c", dir[key]);
	doc[*head] = 1;
}
 
 
//头的处理函数
Boolean setHeadDir(int key, int snake_head) {
	gotoxy(snake_head%80 + 1, snake_head/80 + 1);
	printf("%c", dir[key]);
}

//获得键值,判断蛇头方向
int getSnakeKey(int oldkey) {
	int i;
	int key;
	
	key = getKey(keyValue[oldkey]);
	moreKey(key);
	if (-1 == key) {
		return -1;
	}
	for (i = 0;i < KEYVALUE_COUNT; i++) {
		if(key == keyValue[i]){
			return i;
		}
	}
	return -1;
}

//处理按键冲突,向左的时候向右不执行,向上的时候向下不执行。
int dealKeyConflict(int oldkey, int key) {
	if (oldkey == keyValue[KEY_RIGHT] && key == keyValue[KEY_LEFT]) {
		return -1;
	} else if (oldkey == keyValue[KEY_LEFT] && key == keyValue[KEY_RIGHT]) {
		return -1;
	} else if (oldkey == keyValue[KEY_UP] && key == keyValue[KEY_DOWN]) {
		return -1;
	} else if (oldkey == keyValue[KEY_DOWN] && key == keyValue[KEY_UP]) {
		return -1;
	} else if (oldkey == key) {
		return -1;
	}
}

//获得键值,(只要按了就要判断)
int getKey(int oldkey) {
	int num;
	int key;
	
	num = bioskey(1);
	if (!num){
	 	return -1;
	}
	key = bioskey(0);
	
	if(-1 == dealKeyConflict(oldkey, key)) {
		return -1;
	}
	
	return key;
}


int main() {
	int key = KEY_RIGHT;
	int num = 0;
	int delay = 0;
	int snake_tail_index = 0;
	int snake_head_index = 0;
	int LIFE = LIVE;
	int snake_head = 1000;
	int len = SNAKE_LENGTH;
	int score = 0;
	
	clrscr();
	printWord();
	clrscr();
	printBorderWall();
		
	while (FINISHED != key && LIFE == LIVE) {
		num = getSnakeKey(key);
		
		if (delay < TIME) {
			if (-1 != num) {
				key = num;
				setHeadDir(key, snake_head);
			} else {
				++delay;
				continue;
			}
		}
		delay = 0;
		productObstacles();
		ifDied(snake_head, &LIFE, key);
		if(LIFE == LIVE){
			eatFood(snake_head, &len, &score);
			moveSnakeBody(key, &snake_head, &snake_head_index, &snake_tail_index, &len);
		} else {
			getch(); 
		}
	}
	dealEnd(score);
	return 0;
}
           

继续阅读