#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#include<bios.h>
#include<graphics.h>
#include<malloc.h>
#include<stdlib.h>
#define VK_UP 0x4800
#define VK_DOWN 0x5000
#define VK_LEFT 0x4b00
#define VK_RIGHT 0x4d00
#define VK_ESC 0x011b
#define VK_ENTER 0x1c0d
#define TIME_UNIT 100 /*this match's time unit(millisecond)*/
#define GAME_TIME 8000 /*every game's time(in TIME_UNIT)*/
enum Direction{UP,DOWN,LEFT,RIGHT};
struct SnakeSegment{
int head_x,head_y; /*the position of the left-up point */
int block_num; /*the number of blocks in this segment*/
enum Direction dir; /*direction*/
struct SnakeSegment* prev;
struct SnakeSegment* next;
};
struct GreedySnake{
int seg_num; /*the number of snake's segments*/
struct SnakeSegment* first;
struct SnakeSegment* last;
int width; /*the snake's width*/
int block_length; /*a block's length*/
};
int get_velocity(int grade)
{
int v;
switch(grade){
case 1:
v=12;
break;
case 2:
v=8;
break;
case 3:
v=4;
break;
case 4:
v=2;
break;
case 5:
v=1;
break;
}
return v;
}
void initialize_snake(struct GreedySnake* s)
{
s->width=2;
s->block_length=3;
s->seg_num=1;
s->first=s->last=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
s->first->head_x=20;
s->first->head_y=0;
s->first->block_num=13;
s->first->dir=DOWN;
s->first->prev=s->first->next=NULL;
}
void show_current_status(struct GreedySnake* s)
{
int hx,hy,tx,ty;
struct SnakeSegment* f=s->first;/*begin from the fist segment*/
cleardevice();
/*show a segment everytime*/
while(f != NULL){
hx=f->head_x;
hy=f->head_y;
switch(f->dir){
case UP:
case DOWN:
tx=hx+s->width;
ty=hy+f->block_num * s->block_length;
break;
case LEFT:
case RIGHT:
tx=hx+f->block_num * s->block_length;
ty=hy+s->width;
break;
}
bar(hx,hy,tx,ty);
f=f->next;/*show the next segment*/
}
}
void update_status(struct GreedySnake* s,enum Direction d,int grow_block_num)
{
struct SnakeSegment* f=s->first;
struct SnakeSegment* l=s->last;
struct SnakeSegment* add;
int seg_num=s->seg_num;
int first_segment_changed=1;/*when the quantity of a snake's segments is over or equal with 2,this variable is useful*/
if(seg_num==1){
/*only one segment*/
switch(f->dir){
case UP:
switch(d){
case UP:
f->head_y -= s->block_length;
break;
case LEFT:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=LEFT;
if(f->block_num<=0){
add->head_x=f->head_x + s->width - s->block_length;
add->head_y=f->head_y + s->block_length - s->width;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
f->head_y += s->block_length;
add->head_x = f->head_x - s->block_length;
add->head_y = f->head_y;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
case RIGHT:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=RIGHT;
if(f->block_num<=0){
add->head_x=f->head_x;
add->head_y=f->head_y + s->block_length - s->width;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
f->head_y += s->block_length;
add->head_x=f->head_x + s->width;
add->head_y=f->head_y;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
}
break;
case DOWN:
switch(d){
case DOWN:
f->head_y += s->block_length;
break;
case LEFT:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=LEFT;
if(f->block_num<=0){
add->head_x=f->head_x + s->width - s->block_length;
add->head_y=f->head_y;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
add->head_x=f->head_x - s->block_length;
add->head_y=f->head_y + (f->block_num * s->block_length) - s->width;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
case RIGHT:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=RIGHT;
if(f->block_num<=0){
add->head_x=f->head_x;
add->head_y=f->head_y;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
add->head_x=f->head_x + s->width;
add->head_y=f->head_y + (f->block_num * s->block_length) - s->width;;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
}
break;
case LEFT:
switch(d){
case LEFT:
f->head_x -= s->block_length;
break;
case UP:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=UP;
if(f->block_num<=0){
add->head_x=f->head_x + s->block_length - s->width;
add->head_y=f->head_y + s->width - s->block_length;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
f->head_x += s->block_length;
add->head_x=f->head_x;
add->head_y=f->head_y - s->block_length;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
case DOWN:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=DOWN;
if(f->block_num<=0){
add->head_x=f->head_x + s->block_length - s->width;
add->head_y=f->head_y;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
f->head_x += s->block_length;
add->head_x=f->head_x;
add->head_y=f->head_y + s->width;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
}
break;
case RIGHT:
switch(d){
case RIGHT:
f->head_x += s->block_length;
break;
case UP:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=UP;
if(f->block_num<=0){
add->head_x=f->head_x;
add->head_y=f->head_y + s->width - s->block_length;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
add->head_x=f->head_x + (f->block_num * s->block_length) - s->width;
add->head_y=f->head_y - s->block_length;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
case DOWN:
f->block_num--;
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=DOWN;
if(f->block_num<=0){
add->head_x=f->head_x;
add->head_y=f->head_y;
add->prev=add->next=NULL;
free(f);
f=l=add;
}
else{
add->head_x=f->head_x + (f->block_num * s->block_length) - s->width;
add->head_y=f->head_y + s->width;
f->prev=add;
add->next=f;
add->prev=NULL;
f=add;
seg_num++;
}
s->first=f;
s->last=l;
s->seg_num=seg_num;
break;
}
break;
}
}
else{
/*deal with the first segment*/
switch(f->dir){
case UP:
switch(d){
case UP:
f->block_num++;
f->head_y -= s->block_length;
break;
case DOWN:
first_segment_changed=0;
break;
case LEFT:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=LEFT;
add->head_x = f->head_x - s->block_length;
add->head_y = f->head_y;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
case RIGHT:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=RIGHT;
add->head_x = f->head_x + s->width;
add->head_y = f->head_y;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
}
break;
case DOWN:
switch(d){
case UP:
first_segment_changed=0;
break;
case DOWN:
f->block_num++;
break;
case LEFT:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=LEFT;
add->head_x = f->head_x - s->block_length;
add->head_y = f->head_y + (f->block_num * s->block_length) - s->width;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
case RIGHT:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=RIGHT;
add->head_x = f->head_x + s->width;
add->head_y = f->head_y + (f->block_num * s->block_length) - s->width;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
}
break;
case LEFT:
switch(d){
case LEFT:
f->block_num++;
f->head_x -= s->block_length;
break;
case RIGHT:
first_segment_changed=0;
break;
case UP:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=UP;
add->head_x = f->head_x;
add->head_y = f->head_y - s->block_length;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
case DOWN:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=DOWN;
add->head_x = f->head_x;
add->head_y = f->head_y + s->width;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
}
break;
case RIGHT:
switch(d){
case LEFT:
first_segment_changed=0;
break;
case RIGHT:
f->block_num++;
break;
case UP:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=UP;
add->head_x = f->head_x + (f->block_num * s->block_length) - s->width;
add->head_y = f->head_y - s->block_length;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
case DOWN:
add=(struct SnakeSegment*)malloc(sizeof(struct SnakeSegment));
add->block_num=1;
add->dir=DOWN;
add->head_x = f->head_x + (f->block_num * s->block_length) - s->width;
add->head_y = f->head_y + s->width;
f->prev=add;
add->next=f;
add->prev=NULL;
s->first=add;
s->seg_num++;
break;
}
break;
}
/*deal with the last segment if the first segment has changed*/
if(first_segment_changed==1){
l->block_num--;
if(l->block_num <= 0){
l->prev->next=NULL;
s->last=l->prev;
free(l);
s->seg_num--;
}
else{
if(l->dir==DOWN)
l->head_y += s->block_length;
else if(l->dir==RIGHT)
l->head_x += s->block_length;
}
}
}
/*execute the grow blocks*/
if(grow_block_num>0){
l=s->last;
l->block_num += grow_block_num;
if(l->dir==DOWN)
l->head_y -= grow_block_num * s->block_length;
else if(l->dir==RIGHT)
l->head_x -= grow_block_num * s->block_length;
}
}
int out_range(struct GreedySnake*s)
{
struct SnakeSegment* f=s->first;
struct SnakeSegment* l=s->last;
int seg_num=s->seg_num;
int f_minx,f_miny,f_maxx,f_maxy;
int l_minx,l_miny,l_maxx,l_maxy;
/*judge if the first segment comes up against bordlines*/
switch(f->dir){
case UP:
if(f->head_y < 0)
return 1;
break;
case DOWN:
if( ( f->head_y + (f->block_num * s->block_length) ) > 480)
return 1;
break;
case LEFT:
if(f->head_x < 0)
return 1;
break;
case RIGHT:
if( ( f->head_x + (f->block_num * s->block_length) ) > 640)
return 1;
break;
}
/*judge if the first segment comes up against other segments*/
f_minx=f->head_x;
f_miny=f->head_y;
switch(f->dir){
case UP:
case DOWN:
f_maxx=f->head_x + s->width;
f_maxy=f->head_y + (f->block_num * s->block_length);
break;
case LEFT:
case RIGHT:
f_maxx=f->head_x + (f->block_num * s->block_length);
f_maxy=f->head_y + s->width;
break;
}
while(seg_num>=4){
l_minx=l->head_x;
l_miny=l->head_y;
switch(l->dir){
case UP:
case DOWN:
l_maxx=l->head_x + s->width;
l_maxy=l->head_y + (l->block_num * s->block_length);
break;
case LEFT:
case RIGHT:
l_maxx=l->head_x + (l->block_num * s->block_length);
l_maxy=l->head_y + s->width;
break;
}
if( ( (f_minx>=l_minx && f_minx<=l_maxx) && (f_miny>=l_miny && f_miny<=l_maxy) ) || ( (f_maxx>=l_minx && f_maxx<=l_maxx) && (f_maxy>=l_miny && f_maxy<=l_maxy) ) )
return 1;
l=l->prev;
seg_num--;
}
/*the first segment come up against nothing*/
return 0;
}
void initialize_game()
{
int gdriver,gmode;
/*configure the monitor*/
gdriver=VGA;
gmode=VGAHI;
registerbgidriver(EGAVGA_driver);
/*change to the graph mode*/
initgraph(&gdriver,&gmode,"");
/*initialize the screen*/
setbkcolor(WHITE);
cleardevice();
setfillstyle(1,RED);
}
int play_game(struct GreedySnake* s,int grade)
{
int key;
int velocity;/*the snake's moving velocity(in TIME_UNIT) in the current game*/
int time_count;/*the time(in TIME_UNIT) which the current game has used*/
int grow_interval;
int grow_block_num;
int no_grow_time;
int need_grow;
enum Direction update_dir;
/*configure this game*/
time_count=0;
velocity=get_velocity(grade);
grow_interval=100;
grow_block_num=8;
no_grow_time=0;
need_grow=0;
/*initialize the snake and show it*/
initialize_snake(s);
show_current_status(s);
for(;;)
{
if(bioskey(1) != 0){/*user pressed a key*/
key=bioskey(0);
switch(key){
case VK_UP:
update_dir=UP;
break;
case VK_DOWN:
update_dir=DOWN;
break;
case VK_LEFT:
update_dir=LEFT;
break;
case VK_RIGHT:
update_dir=RIGHT;
break;
case VK_ESC:
return 0;
}
}
else
/*follow the current direction to move*/
update_dir=s->first->dir;
/*update the snake's status*/
if(need_grow==0)
update_status(s,update_dir,0);
else
update_status(s,update_dir,grow_block_num);
/*show the snake's current status*/
show_current_status(s);
/*judge if the snake is out of range*/
if(out_range(s))
return 1;
delay(velocity * TIME_UNIT);
time_count += velocity;
/*judge if this game is time-expired*/
if(time_count>=GAME_TIME)
return 2;
if(need_grow==1){
need_grow=0;
no_grow_time += velocity;
}
else{
no_grow_time += velocity;
if(no_grow_time >= grow_interval){
need_grow=1;
no_grow_time=0;
}
}
}
}
void end_game(struct GreedySnake* s)
{
struct SnakeSegment* temp;
struct SnakeSegment* f=s->first;
/*close the graph mode*/
closegraph();
/*set allocated memory free*/
while(f != NULL){
temp=f;
f=f->next;
free(temp);
}
}
int main(){
char ch;
struct GreedySnake snake;
int end_match;/*control the match's end*/
int key;
int grade;/*game difficulty*/
int game_result;
/*let the user select a game*/
do{
clrscr();
gotoxy(30,12);
cprintf("Start the game?(Y/N):");
ch=getchar();
ch=tolower(ch);
}while(ch != 'y' && ch != 'n');
if(ch =='n'){
clrscr();
return 0;
}
else{
/*let the user decide the game's difficulty*/
do{
clrscr();
gotoxy(30,12);
cprintf("Select the grade(1-5):");
ch=getchar();
}while(ch!='1' && ch!='2' && ch!='3' && ch!='4' && ch !='5');
switch(ch){
case '1':
grade=1;
break;
case '2':
grade=2;
break;
case '3':
grade=3;
break;
case '4':
grade=4;
break;
case '5':
grade=5;
break;
}
}
/*start the match*/
end_match=0;
do{
initialize_game();
game_result=play_game(&snake,grade);
end_game(&snake);
if(game_result==0){
/*abort the match*/
end_match=1;
}
else if(game_result==1){
/*lose the game*/
clrscr();
gotoxy(27,12);
cprintf("You have lose the game!");
do{
while(bioskey(1)==0);
key=bioskey(0);
}while(key != VK_ENTER);
/*end the match*/
end_match=1;
}
else{
if(grade>=5){
/*win the match*/
clrscr();
gotoxy(15,12);
cprintf("Congratulations!You have pass all the grades!");
do{
while(bioskey(1)==0);
key=bioskey(0);
}while(key != VK_ENTER);
/*end the match*/
end_match=1;
}
else{
/*pass a game,continue or quit*/
do{
clrscr();
gotoxy(20,12);
cprintf("You win!Come to the next grade?(Y/N):");
ch=getchar();
ch=tolower(ch);
}while(ch != 'y' && ch != 'n');
if(ch=='n')
/*quit the match*/
end_match=1;
else
/*play the next grade*/
grade++;
}
}
}while(end_match==0);
/*clear the screen*/
clrscr();
return 0;
}