console下纯字符实现的俄罗斯方块

本文介绍了一个使用C语言在Windows环境下实现的简单俄罗斯方块游戏。游戏包括移动、旋转方块的功能,并支持基本的游戏逻辑如消除行等。文章提供了完整的源代码及详细注释。

忙里偷闲,消遣一下,先上一张寒酸的效果图:



废话不多说,直接上代码,win7 64 code blocks编译通过。

吐槽一下cb的watch功能实在不够友好,不过免费的也不能要求太高。


【按键说明】

A:向左

D:向右

S:向下

Space:变化



#include "stdio.h"
#include "stdlib.h"
#include "windows.h"
#include "time.h"


// ----------------------------------------------------------------------------
//                 local define
// ----------------------------------------------------------------------------

#define _KEY_DOWN           's'
#define _KEY_LEFT           'a'
#define _KEY_RIGHT          'd'

#define _KEY_CHANGE         ' '

#define _BLOCK_X_MAX        20
#define _BLOCK_Y_MAX        20
#define _BLOCK_UNIT_NONE    ' '
#define _BLOCK_UNIT_TETRIS  '@'
#define _BLOCK_UNIT_EDGE    '*'

#define _TETRIS_BUF_SIZE    4
#define _TETRIS_TYPE_NUM    7

#define _TETRIS_SPEED       600

#define _CHANGE_TIME_MAX    4

// ----------------------------------------------------------------------------
//                 local 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;



typedef enum
{
    _E_KT_NONE,

    _E_KT_DOWN,
    _E_KT_LEFT,
    _E_KT_RIGHT,
    _E_KT_CHANGE,

    _E_KT_SIZE
}E_KEY_TYPE;


typedef struct
{
    int i_x;
    int i_y;
}T_Tetris_Unit_Pos;

// ----------------------------------------------------------------------------
//                 local vars
// ----------------------------------------------------------------------------
const T_Tetris_Unit_Pos __DB[_TETRIS_TYPE_NUM][_TETRIS_BUF_SIZE] =
{
/*
 @@
  @@
 */
{{_BLOCK_X_MAX/2, 0},{_BLOCK_X_MAX/2+1, 0},{_BLOCK_X_MAX/2+1, 1},{_BLOCK_X_MAX/2+2, 1}},
/*
  @@
 @@
 */
{{_BLOCK_X_MAX/2+1, 0},{_BLOCK_X_MAX/2+2, 0},{_BLOCK_X_MAX/2, 1},{_BLOCK_X_MAX/2+1, 1}},
/*
  @
 @@@
 */
{{_BLOCK_X_MAX/2, 0},{_BLOCK_X_MAX/2-1, 1},{_BLOCK_X_MAX/2, 1},{_BLOCK_X_MAX/2+1, 1}},
/*
   @
 @@@
 */
{{_BLOCK_X_MAX/2, 0},{_BLOCK_X_MAX/2-2, 1},{_BLOCK_X_MAX/2-1, 1},{_BLOCK_X_MAX/2, 1}},
/*
 @
 @@@
 */
{{_BLOCK_X_MAX/2, 0},{_BLOCK_X_MAX/2, 1},{_BLOCK_X_MAX/2+1, 1},{_BLOCK_X_MAX/2+2, 1}},
/*
 @@
 @@
 */
{{_BLOCK_X_MAX/2, 0},{_BLOCK_X_MAX/2+1, 0},{_BLOCK_X_MAX/2, 1},{_BLOCK_X_MAX/2+1, 1}},
/*
 @@@@
 */
{{_BLOCK_X_MAX/2, 1},{_BLOCK_X_MAX/2+1, 1},{_BLOCK_X_MAX/2+2, 1},{_BLOCK_X_MAX/2+3, 1}},
};

const DWORD __OFFSET[_TETRIS_TYPE_NUM][_CHANGE_TIME_MAX] =
{
/*
 @@
  @@
 */
{0x00101121, 0x10110102, 0x00101121, 0x10110102},
/*
  @@
 @@
 */
{0x10200111, 0x01001211, 0x10200111, 0x01001211},
/*
  @
 @@@
 */
{0x10011121, 0x21101112, 0x12211101, 0x01121110},
/*
   @
 @@@
 */
{0x20011121, 0x22101112, 0x02211101, 0x00121110},
/*
 @
 @@@
 */
{0x00011121, 0x10000102, 0x21201000, 0x02121110},
/*
 @@
 @@
 */
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
/*
 @@@@
 */
{0x01112131, 0x00010203, 0x01112131, 0x00010203},
};


T_Tetris_Unit_Pos l_at_cur_tetris[_TETRIS_BUF_SIZE];
BYTE l_by_offset_index = 0;
BYTE l_by_db_index = 0;
BYTE l_aby_block[_BLOCK_Y_MAX][_BLOCK_X_MAX];


// ----------------------------------------------------------------------------
//                 funcs part
// ----------------------------------------------------------------------------

void Pos_Jump(int x, int y)
{
    COORD  pos  = {x, y};
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut, pos);
}

void Pos_Jump_In_Block(int x, int y)
{
    Pos_Jump(x+1, y+1);
}

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

    case _KEY_CHANGE:
        e_kt = _E_KT_CHANGE;
        break;

    default:
        e_kt = _E_KT_NONE;
        break;
    }

    return e_kt;
}


void Show_Block()
{
    int i, j;

    // set default value -----
    for(i=0 ; i<_BLOCK_Y_MAX ; i++)
    {
        for(j=0 ; j<_BLOCK_X_MAX ; j++)
        {
            l_aby_block[i][j] = _BLOCK_UNIT_NONE;
        }
    }

    // show frame -------
    // top
    Pos_Jump(0, 0);
    for(i=0 ; i<_BLOCK_X_MAX+2 ; i++)
    {
        printf("%c", _BLOCK_UNIT_EDGE);
    }

    // bottom
    Pos_Jump(0, _BLOCK_Y_MAX+1);
    for(i=0 ; i<_BLOCK_X_MAX+2 ; i++)
    {
        printf("%c", _BLOCK_UNIT_EDGE);
    }

    // side
    for(j=1 ; j<_BLOCK_Y_MAX+1 ; j++)
    {
        Pos_Jump(0, j);
        printf("%c", _BLOCK_UNIT_EDGE);
        Pos_Jump(_BLOCK_X_MAX+1, j);
        printf("%c", _BLOCK_UNIT_EDGE);
    }
}


BOOL Get_New()
{
    int i_type_num;
    int i;

    srand(time(0));
    i_type_num = rand()%(_TETRIS_TYPE_NUM);

    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        l_at_cur_tetris[i] = __DB[i_type_num][i];
    }
    l_by_offset_index = 0;
    l_by_db_index = i_type_num;

    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        if(_BLOCK_UNIT_TETRIS == l_aby_block[l_at_cur_tetris[i].i_y][l_at_cur_tetris[i].i_x])
        {
            return FALSE;
        }
    }

    return TRUE;
}

void Clear_Cur_Tetris()
{
    int i;
    // draw new ----------
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        Pos_Jump_In_Block(l_at_cur_tetris[i].i_x, l_at_cur_tetris[i].i_y);
        printf(" ");
    }
}

void Show_Cur_Tetris()
{
    int i;
    // draw new ----------
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        Pos_Jump_In_Block(l_at_cur_tetris[i].i_x, l_at_cur_tetris[i].i_y);
        printf("@");
    }
}

void Move_Left()
{
    int i;
    T_Tetris_Unit_Pos at_next[_TETRIS_BUF_SIZE];

    // calc next ---
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        at_next[i] = l_at_cur_tetris[i];
        if(0 == at_next[i].i_x)
        {
            return;
        }
        at_next[i].i_x--;
    }

    // clear old ---------
    Clear_Cur_Tetris();
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        l_at_cur_tetris[i] = at_next[i];
    }
    Show_Cur_Tetris();
}

void Move_Right()
{
    int i;
    T_Tetris_Unit_Pos at_next[_TETRIS_BUF_SIZE];

    // calc next ---
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        at_next[i] = l_at_cur_tetris[i];
        at_next[i].i_x++;
        if(_BLOCK_X_MAX == at_next[i].i_x)
        {
            return;
        }
    }

    // clear old ---------
    Clear_Cur_Tetris();
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        l_at_cur_tetris[i] = at_next[i];
    }
    Show_Cur_Tetris();
}

BOOL Move_Down()
{
    int i;
    T_Tetris_Unit_Pos at_next[_TETRIS_BUF_SIZE];
    BOOL b_can_down = FALSE;

    // calc next ---
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        at_next[i] = l_at_cur_tetris[i];
        at_next[i].i_y++;
    }

    // check if next is ok ---
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        if(  _BLOCK_UNIT_TETRIS == l_aby_block[at_next[i].i_y][at_next[i].i_x]
           ||_BLOCK_Y_MAX == at_next[i].i_y)
        {
            b_can_down = FALSE;
            return b_can_down;
        }
    }

    // clear old ---------
    Clear_Cur_Tetris();
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        l_at_cur_tetris[i] = at_next[i];
    }
    Show_Cur_Tetris();

    b_can_down = TRUE;
    return b_can_down;
}


void On_Change()
{
    int i;
    DWORD dw_cur, dw_next;
    int i_x_offset, i_y_offset;
    int i_x_min, i_x_max;
    T_Tetris_Unit_Pos at_next[_TETRIS_BUF_SIZE];

    if(_CHANGE_TIME_MAX-1 != l_by_offset_index)
    {
        dw_cur = __OFFSET[l_by_db_index][l_by_offset_index];
        dw_next = __OFFSET[l_by_db_index][l_by_offset_index+1];
    }
    else
    {
        dw_cur = __OFFSET[l_by_db_index][_CHANGE_TIME_MAX-1];
        dw_next = __OFFSET[l_by_db_index][0];
    }

    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        i_x_offset = (int)(((dw_next>>8*(4-i-1))&0xF0)>>4) - (int)(((dw_cur>>8*(4-i-1))&0xF0)>>4);
        i_y_offset = (int)((dw_next>>8*(4-i-1))&0x0F) - (int)((dw_cur>>8*(4-i-1))&0x0F);

        at_next[i] = l_at_cur_tetris[i];

        at_next[i].i_x += i_x_offset;
        at_next[i].i_y += i_y_offset;
    }

    // check ------
    i_x_min = at_next[0].i_x;
    i_x_max = at_next[0].i_x;
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        if(i_x_min > at_next[i].i_x)
        {
           i_x_min = at_next[i].i_x;
        }

        if(i_x_max < at_next[i].i_x)
        {
           i_x_max = at_next[i].i_x;
        }
    }

    if(i_x_min < 0)
    {
        for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
        {
            at_next[i].i_x -= i_x_min;
        }
    }

    if(i_x_max > _BLOCK_X_MAX-1)
    {
        for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
        {
            at_next[i].i_x -= i_x_max - (_BLOCK_X_MAX-1);
        }
    }

    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        if(_BLOCK_UNIT_TETRIS == l_aby_block[at_next[i].i_x][at_next[i].i_y])
        {
            // can not change -------
            return;
        }
    }

    // ----------------
    l_by_offset_index++;
    l_by_offset_index = l_by_offset_index % _CHANGE_TIME_MAX;

    Clear_Cur_Tetris();
    for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
    {
        l_at_cur_tetris[i] = at_next[i];
    }
    Show_Cur_Tetris();
}

void On_Key_Detecting()
{
    E_KEY_TYPE e_type;

    e_type = Key_Detect();

    if(_E_KT_NONE == e_type)
    {
        return;
    }

    if(_E_KT_CHANGE == e_type)
    {
        On_Change();
    }

    if(_E_KT_LEFT == e_type)
    {
        Move_Left();
    }

    if(_E_KT_RIGHT == e_type)
    {
        Move_Right();
    }

    if(_E_KT_DOWN == e_type)
    {
        Move_Down();
    }
}

void Show_Game_Over()
{
    Pos_Jump(0, _BLOCK_Y_MAX+2);
    printf("Game Over!!!");
}


BOOL On_Timer()
{
    static DWORD dw_time_cur  = 0;
    static DWORD dw_time_last = 0;
    int i;

    // check speed
    dw_time_cur = GetTickCount();
    if(dw_time_cur < dw_time_last + _TETRIS_SPEED)
    {
        return FALSE;
    }
    dw_time_last = dw_time_cur;

    if(FALSE == Move_Down())
    {
        for(i=0 ; i<_TETRIS_BUF_SIZE ; i++)
        {
            l_aby_block[l_at_cur_tetris[i].i_y][l_at_cur_tetris[i].i_x] = _BLOCK_UNIT_TETRIS;
        }

        if(FALSE == Get_New())
        {
            Show_Cur_Tetris();
            return TRUE;
        }
    }

    return FALSE;
}


void Line_Blink(int y, BOOL b_show)
{
    int i;
    // draw new ----------
    Pos_Jump_In_Block(0, y);
    for(i=0 ; i<_BLOCK_X_MAX ; i++)
    {
        if(b_show)
        {
            printf("%c", _BLOCK_UNIT_TETRIS);
        }
        else
        {
            printf("%c", _BLOCK_UNIT_NONE);
        }
    }
}


void Eliminate()
{
    int i, j, k;
    int i_blink_times;
    BOOL ab_eliminate_flag[_BLOCK_Y_MAX], b_need_blink = FALSE;
    DWORD dw_blink_time = 200;
    DWORD dw_time_cur;

    // check which line need to eliminate ------
    for(j=0 ; j<_BLOCK_Y_MAX ; j++)
    {
        ab_eliminate_flag[j] = TRUE;
        for(i=0 ; i<_BLOCK_X_MAX ; i++)
        {
            if('@' != l_aby_block[j][i])
            {
                ab_eliminate_flag[j] = FALSE;
                break;
            }
        }

        if(ab_eliminate_flag[j])
        {
            b_need_blink = TRUE;
        }
    }

    if(FALSE == b_need_blink)
    {
        return;
    }

    // blink -----------
    i_blink_times = 3;
    for(i=0 ; i<i_blink_times ; i++)
    {
        dw_time_cur = GetTickCount();
        while(TRUE)
        {
            if((dw_time_cur + dw_blink_time) < GetTickCount())
            {
                break;
            }
        }

        for(j=0 ; j<_BLOCK_Y_MAX ; j++)
        {
            if(ab_eliminate_flag[j])
            {
                Line_Blink(j, FALSE);
            }
        }

        dw_time_cur = GetTickCount();
        while(TRUE)
        {
            if((dw_time_cur + dw_blink_time) < GetTickCount())
            {
                break;
            }
        }

        for(j=0 ; j<_BLOCK_Y_MAX ; j++)
        {
            if(ab_eliminate_flag[j])
            {
                Line_Blink(j, TRUE);
            }
        }
    }

    // remove ----------
    for(j=0 ; j<_BLOCK_Y_MAX ; j++)
    {
        if(ab_eliminate_flag[j])
        {
            for(i=0 ; i<_BLOCK_X_MAX ; i++)
            {
                l_aby_block[j][i] = ' ';
            }

            for(k=j ; k>0 ; k--)
            {
                for(i=0 ; i<_BLOCK_X_MAX ; i++)
                {
                    l_aby_block[k][i] = l_aby_block[k-1][i];
                }
            }
        }
    }

    for(j=0 ; j<_BLOCK_Y_MAX ; j++)
    {
        Pos_Jump_In_Block(0, j);
        for(i=0 ; i<_BLOCK_X_MAX ; i++)
        {
            printf("%c", l_aby_block[j][i]);
        }
    }

}


int main()
{
    BOOL b_game_over;

    Show_Block();
    Get_New();
    Show_Cur_Tetris();

    while(TRUE)
    {
        On_Key_Detecting();

        b_game_over = On_Timer();
        if(b_game_over)
        {
            Show_Game_Over();
            break;
        }

        Eliminate();
    }

    getch();

    return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值