Bootstrap

C++ 俄罗斯方块

C++ 实现俄罗斯方块

感谢接口实验,在8086上实现俄罗斯方块还是相当酸爽的。。。。
考虑到逻辑的复杂性,就先使用C++实现了算法,以确保算法的正确性,此处放出C++代码,需要注意的是,并没有模拟自动时钟,而是将方块自动下落的时钟改为外部控制:
具体而言,程序运行时的不同种类控制指令如下,需要特别指出的是,n表示时钟,即使得方块按照一定频率自动下落的信号,如果你想要得到俄罗斯方块自动下落一格的下一状态,输入n即可

op: d 直接下落到底
op: l 左移
op: r 右移
op: s 旋转(逆时针)
op: n 一个时钟沿
op: q 退出
种类号与各个方块对应关系如下:
在这里插入图片描述

关于方块存储的数据结构的一点更详细的举例说明:

struct block{
int w,h;//方块占用的列数w、行数h(将其看作一个矩形)
int row,column;//方块所在矩形的最左上角坐标
int b[4];//当前方块每行的状态,具体可参照init函数实现
};
0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
如上图,则当前图中的方块所对应各项数值:w 2,h 3,row 1,column 0
b={1, 3, 2},需要注意的是,在状态图每行从左到右依次为所对应2进制状态数的低位和高位

#include<iostream>
#include<ctime>
using namespace std;
int mp[10],now_block;
int row,column;
int score=0;
bool over=false;//游戏是否结束
/*
status: 0 正在下落
        1 触底
        2 game over
*/
/*
本程序为俄罗斯方块的模拟,棋盘大小为8*8,
由于棋盘大小为8*8,所以使用大小为8的一维数组存储即可,
每行用一个8位二进制数表示,0表示无方块,1表示有方块
*/
struct block{
    int w,h;//方块占用的列数w、行数h(将其看作一个矩形)
    int row,column;//方块所在矩形的最左上角坐标
    int b[4];//当前方块每行的状态,具体可参照init函数实现
    block(){}
    block(int _h,int _w){
        row=0;
        column=0;
        w=_w;
        h=_h;
    }
}blocks[19],now;

//判断下一步能不能走通
bool judge(block);

//一些初始化,构造不同种类的俄罗斯方块,不同方向、不同形状共19种
void init();

/*响应一些控制:
    op: d 直接下落到底
    op: l 左移
    op: r 右移
    op: s 旋转(逆时针)
    op: n 一个时钟沿
    op: q 退出
*/
void control(char);

//当有一个方块触底时,更新状态图
void draw();

//打印当前的状态图
void print();

int main(){
    init();
    char ch;
    srand(time(0));
    now_block = rand()%19;
    now=blocks[now_block];
    while(cin>>ch){
        if(ch=='\n'||ch==' ') continue;
        if(ch=='q') break;
        control(ch);
        print();
        if(over){
            cout<<"Game Over!!!\n"<<"You've got"<<score<<"points.\n"<<"Hope to see you again~"<<endl;
        }
    }
    return 0;
}

void init(){
    blocks[0]=block(2,3);
    blocks[0].b[0]=6;
    blocks[0].b[1]=3;

    blocks[1]=block(3,2);
    blocks[1].b[0]=1;
    blocks[1].b[1]=3;
    blocks[1].b[2]=2;

    blocks[2]=block(2,3);
    blocks[2].b[0]=3;
    blocks[2].b[1]=6;

    blocks[3]=block(3,2);
    blocks[3].b[0]=2;
    blocks[3].b[1]=3;
    blocks[3].b[2]=1;

    blocks[4]=block(2,2);
    blocks[4].b[0]=3;
    blocks[4].b[1]=3;

    blocks[5]=block(1,4);
    blocks[5].b[0]=15;
    
    blocks[6]=block(4,1);
    blocks[6].b[0]=2;
    blocks[6].b[1]=2;
    blocks[6].b[2]=2;
    blocks[6].b[3]=2;

    blocks[7]=block(2,3);
    blocks[7].b[0]=2;
    blocks[7].b[1]=7;

    blocks[8]=block(3,2);
    blocks[8].b[0]=2;
    blocks[8].b[1]=3;
    blocks[8].b[2]=2;

    blocks[9]=block(2,3);
    blocks[9].b[0]=7;
    blocks[9].b[1]=2;

    blocks[10]=block(3,2);
    blocks[10].b[0]=1;
    blocks[10].b[1]=3;
    blocks[10].b[2]=1;

    blocks[11]=block(2,3);
    blocks[11].b[0]=1;
    blocks[11].b[1]=7;

    blocks[12]=block(3,2);
    blocks[12].b[0]=2;
    blocks[12].b[1]=2;
    blocks[12].b[2]=3;

    blocks[13]=block(2,3);
    blocks[13].b[0]=7;
    blocks[13].b[1]=4;

    blocks[14]=block(3,2);
    blocks[14].b[0]=3;
    blocks[14].b[1]=1;
    blocks[14].b[2]=1;

    blocks[15]=block(2,3);
    blocks[15].b[0]=4;
    blocks[15].b[1]=7;

    blocks[16]=block(3,2);
    blocks[16].b[0]=3;
    blocks[16].b[1]=2;
    blocks[16].b[2]=2;

    blocks[17]=block(2,3);
    blocks[17].b[0]=7;
    blocks[17].b[1]=1;

    blocks[18]=block(3,2);
    blocks[18].b[0]=1;
    blocks[18].b[1]=1;
    blocks[18].b[2]=3;
}

void control(char op){
/*
    op: d 直接下落到底
    op: l 左移
    op: r 右移
    op: s 旋转(逆时针)
    op: n 一个时钟沿
*/
    block tmp=now;
    int status=now_block;
    if(op=='d'){
        tmp.row++;
        while(judge(tmp))
            tmp.row++;
        tmp.row--;
        now=tmp;
        draw();

        //new block
        now_block = rand()%19;
        now=blocks[now_block];
        if(!judge(now)){
            draw();
            over=true;
            return;
        }
        // draw();
    }else if(op=='r'){
        bool flag=true;
        for(int i=0;i<tmp.h;i++){
            int tp=(tmp.b[i]<<1);
            if(tp>255){
                flag=false;
                break;
            }else{
                tmp.b[i]=tp;
            }
        }
        if(judge(tmp)){
            now=tmp;
            now.column++;
        }
    }else if(op=='s'){
        switch (status)//此处状态转换暴力地使用多个case语句实现,更简洁地做法是用一维数组存储状态转移值,每次直接取数组值即可
        {
        case 0:
            status=1;
            break;
        case 1:
            status=0;
            break;
        case 2:
            status=3;
            break;
        case 3:
            status=2;
            break;
        case 4:
            status=4;
            break;
        case 5:
            status=6;
            break;
        case 6:
            status=5;
            break;
        case 7:
            status=8;
            break;
        case 8:
            status=9;
            break;
        case 9:
            status=10;
            break;
        case 10:
            status=7;
            break;
        case 11:
            status=12;
            break;
        case 12:
            status=13;
            break;
        case 13:
            status=14;
            break;
        case 14:
            status=11;
            break;
        case 15:
            status=16;
            break;
        case 16:
            status=17;
            break;
        case 17:
            status=18;
            break;
        case 18:
            status=15;
            break;
        default:
            cout<<"Error!"<<endl;
            break;
        }
        tmp=blocks[status];
        tmp.column=now.column;
        tmp.row=now.row;
        if(tmp.row+tmp.h>8||tmp.column+tmp.w>8) 
            return;
        for(int i=0;i<tmp.h;i++){
            for(int j=1;j<=tmp.column;j++)
                tmp.b[i]<<=1;
        }
        if(judge(tmp)) {
            now_block=status;
            now=tmp;
        }
    }else if(op=='l'){
        bool flag=true;
        block t_block=tmp;
        for(int i=0;i<tmp.h;i++){
            int tp=(tmp.b[i]>>1);
            if(tp*2!=tmp.b[i]){
                flag=false;
                break;
            }else{
                tmp.b[i]=tp;
            }
        }
        if(judge(tmp)){
            now=tmp;
            now.column--;
        }
    }else if(op=='n'){
        tmp.row++;
        if(judge(tmp)) {
            cout<<"judge true"<<endl;
            now=tmp;
            // draw();
        }else {
            cout<<"judge false!"<<endl;
            draw();
            now_block = rand()%19;
            now=blocks[now_block];
            if(!judge(now)){
                draw();
                over=true;
                return;
            }   
        }
    }
}

bool judge(block tmp){
    if(tmp.h+tmp.row>8) return false;
    for(int i=0;i<tmp.h;i++){
        if((mp[tmp.row+i]|tmp.b[i])!=mp[tmp.row+i]+tmp.b[i])
            return false;
    }
    return true;
}

void draw(){
    for(int i=0;i<now.h;i++){
        mp[now.row+i]|=now.b[i];
    }
    int p_i=7;
    for(int i=0;i<=7;i++){
        if(mp[i]==255) {
            score++;
            for(int j=i;j>=1;j--){
                mp[j]=mp[j-1];
            }
        }
    }
}

void print(){
    cout<<"now is "<<now_block<<endl;
    int t_mp[10];
    for(int i=0;i<8;i++){
        t_mp[i]=mp[i];
    }
    for(int i=0;i<now.h;i++){
        // cout<<"last t_mp[i]="<<t_mp[i]<<endl;
        t_mp[i+now.row]|=now.b[i];    
        // cout<<"now t_mp[i]="<<t_mp[i]<<endl;
    }
    // for(int i=0;i<now.h;i++){
    //     cout<<"now.b"<<i<<"="<<now.b[i];
    // }
    // cout<<"now.row="<<now.row<<endl;
    for(int i=0;i<8;i++){
        int t_num=t_mp[i];
        for(int j=0;j<8;j++){
            cout<<(t_num&1)<<" ";
            t_num>>=1;
        }
        cout<<endl;
    }
}

运行示例:

$ ./a.exe 
n
judge true
now is 12        
0 0 0 0 0 0 0 0  
0 1 0 0 0 0 0 0  
0 1 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
s
now is 13
0 0 0 0 0 0 0 0  
1 1 1 0 0 0 0 0  
0 0 1 0 0 0 0 0  
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
s
now is 14
0 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
s
now is 11
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 1 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
d
now is 4
1 1 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 1 0 0 0 0 0  
e
now is 4
1 1 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 1 0 0 0 0 0  
r
now is 4
0 1 1 0 0 0 0 0  
0 1 1 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 1 0 0 0 0 0  
r
now is 4
0 0 1 1 0 0 0 0  
0 0 1 1 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 1 0 0 0 0 0  
r
now is 4
0 0 0 1 1 0 0 0  
0 0 0 1 1 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 1 0 0 0 0 0  
d
now is 0
0 1 1 0 0 0 0 0  
1 1 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
r
now is 0
0 0 1 1 0 0 0 0  
0 1 1 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0  
1 0 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
s
now is 1
0 1 0 0 0 0 0 0  
0 1 1 0 0 0 0 0  
0 0 1 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0  
1 0 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
l
now is 1
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
0 1 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
d
now is 4
1 1 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
r
now is 4
0 1 1 0 0 0 0 0  
0 1 1 0 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
r
now is 4
0 0 1 1 0 0 0 0  
0 0 1 1 0 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
r
now is 4
0 0 0 1 1 0 0 0  
0 0 0 1 1 0 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
r
now is 4
0 0 0 0 1 1 0 0  
0 0 0 0 1 1 0 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0 
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
r
now is 4
0 0 0 0 0 1 1 0  
0 0 0 0 0 1 1 0  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0 
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
r
now is 4
0 0 0 0 0 0 1 1  
0 0 0 0 0 0 1 1  
0 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 0 0  
1 1 1 1 1 0 0 0  
d
now is 6
0 1 0 0 0 0 0 0  
0 1 0 0 0 0 0 0  
0 1 0 0 0 0 0 0  
0 1 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 1 1  
1 1 1 1 1 0 1 1  
r
now is 6
0 0 1 0 0 0 0 0  
0 0 1 0 0 0 0 0  
0 0 1 0 0 0 0 0  
0 0 1 0 0 0 0 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 1 1  
1 1 1 1 1 0 1 1  
r
now is 6
0 0 0 1 0 0 0 0  
0 0 0 1 0 0 0 0  
0 0 0 1 0 0 0 0  
0 0 0 1 0 0 0 0 
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 1 1  
1 1 1 1 1 0 1 1  
r
now is 6
0 0 0 0 1 0 0 0  
0 0 0 0 1 0 0 0  
0 0 0 0 1 0 0 0  
0 0 0 0 1 0 0 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 1 1  
1 1 1 1 1 0 1 1  
r
now is 6
0 0 0 0 0 1 0 0  
0 0 0 0 0 1 0 0  
0 0 0 0 0 1 0 0  
0 0 0 0 0 1 0 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 1 1  
1 1 1 1 1 0 1 1 
r
now is 6
0 0 0 0 0 0 1 0  
0 0 0 0 0 0 1 0  
0 0 0 0 0 0 1 0  
0 0 0 0 0 0 1 0  
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 1 1  
1 1 1 1 1 0 1 1  
l
now is 6
0 0 0 0 0 1 0 0  
0 0 0 0 0 1 0 0  
0 0 0 0 0 1 0 0  
0 0 0 0 0 1 0 0 
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 1 0 1 1 0 1 1  
1 1 1 1 1 0 1 1  
d
now is 10
1 0 0 0 0 0 0 0  
1 1 0 0 0 0 0 0  
1 0 0 0 0 0 0 0  
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0  
1 0 0 0 0 1 0 0  
1 1 0 0 0 1 0 0  
1 1 0 1 1 1 1 1
;