CSP 俄罗斯方块(201604-2)
问题描述
俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏。
游戏在一个15行10列的方格图上进行,方格图上的每一个格子可能已经放置了方块,或者没有放置方块。每一轮,都会有一个新的由4个小方块组成的板块从方格图的上方落下,玩家可以操作板块左右移动放到合适的位置,当板块中某一个方块的下边缘与方格图上的方块上边缘重合或者达到下边界时,板块不再移动,如果此时方格图的某一行全放满了方块,则该行被消除并得分。
在这个问题中,你需要写一个程序来模拟板块下落,你不需要处理玩家的操作,也不需要处理消行和得分。
具体的,给定一个初始的方格图,以及一个板块的形状和它下落的初始位置,你要给出最终的方格图。
游戏在一个15行10列的方格图上进行,方格图上的每一个格子可能已经放置了方块,或者没有放置方块。每一轮,都会有一个新的由4个小方块组成的板块从方格图的上方落下,玩家可以操作板块左右移动放到合适的位置,当板块中某一个方块的下边缘与方格图上的方块上边缘重合或者达到下边界时,板块不再移动,如果此时方格图的某一行全放满了方块,则该行被消除并得分。
在这个问题中,你需要写一个程序来模拟板块下落,你不需要处理玩家的操作,也不需要处理消行和得分。
具体的,给定一个初始的方格图,以及一个板块的形状和它下落的初始位置,你要给出最终的方格图。
输入格式
输入的前15行包含初始的方格图,每行包含10个数字,相邻的数字用空格分隔。如果一个数字是0,表示对应的方格中没有方块,如果数字是1,则表示初始的时候有方块。输入保证前4行中的数字都是0。
输入的第16至第19行包含新加入的板块的形状,每行包含4个数字,组成了板块图案,同样0表示没方块,1表示有方块。输入保证板块的图案中正好包含4个方块,且4个方块是连在一起的(准确的说,4个方块是四连通的,即给定的板块是俄罗斯方块的标准板块)。
第20行包含一个1到7之间的整数,表示板块图案最左边开始的时候是在方格图的哪一列中。注意,这里的板块图案指的是16至19行所输入的板块图案,如果板块图案的最左边一列全是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 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
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 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
思路
一种方法是像游戏中的那样模拟逐步下落,每次判断是否与原有方块重叠。需要注意的是原有方块可能都是空白。
另一种方法是直接通过计算原有方块每列最高点的位置和掉落方块每列最低点的位置来判断掉落方块会在哪一行停住。所以直接通过计算每列方块的长度(准确的说应该是掉落方块最低点的相对长度,原有方块最高点的相对长度)。
图一中所示原有长度为5 2 3。掉落方块长度为1 1 2。叠加长度为6 3 5,即掉落方块的最高点为6;
图二中所示原有长度为5 2。掉落方块长度为3 3。叠加长度为8 5,即掉落方块的最高点为8。
![](https://images2015.cnblogs.com/blog/841932/201703/841932-20170318111150120-1345903156.png)
![](https://images2015.cnblogs.com/blog/841932/201703/841932-20170318115830666-1395917363.png)
第二种思路代码如下:
1 #include<iostream> 2 using namespace std; 3 4 int main(){ 5 int a[15][10]; 6 int in[4][4]; 7 for(int i=0;i<15;i++){ 8 for(int j=0;j<10;j++){ 9 cin>>a[i][j]; 10 } 11 } 12 for(int i=0;i<4;i++){ 13 for(int j=0;j<4;j++){ 14 cin>>in[i][j]; 15 } 16 } 17 int n; 18 cin>>n; 19 20 int m[4]; 21 for(int i=0;i<4;i++){ //计算掉落方块每列的相对长度 22 m[i]=0; 23 for(int j=0;j<4;j++){ 24 if(in[j][i]==1) m[i]=j+1; 25 } 26 } 27 int f[4]; 28 for(int i=n-1;i<n+3;i++){ //计算原有方块每列的相对长度 29 f[i-n+1]=0; 30 for(int j=0;j<15;j++){ 31 if(a[j][i]==1){ 32 f[i-n+1]=15-j; 33 break; 34 } 35 } 36 } 37 int max=0; 38 for(int i=0;i<4;i++){ //计算最大长度,即掉落方块的最高点 39 if(m[i]!=0&&m[i]+f[i]>=max){ 40 max=m[i]+f[i]; 41 } 42 } 43 for(int i=0;i<4;i++){ 44 for(int j=0;j<4;j++){ 45 if(in[i][j]) a[15-max+i][n-1+j]=1; 46 } 47 } 48 for(int i=0;i<15;i++){ 49 for(int j=0;j<10;j++){ 50 cout<<a[i][j]<<" "; 51 } 52 cout<<endl; 53 } 54 return 0; 55 }
第一种思路的代码:
1 #include<stdio.h> 2 int a[19][10],b[4][4]; 3 int compareBlock(int r,int c){ 4 for(int i=0;i<4;i++){ 5 for(int j=0;j<4;j++){ 6 if(b[i][j]==1&&a[i+r][j+c]==1) return 1; 7 } 8 } 9 return 0; 10 } 11 int main() 12 { 13 for(int i=15;i<19;i++){ 14 for(int j=0;j<10;j++){ 15 a[i][j]=1; 16 } 17 } 18 int n,temp=0; 19 for(int i=0;i<15;i++) 20 { 21 for(int j=0;j<10;j++) 22 { 23 scanf("%d",&a[i][j]); 24 } 25 } 26 for(int i=0;i<4;i++) 27 { 28 for(int j=0;j<4;j++) 29 { 30 scanf("%d",&b[i][j]); 31 } 32 } 33 scanf("%d",&n); 34 int mark; 35 36 for(int i=0;i<=14;i++) 37 { 38 if(compareBlock(i,n-1)) break; 39 mark=i; 40 } 41 for(int i=0;i<4;i++){ 42 for(int j=0;j<4;j++){ 43 if(b[i][j]==1) a[mark+i][n-1+j]=1; 44 } 45 } 46 for(int i=0;i<15;i++){ 47 for(int j=0;j<10;j++){ 48 printf("%d ",a[i][j]); 49 } 50 printf("\n"); 51 } 52 return 0; 53 }