天天看點

貪吃蛇(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;
}
           

繼續閱讀