Problem:
Problem C: コンパイル

東京大学に入学したきたまさ君はTSG(東大スーパーゲーマーズ)というサークルに入った。

このサークルは毎年、駒場祭でゲームを展示しており、きたまさ君もゲームを作成して展示することにした。

きたまさ君の作成するゲームは次のような、よくある落ち物パズルゲームである。

横6マス×縦12マスの格子状のフィールドがあり、各マスにつき1個のブロックを置くことができる。

上からブロックが2つ1組で落下してくる。ブロックには赤・緑・青・黄・紫の5色の基本ブロックとお邪魔ブロックの計6種類がある。プレイヤーはブロックを回転、横移動により操作し、落下位置を変更することができる。

落下してきたブロックがフィールドの床やほかのブロックに衝突すると、その位置にブロックが固定される。

固定されたブロックと同色のブロックが周囲4方向にある場合、それらは互いにくっつく。ただし、お邪魔ブロックは互いにくっつかない。

ブロックが4個以上くっつくと消滅し得点となる。お邪魔ブロックの周囲4方向に存在する基本ブロックが消滅すると、そのお邪魔ブロックも一緒に消滅する。ブロックの消滅は、全てのブロックの落下が終了したタイミングで同時に起こる。

ブロックの消滅により、その上にあったブロックが落下する。このブロックの落下はプレイヤーが操作できない。このとき再びブロックが4個以上くっつくと消滅し、連鎖が起きる。ただし、複数色を同時に消した場合でも、1連鎖扱いとなる。

きたまさ君はこのゲームの大部分のプログラムを書き終えたが、どうしてもブロックがくっついて消滅したときの処理を書くことが出来なかった。そこでサークルの友人であるあなたにその部分のプログラムを書いてもらうことにした。

Input

入力は12行からなる。

入力の i 行目は長さ6の文字列からなり、その j 文字目はフィールドの上から i 行目、左から j 列目のマスの状態を表している。

マスの状態を表す文字は以下の7つのうちのいずれかである。

文字

種類

R

赤

G

緑

B

青

Y

黄

P

紫

O

お邪魔

.

空きマス

また、入力に含まれる全てのブロックは床の上か他のブロックの上に乗っている。

Output

入力の状態から、ルールに従ってブロックを消していった時の連鎖数を計算し、一行で出力せよ。

ブロックが一つも消えない場合は0と出力せよ。

Notes on Test Cases

上記入力形式で複数のデータセットが与えられます。

入力の1行目にデータセットの数Tが与えられます。

各データセットに対して上記出力形式で出力を行うプログラムを作成して下さい。

Sample Input

3
......
......
......
......
......
......
......
......
.RGB..
RGOP..
RGBPB.
RGBPP.
GBRGYP
GBRRYP
BGGRBB
BPRGYY
GGPRRY
BYPPRB
YGGGPB
GYYYPR
YRBRBR
YBRBRB
BRBRBR
BRBRBR
......
......
......
......
......
......
......
......
......
......
..OO..
..OO..

Output for Sample Input

3
18
0

Solution in JAVA (judge verdict: Accepted)


import java.util.Arrays;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		new Main().run();
	}

	private void run() {
		Scanner scanner = new Scanner(System.in);
		int t = scanner.nextInt();
		while (t-- > 0) {
			map = new char[h][w];
			for (int i = 0; i < h; i++)
				map[i] = scanner.next().toCharArray();
			int ans = 0;
			v = new boolean[h][w];
			while (true) {
				boolean flag = false;
				for (int i = 0; i < h; i++)
					Arrays.fill(v[i], false);
				for (int y = 0; y < h; y++) {
					for (int x = 0; x < w; x++) {
						if (map[y][x] == '.' || map[y][x] == 'O' || v[y][x])
							continue;
						step = 0;
						if (!slove(y, x, map[y][x]))
							continue;
						flag = true;
						dfs(y, x, map[y][x]);
					}
				}
				if (!flag) {
					System.out.println(ans);
					break;
				}
				ans++;
				for (int i = 0; i < 11; i++) {
					for (int y = 0; y < 11; y++) {
						for (int x = 0; x < w; x++) {
							if (map[y][x] != '.' && map[y + 1][x] == '.') {
								map[y + 1][x] = map[y][x];
								map[y][x] = '.';
							}
						}
					}
				}
			}
		}
	}

	private void dfs(int y, int x, char c) {
		map[y][x] = '.';
		for (int[] m : move) {
			int ny = y + m[0];
			int nx = x + m[1];
			if (!isOK(ny, nx))
				continue;
			if (map[ny][nx] == 'O') {
				map[ny][nx] = '.';
				continue;
			}
			if (map[ny][nx] != c)
				continue;
			dfs(ny, nx, c);
		}

	}

	private boolean slove(int y, int x, char c) {
		step++;
		v[y][x] = true;
		if (step == 4)
			return true;
		for (int[] m : move) {
			int ny = y + m[0];
			int nx = x + m[1];
			if (!isOK(ny, nx))
				continue;
			if (map[ny][nx] != c || v[ny][nx])
				continue;
			if (slove(ny, nx, c))
				return true;
		}
		return false;
	}

	private boolean isOK(int ny, int nx) {
		return 0 <= ny && ny < h && 0 <= nx && nx < w;
	}

	int h = 12, w = 6;
	int step;
	char[][] map;
	boolean[][] v;
	int[][] move = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } };
}