gcc -o snakee snakee.c
ubuntu 9.04 bash终端通过。A
w/s/a/d 上下左右, P 退出.
[img]http://dl.iteye.com/upload/attachment/282377/b8c59f2f-27cc-3de7-a6d5-5cc26def34d1.jpg[/img]
ubuntu 9.04 bash终端通过。A
w/s/a/d 上下左右, P 退出.
[img]http://dl.iteye.com/upload/attachment/282377/b8c59f2f-27cc-3de7-a6d5-5cc26def34d1.jpg[/img]
/*
============================================================================
Name : snakee.c
Author : bthust@163.com
Version :
Copyright : all rights reserved
Description : greed snake
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include "snkdef.h"
struct grid *foods[MAXFOOD];
char dirc=EAST;
struct grid _sk;
struct grid *sk= &_sk;
int main(void)
{
sk->c=SNK_CHAR;
sk->x=WIDTH*STEP/2;
sk->y=HEIGHT/2;
sk->next=NULL;
int i;
for(i=0; i<MAXFOOD; i++)
foods[i]=NULL;
frame_init();
paint_snk();
int fd[2];
pipe(fd);
int pid;
pid= fork();
if(pid==0)
{
close(fd[0]);
set_nblock(fd[1]);
char c;
int chr=-1;
while( (c=getch())!=EXIT_CHAR)
{
if( c==EAST || c==WEST || c==SOUTH || c==NORTH)
write(fd[1], &c, 1);
}
write(fd[1],&c,1);
}
else if(pid>0)
{
close(fd[1]);
set_nblock(fd[0]);
char input_dirc[20];
int idx;
for(; ; )
{
idx=read(fd[0], input_dirc, 20);
if(idx>0)
update_dirc( input_dirc, idx);
erase_sk();
int ret=move();
if(ret!=0)
{
break;
}
gen_food();
paint_food();
paint_snk();
fflush(stdout);
usleep(1000000*TIME_INTVL);//s
}
g_over();
int stat;
waitpid(pid,&stat ,0);
}
exit(0);
}
void mv_pos(struct grid * dest)
{
int x= dest->x+1;
int y= dest->y+1;
printf("\033[%d;%dH",y,x);
}
void frame_init()
{
printf("\33[2J");
printf("\033[%d;%dH",0,0);
int i;
for(i=0; i<WIDTH*STEP; i++)
printf("%c",FRAME_CHAR);
printf("\033[%d;%dH",HEIGHT,0);
for(i=0;i<WIDTH*STEP;i++)
printf("%c",FRAME_CHAR);
for(i=1;i<HEIGHT+1;i++)
{
printf("\033[%d;%dH",i,0);
printf("%c",FRAME_CHAR);
printf("\033[%d;%dH",i,WIDTH*STEP);
printf("%c",FRAME_CHAR);
}
}
void paint_grid(struct grid *dest)
{
mv_pos(dest);
printf("%c%c", dest->c,'\b');
}
void paint_snk()
{
struct grid *s = sk;
for( ; s!=NULL;s=s->next)
paint_grid(s);
}
void paint_food()
{
int i;
for(i=0; i<MAXFOOD; i++)
{
if(foods[i]!=NULL)
paint_grid(foods[i]);
}
}
void erase_sk()
{
struct grid *s = sk;
for( ; s!=NULL;s=s->next)
{
mv_pos(s);
printf("%c%c",' ','\b' );
}
}
int check_body(int nx , int ny)
{
struct grid *s=sk;
for( ; s!=NULL;s=s->next)
if( s->x==nx && s->y==ny)
return -2;
return 0;
}
//碰到frame 返回-1
//碰到body 返回-2
//正常 返回0
int next_pos(int *x, int *y)
{
if( dirc== NORTH )
*y=sk->y-1;
else if( dirc== SOUTH )
*y=sk->y+1;
else if( dirc == WEST )
*x=sk->x-STEP;
else if( dirc== EAST )
*x=sk->x+STEP;
if( *x<1 || *x> ((WIDTH-1)*STEP+1)
|| *y<1 || *y>(HEIGHT-2) )
return -1;
return check_body(*x,*y);
}
void update_dirc(char *new_dirc, int n)
{
char cntr_dirc;
if(dirc==EAST)
cntr_dirc=WEST;
else if(dirc==WEST)
cntr_dirc=EAST;
else if(dirc==NORTH)
cntr_dirc=SOUTH;
else if(dirc==SOUTH)
cntr_dirc=NORTH;
int i;
for(i=0;i<n; i++)
{
if( new_dirc[i]==EXIT_CHAR)
exit(0);
if( new_dirc[i]==cntr_dirc)
continue;
dirc=new_dirc[i];
}
}
//成功返回0,over返回-1或-2
int move()
{
int nx=sk->x;
int ny=sk->y;
int ret=next_pos(&nx,&ny);
if(ret!=0)
return ret;
struct grid *fd = chk_has_fd(nx , ny);
if( fd==NULL)
{
struct grid *tail=NULL;
struct grid *sk_next = sk->next;
tail= cut_tail();
tail->x=nx; tail->y=ny;
//如果原来的sk->next不为NULL,即长度大于1
if( sk_next!=NULL)
{
tail->next= sk;
}
sk= tail;
}
else
{
fd->next= sk;
sk = fd;
sk->c= SNK_CHAR;
}
return 0;
}
//如果长大于1, 剪掉尾返回;否则返回本身
struct grid *cut_tail()
{
struct grid *pre = sk;
struct grid *nxt = NULL;
//找出最后2个节点
for( nxt=pre; nxt->next != NULL; pre=nxt, nxt= nxt->next )
;
pre->next = NULL;
return nxt;
}
struct grid *chk_has_fd(int x, int y)
{
int i;
for(i=0; i<MAXFOOD ; i++)
{
if( foods[i]!=NULL && x==foods[i]->x && y==foods[i]->y)
{
struct grid *tmp=foods[i];
foods[i]=NULL;
return tmp;
}
}
return NULL;
}
int get_fd_slot()
{
int i;
for(i=0; foods[i]!=NULL && i<MAXFOOD; i++)
;
return i>=MAXFOOD?-1:i;
}
void gen_food()
{
int idx =-1;
time_t tt;
srand(time(&tt));
int n_fd= rand()%2; //随机产生0~1个
for( ; n_fd>0; n_fd--)
{
if( (idx = get_fd_slot())==-1) //如果数量达到最大值,不再增加
break;
struct grid *td = malloc(sizeof(struct grid)); //产生一个
int x,y;
do{
td->x= STEP*(rand() % (WIDTH-3))+1;
td->y= rand()%(HEIGHT-3)+1;
td->c=FOOD_CHAR;
}while(0); //这里应该检查位置重复
td->next=NULL;
foods[idx] = td;
}
}
void erase_food()
{
int i;
for(i=0 ; i<MAXFOOD;i++)
{
if(foods[i]==NULL)
continue;
mv_pos(foods[i]);
printf("%c%c",' ','\b' );
}
}
void g_over()
{
erase_food();
erase_sk();
printf("\033[%d;%dH",HEIGHT/2,WIDTH*STEP/2);
printf("GAME OVER !");
printf("\033[%d;%dH",HEIGHT+3,0);
printf("press %c to exit\n",EXIT_CHAR);
fflush(stdout);
}
int getch(void)
{
int c=0;
struct termios org_opts, new_opts;
int res=0;
res=tcgetattr(STDIN_FILENO, &org_opts);
//assert(res==0);
memcpy(&new_opts, &org_opts,sizeof(new_opts));
new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
tcsetattr(STDIN_FILENO,TCSANOW, &new_opts);
c=getchar();
res=tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);//assert(res==0);
return c;
}
int set_nblock(int fd)
{
int val;
val = fcntl( fd, F_GETFL);
val |= O_NONBLOCK;
return fcntl(fd, F_SETFL,val);
}
#define EXIT_CHAR 'P'
#define TIME_INTVL 0.35
#define SNK_CHAR 'O'
#define FOOD_CHAR '@'
#define FRAME_CHAR '#'
#define HEIGHT 25
#define STEP 3
#define WIDTH 25
#define NORTH 'w'
#define SOUTH 's'
#define WEST 'a'
#define EAST 'd'
#define MAXFOOD 7
struct grid
{
int x;
int y;
char c;
struct grid *next;
};
void mv_pos(struct grid *);
void frame_init(void);
void paint_grid(struct grid *);
void paint_snk(void);
void paint_food(void);
void erase_sk(void);
int check_body(int, int);
int next_pos(int *, int *);
void update_dirc(char *, int );
int move(void);
struct grid *cut_tail(void);
struct grid *chk_has_fd(int x, int y);
int get_fd_slot(void);
void gen_food(void);
void erase_food(void);
void g_over(void);
int getch(void);
int set_nblock(int);