zoukankan      html  css  js  c++  java
  • 用C写的俄罗斯方块游戏 By: hoodlum1980 编程论坛

    /************************************
    * Desc:    俄罗斯方块游戏        
    * By:    hoodlum1980        
    * Email:    jinfd@126.com        
    * 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();
    }
  • 相关阅读:
    侦测卡 变色龙侦测卡 chameleon-Mini(迷你变色龙) (三)
    侦测卡 变色龙侦测卡 chameleon-Mini(迷你变色龙) (二)
    侦测卡 变色龙侦测卡 chameleon-Mini(迷你变色龙) (一)
    Android使用NFC模拟M卡实现 (二)
    scala中eq,==和equals的区别
    scala @BeanProperty 自动添加getter 和setter
    Scala 可变参数
    Flink 侧输出流 DEMO
    Flink 写数据到MySql (JDBC Sink)
    Fink 写数据到kafka (kafka sink)
  • 原文地址:https://www.cnblogs.com/hello-2015/p/4448059.html
Copyright © 2011-2022 走看看