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