问题描述
俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏。
游戏在一个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
为了好说明问题,先上几个Case来测试下:(发现许多人写的博客,里面的思路清新,代码正确,但是对于多数不是很难的题,多数人还是能写出来的,但是出了错,最想找的是全面的case,而不是一份完整的代码。)
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 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 1 0
1 1 1 0
0 0 0 0
0 0 0 0
7
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 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 1 0 0
0 1 1 0
0 0 1 0
0 0 0 0
4
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 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 0
0 0 1 0
0 0 1 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 0 0 0 1 1 1 1
0 0 0 0 1 0 0 0 0 0
0 0 1 0
0 0 1 0
0 0 1 0
2
如果上面的case都做的对,那么整个程序应该没有什么问题:
下面介绍下我的思路,为表示尊重原创,思路来自《编程之美》上的俄罗斯方块中,提到的一句下落的最低高度取决于已有方块的那一列。由此可以计算每一列触底高度的最小值,即:图片
,其中di是该列堆积方块的高度。
下面上代码,如果不懂,可以单步调试,并采用逐段注释的方式进行查看代码。看看代码异样的输出。
package com.qjg;
import java.util.Scanner;
public class Main1604_21 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[][] graph = new int[15][10];
for(int i = 0;i<15;i++){
for(int j =0;j<10;j++){
graph[i][j]=sc.nextInt();
}
}
int[][] block = new int[4][4];
for(int i = 0;i<4;i++){
for(int j = 0;j<4;j++){
block[i][j]= sc.nextInt();
}
}
int startIndex = sc.nextInt();
int[] blockMaxRow = new int[4];
int[] graphMaxRow = new int[4];
int minRowBlock = -1;
int maxRowBlock = 0;
for(int i=0;i<4;i++){
for(int j = 0;j<4;j++){
if(block[i][j]==1 && minRowBlock==-1){
minRowBlock = i;
}
if(block[i][j] == 1){
maxRowBlock = i;
}
}
}
//计算每列行高
calcBlockColHigh(block,blockMaxRow,minRowBlock,maxRowBlock);
calcGraphColHigh(graph,graphMaxRow,startIndex);
// 在图中找到最小的行高
int minRowGraph = 15;
for(int i = 0;i<blockMaxRow.length;i++){
if(blockMaxRow[i] != 0){
int diff = graphMaxRow[i]-blockMaxRow[i];
if(diff<minRowGraph){
minRowGraph = diff;
}
}
}
int k = minRowGraph;
for(int i = minRowBlock;i<=maxRowBlock;i++,k++){
for(int j = 0;j<4;j++){
graph[k][startIndex-1+j] += block[i][j];
}
}
for(int i = 0;i<graph.length;i++){
for(int j = 0;j<graph[0].length;j++){
System.out.print(graph[i][j]+" ");
}
System.out.println();
}
}
private static void calcBlockColHigh(int[][] block, int[] blockMaxRow, int minRowBlock, int maxRowBlock) {
// TODO Auto-generated method stub
for(int i = 0;i<blockMaxRow.length;i++){
for(int j = maxRowBlock;j>=minRowBlock;j--){
// if(block[j][i]==1){//统计小木块的个数,这种方法对于翻转的L并不适用
// blockMaxRow[i] += 1;
// }
if(block[j][i]==1){
if(j == maxRowBlock){
// 0 0 1 0//这种是比较坑的
// 1 1 1 0
// 0 0 0 0
// 0 0 0 0
blockMaxRow[i] = maxRowBlock-minRowBlock+1;
break;
}else{
// 0 0 0 0
// 0 1 1 1
// 0 0 0 1
// 0 0 0 0
blockMaxRow[i] += 1;
}
}
}
}
}
private static void calcGraphColHigh(int[][] graph, int[] graphMaxRow,int startIndex) {
for(int i = startIndex-1;i<startIndex-1+4;i++){
for(int j = 0;j<graph.length;j++){
if(graph[j][i]==1){
graphMaxRow[i-startIndex+1] = j;
break;
}else{
graphMaxRow[i-startIndex+1] = graph.length;
}
}
}
}
// private static void calcBlockColHigh(int[][] block, int[] blockMaxRow) {
// for(int i = 0;i<blockMaxRow.length;i++){
// for(int j = 3;j>=0;j--){
if(block[j][i]==1){//统计小木块的个数,这种方法对于翻转的L并不适用
blockMaxRow[i] += 1;
}
// if(block[j][i]==1){
// blockMaxRow[i] = j+1;
// break;
// }
//
// }
// }
// }
}