神出鬼没的老七

导航

console下纯字符实现的贪吃蛇

最近简直超级无聊……


code blocks win7 64编译运行无问题,应该其他编译器也不会有问题。

w:上

s:下

a:左

d:右

CS标准方向控制,AK47和M4这种高级货是没有滴……


废话不多说,直接上代码。


#include "stdio.h"
#include "stdlib.h"
#include "windows.h"
#include "time.h"
// ----------------------------------------------------------------------------
//                 definition
// ----------------------------------------------------------------------------

// basic char node
#define _FOOD                   "#"
#define _SNAKE_NODE             "O"
#define _SNAKE_END              "+"
#define _SNAKE_HEAD             "@"
#define _MAP_NODE               " "
#define _MAP_EDGE               "O"

// area pos and range
#define _AREA_X_OFFSET           10
#define _AREA_Y_OFFSET           5
#define _AREA_X_LINE_MAX         30         // max line num in x direction
#define _AREA_Y_LINE_MAX         20         // max line num in y direction


#define _SNAKE_LENGTH_MAX        30


// key val defintion
#define _KEY_UP             'w'
#define _KEY_DOWN           's'
#define _KEY_LEFT           'a'
#define _KEY_RIGHT          'd'


// default snake speed
#define _DEFAULT_SNAKE_SPEED  300             // 1 step per second


// ----------------------------------------------------------------------------
//                 type
// ----------------------------------------------------------------------------

// basic type
typedef unsigned char     BYTE;
typedef unsigned short    WORD;
typedef unsigned long     DWORD;

typedef unsigned char  *  PBYTE;
typedef unsigned short *  PWORD;
typedef unsigned long  *  PDWORD;


// element type
typedef enum
{
    _ET_MAP_NODE,
    _ET_MAP_EDGE,

    _ET_FOOD,

    _ET_SNAKE_HEAD,
    _ET_SNAKE_NODE,
    _ET_SNAKE_END
}E_ET;

// snake node type
typedef enum
{
    _ESNT_HEAD = _ET_SNAKE_HEAD,
    _ESNT_NODE = _ET_SNAKE_NODE,
    _ESNT_END  = _ET_SNAKE_END
}E_SNT;

// node pos
typedef struct
{
    BYTE by_x;
    BYTE by_y;
}T_Pos, *PT_Pos;

// snake node
typedef struct
{
    E_SNT e_type;
    T_Pos t_pos;
    //BOOL  b_valid;
}T_Snake_Node;

// direction
typedef enum
{
    _UP,
    _DOWN,
    _LEFT,
    _RIGHT
}E_DRCT;


// snake
typedef struct
{
    DWORD        dw_speed;
    E_DRCT       e_direction;
    BYTE         by_node_num;
    T_Snake_Node at_node[_SNAKE_LENGTH_MAX];
}T_Snake;

// food
typedef struct
{
    BOOL b_eaten;
    T_Pos t_pos;
}T_Food;

// key type
typedef enum
{
    _E_KT_NONE,

    _E_KT_UP,
    _E_KT_DOWN,
    _E_KT_LEFT,
    _E_KT_RIGHT,

    _E_KT_SIZE
}E_KEY_TYPE;



// ----------------------------------------------------------------------------
//                 local para
// ----------------------------------------------------------------------------

// range buffer
E_ET l_ae_area[_AREA_Y_LINE_MAX][_AREA_X_LINE_MAX];

// snake
T_Snake l_t_snake;
BOOL    l_b_key_lock = FALSE;
T_Food   l_t_food = {.b_eaten = TRUE};

// ----------------------------------------------------------------------------
//                 function
// ----------------------------------------------------------------------------

// ------------------------------------
// pos jump
// ------------------------------------
void Pos_Jump(int x, int y)
{
    COORD  pos  = {_AREA_X_OFFSET + x, _AREA_Y_OFFSET + y};
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut, pos);
}

// ------------------------------------
// draw rect element
// ------------------------------------
void Rect_Elem_Draw(E_ET e_et)
{
    switch(e_et)
    {
    case _ET_FOOD:
        printf(_FOOD);
        break;

    case _ET_SNAKE_NODE:
        printf(_SNAKE_NODE);
        break;

    case _ET_SNAKE_HEAD:
        printf(_SNAKE_HEAD);
        break;

    case _ET_SNAKE_END:
        printf(_SNAKE_END);
        break;

    case _ET_MAP_EDGE:
        printf(_MAP_EDGE);
        break;

    case _ET_MAP_NODE:
    default:
        printf(_MAP_NODE);
        break;
    }
}
// ------------------------------------
// draw map
// ------------------------------------
void Area_Refresh( void )
{
    BYTE i, j, k;

    // make Y offset
    for(i=0 ; i<_AREA_Y_OFFSET ; i++)
    {
        printf("\r\n");
    }

    // refresh rect line by line
    for(i=0 ; i<_AREA_Y_LINE_MAX ; i++)
    {
        // make X offset
        for(k=0 ; k<_AREA_X_OFFSET ; k++)
        {
            printf(" ");
        }

        // draw line
        for(j=0 ; j<_AREA_X_LINE_MAX ; j++)
        {
            Rect_Elem_Draw(l_ae_area[i][j]);
        }
        printf("\r\n");
    }
}


// ------------------------------------
// snake init
// ------------------------------------
void Snake_Init()
{
    l_t_snake.dw_speed              = _DEFAULT_SNAKE_SPEED;

    l_t_snake.e_direction           = _RIGHT;

    l_t_snake.by_node_num           = 3;

    //l_t_snake.at_node[0].b_valid    = TRUE;
    l_t_snake.at_node[0].e_type     = _ESNT_END;
    l_t_snake.at_node[0].t_pos.by_x = 2;
    l_t_snake.at_node[0].t_pos.by_y = 1;

    //l_t_snake.at_node[0].b_valid    = TRUE;
    l_t_snake.at_node[1].e_type     = _ESNT_NODE;
    l_t_snake.at_node[1].t_pos.by_x = 2;
    l_t_snake.at_node[1].t_pos.by_y = 2;

    //l_t_snake.at_node[0].b_valid    = TRUE;
    l_t_snake.at_node[2].e_type     = _ESNT_HEAD;
    l_t_snake.at_node[2].t_pos.by_x = 2;
    l_t_snake.at_node[2].t_pos.by_y = 3;
}

// ------------------------------------
// area init
// notice: should be called after snake
//         init
// ------------------------------------
void Area_Init()
{
    BYTE by_i, by_j;

    // set area default value
    for(by_i=0 ; by_i<_AREA_X_LINE_MAX ; by_i++)
    {
        for(by_j=0 ; by_j<_AREA_Y_LINE_MAX ; by_j++)
        {
            l_ae_area[by_i][by_j] = _ET_MAP_NODE;
        }
    }

    // set area edge value
    for(by_i=0 ; by_i<_AREA_X_LINE_MAX ; by_i++)
    {
        l_ae_area[0][by_i]                    = _ET_MAP_EDGE;
        l_ae_area[_AREA_Y_LINE_MAX - 1][by_i] = _ET_MAP_EDGE;
    }

    for(by_j=0 ; by_j<_AREA_Y_LINE_MAX ; by_j++)
    {
        l_ae_area[by_j][0]                    = _ET_MAP_EDGE;
        l_ae_area[by_j][_AREA_X_LINE_MAX - 1] = _ET_MAP_EDGE;
    }
}

void Show_Game_Over()
{
    Pos_Jump(_AREA_X_LINE_MAX/4, _AREA_X_LINE_MAX+1);
    printf("Game Over!");
    Pos_Jump(_AREA_X_LINE_MAX/4, _AREA_X_LINE_MAX+2);
    printf("Press Anykey to Exit...");
}


BOOL Snake_Is_Dead()
{
    T_Pos t_head_pos = l_t_snake.at_node[l_t_snake.by_node_num-1].t_pos;
    BYTE i;

    // touch area ----------------
    if(   t_head_pos.by_x == 0
       || t_head_pos.by_x >= _AREA_X_LINE_MAX-1
       || t_head_pos.by_y == 0
       || t_head_pos.by_y >= _AREA_Y_LINE_MAX-1)
    {
        Show_Game_Over();
        return TRUE;
    }

    // touch body --------
    for(i=0 ; i<l_t_snake.by_node_num-1 ; i++)
    {
        if(  t_head_pos.by_x == l_t_snake.at_node[i].t_pos.by_x
           &&t_head_pos.by_y == l_t_snake.at_node[i].t_pos.by_y)
        {
            return TRUE;
        }
    }

    return FALSE;
}


// ------------------------------------
// on snake moving
// ------------------------------------
On_Snake_Moving()
{
    static DWORD dw_time_cur  = 0;
    static DWORD dw_time_last = 0;
    BYTE         by_i = 0;
    T_Pos        t_end_pos_before_moving;
    BYTE by_neck_index, by_head_index;

    // check speed
    dw_time_cur = GetTickCount();
    if(dw_time_cur < dw_time_last + l_t_snake.dw_speed)
    {
        return;
    }
    l_b_key_lock = FALSE;
    dw_time_last = dw_time_cur;

    // move
    by_head_index = l_t_snake.by_node_num - 1;
    by_neck_index = l_t_snake.by_node_num - 2;

    if(  l_t_snake.at_node[by_neck_index].t_pos.by_x != l_t_snake.at_node[by_head_index].t_pos.by_x
       ||l_t_snake.at_node[by_neck_index].t_pos.by_y != l_t_snake.at_node[by_head_index].t_pos.by_y) // last step not eat food
    {
        t_end_pos_before_moving = l_t_snake.at_node[0].t_pos;
        for(by_i=1 ; by_i<l_t_snake.by_node_num ; by_i++)
        {
            l_t_snake.at_node[by_i - 1].t_pos = l_t_snake.at_node[by_i].t_pos;
        }

        // refresh snake
        Pos_Jump(t_end_pos_before_moving.by_x,
                 t_end_pos_before_moving.by_y);
        Rect_Elem_Draw(_ET_MAP_NODE);
    }

    switch(l_t_snake.e_direction)
    {
    case _UP:
        l_t_snake.at_node[by_head_index].t_pos.by_y--;
        break;

    case _DOWN:
        l_t_snake.at_node[by_head_index].t_pos.by_y++;
        break;

    case _LEFT:
        l_t_snake.at_node[by_head_index].t_pos.by_x--;
        break;

    case _RIGHT:
        l_t_snake.at_node[by_head_index].t_pos.by_x++;
        break;
    }

    for(by_i=0 ; by_i<l_t_snake.by_node_num ; by_i++)
    {
        Pos_Jump(l_t_snake.at_node[by_i].t_pos.by_x,
                 l_t_snake.at_node[by_i].t_pos.by_y);
        Rect_Elem_Draw(l_t_snake.at_node[by_i].e_type);
    }

    // eat food
    if(  l_t_snake.at_node[by_head_index].t_pos.by_x == l_t_food.t_pos.by_x
       &&l_t_snake.at_node[by_head_index].t_pos.by_y == l_t_food.t_pos.by_y)
    {
        l_t_snake.at_node[by_head_index+1] = l_t_snake.at_node[by_head_index];
        l_t_snake.at_node[by_head_index].e_type = _ESNT_NODE;
        l_t_snake.by_node_num++;
        l_t_food.b_eaten = TRUE;
    }
}

// ------------------------------------
// key detect
// ------------------------------------
E_KEY_TYPE Key_Detect()
{
    BYTE       by_key_value;
    E_KEY_TYPE e_kt;

    if(0 == kbhit())
    {
        return _E_KT_NONE;
    }

    by_key_value = (BYTE)(getch());

    if(l_b_key_lock)
    {
        return _E_KT_NONE;
    }

    switch(by_key_value)
    {
    case _KEY_UP:
        e_kt = _E_KT_UP;
        break;

    case _KEY_DOWN:
        e_kt = _E_KT_DOWN;
        break;

    case _KEY_LEFT:
        e_kt = _E_KT_LEFT;
        break;

    case _KEY_RIGHT:
        e_kt = _E_KT_RIGHT;
        break;

    default:
        e_kt = _E_KT_NONE;
        break;
    }

    return e_kt;
}


// ------------------------------------
// changing snake direction
// ------------------------------------
void On_Changing_Snake_Drctn(E_KEY_TYPE e_kt)
{
    switch(e_kt)
    {
    case _E_KT_UP:
        if(  (_LEFT  == l_t_snake.e_direction)
           ||(_RIGHT == l_t_snake.e_direction))
        {
            l_t_snake.e_direction = _UP;
        }
        break;

    case _E_KT_DOWN:
        if(  (_LEFT  == l_t_snake.e_direction)
           ||(_RIGHT == l_t_snake.e_direction))
        {
            l_t_snake.e_direction = _DOWN;
        }
        break;

    case _E_KT_LEFT:
        if(  (_UP    == l_t_snake.e_direction)
           ||(_DOWN  == l_t_snake.e_direction))
        {
            l_t_snake.e_direction = _LEFT;
        }
        break;

    case _E_KT_RIGHT:
        if(  (_UP   == l_t_snake.e_direction)
           ||(_DOWN == l_t_snake.e_direction))
        {
            l_t_snake.e_direction = _RIGHT;
        }
        break;
    }
}

// ------------------------------------
// On key down
// ------------------------------------
void On_Key_Down()
{
    E_KEY_TYPE e_kt;

    e_kt = Key_Detect();

    if(_E_KT_NONE != e_kt)
    {
        // lock keyboard
        l_b_key_lock = TRUE;

        // changing snake direction
        On_Changing_Snake_Drctn(e_kt);

        // system operation
    }

}

void Refresh_Food()
{
    T_Pos t_food_pos;
    if(l_t_food.b_eaten)
    {
        srand(time(0));

        t_food_pos.by_x = rand()%(_AREA_X_LINE_MAX-1-1)+1;
        t_food_pos.by_y = rand()%(_AREA_Y_LINE_MAX-1-1)+1;

        l_t_food.t_pos = t_food_pos;
        Pos_Jump(l_t_food.t_pos.by_x, l_t_food.t_pos.by_y);
        Rect_Elem_Draw(_ET_FOOD);

        l_t_food.b_eaten = FALSE;
    }
}


// ------------------------------------
// main
// ------------------------------------
int main()
{
    int i_tmp = 0;

    Area_Init();
    Area_Refresh();
    Snake_Init();

    while(1)
    {
        On_Key_Down();
        On_Snake_Moving();
        Refresh_Food();
        if(TRUE == Snake_Is_Dead())
        {
            break;
        }
    }

    getch();

    return 0;
}




上张截图


posted on 2016-02-17 21:52  神出鬼没的老七  阅读(135)  评论(0编辑  收藏  举报