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

昨日の夜、「第二回 オフラインリアルタイムどう書く」に参加してきました。

例によって、鍋谷さんが問題を作ってくださいました。今回は、テトリスです!

正確な問題文が知りたい方は、上のページをご覧ください。

雰囲気をざっくり絵にすると、こんな感じです。

ビット演算で解くとカンタンなのだそうですが、次のように腕力で解きました。

  1. 1が揃ったかどうかは行を見て判定しますが、入力値は列の形です。そこで、まず転置します。
  2. 次に、1が揃った行の行番号を調べて、保持します。
  3. そして、その行番号部分を、せっせと除去します。
  4. 最後に、出力値を作るために、元の形になるように転置します。

最後の部分は、「転置した配列を元に戻したいときは、3回転置すればいい」と教えていただき、その発想はなかったと思ったので、使ってみました :-P

コードはこんな感じです。

import java.util.*;

/**
 * 問題: http://nabetani.sakura.ne.jp/hena/ord2/
 */
public class BitTetris {

	String execute(String input) {
		String[] split = input.split("-");
		String[] cols = getCols(split);
		String[] rows = _tr(cols);

		List<Integer> deleteIndexes = getDeleteIndexes(rows);
		String[] deleted = getDeleted(rows, deleteIndexes);

		String[] result = new String[deleted.length];
		result = _tr(deleted);
		result = _tr(result);
		result = _tr(result);
		String resultStr = getResultStr(result);
		return resultStr;
	}

	String toData(String hexStr) {
		String binStr = Integer.toBinaryString(Integer.parseInt(hexStr, 16));
		Formatter f = new Formatter();
		f.format("%04d", Integer.parseInt(binStr));
		return f.toString();
	}

	String[] getDeleted(String[] rows, List<Integer> deleteRowList) {
		String[] clone = new String[rows.length + 1];
		for (int i = 0; i < rows.length; i++) {
			clone[i] = rows[i];
		}
		clone[clone.length - 1] = "00000000";

		String[] tmp = new String[rows.length - deleteRowList.size()];
		int cnt = 0;
		for (int i : deleteRowList) {
			for (int k = i - cnt; k < rows.length; k++) {
				clone[k] = clone[k + 1];
			}
			cnt++;
		}

		for (int i = 0; i < tmp.length; i++) {
			tmp[i] = clone[i];
		}
		return tmp;
	}

	boolean canDelete(String row) {
		if (row.indexOf("0") == -1) {
			return true;
		}
		return false;
	}

	String getResultStr(String[] result) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < result.length; i++) {
			Formatter f = new Formatter();
			f.format("%08d", Integer.parseInt(result[i]));
			String string = f.toString();
			sb.append(Integer.toHexString(Integer.valueOf(
					string.substring(0, 4), 2)));
			sb.append(Integer.toHexString(Integer.valueOf(
					string.substring(4, 8), 2)));
			sb.append("-");
		}
		sb.deleteCharAt(sb.length() - 1);
		return new String(sb);
	}

	String[] getCols(String[] split) {
		String[] result = new String[split.length];
		for (int i = 0; i < split.length; i++) {
			String data = "";
			for (int k = 0; k < 2; k++) {
				data += toData(String.valueOf(split[i].charAt(k)));
			}
			result[i] = data;
		}
		return result;
	}

	List<Integer> getDeleteIndexes(String[] rows) {
		List<Integer> result = new ArrayList<>();
		for (int i = 0; i < rows.length; i++) {
			if (canDelete(rows[i])) {
				result.add(i);
			}
		}
		return result;
	}

	String[] _tr(String[] str) {
		String[] result = new String[str[0].length()];
		for (int i = 0; i < result.length; i++) {
			for (int k = 0; k < str.length; k++) {
				if (result[i] == null) {
					result[i] = String.valueOf(str[k].charAt(i));
				} else {
					String s = result[i];
					result[i] = s + String.valueOf(str[k].charAt(i));
				}
			}
		}
		return result;
	}
}

(長すぎる)

ちなみに、またしても時間内に終わりませんでした。が、最後に出力値を16進数に戻す手前まで書けたので、メインロジックに到達すらしなかった前回よりは、機嫌良く家に帰ってきました。

しかし、Rubyを使って10行くらいでさくっと書いている方もいて、ぐぬぬって感じです。

ビット演算を使えるようになって、15分くらいで解けるようになりたいです。

あるいは、Groovyを習得して、15行くらいで書けるようになりたいです。

もちろん、その両方でも素敵ですね!! ……精進します。

最後になりましたが、鍋谷さん、一緒に参加された皆さん、ありがとうございました。またよろしくお願いします。