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

鍋谷さんが「第2回 オフラインリアルタイムどう書く」の参考問題を出題してくださったので、Javaで解きました。

# Qiitaのアカウントを作ってみたのですが、行数がほかの人の5倍以上多くて、投稿する勇気が出ない>< というわけで、こちらに貼ります。すみません。

自分の解答

public class SpinImage {

	protected String execute(String string) {

		String[] split = string.split(":");
		final int imageLength = Integer.valueOf(split[0]);

		String originHex = split[1];
		final int hexLength = originHex.length();

		String binaryString = "";
		for (int i = 0; i < hexLength; i++) {
			char c = originHex.charAt(i);
			int dec = Integer.parseInt(String.valueOf(c), 16);

			// 左端を0パディングした4桁の二進数に変換
			String bin = Integer.toBinaryString(dec);
			for (int k = bin.length(); k < 4; k++) {
				binaryString += "0";
			}
			binaryString += bin;
		}
		final int binaryStrLength = binaryString.length();

		// 画像に不要な右端のbitを捨てる
		if (imageLength * imageLength < binaryString.length()) {
			binaryString = binaryString.substring(0, imageLength * imageLength);
		}

		// 回転前の画像
		int counter = 0;
		char[][] source = new char[imageLength][imageLength];
		for (int i = 0; i < imageLength; i++) {
			for (int k = 0; k < imageLength; k++) {
				source[i][k] = binaryString.charAt(counter++);
			}
		}

		// 回転後の画像
		char[][] dest = new char[imageLength][imageLength];
		int m = 0;
		for (int i = 0; i < imageLength; i++) {
			int p = imageLength - 1;
			for (int k = 0; k < imageLength; k++) {
				dest[i][k] = source[p][m];
				--p;
			}
			m++;
		}

		// 16進表記に戻す準備: 2進表現を1つにまとめる
		String preResult = "";
		for (int i = 0; i < imageLength; i++) {
			for (int k = 0; k < imageLength; k++) {
				preResult += dest[i][k];
			}
		}

		// 2進表現の末尾に、16進変換に必要な0を継ぎ足す
		for (int i = preResult.length(); i < binaryStrLength; i++) {
			preResult += "0";
		}

		String hexString = "";
		for (int i = 0; i < preResult.length(); i += 4) {
			String s = "";
			if (i + 4 < preResult.length()) {
				s += preResult.substring(i, i + 4);
			} else {
				s += preResult.substring(i);
			}
			int parseInt = Integer.parseInt(s, 2);
			hexString += Integer.toHexString(parseInt);
		}

		StringBuilder result = new StringBuilder(String.valueOf(imageLength));
		result.append(":");

		// 16進表記を元の桁数に揃える(先頭に0パディング)
		for (int i = preResult.length(); i < hexLength; i++) {
			result.append("0");
		}
		result.append(hexString);
		return new String(result);
	}

	public static void main(String[] args) {

		// すべてのテストデータは、SpinImageTest.java(https://gist.github.com/3177352)を参照。
		SpinImage spin = new SpinImage();
		System.out.println(spin.execute("6:123456789"));
	}
}

わーい、Javaである必要が微塵もないコードできたよー\(^o^)/

感想

1時間ではムリでした。ロジックは一直線でカンタンそうだからいけるかと思いきや、細部で引っかかりました。

たとえば、コロンの右も左も入力値と同じ桁数に戻さなければならないのですが、問題文からそのことを読み取り損ねていて、上位桁の0パディングを忘れていました。また、長い桁の数字を一気に十六進に変換しようとして、例外で死にました(……)。で、テストデータを突っ込むと、特定のデータのときだけエラーになり、あれれ??と。

そんな感じでしたが、本番も楽しみです。