/*
贪吃蛇
规则:在BOUNDRY*BOUNDRY的矩阵上有一条初始长度为2的蛇,BOUNDRY*BOUNDRY矩阵内
随机产生一个食物,当蛇与食物相遇时,长度加1,运动方向由方向键控制。初始向右。
流程如下:
开始->监听键盘->方向键1,暂停键2,其他键3
方向键1->下一秒蛇身按照方向键运动->判断->蛇身是否与便捷或自身相碰->是4,否5
是4->游戏结束
否5->判断:是否碰到食物->是6,否7
是6->蛇身长度加1,蛇头坐标变为食物所在坐标->监听键盘
否7->监听键盘
暂停键2:暂停
其他键3:无动作
关键的一个函数:kbhit(),非阻塞函数,用于判断是否按下键盘,按下返回键值,否则返回0
迷你了TC的gotoxy(int x,int y)函数,从而解决了屏幕闪烁问题
*/
/*Made by Shadow*/
/*---------------CODE-------------*/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>
#include<windows.h>
#define BOUNDRY 21
int area[BOUNDRY][BOUNDRY];
/*Map:
0-normal
1-snake
2-food
3-boundry
4-obstacle(optional)*/
struct snake
{
int x,y;/*each node's location*/
struct snake *next;/*a pionter to the next node*/
}*head;
int foodon=0;/*a flag wether there's food on the map*/
char direction='d';/*use w-up,s-down,a-left,d-right*/
float speed=0.5;/*initilize speed*/
int s_length=2;/*snake's length*/
int level=1;/*game level which is related to snake's length*/
struct
{
int x,y;
}food;/*food's location*/
void makemap()/*initialization of map*/
{
int i,j;
for (i=0;i<BOUNDRY;i++)
for (j=0;j<BOUNDRY;j++) area[i][j]=0;
for (i=0,j=0;j<BOUNDRY;j++) area[i][j]=3;
for (i=0,j=0;i<BOUNDRY;i++) area[i][j]=3;
for (i=BOUNDRY-1,j=0;j<BOUNDRY;j++) area[i][j]=3;
for (i=0,j=BOUNDRY-1;i<BOUNDRY;i++) area[i][j]=3;
//area[(int)BOUNDRY/2][(int)BOUNDRY/2]=1;
//area[(int)BOUNDRY/2-1][(int)BOUNDRY/2-1]=1;
}
void locatesnake()/*head for finding snake's location*/
{
struct snake *p_snake;/*current node of snake*/
for (p_snake=head;p_snake->next!=NULL;p_snake=p_snake->next)
area[p_snake->x][p_snake->y]=1;
area[p_snake->x][p_snake->y]=1;
}
void locatefood()/*create food in a normal block*/
{
do
{
food.x=(int)(rand()/(RAND_MAX+1.0)*BOUNDRY);
food.y=(int)(rand()/(RAND_MAX+1.0)*BOUNDRY);
}while(area[food.x][food.y]!=0);
foodon=1;
area[food.x][food.y]=2;
}
void createsnake()/*initilize the snake*/
{
head=(struct snake *)malloc(sizeof(struct snake));
head->x=(int)BOUNDRY/2;
head->y=(int)BOUNDRY/2;
head->next=(struct snake *)malloc(sizeof(struct snake));
head->next->x=head->x-1;
head->next->y=head->y;/*creat a snake in the center of the matrix*/
head->next->next=NULL;
}
void freesnake()/*to free the allocated memories*/
{
struct snake *p_snake;
for (p_snake=head;p_snake->next!=NULL;p_snake=p_snake->next)
{
free(head);
head=p_snake;
}
free(p_snake);/*to free the last allocated memory*/
}
void key_listener(float sp)/*to listen the keybord,sp for the speed*/
{
char key;
struct snake *p_snake;
if(kbhit()) key=getch();
else return;/*no key is pressed*/
if ((key>='A')&&(key<='Z')) key+=32;
switch (key)
{
case 'p':
if(speed!=0) speed=0;
else speed=sp;
break;
case 'w':
direction='w';
break;
case 'a':
direction='a';
break;
case 's':
direction='s';
break;
case 'd':
direction='d';
break;
case 'e':
freesnake();
system("cls");
printf("/n/nYour Record:/nYour snake's length: %d/nTime you remained: %d s/n",s_length,(int)(clock()/CLOCKS_PER_SEC));
puts("/n/nThanks for playing!");
system("pause");
exit(0);
case 'c': /*for changing speed*/
printf("Please enter a new speed interval:(one move/per second)");
scanf("%f",&speed);
default:;
}
}
struct snake *snakemove()
{
/*return the snake's head pointer if the snake is alive,or return NULL
首先判断移动之后的格子是否是边界或者蛇自身,都不是在判断是否食物,
也不是再移动*/
struct snake *p_snake;
int last_x,last_y,cur_x,cur_y;
switch (direction)
{
case 'w':/*for moving upward*/
if ((area[head->x][head->y-1]==3)||(area[head->x][head->y-1]==1)) return NULL;
else if (area[head->x][head->y-1]==2)
{
p_snake=head;
head=(struct snake *)malloc(sizeof(struct snake));
head->x=p_snake->x;
head->y=p_snake->y-1;
head->next=p_snake;/*p_snake在之前head的位置*/
foodon=0;
s_length++;
return head;
}
else /*area[head->x][head->y-1]==0,just move to the next block*/
{
cur_x=head->x;
cur_y=head->y;
head->y-=1;
for (p_snake=head->next;p_snake->next!=NULL;p_snake=p_snake->next)
{
last_x=p_snake->x;
last_y=p_snake->y;
p_snake->x=cur_x;
p_snake->y=cur_y;
cur_x=last_x;
cur_y=last_y;
}/*only change the location of each node,not the chain*/
p_snake->x=cur_x;
p_snake->y=cur_y;
/*the last node's x/y*/
return head;
}
break;
case 'a':/*for moving left*/
if ((area[head->x-1][head->y]==3)||(area[head->x-1][head->y]==1)) return NULL;
else if (area[head->x-1][head->y]==2)
{
p_snake=head;
head=(struct snake *)malloc(sizeof(struct snake));
head->x=p_snake->x-1;
head->y=p_snake->y;
head->next=p_snake;/*p_snake在之前head的位置*/
foodon=0;
s_length++;
return head;
}
else /*area[head->x-1][head->y]==0,just move to the next block*/
{
cur_x=head->x;
cur_y=head->y;
head->x-=1;
for (p_snake=head->next;p_snake->next!=NULL;p_snake=p_snake->next)
{
last_x=p_snake->x;
last_y=p_snake->y;
p_snake->x=cur_x;
p_snake->y=cur_y;
cur_x=last_x;
cur_y=last_y;
}/*only change the location of each node,not the chain*/
p_snake->x=cur_x;
p_snake->y=cur_y;
/*the last node's x/y*/
return head;
}
break;
case 'd':/*for moving right*/
if ((area[head->x+1][head->y]==3)||(area[head->x+1][head->y]==1)) return NULL;
else if (area[head->x+1][head->y]==2)
{
p_snake=head;
head=(struct snake *)malloc(sizeof(struct snake));
head->x=p_snake->x+1;
head->y=p_snake->y;
head->next=p_snake;/*p_snake在之前head的位置*/
foodon=0;
s_length++;
return head;
}
else /*area[head->x+1][head->y]==0,just move to the next block*/
{
cur_x=head->x;
cur_y=head->y;
head->x+=1;
for (p_snake=head->next;p_snake->next!=NULL;p_snake=p_snake->next)
{
last_x=p_snake->x;
last_y=p_snake->y;
p_snake->x=cur_x;
p_snake->y=cur_y;
cur_x=last_x;
cur_y=last_y;
}/*only change the location of each node,not the chain*/
p_snake->x=cur_x;
p_snake->y=cur_y;
/*the last node's x/y*/
return head;
}
break;
case 's':/*for moving downward*/
if ((area[head->x][head->y+1]==3)||(area[head->x][head->y+1]==1)) return NULL;
else if (area[head->x][head->y+1]==2)
{
p_snake=head;
head=(struct snake *)malloc(sizeof(struct snake));
head->x=p_snake->x;
head->y=p_snake->y+1;
head->next=p_snake;/*p_snake在之前head的位置*/
foodon=0;
s_length++;
return head;
}
else /*area[head->x][head->y+1]==0,just move to the next block*/
{
cur_x=head->x;
cur_y=head->y;
head->y+=1;
for (p_snake=head->next;p_snake->next!=NULL;p_snake=p_snake->next)
{
last_x=p_snake->x;
last_y=p_snake->y;
p_snake->x=cur_x;
p_snake->y=cur_y;
cur_x=last_x;
cur_y=last_y;
}/*only change the location of each node,not the chain*/
p_snake->x=cur_x;
p_snake->y=cur_y;
/*the last node's x/y*/
return head;
}
break;
}/*switch strcuture ended*/
}
void gotoxy(int x,int y) /*gotoxy的替代函数*/
{
COORD c;
c.X=x-1;
c.Y=y-1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}
void refreshscreen()
{
gotoxy(1,1);
int i,j;
printf("/t/tYour level: %d/n/n",level);
for (j=0;j<BOUNDRY;j++)
{
printf("/t/t");
for (i=0;i<BOUNDRY;i++)
{
switch (area[i][j])
{
case 0: /*normal block*/
printf(" ");
break;
case 1: /*snake body*/
printf("◎");
break;
case 2: /*food*/
printf("◆");
break;
case 3: /*Boundry*/
printf("☆");
break;
default:
;
}/*switch ended*/
}
putchar('/n');
}
}
int main()
{
struct snake *p;
srand((unsigned)time(NULL));/*initilize rand() seed*/
float speedhold=0.0;/*initilize speedholder*/
createsnake();
makemap();
locatesnake();
locatefood();
clock_t t1,t2;
t1=t2=clock();/*set 2 time spots*/
/*-------Game Helper-------*/
printf("/n/n/t/tGame SNAKE/n/nWelcome to my first game:SNAKE!/n");
printf("/nHow to play:/n Your little snake has only 2-length long body, there will be a food in the boundry.Try to move your snake reach it.");
printf("When your snake eats a block of food,he will grow longer.Try your best to make him the longest!/n");
printf("/nGame Tips:/n1.To change the direction of your snake, use:/n/tw-upward/n/ta-left/n/td-right/n/ts-downward/n");
printf("/n2.Press p for PAUSE at any time you want to pause the game./n");
printf("/n3.Press e for EXIT at any time you want to exit the game./nYou'll get your grade before you exit./n");
printf("/n4.Every more 10-length long body will level up./nThe speed will be faster at the same time./n");
printf("/nAttention:If your direction towards snake's body.YOU DEAD./n/tThe same thing happened when the snake knocks against the wall./n");
printf("/n/t/tThat's all. Just Have Fun!/n");
printf("/t/t/tThis game is written by Shadow./n");
system("pause");
system("cls");
/*-------Start The Game-----*/
refreshscreen();
while (1)
{
if ((float)(t2-t1)/CLOCKS_PER_SEC>=speed)
{
speedhold=speed;
key_listener(speed);
if (speed==0) /*to pause the game*/
{
puts("The game is paused.");
while (speed!=speedhold)
{
key_listener(speedhold);
}
}
else
{
p=snakemove();
if (p==NULL)
{
freesnake();
system("cls");
printf("/n/nYour Record:/nYour snake's length: %d/nTime you remained: %d s/n",s_length,(int)(clock()/CLOCKS_PER_SEC));
puts("/n/nThanks for playing!");
system("pause");
exit(0);
}
else
{
level=(int)(s_length/10+1);
if (speed>=0.1)speed=0.5-(float)s_length/100;
makemap();
if (foodon==0) locatefood();
locatesnake();
area[food.x][food.y]=2;
}
}
refreshscreen();
printf("Your snake's length: %d/tTime you remained: %d s/n",s_length,(int)(clock()/CLOCKS_PER_SEC));
t1=clock();
}
else t2=clock();
}
return 0;
}