分享自己写的一个贪吃蛇的游戏(Linux)

转载请注明出处。http://www.cnblogs.com/dave_cn/

本程序需要ncurses库,ubuntu下安装ncurses可以执行下面命令:

sudo apt-get install libncurses5-dev 

关于ncurses的用法,读者可以Google之。

程序运行的效果如下:

其中包含两个窗口,一个为game窗口,一个为日志窗口。 

分享自己写的一个贪吃蛇的游戏(Linux) 

 

 代码如下:

/**

 * Snake

 * author: dave_cn

 * date  : 2010/7/14

 * info  :

 *        @ ...... food

 */

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include <ncurses.h>



#define TBool            int

#define True             1

#define False            0    

#define SHAPE_FOOD       '@'

#define SHAPE_SNAKE      '*'

#define GAMEWIN_YLEN     15

#define GAMEWIN_XLEN     60

#define LOGWIN_YLEN      7

#define LOGWIN_XLEN      (GAMEWIN_XLEN)

#define LOGBUF_NUM       (LOGWIN_YLEN-2)

#define LOGBUF_LEN       (GAMEWIN_XLEN-2)

#define MAXLEVEL         12



#define GetSnakeTail(s)  ((s)->head->front)



WINDOW *logwin;

#define INITRUNLOG()     logwin = newlogw()

#define RUNLOG(str)      runlog(logwin, str)

#define DESTROYRUNLOG()  delwin(logwin)



int g_level;



enum TDirection {

    DIR_UP,

    DIR_DOWN,

    DIR_LEFT,

    DIR_RIGHT

};



struct TFood {

    int y;

    int x;

};



struct TSnakeNode {

    int y;

    int x;

    struct TSnakeNode *front;

};



struct TSnake {

    int    length;

    struct TSnakeNode *head;

    enum   TDirection  dir;

};



int refreshgamew(WINDOW *win, struct TSnake *psnake);

void movesnake(struct TSnake *psnake);

int checksnake(struct TFood *pfood, struct TSnake *psnake);

void snakegrowup(struct TFood *pfood, struct TSnake *psnake);

void gameover(WINDOW *win, char *str);

struct TSnakeNode *newsnakenode(struct TSnakeNode **ppsnode, int y, int x);

WINDOW* newgamew();

struct TSnake* initsnake();

void destroysnake(struct TSnake *psnake);

void drawsnakew(WINDOW *win, struct TSnake *psnake);

void drawfoodw(WINDOW *win, struct TFood *pfood, struct TSnake *psnake);

TBool checkfood(struct TFood *pfood, struct TSnake *psnake);

WINDOW* newlogw();

void runlog(WINDOW *win, char *str);

void cleanline(WINDOW *win, int y, int x);



int main()

{

    initscr();

    raw();

    noecho();

    keypad(stdscr, TRUE);

    curs_set(0);

    refresh();



    g_level = 1;

    INITRUNLOG();

    RUNLOG("  Press 'q' or 'Q' to quit.");

    RUNLOG("  Press 'w/s/a/d' or 'W/S/A/D' to move the snake.");

    RUNLOG("Info:");

    

    WINDOW *gwin = newgamew();

    struct TSnake *psnake = initsnake();

    drawsnakew(gwin, psnake);

    

    while (refreshgamew(gwin, psnake) >= 0) ;

    

    getch();

    

    destroysnake(psnake);

    delwin(gwin);

    DESTROYRUNLOG();

    endwin();

    

    return 0;

}



int refreshgamew(WINDOW *win, struct TSnake *psnake)

{

    static TBool ffood = False;

    struct TFood pfood;

    

    if (!ffood) {

        drawfoodw(win, &pfood, psnake);

        ffood = True;

    }



    int key = -1;

    

    fd_set set;

    FD_ZERO(&set);

    FD_SET(0, &set);

    

    struct timeval timeout;

    timeout.tv_sec = 0;

    timeout.tv_usec= (6 - (int)(g_level/3)) * 100*1000;

    

    if (select(1, &set, NULL, NULL, &timeout) < 0)

        return -1;

    

    if (FD_ISSET(0, &set)) {

        while ((key = getch()) == -1) ;

    

        switch (key) {

        case 'w':

        case 'W':

            (psnake->dir == DIR_DOWN) ? : (psnake->dir = DIR_UP);

            break;

        

        case 's':

        case 'S':

            (psnake->dir == DIR_UP) ? : (psnake->dir = DIR_DOWN);

            break;

        

        case 'a':

        case 'A':

            (psnake->dir == DIR_RIGHT) ? : (psnake->dir = DIR_LEFT);

            break;

        

        case 'd':

        case 'D':

            (psnake->dir == DIR_LEFT) ? : (psnake->dir = DIR_RIGHT);

            break;

        

        case 'q':

        case 'Q':

            RUNLOG("Quit Game!");

            gameover(win, "Quit Game!");

            return -1;

        

        default:

            break;

        }

    }



    movesnake(psnake);

    drawsnakew(win, psnake);

    switch (checksnake(&pfood, psnake)) {

    case 0:

        break;

        

    case 1:

        ffood = False;

        if (++g_level > MAXLEVEL) {

            RUNLOG("Win!!!");

            gameover(win, "Win!!!");

            return -1;

        }

        mvwprintw(win, GAMEWIN_YLEN-1, 2, " Level: %d ", g_level);

        mvwprintw(win, GAMEWIN_YLEN-1, 30, " Speed: %d ", (int)(g_level/3));

        wrefresh(win);

        RUNLOG("Level UP!");

        snakegrowup(&pfood, psnake);

        break;

        

    default:

        RUNLOG("Game over!");

        gameover(win, "Game over!");

        return -1;

    }

    

    return 1;

}



/**

 * stuct TSnake是一个倒置的首尾相连的链表,head->front指向snake的尾部

 * 如: [a]<-[b]<-[c]<-[d]    a为head

 *      |              ^     snake移动的时候,只用head指向d,

 *      `--------------'     并且修改d的(y,x)为snake头移动到的位置.

 */

void movesnake(struct TSnake *psnake)

{

    int hy = psnake->head->y;

    int hx = psnake->head->x;

    

    psnake->head = GetSnakeTail(psnake);

    

    switch (psnake->dir) {

    case DIR_UP:

        psnake->head->y = hy - 1;

        psnake->head->x = hx;

        break;

    

    case DIR_DOWN:

        psnake->head->y = hy + 1;

        psnake->head->x = hx;

        break;

    

    case DIR_LEFT:

        psnake->head->y = hy;

        psnake->head->x = hx - 1;

        break;

    

    case DIR_RIGHT:

        psnake->head->y = hy;

        psnake->head->x = hx + 1;

        break;

        

    default:

        break;

    }

}



int checksnake(struct TFood *pfood, struct TSnake *psnake)

{

    if ( psnake->head->y <= 0 || psnake->head->y >= GAMEWIN_YLEN

      || psnake->head->x <= 0 || psnake->head->x >= GAMEWIN_XLEN)

    {

        return -1;

    }



    struct TSnakeNode *pnode = GetSnakeTail(psnake);

    int i = 0;

    for (; i < psnake->length - 1; ++i, pnode = pnode->front)

        if (psnake->head->y == pnode->y && psnake->head->x == pnode->x)

            return -1;



    if (psnake->head->y == pfood->y && psnake->head->x == pfood->x)

        return 1;

    

    return 0;

}



void snakegrowup(struct TFood *pfood, struct TSnake *psnake)

{

    struct TSnakeNode *pnode = (struct TSnakeNode *)malloc(sizeof(struct TSnakeNode));

    

    switch (psnake->dir) {

    case DIR_UP:

        pnode->y = psnake->head->y - 1;

        pnode->x = psnake->head->x;

        break;

    

    case DIR_DOWN:

        pnode->y = psnake->head->y + 1;

        pnode->x = psnake->head->x;

        break;

    

    case DIR_LEFT:

        pnode->y = psnake->head->y;

        pnode->x = psnake->head->x - 1;

        break;

    

    case DIR_RIGHT:

        pnode->y = psnake->head->y;

        pnode->x = psnake->head->x + 1;

        break;

        

    default:

        break;

    }

    

    pnode->front = GetSnakeTail(psnake);

    psnake->head->front = pnode;

    psnake->head = pnode;

    ++psnake->length;

}



void gameover(WINDOW *win, char *str)

{

    mvwprintw(win, (int)(GAMEWIN_YLEN/2), (GAMEWIN_XLEN/2 - strlen(str)/2), str);

    mvwprintw(win, (int)(GAMEWIN_YLEN/2 + 1), 20, "Press any key to quit...");

    wrefresh(win);

}



WINDOW* newgamew()

{

    WINDOW *win = newwin(GAMEWIN_YLEN, GAMEWIN_XLEN, 1, 3);

    box(win, 0, 0);

    mvwprintw(win, 0, 2, " GAME ");

    mvwprintw(win, GAMEWIN_YLEN-1, 2, " Level: %d ", g_level);

    mvwprintw(win, GAMEWIN_YLEN-1, 30, " Speed: %d ", (int)(g_level/3));

    wrefresh(win);

    

    return win;

}



struct TSnake* initsnake()

{

    struct TSnake *psnake = (struct TSnake *)malloc(sizeof(struct TSnake));



    psnake->dir    = DIR_LEFT;

    psnake->length = 4;

    

    newsnakenode (

        &newsnakenode (

            &newsnakenode (

                &newsnakenode( &psnake->head, 4, 50 )->front, 4, 53

            )->front, 4, 52

        )->front, 4, 51

    )->front = psnake->head;



    return psnake;

}



struct TSnakeNode *newsnakenode(struct TSnakeNode **ppsnode, int y, int x)

{

    *ppsnode = (struct TSnakeNode *)malloc(sizeof(struct TSnakeNode));

    (*ppsnode)->y = y;

    (*ppsnode)->x = x;

    (*ppsnode)->front = NULL;

    

    return *ppsnode;

}



void destroysnake(struct TSnake *psnake)

{

    struct TSnakeNode *psnode = GetSnakeTail(psnake);

    struct TSnakeNode *ptmp   = NULL;

    

    int i = 0;

    for (; i < psnake->length; ++i) {

        ptmp   = psnode;

        psnode = psnode->front;

        free(ptmp);

    }

    

    free(psnake);

    psnake = NULL;

}



void drawsnakew(WINDOW *win, struct TSnake *psnake)

{

    static int taily = 0;

    static int tailx = 0;

    if (taily != 0 && tailx != 0) {

        mvwaddch(win, taily, tailx, ' ');

    }

    

    struct TSnakeNode *psnode = GetSnakeTail(psnake);

    

    int i = 0;

    for (; i < psnake->length; ++i) {

        mvwaddch(win, psnode->y, psnode->x, SHAPE_SNAKE);

        psnode = psnode->front;

    }

    

    taily = GetSnakeTail(psnake)->y;

    tailx = GetSnakeTail(psnake)->x;



    wrefresh(win);

}



void drawfoodw(WINDOW *win, struct TFood *pfood, struct TSnake *psnake)

{

    do {

        pfood->y = random() % (GAMEWIN_YLEN - 1) + 1;

        pfood->x = random() % (GAMEWIN_XLEN - 1) + 1;

    } while (False == checkfood(pfood, psnake));

    checkfood(pfood, psnake);

    

    mvwaddch(win, pfood->y, pfood->x, SHAPE_FOOD);

    wrefresh(win);

}



TBool checkfood(struct TFood *pfood, struct TSnake *psnake)

{

    struct TSnakeNode *pnode = GetSnakeTail(psnake);



    int i = 0;

    for (; i < psnake->length; ++i, pnode = pnode->front)

        if (pfood->y == pnode->y && pfood->x == pnode->x)

            return False;



    return True;

}



WINDOW* newlogw()

{

    WINDOW *win = newwin(LOGWIN_YLEN, LOGWIN_XLEN, GAMEWIN_YLEN + 2, 3);

    box(win, 0, 0);

    mvwprintw(win, 0, 2, " LOG ");

    wrefresh(win);

    

    return win;

}



void runlog(WINDOW *win, char *str)

{

    static char logbuf[LOGBUF_NUM][LOGBUF_LEN] = {0};

    static int  index = 0;

    

    strcpy(logbuf[index], str);

    

    int i = 0;

    for (; i < LOGBUF_NUM; ++i) {

        cleanline(win, i+1, 1);

        mvwprintw(win, i+1, 1, logbuf[(index+i) % LOGBUF_NUM]);

        wrefresh(win);

    }

    

    index = (index + LOGBUF_NUM - 1) % LOGBUF_NUM;

}



void cleanline(WINDOW *win, int y, int x)

{

    char EMPTYLINE[LOGBUF_LEN] = {0};

    memset(EMPTYLINE, ' ', LOGBUF_LEN-1);

    

    mvwprintw(win, y, x, EMPTYLINE);

    wrefresh(win);

}

 

 我在ubuntu10.04下面测试过。

编译方法:

cc -o snake filename.c -lncurses 

 

 

你可能感兴趣的:(linux)