HDU 5374 Tetris 俄罗斯方块 模拟

这道题是喜闻乐见的大模拟题。

题目大意:在一个9X12的格子中玩俄罗斯方块,给定所有可能的方块形态,给定方块的掉落顺序,给定操作,w表示旋转,a表示左移,b表示右移,d表示下落一格(实际下落两格),p表示pass(即下落一格),输入数据保证不会GameOver,求最后的分数。

题意虽然简单,但是由于编程复杂度等众多原因,考场上写的人不多。这里有几个可以简化代码的trick,由于旋转最大循环节为4,方块最大长宽也为4,那么我们可以把每一种方块的形态用4*4*4的数组存下来,这样判断以及旋转操作都很容易实现;还有就是方块在移动过程中,只需把基点即左下角的点的坐标记下来,不需要每操作都把当前状态表示出来。

虽然我考场上用了这俩技巧,然而还是没有调出来哪里写错了,考完以后发现判断消除行的时候要从上往下枚举...非常可惜。

144737672015-08-12 11:19:26Accepted53740MS1412K2027 BG++Kurama
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define MAXN 1001
using namespace std;
int order[MAXN],n,no,st,X,Y,score;
//order为方块下落顺序,no表示该方块处于第几种旋转状态
//X,Y为现在的位置,score统计分数 
bool Brick[3][4][4][4]={
{
    {{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
    {{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
    {{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
    {{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}}
},{
    {{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}},
    {{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
    {{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}},
    {{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
},{
    {{1,1,1,0},{1,0,0,0},{0,0,0,0},{0,0,0,0}},
    {{1,0,0,0},{1,0,0,0},{1,1,0,0},{0,0,0,0}},
    {{0,0,1,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},
    {{1,1,0,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}}}
};
//为了方便我们将所有类型的方块存成4*4 
char oper[MAXN];
//操作字符串 
bool dB,tetris[20][20];
//dB表示是否有下落完全的方块,tetris保存每个方块的最后状态 
void Fresh(){
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            if(Brick[order[no]][st][i][j])
                tetris[Y+i][X+j]=true;
}
//更新状态 
bool Attempt(char op){
    int x=X,y=Y,s=st,ty=order[no];
    if(op=='w')s=(st+1)%4;else
    if(op=='s')y--;else
    if(op=='d')x++;else
    if(op=='a')x--;
    if(y==0 || x==0)return false;
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            if(Brick[ty][s][i][j])
                if(x+j>9 || tetris[y+i][x+j])return false;
    X=x;Y=y;st=s;
    return true;
}
//尝试操作,若操作不合法则忽略 
bool check(int r){
    for(int i=1;i<=9;i++)if(!tetris[r][i])return false;
    return true;
}
//检查是否可以消除 
void delet(int r){
    for(int i=r;i<=12;i++)
        for(int j=1;j<=9;j++)tetris[i][j]=tetris[i+1][j];
}
//消除满行 
void simulate(char op){
    if(!dB){X=4,Y=9,st=0;dB=true;}
    if(op!='p')Attempt(op);
    if(Attempt('s'))return; // 
    else{
        Fresh();
        dB=false;
        no++;
        for(int i=12;i>=1;i--)
            if(check(i)){
                delet(i);
                score++;
            }
    }
}
//模拟操作 
int main()
{
    int t;
    scanf("%d",&t);
    for(int casen=1;casen<=t;casen++){
        memset(tetris,0,sizeof tetris);
        no=score=0;dB=false;
        scanf("%d%s",&n,oper);
        for(int i=0;i<n;i++)scanf("%d",&order[i]);
        int len=strlen(oper);
        for(int i=0;i<len;i++)simulate(oper[i]);
        printf("Case %d: %d\n",casen,score);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值