C language implementation Snake game

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/times.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    20
#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;        //declare a windows for displaying message
#define INITRUNLOG()    logwin = newlogw()
#define RUNLOG(str)        runlog(logwin, str)
#define DESTROYRUNLOG()    delwin(logwin)

int g_level;    //level of player

enum TDirection
{
    DIR_UP,
    DIR_DOWN,
    DIR_LEFT,
    DIR_RIGHT
};

struct TFood
{
    you work;
    you y;
};

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);
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*    newgamew();
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 * wine = newgamew ();

    struct TSnake *psnake = initsnake();
    drawsnakew (wine, psnake);

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

    getch();
    destroysnake(psnake);
    delwin (wine);
    DESTROYRUNLOG();
    endwin();

    return 0;
}

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;
}

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;
}    

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;
}

// window win coordinates (x, y) empty 
void Cleanline (the WINDOW * win, int Y, int X)
{
    char EMPTYLINE [LOGBUF_LEN] = { 0 }; // LOGBUF_LEN = 57
    
    // blanking array positions 0-56 
    Memset (EMPTYLINE, '  ' , LOGBUF_LEN- . 1 );
    
    // Move the cursor to the window win (y, x) and the print string EMPTYLINE 
    mvwprintw (win, Y, X, EMPTYLINE);
    
    // displayed on the specified window contents 
    wrefresh (win);    
}
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 (wine, 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 linked list is an inverted end to end, head-> front point of snake tail
 * As: [a] <- [b] <- [c] <- [d] a head of
 * | ^ Snake is moving, the only point d with head,
 -------------- * ` 'and is moved to modify the snake head position (y, x) d a.
 */
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)
{
    int hy = psnake->head->y;
    int hx = psnake->head->x;
    if (hy <= 0 || hy >= GAMEWIN_YLEN || hx <= 0 || hx >= GAMEWIN_XLEN)
    {
        return -1;
    }

    struct TSnakeNode *pnode = GetSnakeTail(psnake);
    int i = 0;
    for (; i < psnake->length - 1; ++i, pnode = pnode->front)
    {
        if (hy == pnode->y && hx == pnode->x)
        {
            return -1;
        }

    }
    if (hy == pfood->y && hx == 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, "Please any key to quit...");
    wrefresh(win);
}

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;
}

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;
}

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);
    Psnak = NULL;
}

void drawsnakew(WINDOW *win, struct TSnake *psnake)
{
    static int taily = 0;
    static int tailx = 0;
    if (taily != 0 && tailx != 0)
    {
        // Move the cursor to the specified position of the specified window (taily, tailx) and then outputs the character 
        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 - 2 ) + 1 ;
        pfood->x = random() % (GAMEWIN_XLEN - 2) + 1;
    }while(False == checkfood(pfood, psnake));
    
    checkfood(pfood, psnake);
    mvwaddch(win, pfood->y, pfood->x, SHAPE_FOOD);
    wrefresh(win);
}

// Check the position of food does not appear on the Snake 
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;
}

 

Two key points:

1. The entire window to coordinate (0, 0) as an origin, x-axis, y-axis coordinate point established, x-axis positive and negative y-axis direction as the value increases, the downward movement of the y-axis coordinate when the coordinate + 1, otherwise -1

2. When the snake to move, each move only one unit of distance, so only need to take the last node, the location where you want to move on to the feeling of the movement as a whole, as a function of the position will be moved to detect whether legitimate.

 

note:

Procedures used by ncurses library, if not, then you need to download:

# Update all software source software list
$ sudo apt-get update

# Install `curses` library
$ sudo apt-get install libncurses5-dev

 

Finally, add -lncurses compile time

Guess you like

Origin www.cnblogs.com/wanghao-boke/p/11996380.html