「第8回 オフラインリアルタイムどう書く」へなちょこ解答(Java)

オフラインリアルタイムどう書くとは
鍋谷さんが出してくださるお題を、参加者が好きなプログラミング言語で解いて楽しむ会です。

今夜は、今年3回目のどう書くでした。

通算8回目なので、事前に出題される参考問題を含めると、ついに16問目に到達ですね。おめでとうございます。>鍋谷さん

今回は、ボンバーマンです!

なんともタイムリーな*1お題ですね。

残念ながら、今回は時間内に解けませんでした。ボンバーマンをやったことがないのに、ルールを早とちりして解いてしまったのが敗因です。爆風になるのは、爆弾に隣接した上下左右1マスずつだとカン違いしていました。正しくは、壁に当たるまで突き抜けるんですね。

というわけで、帰りの電車で少し直したところ、テストが通りました。

自分の解答

public class Biboma {
	protected final int COLUMN_MAX = 6;
	protected final int ROW_MAX = 5;
	protected final int BIT_MAX = 32;

	protected String getData(String str) {
		long tmpL = Long.decode("0x" + str);
		String result = Long.toBinaryString(tmpL);
		return padding(result, BIT_MAX);
	}

	protected String solve(String input) {
		String[] split = input.split("/");
		String wall = getData(split[0]);
		String bomb = getData(split[1]);

		int[][] wallTable = getTable(wall);
		int[][] bombTable = getTable(bomb);
		int[][] resultTable = new int[ROW_MAX][COLUMN_MAX];

		for (int i = 0; i < ROW_MAX; i++) {
			for (int k = 0; k < COLUMN_MAX; k++) {
				if (bombTable[i][k] == 1) {
					resultTable[i][k] = 1;
					for (int n = i; -1 < n && isNotWall(n, k, wallTable); n--) {
						resultTable[n][k] = 1;
					}
					for (int n = i; n < ROW_MAX && isNotWall(n, k, wallTable); n++) {
						resultTable[n][k] = 1;
					}
					for (int n = k; -1 < n && isNotWall(i, n, wallTable); n--) {
						resultTable[i][n] = 1;
					}
					for (int n = k; n < COLUMN_MAX
							&& isNotWall(i, n, wallTable); n++) {
						resultTable[i][n] = 1;
					}
				}
			}
		}

		StringBuilder result = new StringBuilder();
		for (int i = 0; i < ROW_MAX; i++) {
			for (int k = 0; k < COLUMN_MAX; k++) {
				result.append(String.valueOf(resultTable[i][k]));
			}
		}
		result.append("00");
		String hexString = Long
				.toHexString(Long.valueOf(new String(result), 2));
		return padding(hexString, 8);
	}

	protected String padding(String str, int n) {
		String result = str;
		if (str.length() < n) {
			for (int i = str.length(); i < n; i++) {
				result = "0" + result;
			}
		}
		return result;
	}

	protected boolean isNotWall(int i, int k, int[][] wallTable) {
		if (wallTable[i][k] == 0) {
			return true;
		}
		return false;
	}

	protected int[][] getTable(String input) {
		String[] tmp = new String[ROW_MAX];
		for (int i = 0, j = 0, k = 6; i < ROW_MAX && k < input.length() + 1; i++, j += COLUMN_MAX, k += COLUMN_MAX) {
			tmp[i] = input.substring(j, k);
		}
		int[][] result = new int[ROW_MAX][COLUMN_MAX];
		for (int i = 0; i < ROW_MAX; i++) {
			String str = tmp[i];
			for (int k = 0; k < COLUMN_MAX; k++) {
				result[i][k] = Integer.parseInt(String.valueOf(str.charAt(k)),
						2);
			}
		}
		return result;
	}
}

さくせん: たとえば、ビット演算を避ける

考え方

二次元配列を3つ使います。壁テーブル、爆弾テーブル、爆風(解答)テーブルです。

爆弾テーブルを調べて、まず、爆弾があるマスをマークします。次に、爆弾から上方向、右方向、下方向、左方向に、連続するマスをマークしていきます。途中で、壁に当たるか、テーブルの端にきたらやめます。

nidoさんの解答の「indexをインクリメント、デクリメントしながら爆風位置をマークにしていき、壁に当たったらbreakする」というロジックを参考にさせてもらいました)

ほかの解答について

ほとんどの人が二次元配列で解く中、鍋谷さんが一次元かつビット演算を使った解答を披露してくださったのが、新鮮でした。

また、一連の処理を断面で見せてくださったkei_qさんの解答も、デバッガビリティが高そうで素晴らしいなぁと思いました。Javaでも、工夫すればあんなふうに書けるんでしょうか。。。

というわけで、今回も楽しかったです。ありがとうございました。