forest077 发表于 2008-06-25 13:16

[原创]贡献一个unix的贪吃蛇小游戏

许久没来,贡献一个原创小程序,是unix下用终端控制字符实现的贪吃蛇小游戏,供大家一乐。

/***snake.c***/
#include <stdio.h>
#include <malloc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <termio.h>
#include <fcntl.h>

#define SNAKE_INITX 5
#define SNAKE_INITY 5
#define SNAKE_SHAPE '*'
#define SNAKE_INITLEN 8

#define WIN_X1 1
#define WIN_X2 80
#define WIN_Y1 1
#define WIN_Y2 24

#define MAX_LEVEL 20
#define MAX_INTER 200000
#define MIN_INTER 0
#define MAX_RICH 10
#define DEVRATE 5
#define OVER "Game Over!!!"

struct stNode
{
        int x;
        int y;
        char shape;
        struct stNode *next;
};

struct stFood
{
        int x;
        int y;
};

struct stNode *gpstHead,*gpstTail;
struct stFood gastFood;
int giLevel=1;
int giRich=1;
int giScore=0;
int giLen=0;

void settty(int iFlag)
{
        int fd;
        struct termio stTerm;

        if((fd = open(ttyname(1),O_RDWR))==-1)        return;
        if(iFlag == 1)
        {
                ioctl(fd,TCGETA,&stTerm);
                stTerm.c_lflag &= ~ICANON;
                stTerm.c_lflag &= ~ECHO;
                stTerm.c_cc = 1;
                stTerm.c_cc = 0;
                stTerm.c_iflag &= ~ISTRIP;
                stTerm.c_cflag |= CS8;
                stTerm.c_cflag &= ~PARENB;
                ioctl(fd,TCSETA,&stTerm);
        }
        else
        {
                ioctl(fd,TCGETA,&stTerm);
                stTerm.c_lflag |= ICANON;
                stTerm.c_lflag |= ECHO;
                stTerm.c_cc = 4;
                stTerm.c_cc = 5;
                stTerm.c_iflag &= ~ISTRIP;
                stTerm.c_cflag |= CS8;
                stTerm.c_cflag &= ~PARENB;
                ioctl(fd,TCSETA,&stTerm);
        }
        close(fd);
}

void vDrawOneNode(struct stNode *pstNode,int iFlag)
{
        printf("\033[%dm\033[40;%dm\033[%d;%d;H%c",
                iFlag,iFlag*3+30,pstNode->y,pstNode->x,pstNode->shape);
        fflush(stdout);
}

void vDrawOneFood(int x,int y)
{
        printf("\033[1m\033[40;36m\033[%d;%d;H%c",y,x,'@');
        fflush(stdout);
}

int iGetDir(int iOriDir)
{
        fd_set rset;
        struct        timeval        hTmo;
        int iRet,iFlag=0;
        char cCh;

        FD_ZERO(&rset);
        FD_SET(0,&rset);
        hTmo.tv_sec=0;
        hTmo.tv_usec=MAX_INTER-(MAX_INTER-MIN_INTER)/MAX_LEVEL*giLevel;

        iRet=select(1,&rset,NULL,NULL,&hTmo);
        if(iRet<=0)
        {
                return(iOriDir);
        }
        for(;;)
        {
                cCh=getchar();
                if(cCh != -1)
                {
                        switch(cCh)
                        {       
                        case 27:
                        case 91:
                                iFlag++;
                                break;
                        case 65://UP
                        case 66 ://DOWN
                        case 67://RIGHT
                        case 68 ://LEFT
                        if(iFlag==2)
                                return((!((cCh-0x41)^iOriDir^1))^(cCh-0x41));
                        default:
                                return(iOriDir);
                        }
                }
        }
}
void vInitScreen()
{
        settty(1);
        printf("\033[?25l\033[2J");
}

void vRestoreScreen()
{
        printf("\033[24;1H\033[1m\033[40;34m\033[?25h");
        settty(0);
}

void vDrawScope()
{
        int i,j;
       
        for(j=WIN_Y1;j<=WIN_Y2;j+=WIN_Y2-WIN_Y1)
        {
                printf("\033[%d;%dH+",j,WIN_X1);
                for(i=WIN_X1+1;i<WIN_X2;i++)
                        printf("-");
                printf("+");
        }
        for(i=WIN_Y1+1;i<WIN_Y2;i++)
                printf("\033[%d;%dH|%*c|\n",i,WIN_X1,WIN_X2-WIN_X1-1,' ');
}

void vCreateSnake()
{
        struct stNode *pstNew;
        int i;

        gpstHead=(struct stNode*)malloc(sizeof(struct stNode));
        gpstHead->x=SNAKE_INITX;       
        gpstHead->y=SNAKE_INITY;
        gpstHead->shape=SNAKE_SHAPE;
        gpstHead->next=NULL;
        vDrawOneNode(gpstHead,1);
        gpstTail=gpstHead;
        for(i=1;i<SNAKE_INITLEN;i++)
        {
                pstNew=(struct stNode*)malloc(sizeof(struct stNode));
                pstNew->x=gpstHead->x+1;       
                pstNew->y=gpstHead->y;
                pstNew->shape=SNAKE_SHAPE;
                pstNew->next=NULL;
                vDrawOneNode(pstNew,1);
                gpstHead->next=pstNew;
                gpstHead=pstNew;
        }
        return;
}

void vKillSnake()
{
        struct stNode *pstNode;

        for(pstNode=gpstTail;gpstTail!=NULL;)
        {
                gpstTail=pstNode->next;
                free(pstNode);
                pstNode=gpstTail;
        }
}

void vGenFood(int iIdx)
{
        struct stNode *pstNode;
        int i,iFound=0;
       
        for(;!iFound;)
        {
                iFound=1;
                gastFood.x=rand()%(WIN_X2-WIN_X1-1)+WIN_X1+1;
                gastFood.y=rand()%(WIN_Y2-WIN_Y1-1)+WIN_Y1+1;
                for(i=0;i<giRich;i++)
                {
                        if(i!=iIdx && gastFood.x==gastFood.x &&
                                gastFood.y==gastFood.y)
                        {
                                iFound=0;
                                break;
                        }
                }
                if(!iFound) continue;
                for(pstNode=gpstTail;pstNode!=NULL;pstNode=pstNode->next)
                {
                        if(gastFood.x==pstNode->x &&
                                gastFood.y==pstNode->y)
                        {
                                iFound=0;
                                break;
                        }
                }
                if(!iFound) continue;
        }
        vDrawOneFood(gastFood.x,gastFood.y);
}

void vInitFood()
{
        int i;
       
        srand(getpid());
        for(i=0;i<giRich;i++)        vGenFood(i);
}
       
int iIsValid(int x,int y)
{
        struct stNode *pstNode;

        if(x<=WIN_X1 || x>=WIN_X2 || y<=WIN_Y1 || y>=WIN_Y2)
                return(0);
        pstNode=gpstTail;
        for(;pstNode!=NULL;)
        {
                if(x==pstNode->x && y==pstNode->y)
                        return(0);
                pstNode=pstNode->next;
        }
        return(1);
}

int iEat(int x,int y)
{
        int i,j;
       
        for(i=0;i<giRich;i++)
        {
                if(x==gastFood.x && y==gastFood.y)
                {
                        vGenFood(i);
                        giScore+=giLevel*10;
                        giLen++;
                        if(giLevel<MAX_LEVEL)
                                if(giLen%DEVRATE==0)
                                        giLevel++;
                        return(1);
                }
        }
        return(0);
}
main()
{
        int iDir=2,iNextX,iNextY;
        struct stNode *pstNew;
        char sPrompt;
       
        vInitScreen();
        vDrawScope();
        vCreateSnake();
        vInitFood();
        for(;;)
        {
                iDir=iGetDir(iDir);
                iNextX=gpstHead->x+(iDir>>1)*(5-(iDir<<1));
                iNextY=gpstHead->y-(!(iDir>>1))*(1-(iDir<<1));
                if(!iIsValid(iNextX,iNextY))
                {
                        printf("\033[%d;%dH\033[1m\033[40;34m%s\033[0m",
                                WIN_Y2-1,(WIN_X1+WIN_X2)/2-strlen(OVER)/2,OVER);
                        break;
                }
                pstNew=(struct stNode*)malloc(sizeof(struct stNode));
                pstNew->x=iNextX;
                pstNew->y=iNextY;
                pstNew->shape=SNAKE_SHAPE;
                pstNew->next=NULL;
                gpstHead->next=pstNew;
                gpstHead=pstNew;
                vDrawOneNode(gpstHead,1);
                if(!iEat(iNextX,iNextY))
                {
                        vDrawOneNode(gpstHead,1);
                        vDrawOneNode(gpstTail,0);
                        pstNew=gpstTail;
                        gpstTail=pstNew->next;
                        free(pstNew);
                }
                sprintf(sPrompt,"Score:%7d Level:%2d",giScore,giLevel);
                printf("\033[%d;%dH\033[1m\033[40;34m%s\033[0m",
                        WIN_Y2,(WIN_X1+WIN_X2)/2-strlen(sPrompt)/2,sPrompt);
        }
        vKillSnake();
        vRestoreScreen();
}

编译方法:
AIX下:cc -qcpluscmt -o snake snake.c
sco unix下:cc -o snake snake.c

[ 本帖最后由 forest077 于 2008-6-25 13:23 编辑 ]

LinuxKen 发表于 2008-06-25 13:20

代码写得很漂亮,支持,友情帮顶!:)

LinuxKen 发表于 2008-06-25 13:33

gcc加了-Wall选项之后出现了N多警告,主要是一些头文件没加进去;
另外,不知道搂主是在什么环境下跑这个程序的,我的机器跑了之后没看到什么。

forest077 发表于 2008-06-25 13:37

回复 #3 LinuxKen 的帖子

我在AIX下开发的。 sco下虽然没试过,但是以我的经验,跑起来应该没问题。

204tian 发表于 2008-06-25 14:10

跑了就看到个界面, 看不到蛇和豆子, 一会就 GAME OVER了

converse 发表于 2008-06-25 14:14

我还记得刚来CU时看到LZ在shell版发的shell学习体会~~
:mrgreen: :mrgreen:

forest077 发表于 2008-06-25 14:40

回复 #5 204tian 的帖子

你在什么环境下的?linux下我不敢保证可以运行。

forest077 发表于 2008-06-25 14:42

回复 #6 converse 的帖子

哈哈,多谢,你还记得呀

forest077 发表于 2008-06-25 14:45

可惜我这边找不到linux环境,要不然可以试试

5毛党党员 发表于 2008-06-25 15:11

Segmentation fault (core dumped)

在AIX下。。。
页: [1] 2 3 4 5 6 7 8 9
查看完整版本: [原创]贡献一个unix的贪吃蛇小游戏