貪吃蛇循環隊列實現

19/7/24

更新

這幾天想寫一個32操作系統,操作系統上面跑東西啊要,就又拿着貪吃蛇鞭屍了。。。。

這次用循環隊列實現,效果比數組好,因爲避免了數據的反覆後移。只需要直接入隊,出隊就行

屏幕的刷新上面,沒有采取上一次的整體刷新,代替的是確定光標位置,在光標處刷新。

更詳細註釋見代碼

/*
食物不能產生在身上未加
//////////////////////////////////////////////
使用順序循環隊列實現
kbhit()檢測鍵盤是否有輸入,有返回非零值,否則0


撞牆會死
前進過程中不能突然折回

                    by shuiyihang0981   19/7/24

//////////////////////////////////////////////
*/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
#define MAX_LEN  100
#define Side_X    30
#define Side_Y    25//牆的邊界
//#define  DEBUG
char  dir='s',last_dir='s';//設定默認方向
int test1,test2,test3,test4;//測試bug調用
int count=0,srand_x=0,srand_y=0;
int temp;
bool Game_over=false;
typedef struct
{
	int x,y;
}Pos;
typedef struct
{
	Pos vex;
	bool exist;
}Goal;
typedef struct
{
	Pos date[MAX_LEN];
	int head,rear;

}Snake;
void gotoxy(int x,int y)//任意點確定光標,參考MSDN
{
    COORD point={x,y};
    HANDLE HOutput=GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(HOutput,point);
}
void Init(Snake *S)//牆,蛇初始化
{
	S->head=S->rear=0;
	S->date[S->rear].x=2;
	S->date[S->rear].y=3;
	S->rear=(S->rear+1)%MAX_LEN;
	gotoxy(S->date[S->rear-1].x,S->date[S->rear-1].y);
	printf("O");
	gotoxy(Side_X+5,Side_Y/2-5);
	printf("Snake Game");
	gotoxy(0,Side_Y);
	printf("---------------------------------\n");
	gotoxy(Side_X+5,Side_Y/2);
	printf("Core:%d",count);
	for(int i=0;i<Side_Y;i++)
    {
        gotoxy(0,i);
        gotoxy(Side_X,i);
        printf("|");
    }
}
void CreFood(Goal *food)//食物產生
{
	if(food->exist==false)
	{

		food->vex.x=srand_x;
		food->vex.y=srand_y;
		food->exist=true;
		gotoxy(food->vex.x,food->vex.y);
		printf("*");
	}
}
/*
蛇只管前行,遇到食物入隊,此時不需要尾巴出隊
沒有吃到食物,新的隊首入隊,尾巴出隊
*/
void GoHead(Snake *S,Goal *food)//蛇前行
{
	srand_x=rand()%Side_X;
	temp=((S->rear)-1+MAX_LEN)%MAX_LEN;//0的前一個應該是9,而不是-1
	switch(dir)
	{

		case 's':
			if(last_dir!='w')//Up
            {
                S->date[S->rear].y=(S->date[temp].y+1);
                S->date[S->rear].x=(S->date[temp].x);
            }else
            {
                Game_over=true;
                gotoxy(Side_X+5,Side_Y/2+2);
                printf("Bite Self!");
            }
			break;
		case 'w':
			if(last_dir!='s')//Down
            {
                S->date[S->rear].y=(S->date[temp].y-1);
                S->date[S->rear].x=(S->date[temp].x);
            }else
            {
                Game_over=true;
                gotoxy(Side_X+5,Side_Y/2+2);
                printf("Bite Self!");
            }
			break;
		case 'a':
			if(last_dir!='d')//Left
            {
                S->date[S->rear].x=(S->date[temp].x-1);
                S->date[S->rear].y=(S->date[temp].y);
            }else
            {
                Game_over=true;
                gotoxy(Side_X+5,Side_Y/2+2);
                printf("Bite Self!");
            }
			break;
		case 'd':
			if(last_dir!='a')//Right
            {
                S->date[S->rear].x=(S->date[temp].x+1);
                S->date[S->rear].y=(S->date[temp].y);
            }else
            {
                Game_over=true;
                gotoxy(Side_X+5,Side_Y/2+2);
                printf("Bite Self!");
            }
			break;
		default:
			break;

	}
	#ifdef   DEBUG
	test1=S->date[S->rear].x;
	test2=S->date[S->rear].y;
	#endif // DEBUG
	if((S->date[S->rear].x)<0||(S->date[S->rear].x)>Side_X||(S->date[S->rear].y)<0||(S->date[S->rear].y)>Side_Y)//撞牆
    {
        Game_over=true;
        gotoxy(Side_X+5,Side_Y/2+2);
        printf("Brick Wall!");
    }
    else
    {
        gotoxy(S->date[S->rear].x,S->date[S->rear].y);
        printf("O");
        Sleep(0.5);
        if(food->exist&&(S->date[S->rear].x==food->vex.x)&&(S->date[S->rear].y==food->vex.y))
        {
            count++;
            food->exist=false;
            gotoxy(Side_X+10,Side_Y/2);
            printf("%d",count);
        }else
        {
            gotoxy(S->date[S->head].x,S->date[S->head].y);
            printf(" ");
            Sleep(0.5);
            S->head=(S->head+1)%MAX_LEN;
        }
        S->rear=(S->rear+1)%MAX_LEN;
    }

}
void PlayInput()//檢測輸入
{
    srand_y=rand()%Side_Y;
	if(kbhit())//<conio.h>
	{
	    last_dir=dir;//上一次的方向,規定不能突然折返蛇身
		dir=getch();
		if(dir!='w'&&dir!='a'&&dir!='s'&&dir!='d')
        {
            dir=last_dir;
        }
	}
}
int main()
{
	srand(10);
	Snake Q;
	Goal  food;
	Init(&Q);
	while(false==Game_over)
	{
		PlayInput();
		GoHead(&Q,&food);
		CreFood(&food);
		Sleep(200);//windows.h//遊戲速度設定
	}
	gotoxy(Side_X+5,Side_Y/2);
    printf("Game OVER! Count:%d",count);
    gotoxy(0,Side_Y+2);
	return 0;
}

 

 

 

 

 

 

 

 

上一次的數組實現,有興趣看一下,就不推薦了

貪吃蛇比較簡單,要了解它的步驟:

如果你可以單獨對某個點重畫,就要利用只有蛇頭,蛇尾會變的特點,這樣會快很多。

我是在windows下跑的,通過cls命令清空,所以會有點閃,sleep函數用於調節蛇的速度

O是蛇身,*是食物

//貪吃蛇數組實現,無限生命版(撞牆不會掛)
#include<stdio.h>
#include<conio.h>
#include<windows.h>//窗口大小設爲20,25;
#include<stdlib.h>
char str;
int num=0;
int count=0;
bool eated=false;
int rand_x,rand_y;//提前準備着方便使用
struct Snake{
	int x;
	int y;
	char dir;
}mole[50];//可以設置更長>50
struct food{
	int x;
	int y;
}bread;
/////////////初始化
void init()
{
	mole[0].x=10;
	mole[0].y=15;
	bread.x=5;
	bread.y=5;
	//mole[1].dir='a';//默認向左

}
/////////////方向控制
void PlayInput()
{
	rand_y=rand()%20;
	if(kbhit())
	{
		str=getch();
		switch (str){
			case 'w':
				mole[num].dir='w';//可以直接賦值,防止誤輸入
				break;
			case 'a':
				mole[num].dir='a';
				break;
			case 's':
				mole[num].dir='s';
				break;
			case 'd':
				mole[num].dir='d';
				break;
			default:
				break;
		}
	}
}
/////////////屏幕重畫
void show()
{
	bool flag=false;
	for(int i=0;i<20;i++)
	{
		for(int j=0;j<25;j++)
		{
			for(int k=0;k<=num;k++)
			{
				if(mole[k].x==j&&mole[k].y==i)
				{
					printf("O");
					flag=true;
					break;
				}
			}
			if(bread.x==j&&bread.y==i)//畫食物
			{
				printf("*");
				//flag=true;
			}
			if(flag==false)printf(" ");
			else flag=false;
		}
		printf("\n");
	}
	printf("Your Score:%d\n", count);
}
/////////////蛇移動
void SnakeMove()//清屏重畫
{
	for(int i=0;i<num;i++)
	{
		mole[i]=mole[i+1];
	}
	rand_x=rand()%25;
	switch (mole[num].dir){
		case 'w':
			mole[num].y=mole[num].y-1;
			if(mole[num].y<0)mole[num].y=19;
			break;
		case 'a':
			mole[num].x=mole[num].x-1;
			if(mole[num].x<0)mole[num].x=24;
			break;
		case 's':
			mole[num].y=mole[num].y+1;
			if(mole[num].y>19)mole[num].x=0;
			break;
		case 'd':
			mole[num].x=mole[num].x+1;
			if(mole[num].x>24)mole[num].x=0;
			break;
	}
	system("cls");//如果不刷屏的話,只刪除蛇尾,效果會更好
	show();
}
////////////食物產生
void creatFood()
{
	if(eated==true)//食物被吃掉隨即再次產生
	{
		//範圍是25,20
		bread.x=rand_x;
		bread.y=rand_y;
		eated=false;
	}
}
////////////蛇吃食
void FoodEat()
{
	SnakeMove();
	switch (mole[num].dir){
	case 'w':
		if((mole[num].y-1)==bread.y&&mole[num].x==bread.x)
		{
			num++;
			mole[num].x=bread.x;
			mole[num].y=bread.y;
			eated=true;
			count++;
		}
		break;
	case 'a':
		if((mole[num].x-1)==bread.x&&mole[num].y==bread.y)
		{
			num++;
			mole[num].x=bread.x;
			mole[num].y=bread.y;
			eated=true;
			count++;
		}
		break;
	case 's':
		if((mole[num].y+1)==bread.y&&mole[num].x==bread.x)
		{
			num++;
			mole[num].x=bread.x;
			mole[num].y=bread.y;
			eated=true;
			count++;
		}
		break;
	case 'd':
		if((mole[num].x+1)==bread.x&&mole[num].y==bread.y)
		{
			num++;
			mole[num].x=bread.x;
			mole[num].y=bread.y;
			eated=true;
			count++;
		}
		break;
}
	creatFood();
}
int main()
{
	srand(10);
	init();
	while(1)
	{
		PlayInput();
		FoodEat();
		Sleep(250);
	}
	return 0;
}
//-----------------------------By shuiyihang------------------------------------//
//-----------------------------CodeBlocks下測試----------------------------------//

程序肯定是有Bug的,但是目前來看還行,就是有點閃,還可以優化,當然你也可以考慮使用鏈表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章