问题描述
俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏。
游戏在一个15行10列的方格图上进行,方格图上的每一个格子可能已经放置了方块,或者没有放置方块。每一轮,都会有一个新的由4个小方块组成的板块从方格图的上方落下,玩家可以操作板块左右移动放到合适的位置,当板块中某一个方块的下边缘与方格图上的方块上边缘重合或者达到下边界时,板块不再移动,如果此时方格图的某一行全放满了方块,则该行被消除并得分。
在这个问题中,你需要写一个程序来模拟板块下落,你不需要处理玩家的操作,也不需要处理消行和得分。
具体的,给定一个初始的方格图,以及一个板块的形状和它下落的初始位置,你要给出最终的方格图。
输入格式
输入的前15行包含初始的方格图,每行包含10个数字,相邻的数字用空格分隔。如果一个数字是0,表示对应的方格中没有方块,如果数字是1,则表示初始的时候有方块。输入保证前4行中的数字都是0。
输入的第16至第19行包含新加入的板块的形状,每行包含4个数字,组成了板块图案,同样0表示没方块,1表示有方块。输入保证板块的图案中正好包含4个方块,且4个方块是连在一起的(准确的说,4个方块是四连通的,即给定的板块是俄罗斯方块的标准板块)。
第20行包含一个1到7之间的整数,表示板块图案最左边开始的时候是在方格图的哪一列中。注意,这里的板块图案指的是16至19行所输入的板块图案,如果板块图案的最左边一列全是0,则它的左边和实际所表示的板块的左边是不一致的(见样例)
输出格式
输出15行,每行10个数字,相邻的数字之间用一个空格分隔,表示板块下落后的方格图。注意,你不需要处理最终的消行。
样例输入
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 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 0 1 0 0 0
0 0 0 0 0 0 1 0 0 0
1 1 1 0 0 0 1 1 1 1
0 0 0 0 1 0 0 0 0 0
0 0 0 0
0 1 1 1
0 0 0 1
0 0 0 0
3
样例输出
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 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 0 1 0 0 0
0 0 0 0 0 0 1 0 0 0
1 1 1 1 1 1 1 1 1 1
0 0 0 0 1 1 0 0 0 0
题目分析
这个题目就是简单的模拟, 没涉及到什么算法, 但是得满分也是要调试一会儿时间的
部分变量说明 map 输入的原始地图
add 输入的4*4方格
addmap 是一个 "平行" 于map的一个新数组, 所谓的 "平行" 是指和map的行和列同步,但数据不再map中
(1) 先将add放入addmap对应的位置中, 然后对addmap操作, 一开始add放在addmap的前四行(初始位置,还没移动)
(2) 写一个check()函数用来判断新加入的图形能否向下移, 判断条件是addmap每一个为1的方格下方不能是1,不然就碰撞了
(3) 如果能移动, 则执行movedown, 将addmap中的add向下移动一格
(4)当然, 如果小方格下方是空白的, 则不会发生碰撞, 不能一直移动, 不然就移过头了
所以再加一个条件, 移动的次数+add最大行数<=15, add最大行数是指实际的行数, 比如题目中给的add最大行数为3, 因为最后一行为0, 不计入其中, 这里也许有人问, 那最上层为0呢, 因为add是向下移动, 最上层不必要考虑
(5) 直到最后不能移动时(发生碰撞 或者 到达边界), 将map和addmap和二为一即是最终结果
如果对addmap还不是很清楚什么概念, 可以在while中输出addmap, 就能看到addmap每一次输出的状态
如代码中while中注释部分print(), 但如要输出addmap注意将print()中的map改为addmap
#include<iostream>
using namespace std;
int map[20][20], addmap[20][20],add[10][10];
int n;
int step=0; //记录向下移动的步数
bool check() //检查是否能往下移
{
for (int i = 1; i <= 14;i++)
for (int j = 1; j <= 10;j++)
if (addmap[i][j] + map[i + 1][j] == 2) return false; //如果将要发生碰撞则返回false
return true;
}
void movedown() //addmap向下移动一格
{
step++; //更新step
for (int i = 1; i <= 15; i++)
for (int j = 1; j <= 10; j++)
addmap[i][j] = 0; //清空addmap,
for (int i = 1; i <= 4; i++)
for (int j = 1; j <= 4; j++)
addmap[i+step][n + j - 1] = add[i][j]; //更新addmap
}
void print() //结果输出
{
for (int i = 1; i <= 15; i++)
{
for (int j = 1; j <= 10; j++)
cout << map[i][j] << ' ';
cout << endl;
}
}
int main()
{
int end;
for (int i = 1; i <= 15;i++)
for (int j = 1; j <= 10; j++)
cin >> map[i][j];
for (int i = 1; i <= 4;i++)
for (int j = 1; j <= 4; j++)
{
cin >> add[i][j];
if (add[i][j] == 1)
end = i; //记录add最大行数
}
//cout <<"end=" <<end << endl;
cin >> n;
for (int i = 1; i <= 4;i++)
for (int j = 1; j <= 4; j++)
addmap[i][n+j-1] = add[i][j]; //将add放到addmap中
while (check()&&end+step<15) //end+step应小于15,考虑到一直不会发生碰撞, 这里不是end+step<=15, 不然又进入循环执行movedown时step+1, 那么end+step=16了
{
//print();
//cout << "------------" << endl;
movedown(); //移动addmap
}
for (int i = 1; i <= 15; i++)
for (int j = 1; j <= 10; j++)
map[i][j] += addmap[i][j]; //因为map和addpp是分开的两张图, 最后合并在一起
print();
return 0;
}