| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 71534 人关注过本帖, 42 人收藏
标题:三天时间写的俄罗斯方块程序
只看楼主 加入收藏
hoodlum1980
Rank: 2
来 自:浙江大学
等 级:论坛游民
威 望:2
帖 子:289
专家分:23
注 册:2008-2-24
收藏(42)
 问题点数:0 回复次数:346 
三天时间写的俄罗斯方块程序
大概在最近两天之内编码完成,但此前一天开始构思。第一天晚上主要完成了方块旋转算法,第二天也就是今天加了消方块的处理算法。但是可能还有一些考虑不周的地方,比如,没有采用定时中断,而是图方便采用了和cpu频率有关的delay()函数来模拟时间间隔,这是需要改进的地方。
其中的主要逻辑有:
(1)由于c的随机性函数不好,所以每次游戏开始根据bios时间设置种子。
(2)得分越高,方块下降速度越快(每200分为单位)。
(3)每下落一个方块加1分,每消除一行加10分,两行加30分,三行加70分,四行加150分。初试分数为100分。
游戏控制:
   up-旋转;空格-下落到底; 左右下方向键-控制方向。P-开始或暂停游戏。 ESC-退出。
特点:
(1)由于tc不支持中文,所以基本都是英文注释。
(2)函数命名尽可能规范的表达其内部处理目的和过程。
(3)代码加上注释仅有577行。(我下载过的两个俄罗斯方块代码一个在1087行,一个在993行,我的比它们代码少)。
(4)除了消除空格时算法比较复杂,其他算法都比较简单易读。
(5)绘图效率和局部代码效率扔有待提高。
(6)FrameTime参数可能依据不同硬件环境进行具体设置,InitGame需要正确的TC路径。

    俄罗斯方块源于大约9年前上大一时的一个梦,我们在学习c语言时,我的同寝室友邀请我合作一起完成俄罗斯方块(课外作业性质),但是当时限于我们的水平比较菜和学习状态比较懒散,我们没有完成。大一的时候我在机房里无意发现别人留下的俄罗斯方块程序,运行,老师发现后激动的问我是我写的吗,我惭愧的摇摇头。那时看到别人做c的大程序深感羡慕(自己只是写几十行的程序)。数年后我仍然看到有不同样式的实现,但是我一直没有实现它,知道今天忽然有这个想法去做,算是弥补多年前的遗憾和心愿吧。
---------------------------------------------
                  [bo]Q&A:[/bo]
----------------------------------------------
Q:我编译时出现错误:fatal error C1083: Cannot open include file: 'bios.h': Nosuch file or directory,该如何解决?
A:正文中的代码,是使用Borland公司的TC2.0编译的,编译结果运行在Windows的16位虚拟机上。bios.h是属于TC的头文件,在VC或者其他编译器中可能没有这个头文件。因此会产生这个错误。
解决办法:
(1)可以下载附件中的压缩包,是使用VC6.0进行编译的版本,编译结果是Windows程序,运行在windows 32系统上。两者之间的算法完全一致,区别仅仅是绘图时采用的接口不同,TC下采用BGI(进入图形模式),VC下采用的是GDI(使用DC进行绘图)。

(2)下载TC2.0进行编译。

Q:使用TC3.0进行编译时,提示未能初始化图形模式,请使用initgraph函数。
A:这是因为TC3.0的BGI文件的路径和TC2.0有所不同。TC2.0的BGI文件位于TC路径下。而TC3.0的BGI文件位于BGI文件夹中。请把initgame函数中的initgraph函数中的第三个参数设置为正确的路径。例如:initgraph(&..,&..,"C:\\TC\\BGI");

Q:编译后运行时,弹出错误对话框报告16位虚拟机遇到不可执行的指令,点击确定后退出。
A:该问题在某些环境中出现,可能是基于软件或者硬件环境造成,具体原因暂时未知。为避免该问题,请加载附件中的压缩包VC6.0版本。


-----------------------------------------------------------------
TC2.0的代码如下(VC6.0版本代码见附件):

程序代码:
/************************************

 * Desc:    俄罗斯方块游戏        

 * By:    hoodlum1980        

 * Email:    jinfd@* Date:    2008.03.12 22:30        

 ************************************/
#include <stdio.h>
#include <bios.h>
#include <dos.h>
#include <graphics.h>
#include <string.h>
#include <stdlib.h>
#define true         1
#define false         0
#define BoardWidth    12
#define BoardHeight     23
#define _INNER_HELPER /*inner helper method */
/*Scan Codes Define*/
enum KEYCODES
{
    K_ESC                =0x011b,
    K_UP                =0x4800,        /* upward arrow */
    K_LEFT            =0x4b00,
    K_DOWN            =0x5000,
    K_RIGHT            =0x4d00,
    K_SPACE            =0x3920,
    K_P                =0x1970
};

/* the data structure of the block */
typedef struct tagBlock
{
    char c[4][4];    /* cell fill info array, 0-empty, 1-filled */
    int x;                /* block position cx [ 0,BoardWidht -1] */
    int y;                /* block position cy [-4,BoardHeight-1] */
    char color;        /* block color */
    char size;        /* block max size in width or height */
    char name;        /* block name (the block's shape) */
} Block;

/* game's global info */
int FrameTime= 1300;
int CellSize= 18;
int BoardLeft= 30;
int BoardTop=    30;

/* next block grid */
int NBBoardLeft= 300;
int NBBoardTop=    30;
int NBCellSize=  10;

/* score board position */
int ScoreBoardLeft= 300;
int ScoreBoardTop=100;
int ScoreBoardWidth=200;
int ScoreBoardHeight=35;
int ScoreColor=LIGHTCYAN;

/* infor text postion */
int InfoLeft=300;
int InfoTop=200;
int InfoColor=YELLOW;

int BorderColor=DARKGRAY;
int BkGndColor=BLACK;
int GameRunning=true;
int TopLine=BoardHeight-1;    /* top empty line */
int TotalScore=100;
char info_score[20];
char info_help[255];
char info_common[255];

/* our board, Board[x][y][0]-isFilled, Board[x][y][1]-fillColor */
unsigned char Board[BoardWidth][BoardHeight][2];
char BufferCells[4][4];    /* used to judge if can rotate block */
Block curBlock;        /* current moving block */
Block nextBlock;    /* next Block to appear */

/* function list */
int GetKeyCode();
int CanMove(int dx,int dy);
int CanRotate();
int RotateBlock(Block *block);
int MoveBlock(Block *block,int dx,int dy);
void DrawBlock(Block *block,int,int,int);
void EraseBlock(Block *block,int,int,int);
void DisplayScore();
void DisplayInfo(char* text);
void GenerateBlock(Block *block);
void NextBlock();
void InitGame();
int PauseGame();
void QuitGame();

/*Get Key Code */
int _INNER_HELPER GetKeyCode()
{
    int key=0;
    if(bioskey(1))
    {
        key=bioskey(0);
    }
    return key;
}

/* display text! */
void _INNER_HELPER DisplayInfo(char *text)
{
    setcolor(BkGndColor);
    outtextxy(InfoLeft,InfoTop,info_common);
    strcpy(info_common,text);
    setcolor(InfoColor);
    outtextxy(InfoLeft,InfoTop,info_common);
}

/* create a new block by key number,

 * the block anchor to the top-left corner of 4*4 cells

 */
void _INNER_HELPER GenerateBlock(Block *block)
{
    int key=(random(13)*random(17)+random(1000)+random(3000))%7;
    block->size=3;/* because most blocks' size=3 */
    memset(block->c,0,16);
    switch(key)
    {
        case 0:
            block->name='T';
            block->color=RED;
            block->c[1][0]=1;
            block->c[1][1]=1, block->c[2][1]=1;
            block->c[1][2]=1;
            break;
        case 1:
            block->name='L';
            block->color=YELLOW;
            block->c[1][0]=1;
            block->c[1][1]=1;
            block->c[1][2]=1, block->c[2][2]=1;
            break;
        case 2:
            block->name='J';
            block->color=LIGHTGRAY;
            block->c[1][0]=1;
            block->c[1][1]=1;
            block->c[1][2]=1, block->c[0][2]=1;
            break;
        case 3:
            block->name='z';
            block->color=CYAN;
            block->c[0][0]=1, block->c[1][0]=1;
            block->c[1][1]=1, block->c[2][1]=1;
            break;
        case 4:
            block->name='5';
            block->color=LIGHTBLUE;
            block->c[1][0]=1, block->c[2][0]=1;
            block->c[0][1]=1, block->c[1][1]=1;
            break;
        case 5:
            block->name='o';
            block->color=BLUE;
            block->size=2;
            block->c[0][0]=1, block->c[1][0]=1;
            block->c[0][1]=1, block->c[1][1]=1;
            break;
        case 6:
            block->name='I';
            block->color=GREEN;
            block->size=4;
            block->c[1][0]=1;
            block->c[1][1]=1;
            block->c[1][2]=1;
            block->c[1][3]=1;
            break;
    }
}

/* get next block! */
void NextBlock()
{
    /* copy the nextBlock to curBlock */
    curBlock.size=nextBlock.size;
    curBlock.color=nextBlock.color;
    curBlock.x=(BoardWidth-4)/2;
    curBlock.y=-curBlock.size;
    memcpy(curBlock.c,nextBlock.c,16);
    /* generate nextBlock and show it */
    EraseBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);
    GenerateBlock(&nextBlock);
    nextBlock.x=1,nextBlock.y=0;
    DrawBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);
}

/* rotate the block, update the block struct data */
int _INNER_HELPER RotateCells(char c[4][4],char blockSize)
{
    char temp,i,j;
    switch(blockSize)
    {
        case 3:
            temp=c[0][0];
            c[0][0]=c[2][0], c[2][0]=c[2][2],    c[2][2]=c[0][2], c[0][2]=temp;
            temp=c[0][1];
            c[0][1]=c[1][0], c[1][0]=c[2][1],    c[2][1]=c[1][2], c[1][2]=temp;
            break;
        case 4:    /* only 'I' block arived here! */
            c[1][0]=1-c[1][0], c[1][2]=1-c[1][2], c[1][3]=1-c[1][3];
            c[0][1]=1-c[0][1], c[2][1]=1-c[2][1],    c[3][1]=1-c[3][1];
            break;
    }
}

/* judge if the block can move toward the direction */
int CanMove(int dx,int dy)
{
    int i,j,tempX,tempY;
    for(i=0;i<curBlock.size;i++)
    {
        for(j=0;j<curBlock.size;j++)
        {
            if(curBlock.c[i][j])
            {
                /* cannot move leftward or rightward */
                tempX = curBlock.x + i + dx;
                if(tempX<0 || tempX>(BoardWidth-1))    return false; /* make sure x is valid! */
                /* cannot move downward */
                tempY = curBlock.y + j + dy;
                if(tempY>(BoardHeight-1))    return false; /* y is only checked lower bound, maybe negative!!!! */
                /* the cell already filled, we must check Y's upper bound before check cell ! */
                if(tempY>=0 && Board[tempX][tempY][0]) return false;
            }
        }
    }
    return true;
}

/* judge if the block can rotate */
int CanRotate()
{
    int i,j,tempX,tempY;
    /* update buffer */
    memcpy(BufferCells, curBlock.c, 16);
    RotateCells(BufferCells,curBlock.size);
    for(i=0;i<curBlock.size;i++)
    {
        for(j=0;j<curBlock.size;j++)
        {
            if(BufferCells[i][j])
            {
                tempX=curBlock.x+i;
                tempY=curBlock.y+j;
                if(tempX<0 || tempX>(BoardWidth-1))
                    return false;
                if(tempY>(BoardHeight-1))
                    return false;
                if(tempY>=0 && Board[tempX][tempY][0])
                    return false;
            }
        }
    }
    return true;
}

/* draw the block */
void _INNER_HELPER DrawBlock(Block *block,int bdLeft,int bdTop,int cellSize)
{
    int i,j;
    setfillstyle(SOLID_FILL,block->color);
    for(i=0;i<block->size;i++)
    {
        for(j=0;j<block->size;j++)
        {
            if(block->c[i][j] && (block->y+j)>=0)
            {
                floodfill(
                    bdLeft+cellSize*(i+block->x)+cellSize/2,
                    bdTop+cellSize*(j+block->y)+cellSize/2,
                    BorderColor);
            }
        }
    }
}

/* Rotate the block, if success, return true */
int RotateBlock(Block *block)
{
    char temp,i,j;
    int b_success;
    if(block->size==2)
        return true;
    if(( b_success=CanRotate()))
    {
        EraseBlock(block,BoardLeft,BoardTop,CellSize);
        memcpy(curBlock.c,BufferCells,16);
        DrawBlock(block,BoardLeft,BoardTop,CellSize);
    }
    return b_success;
}


/* erase a block, only fill the filled cell with background color */
void _INNER_HELPER EraseBlock(Block *block,int bdLeft,int bdTop,int cellSize)
{
    int i,j;
    setfillstyle(SOLID_FILL,BkGndColor);
    for(i=0;i<block->size;i++)
    {
        for(j=0;j<block->size;j++)
        {
            if(block->c[i][j] && (block->y+j>=0))
            {
                floodfill(
                    bdLeft+cellSize*(i+block->x)+cellSize/2,
                    bdTop+cellSize*(j+block->y)+cellSize/2,
                    BorderColor);
            }
        }
    }
}

/* move by the direction if can, donothing if cannot

 * return value: true - success, false - cannot move toward this direction

 */
int MoveBlock(Block *block,int dx,int dy)
{
    int b_canmove=CanMove(dx,dy);
    if(b_canmove)
    {
        EraseBlock(block,BoardLeft,BoardTop,CellSize);
        curBlock.x+=dx;
        curBlock.y+=dy;
        DrawBlock(block,BoardLeft,BoardTop,CellSize);
    }
    return b_canmove;
}

/* drop the block to the bottom! */
int DropBlock(Block *block)
{
    EraseBlock(block,BoardLeft,BoardTop,CellSize);
    while(CanMove(0,1))
    {
        curBlock.y++;
    }
    DrawBlock(block,BoardLeft,BoardTop,CellSize);
    return 0;/* return value is assign to the block's alive */
}


/* init the graphics mode, draw the board grid */
void InitGame()
{
    int i,j,gdriver=DETECT,gmode;
    struct time sysTime;
    /* draw board cells */
    memset(Board,0,BoardWidth*BoardHeight*2);
    memset(nextBlock.c,0,16);
    strcpy(info_help,"P: Pause Game. --by hoodlum1980");
    initgraph(&gdriver,&gmode,"");
    setcolor(BorderColor);
    for(i=0;i<=BoardWidth;i++)
    {
        line(BoardLeft+i*CellSize, BoardTop, BoardLeft+i*CellSize, BoardTop+ BoardHeight*CellSize);
    }
    for(i=0;i<=BoardHeight;i++)
    {
        line(BoardLeft, BoardTop+i*CellSize, BoardLeft+BoardWidth*CellSize, BoardTop+ i*CellSize);
    }
    /* draw board outer border rect */
    rectangle(BoardLeft-CellSize/4, BoardTop-CellSize/4,
        BoardLeft+BoardWidth*CellSize+CellSize/4,
        BoardTop+BoardHeight*CellSize+CellSize/4);

    /* draw next block grids */
    for(i=0;i<=4;i++)
    {
        line(NBBoardLeft+i*NBCellSize, NBBoardTop, NBBoardLeft+i*NBCellSize, NBBoardTop+4*NBCellSize);
        line(NBBoardLeft, NBBoardTop+i*NBCellSize, NBBoardLeft+4*NBCellSize, NBBoardTop+ i*NBCellSize);
    }

    /* draw score rect */
    rectangle(ScoreBoardLeft,ScoreBoardTop,ScoreBoardLeft+ScoreBoardWidth,ScoreBoardTop+ScoreBoardHeight);
    DisplayScore();

    /* set new seed! */
    gettime(&sysTime);
    srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec);

    GenerateBlock(&nextBlock);
    NextBlock();    /* create first block */
    setcolor(DARKGRAY);
    outtextxy(InfoLeft,InfoTop+20,"Up  -rotate  Space-drop");
    outtextxy(InfoLeft,InfoTop+35,"Left-left    Right-right");
    outtextxy(InfoLeft,InfoTop+50,"Esc -exit");
    DisplayInfo(info_help);
}

/* set the isFilled and fillcolor data to the board */
void _INNER_HELPER FillBoardData()
{
    int i,j;
    for(i=0;i<curBlock.size;i++)
    {
        for(j=0;j<curBlock.size;j++)
        {
            if(curBlock.c[i][j] && (curBlock.y+j)>=0)
            {
                Board[curBlock.x+i][curBlock.y+j][0]=1;
                Board[curBlock.x+i][curBlock.y+j][1]=curBlock.color;
            }
        }
    }
}

/* draw one line of the board */
void _INNER_HELPER PaintBoard()
{
    int i,j,fillcolor;
    for(j=max((TopLine-4),0);j<BoardHeight;j++)
    {
        for(i=0;i<BoardWidth;i++)
        {
            fillcolor=Board[i][j][0]? Board[i][j][1]:BkGndColor;
            setfillstyle(SOLID_FILL,fillcolor);
            floodfill(BoardLeft+i*CellSize+CellSize/2,BoardTop+j*CellSize+CellSize/2,BorderColor);
        }
    }
}

/* check if one line if filled full and increase the totalScore! */
void _INNER_HELPER CheckBoard()
{
    int i,j,k,score=10,sum=0,topy,lines=0;
    /* we find the top empty line! */
    j=topy=BoardHeight-1;
    do
    {
        sum=0;
        for(i=0;i< BoardWidth; i++)
        {
            sum+=Board[i][topy][0];
        }
        topy--;
    } while(sum>0 && topy>0);

    /* remove the full filled line (max remove lines count = 4) */
    do
    {
        sum=0;
        for(i=0;i< BoardWidth; i++)
            sum+=Board[i][j][0];

        if(sum==BoardWidth)/* we find this line is full filled, remove it! */
        {
            /* move the cells data down one line */
            for(k=j; k > topy;k--)
            {
                for(i=0;i<BoardWidth;i++)
                {
                    Board[i][k][0]=Board[i][k-1][0];
                    Board[i][k][1]=Board[i][k-1][1];
                }
            }
            /*make the top line empty! */
            for(i=0;i<BoardWidth;i++)
            {
                Board[i][topy][0]=0;
                Board[i][topy][1]=0;
            }
            topy++;        /* move the topline downward one line! */
            lines++;    /* lines <=4 */
            TotalScore+=score;
            score*=2;    /* adding: 10, 30, 70, 150 */
        }
        else
            j--;
    } while(sum>0 && j>topy && lines<4);
    /* speed up the game when score is high, minimum is 400 */
    FrameTime=max(1200-100*(TotalScore/200), 400);
    TopLine=topy;/* update the top line */
    /* if no lines remove, only add 1: */
    if(lines==0)
        TotalScore++;
}

/* display the score */
void _INNER_HELPER DisplayScore()
{
    setcolor(BkGndColor);
    outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score);
    setcolor(ScoreColor);
    sprintf(info_score,"Score: %d",TotalScore);
    outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score);
}

/* we call this function when a block is inactive. */
void UpdateBoard()
{
    FillBoardData();
    CheckBoard();
    PaintBoard();
    DisplayScore();
}

/* pause the game, and timer handler stop move down the block! */
int PauseGame()
{
    int key=0;
    DisplayInfo("Press P to Start or Resume!");
    while(key!=K_P && key!=K_ESC)
    {
        while(!(key=GetKeyCode())){}
    }
    DisplayInfo(info_help);
    return key;
}

/* quit the game and do cleaning work. */
void QuitGame()
{
    closegraph();
}

/* the entry point function. */
void main()
{
    int i,flag=1,j,key=0,tick=0;
    InitGame();
    if(PauseGame()==K_ESC)
        goto GameOver;
    /* wait until a key pressed */
    while(key!=K_ESC)
    {
        /* wait until a key pressed */
        while(!(key=GetKeyCode()))
        {
            tick++;
            if(tick>=FrameTime)
            {
                /* our block has dead! (can't move down), we get next block */
                if(!MoveBlock(&curBlock,0,1))
                {
                    UpdateBoard();
                    NextBlock();
                    if(!CanMove(0,1))
                        goto GameOver;
                }
                tick=0;
            }
            delay(100);
        }
        switch(key)
        {
            case K_LEFT:
                MoveBlock(&curBlock,-1,0);
                break;
            case K_RIGHT:
                MoveBlock(&curBlock,1,0);
                break;
            case K_DOWN:
                MoveBlock(&curBlock,0,1);
                break;
            case K_UP:
                RotateBlock(&curBlock);
                break;
            case K_SPACE:
                DropBlock(&curBlock);
                break;
            case K_P:
                PauseGame();
                break;
        }
    }
GameOver:
    DisplayInfo("GAME OVER!  Press any key to exit!");
    getch(); /* wait the user Press any key. */
    QuitGame();
}


els_vc版_hoodlum1980.rar (52.27 KB) 改编的win(vc6.0)版代码



ELS_WIN_SNAP.jpg (24.81 KB)
图片附件: 游客没有浏览图片的权限,请 登录注册
收到的鲜花
  • cosdos2008-03-16 00:56 送鲜花  6朵   附言:我也想写一个
搜索更多相关主题的帖子: 俄罗斯方块 程序 时间 
2008-03-12 23:05
xianshizhe111
Rank: 1
等 级:新手上路
帖 子:1451
专家分:0
注 册:2007-12-8
收藏
得分:0 
顶..支持.
2008-03-13 14:10
sunkaidong
Rank: 4
来 自:南京师范大学
等 级:贵宾
威 望:12
帖 子:4496
专家分:141
注 册:2006-12-28
收藏
得分:0 
支持。。。。

学习需要安静。。海盗要重新来过。。
2008-03-13 14:25
死了都要C
Rank: 4
来 自:四川成都
等 级:贵宾
威 望:13
帖 子:1582
专家分:116
注 册:2006-12-7
收藏
得分:0 
厉害```我也想写个几千行的代码啊``

女施主``我给你``送茶来了```师太``你就从了老衲吧``
代码本天成~~~妙头偶得之```
2008-03-13 15:27
秦子风
Rank: 1
来 自:陕西
等 级:新手上路
帖 子:7
专家分:0
注 册:2008-3-13
收藏
得分:0 
2008-03-13 17:04
chmlqw
Rank: 1
等 级:新手上路
帖 子:180
专家分:0
注 册:2007-10-11
收藏
得分:0 
哇,等我也时间我也学写一下.....
2008-03-13 17:07
龙眼望天下
Rank: 1
等 级:新手上路
帖 子:8
专家分:0
注 册:2007-12-5
收藏
得分:0 
我也要学一下了!
2008-03-13 18:11
coned
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2008-1-25
收藏
得分:0 
哪天我也能写这么长的代码我就高兴了.
2008-03-13 18:57
lv5sky
Rank: 1
等 级:新手上路
帖 子:76
专家分:0
注 册:2007-10-5
收藏
得分:0 
我也好想像这样!
我一定可以! 办的到!
2008-03-13 19:17
neverTheSame
Rank: 3Rank: 3
来 自:江西农业大学
等 级:新手上路
威 望:9
帖 子:1511
专家分:0
注 册:2006-11-24
收藏
得分:0 
顶一下.

wap酷禾网(http://wap.),提供免费的、优质的、快捷的wap资源下载服务。
2008-03-13 20:17
快速回复:三天时间写的俄罗斯方块程序
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.044058 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved