足きりだけど、DevQuizの回答を晒させて下さい。

GoogleのDevQuizってチャレンジしましたか?
私一応チャレンジしたんですけど…、100点しか取れなかったので足きりになってしまいました。

考えが甘かったんですよね〜。
ZusaarNotify-modokiの開発にのめり込んだりしているうちに時間は経過してしまい。
やっと取り掛かったのが締め切り前日9/11の夜。今にして思えばその時点でもうアウトでした。
数時間でなんとかなるような甘いものじゃ、全然なかったです。(少なくとも、私の実力では。)

折角やったので、回答した分だけでも自分の答えを晒しておこうと思います。

ウォームアップクイズの回答

Chrome

次の HTML5 の要素のうち、Google Chrome 13 でサポートされていないものはどれでしょうか?
 ・

videoをサポートしていることは知ってたのですが、他はわかりませんでした。
適当なHTML書いて全部試してみたら、timeだけ何も起こりませんでした。
調べたところ、timeタグはクローラ等のHTMLを解析するプログラムに情報を与える目的のタグだそうなので、何も起きない=サポートしていないで良いのか? と少し悩みましたが、他になかったのでこれを選びました。

maps API

Google Maps JavaScript API V3 にて以下のコードのように定義した gddMapType では、 通常の地図と比べてどのように見た目が変化するでしょうか? 間違っているものを選択してください。

maps APIを使ったことがなかったので、これも実際に動かしてみて確認しました。
・黒くなっていない道路があったこと
・黒く塗りつぶすと言うより、彩度を落とすことを目的としたコードだったこと
などから、「全ての道路が黒く塗りつぶされる。」を選択しました。
でも、「featureType: "road",」は
http://gmaps-samples-v3.googlecode.com/svn/trunk/styledmaps/wizard/index.html
辺りを見ると全ての道路を示してそうな気がするのですが、何故黒くならなかった道路が存在したのかはまだ良くわかってません。

Google translate

こちらのロシア語を日本語に翻訳すると何になるでしょうか?

ロシア語は全然わからないけど、綴りからみてじゃがいもっぽいな、と思ってGoogle翻訳でじゃがいもを翻訳してみたら、ドンピシャでした。

Android

Android 3.x (Honeycomb)についての次の記述のうち、間違っているものはどれでしょう?

・ドラッグ & ドロップ(ドラッグ中の半透明 UI 表示など)の実装が簡単にできる API が提供されている
・画面描画を高速化するハードウェアアクセラレーションを活用するには Java では足りず、C/C++ を活用した JNI プログラミングが必要である
・Fragment, Action Bar などの考え方は今後 一般の携帯電話用にもリリースされる Ice Cream Sandwich のアプリケーション開発においてもそのまま継承される

Android知らないので、普通に検索して調べてみました。
結果、2番目を選択。

iGoogle

iGoogle ガジェット ダッシュボードのトップページで閲覧できるページビューやインストール数は過去何日間分でしょうか?

これも知らなかったので調べて、「7日分」を選びました。

ウォームアップは翌朝まで結果がでなかったのでヒヤヒヤしましたが、満点が取れていました。

Web Game

ちょうどChrome Extensionを作っていたので、まずはWeb Gameにチャレンジ。
ヒントのExtensionをそのまま使って回答を作成しました。
細かいバグを出しながら、1時間くらい格闘して書き上げたのが下記ソース。

var element = document.getElementById('card0');
if (element == null) {
	alert('Card element is not found. Check element id.');
} else {
	main();
}

function main() {
	var myevent = document.createEvent('MouseEvents');
	myevent.initEvent('click', false, true);

	var i = 0;
	var map = {};
	while(true) {
		var element = document.getElementById('card' + i);
		if(!element)
			break;

		element.dispatchEvent(myevent);
		var color = element.style.backgroundColor;

		if(map[color] || map[color] == 0) {
			var elementX = document.getElementById('card' + map[color]);
			elementX.dispatchEvent(myevent);
			element.dispatchEvent(myevent);
			elementX.dispatchEvent(myevent);
		} else {
			map[color] = i;
		}
		i++;
	}
}

要するに順番にカードをクリックしながらMapに色をどんどん登録していって、過去に同じ色のものが登録されていたら過去のカードと今のカードを適当な回数クリックして揃える操作を実行、というだけのソースです。
色がそろった後のカードは何回クリックしても問題ないことがわかっていたので、揃える操作のクリック回数は本当に適当です。

一人ゲーム

残りの問題の中ではGoが一番簡単そうに見えたのですが、Go書いたことがない & Goの実行環境を構築するだけでも1時間以上はかかりそうだったので、ひとまずAndroidに着手しました。
が、やってる途中で一人ゲームの解法が浮かんできたので、急遽方針転換。
Android用にEclipse立ち上げてたんで、そのままの勢いでJavaで書きました。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class AloneGame {

	public static void main(String[] args) throws IOException {
		new AloneGame().execute();
	}

	public void execute() throws IOException {
		InputStream stream = getClass().getResourceAsStream("AloneGame.dat");
		InputStreamReader reader = new InputStreamReader(stream);
		BufferedReader br = new BufferedReader(reader);

		// ignore first line
		br.readLine();
		
		String line;
		while (null != (line = br.readLine())) {
			int size = Integer.parseInt(line);
			line = br.readLine();
			String[] strs = line.split(" ");
			if (strs.length != size) {
				throw new RuntimeException("invalid data!");
			}
			List<Integer> vals = new ArrayList<Integer>(strs.length);
			for (String s : strs) {
				vals.add(Integer.parseInt(s));
			}
			System.out.println(countMin(vals));
		}
	}

	public int countMin(List<Integer> vals) {
		return countMin(vals, 0);
	}

	private int countMin(List<Integer> vals, int count) {
		count++;
		boolean isAllAvoidOK = true;
		boolean isAllHalfOK = true;
		for (int val : vals) {
			if (val % 5 != 0) {
				isAllAvoidOK = false;
			} else if (val % 10 != 0) {
				isAllHalfOK = false;
			}
		}
		if (isAllAvoidOK)
			return count;
		if (isAllHalfOK)
			return countMin(toHalf(vals), count);
		int case1 = countMin(toHalf(vals), count);
		int case2 = countMin(avoid5(vals), count);
		return case1 < case2 ? case1 : case2;
	}

	private List<Integer> toHalf(List<Integer> vals) {
		List<Integer> newVals = new ArrayList<Integer>(vals.size());
		for (Integer val : vals) {
			newVals.add(val / 2);
		}
		return newVals;
	}

	private List<Integer> avoid5(List<Integer> vals) {
		List<Integer> newVals = new ArrayList<Integer>(vals.size());
		for (Integer val : vals) {
			if (val % 5 != 0)
				newVals.add(val);
		}
		return newVals;
	}
}

つまり、

  1. 全てが5で割り切れるときは終了
  2. 全てが下記どちらかの条件を満たすときは、5で割り切れる数を取り除いても意味がないので半分にする操作を実行
    1. 5で割り切れない
    2. 10で割り切れる
  3. 1, 2以外の場合はどちらの操作が良いのかわからないので、両方やってみて回数が少ない方を採用

という操作を再帰的に実施して回数をカウントするプログラムです。
測ってみたところ、Corei5で100問を200〜300ミリ秒くらいで解くことができていました。

そしてタイムアップ

ここまで解いた時点で、もう朝の5:00くらいでした。
次の日仕事だったためやむなく寝たのですが・・次の日の朝、ボーダーラインが101点前後と判明。
出社途中の電車の中でスライドパズルを数問手作業で解いたりもしたのですが、悪あがきに過ぎませんでした。

感想

結果も残念でしたが、それ以上に残念なことが・・・。
やってみたらすごく楽しかったので、

  • 時間に追われる中でのチャレンジだったこと
  • 最後の問題にチャレンジできなかったこと

が悔やまれます。
またこのような機会があったら、今度は時間をちゃんととってリベンジしたいと思います。

最後に

GDD参加が決定した皆さん、おめでとうございます。私の分まで楽しんできて下されば幸いです。
報告会などがあれば、参加したいと思います。

私も来年こそ参加するつもりですので、よろしく!