こけめも

メモみたいなもの

au REGZA Phone IS04 Iのキャリアメールトラブルを解決するたった一つの方法

釣り臭いタイトルで申し訳ないですが、ぶっちゃけるとただの「ケータイアップデート」です。
自分の環境ではこれでかなりマシになりました。
ケータイアップデートも躊躇している人もいるかも、と思って記事にしておきます。

最近のIS04

みなさん、愛想つかさずにIS04使いつづけてますか?
私はときどきくじけそうになります。最近まともにキャリアメールが使えなくて…
具体的に言うと、「ずっと受信中のまま受信完了せず」「閲覧や送信もできなくて」「応答なしになって」「電池大量消費する」という感じです。


この2chスレがあるある過ぎて笑えません。
VIPPERな俺 : 「は、はじめましてっ!IS04ですっ!REGZAフォンと呼んでください!」


そんなIS04ですが、いつの間にかケータイアップデートが何度か実施されているようです。
通知するように設定しているはずなのにまったく通知無しなので気づきませんでしたが。
この「通知が無い」というのも、「そんなもんだよね」と思えちゃったらあなたも立派なIS04ユーザーです!

最近のIS04ケータイアップデート

ここ最近あったIS04のアップデート内容は以下のとおり。


au携帯電話「REGZA Phone IS04」の「ソフトウェア更新」についてのお知らせ(2011年9月29日)

  • Eメール (@ezweb.ne.jp) の各種改善
    • 宛先選択時に、本体の「連絡先」から選択できるように変更します。
    • 送受信メールの名前が本体の「連絡先」の登録名で表示されるように変更します。
    • メール送信時に確認画面の表示を追加します。
  • Eメールセキュリティ対応
    • Eメール送受信時の認証方法の強化を行います。
  • その他
    • Cメールの連絡先の並び順を50音順に変更します。
    • アラームの停止ボタンが表示されず、アラームが停止できない事象を改善します。
    • フォントを切り替えると文字化け場合があるものを改善いたします。
    • au Smart SportsRun&Walk」アプリで再起動する事象を改善いたします。
  • 今回のケータイアップデートは6月16日以降にAndroid2.2へ更新が完了済みであることが条件となります。
  • ※ 更新されるソフトウェアには、上記の事象以外に、より快適にREGZA Phone IS04をご利用いただくための改善内容が含まれております。


au携帯電話「REGZA Phone IS04」の「ソフトウェア更新」についてのお知らせ(2011年11月1日)

  • ワンセグを起動すると、予期せずエラーが発生する場合があります。
  • Cメールアプリ不具合対応。

ここで重要なのはやはり「Eメール (@ezweb.ne.jp) の各種改善」でしょう。
かねてより不評であった「連絡先」と「Eメール連絡先」の二重管理が、「連絡先」のみで扱えるようになったのは大きいです。
もう目覚ましちゃんと鳴って欲しいとも、アプリサクサク動いて欲しいとも言わないので、通話とメールだけはお願いしますよ、ほんと。

アップデートしてみて

アップデート後、頻発していたEメールの問題は発生していません。
メール削除処理も早くなっているようですし、削除の進捗状況も表示されました。


これでようやく携帯電話としてのスタート地点に立っただけという気もしますが、利用者の声を聞いて改善していけるのは素晴らしいと思います。


IS04ユーザーであれば、このケータイアップデートは間違いな効果ありです。
IS04をお使いの方はぜひともケータイアップデートしてください。

(2011/11/11 追記)

先日のケータイアップデート後、散々悩まされてきたキャリアメールのトラブルがピタリとなくなりました。
もちろん動作が遅かったりはしますが、「送受信が一切できない」なんてことはありません。
これでようやく普通の携帯並の操作性に近づいたか…

GDD 2011 参加してきました!

Google Developer Day 2011 Japan 参加してきました


↑今年のノベルティグッズ。
朝4時に起きて日帰り弾丸参加だったので猛烈に眠いのですが少しだけ。

よかった点

とにかく楽しかった!めちゃくちゃ刺激になった!!
AndroidHTML5ChromeGoogle+ などなど、その一部しか聞けないことが残念です。


スピーカーのみなさん、スタッフのみなさん、展示していた各企業・有志の方々、バッジ交換やNFC QUESTパーティーのみなさん、ありがとう!


見れなかった講演はまたYoutubeで見とこう。

いまいちだった点

完全に私のせいですが、最後の最後まで参加できなかったこと。
帰りの電車の都合もあって19:00を前に会場を後にしました。残ってたらどっか打ち上げに紛れ込んでやったの…
来年関西でやらないかな。


それと、講演を聴くのに十分な知識を持ち合わせていなかったこともあります。
また、急遽Twitter経由でコミュニケーション取った方はいたものの、基本的にネット上で親しくしている方がいないのでぼっちになりそうだったのも危ないとこでした。
これもちょくちょくイベント参加できるといいんでしょうけどね。

最後に

また来年もぜひ参加させてください。
それまでにコーディングと知り合い作り頑張ろう。

GDD2011のDevQuizにチャレンジしたのでコード晒し (スライドパズル編)

GDD2011


先日「参加確定」のメール来ました!
「参加確定」ってとこにやや違和感あるものの、これで参加権を得たことになります。
ふー、一安心。


でも、なんで火曜なんやろ。。関西から日帰りってしんどいかな?
他に関西から参加される方いたら、どのようなスケジュールで行くかぜひ教えて下さい。

チャレンジクイズ

スライドパズル


いまさら感もありますが、スライドパズルのコード晒してみます。
正答数少ない&アルゴリズム丸パクリですが、今後の自分のためのメモも兼ねてサラっと。
自分が調べたこと、他の人の解答を見て知ったアルゴリズムなどもまとめれたらと思ってます。


また、「一人ゲーム」に引き続き、広井 誠(m_hiroi)氏のアルゴリズム解説とサンプルコードに大変お世話になりました。
この場を借りてお礼申し上げます。

提出コード

前述の通り、コア部分のアルゴリズムは丸パクリなのでサラっと行きます。
参考にしたのはこちら。


‚P‚TƒpƒYƒ‹Ž©“®‰ð“šƒvƒƒOƒ‰ƒ€‚̍ì‚è•û
M.Hiroi's Home Page / Puzzle De Programming
M.Hiroi's Home Page / Puzzle De Programming


特にこちらの解説・コードを参考にしています。
Algorithms with Python / 幅優先探索と反復深化


「一人ゲーム」の時に要約勉強した「幅優先探索」「深さ優先探索」という言葉を覚えたとこですが、今回は「反復深化」で解を求めたいと思います。
枝刈りには「マンハッタン距離(MD)」を使用することにしました。


自分で実装したところと言えば、隣接リスト、マンハッタン距離、ボード、ゴールを可変にしたところや、壁の回避処理を付け加えたところくらいでしょうか。
完全には理解できていないとこもあるのでトライ&エラーでチャレンジです。
ホント、何度でも回答提出して良いルールにも救われていますね。

# coding: utf-8
import os.path
import time

#カウンタ
LC = 0
RC = 0
UC = 0
DC = 0


# 隣接リスト
adjacent = []

# 距離
distance = []

# 距離を求める
def get_distance(board):
	v = 0
	for x in xrange(len(board)):
		p = board[x]
		if p == "0": continue
		if p == "=": continue
		#v += distance[p][x]
		v += distance[int(p)][x]
	return v

# ゴールの局面
GOAL = []

# 盤面
board = []

# 動かした駒
move_piece = [None] * 200
move_history = [None] * 200

def convListToStr(array):
	arraybuf = []
	arraybuf = filter((lambda x: x!=None), array)
	return "".join(map(str,arraybuf))

def checkLRUDcount(strAns):
	global LC
	global RC
	global UC
	global DC
	
	global LX
	global RX
	global UX
	global DX
	
	if strAns == "timeout":
		return True
	
	#文字列からLRUDカウント
	LC += strAns.count("L")
	RC += strAns.count("R")
	UC += strAns.count("U")
	DC += strAns.count("D")
	
	if LC > LX:
		return False
	elif RC > RX:
		return False
	elif UC > UX:
		return False
	elif DC > DX:
		return False
	return True

# 下限値枝刈り法
def id_lower_search(limit, move, space, lower, w, h, s, tl):
	e = time.clock()
	if move == limit:
		if board == GOAL:
			global count
			count += 1
			global result
			result = convListToStr(move_history)
	elif e - s > tl:
		count += 1
		result = "timeout"
	else:
		for x in adjacent[space]:
			p = board[x]
			if p == "=": continue
			if move_piece[move] == p: continue
			# 駒を動かす
			board[space] = p
			board[x] = "0"
			move_piece[move + 1] = p
			move_distance = x - space	
			if move_distance == -w:			#上移動
				move_history[move] = "U"
			elif move_distance == -1:		#左移動
				move_history[move] = "L"
			elif move_distance == 1:		#右移動
				move_history[move] = "R"
			elif move_distance == w:		#下移動
				move_history[move] = "D"
				
			new_lower = lower - distance[int(p)][x] + distance[int(p)][space]
			# 下限値枝刈り法
			if new_lower + move <= limit:
				id_lower_search(limit, move + 1, x, new_lower, w, h, s, tl)
			# 元に戻す
			board[space] = "0"
			board[x] = p
			

def get_board(w,h,b):
	new_board = []
	for i in xrange(w*h):
		if b[i].isalpha():
			#英数字
			new_board.append(str(ord(b[i])-55))
		else:
			new_board.append(b[i])
	return new_board[:]

def get_GOAL(w,h,b):
	new_GOAL = []
	for i in xrange(w*h):
		if b[i] != "=":
			new_GOAL.append(str(i+1))
		else:
			new_GOAL.append("=")
	new_GOAL[len(new_GOAL)-1] = "0"
	return new_GOAL[:]

def setAdjacent(w,h):
	global adjacent
	adjacent = []
	for i in xrange(w*h):
		buf = []
		if i - w >= 0 and i - w < w*h:
			buf.append(i-w)
		if i - 1 >= 0 and i - 1 < w*h:
			if i % w != 0: 					#左端でなかったら
				buf.append(i-1)
		if i + 1 >= 0 and i + 1 < w*h:
			if i % w != w-1: 				#右端でなかったら
				buf.append(i+1)
		if i + w >= 0 and i + w < w*h:
			buf.append(i+w)
		adjacent.append(buf)

def setDistance(w,h):
	global distance
	distance = []
	for i in xrange(w*h):
		buf = []
		if i != 0: 
			for j in xrange(1,w*h+1):
				#距離計算
				dx = (j-1)%w - (i-1)%w if (j-1)%w - (i-1)%w > 0 else -((j-1)%w - (i-1)%w)	#横
				dy = (j-1)/w - (i-1)/w if (j-1)/w - (i-1)/w > 0 else -((j-1)/w - (i-1)/w)	#縦
				#if dx < 0:dx = -dx
				buf.append(dx + dy)
		distance.append(buf)

count = 0
result = ""
def solve_slide(w, h, b, tl):
	s = time.clock()
	global board
	global GOAL
	board = get_board(w,h,b)
	GOAL = get_GOAL(w,h,b)
	
	setAdjacent(w,h)
	setDistance(w,h)
	n = get_distance(board)
	strAns = ""
	global result
	for x in xrange(n, 200):
		#print 'move ', x
		#print board
		id_lower_search(x, 0, board.index("0"), n, w, h, s, tl)
		if count > 0: break
	return result


#メイン処理
LX = 0
RX = 0
UX = 0
DX = 0
N = 0

def main(start, end, min, max, tl, status):
	global LX
	global RX
	global UX
	global DX
	global N
	global count
	global move_piece
	global move_history

	#入力データ取得
	inputfile = "input_status.data"
	if os.path.exists(inputfile):
		fi = open(inputfile, 'r')
	else:
		exit()

	#出力ファイル作成
	outputfile = "output.data"
	fo =  open(outputfile, 'w')


	#使うことができる L, R, U, D それぞれの総数
	line = fi.readline().split(' ')
	LX = int(line[0])
	RX = int(line[1])
	UX = int(line[2])
	DX = int(line[3])

	N = int(fi.readline())

	for i in xrange(N):
		print i+1
		line = fi.readline().split(',')
		sta = line[0]
		w = int(line[1])
		h = int(line[2])
		b = line[3]
		if i + 1 < start:
			fo.write('\n')
		elif i + 1 > end:
			fo.write('\n')
		elif w * h < min:
			fo.write('\n')
		elif w * h > max:
			fo.write('\n')
		elif sta == status:
	#		if b.find("=") == -1:
			strAns = solve_slide(w,h,b,tl)
			if checkLRUDcount(strAns) == True:
				fo.write(strAns + '\n')
				print strAns
			else:
				fo.write('\n')
				continue
			#fo.write(str(w) + "," + str(h) + "," + b + '\n')
			#グローバル変数初期化
			count = 0
			move_piece = [None] * 200
			move_history = [None] * 200
	#		else:
	#			fo.write('\n')
		else:
			fo.write('\n')
	fi.close()
	fo.close()
	
if __name__ == "__main__":
	main(1,5000,0,99,300,"yet")	#1問目から


実はアルゴリズムを変更しないままpython→cython→C言語と作り替えてみましたが、大した速度向上は見られず。
問題によっては速いこともあるかなー程度でした。


小手先ではなくアルゴリズムを工夫しろってことなんでしょうね。

経路探索アルゴリズム覚書

幅優先探索(breadth-first search、BFS)

幅優先探索 - Wikipedia
ある階層をすべて調べ、それが終わるとひとつ深い階層をすべて調べるということを繰り返す。
ある階層までの探索経路をキューに貯め、ひとつ深い階層の状態を追加していく。
○特徴
最適解(最短経路)が最初に見つかる。
メモリを大量消費する可能性がある。


devquizのスライドパズル
→マンハッタン距離で枝刈り
DevQuiz スライドパズル 解答 - saito’s blog
→枝刈りやマルチコア
Google DevQuiz 2011 解答例「スライドパズル」編 | ビットログ
→双方向・幅優先探索+評価値
http://www.cattaka.net/sphpblog/index.php?entry=entry110912-211621
→幅優先+枝刈り?答え合わせ大会の資料も。
yamablo » Google Developer Day Dev Quiz 〜スライドパズル〜
→幅優先+パターン記録

深さ優先探索(depth-first search, DFS)

深さ優先探索 - Wikipedia
それ以上進めなくなるまで一つの経路を進み、進めなくなったら一手戻って別経路を調査する。
再起をつかって表現できる。
○特徴
最適解(最短経路)が最初に見つかるとは限らない
メモリ消費を抑えられる

反復深化深さ優先探索(iterative deepening depth-first search、IDDFS)

反復深化深さ優先探索 - Wikipedia
深さ優先探索の「深さ」に上限値を設定し、解が見つかるまで上限値を段階的に増やしていく。
深さ優先探索のメモリ効率と幅優先探索の完全性(分岐が有限の場合)を併せ持っている。
同じ経路探索を何度も行うことになるので、下限値枝刈りなどの工夫が必要となる。
○特徴
最適解(最短経路)が最初に見つかる。
メモリ消費を抑えられる


DevQuizのスライドパズルのひねた解法 — KaoriYa
GDD2011 DevQuiz スライドパズル - だらだらとだらだら
コンデンサの隣からひとこと
GDD2011 DevQuiz - 瓶詰堂日記
みなさん、双方向と組み合わせたり工夫しています。

双方向探索(bidirectional search)

双方向探索 - Wikipedia
同時に2つの方向から探索を行う。通常は初期状態と最終状態(ゴールした状態)から。
他の探索アルゴリズム(幅優先探索など)と組み合わせて使う。


↓このあたりからまだよく分かっていません。

ダイクストラ

ダイクストラ法 - Wikipedia
ダイクストラ法(最短経路問題)

1. 初期化:スタートノードの値(最小コスト候補)を0,他のノードの値を未定義(または∞)に設定。
2. 確定ノードをピックアップすることができなくなるまで(=変化がなくなるまで)以下のループを繰り返す:
2-1. まだ確定されていないノードのうち,最小の値を持つノードを見つけ,確定ノードとする(確定フラグを立てる)。
2-2. 確定ノードからの伸びているエッジをそれぞれチェックし,「確定ノードまでのコスト+エッジのコスト」を計算し,そのノードの現在値よりも小さければ更新する (経路情報も必要であれば,「どこから来たのか」を表す変数が確定ノードを指すようにする)。

Google DevQuiz 回答アップ「スライドパズル編」 - from scratch
→ただし、距離を求める関数の中で。
ソルバー本体は幅優先+枝刈り

A*(A-star, エースター)

A* - Wikipedia
Algorithms with Python / ヒューリスティック探索

4000問とかたくさん解いている人の中にはこれが多い気がする。

A*アルゴリズムについて復習した - Yoh Okunoの日記
→探索アルゴリズムは色々と関わりあっている。
GDD2011 DevQuiz のスライドパズルに挑戦してみました | blog.k11i.biz: GDD2011 DevQuiz のスライドパズルに挑戦してみました
→A*+双方向探索
http://charites.info/archive/2011/09/16113910.php
→A*+双方向探索
DevQuizの解答(ソースコード)晒し スライドパズル編 #gdd11jp | mzsm.me


その他参考
GDD2011 DevQuiz のスライドパズル晒し祭りをまとめてみた - Fire and Motion
探索 - Wikipedia
http://www.geocities.jp/m_hiroi/light/pyalgo05.html
Algorithms with Python / 幅優先探索と反復深化
GDD2011JP Sliding Puzzle
→5000問を168分で解くとかもう…
[GDD2011][DevQuiz]スライドパズルをPerlで解く|キッズプレート、パスタおかわり
Perlによる解答
[観] GDD2011 Japan の DevQuiz を解くために書いたコードを公開してみました
→パズルを手で解いて解答として出力
[Google] Google Developer Day 2011 DevQuiz - adakoda
→IDA*(反復深化A*)による解答


↓ここからアルゴリズム紹介・解説資料。大学などのプレゼン資料?
ヒューリスティック探索」というのもひとつのキーワードだったかも。
2007年度 計算知能論A ヒューリスティクス探索
アルゴリズム解説。A*やIDA*も
最適解を求める2 つの探索アルゴリズムのスーパーパズにおける性能比較について
知能処理アルゴリズム論 第2回 探索技法

GDD2011のDevQuizにチャレンジしました。(結果報告)

DevQuiz終了


約10日に渡る挑戦も本日で終了。
悔いは残るけど、楽しく勉強になる日々でした。


最終的なスコアは110.2点。
なんとかボーダーラインクリアです。


せっかくなので、この後のエントリーで勉強した内容や感想を振り返ってみようと思います。
正直「恥」以外のなにものでもないですが、反省も含め作成したコードも公開してみます。

GDD2011のDevQuizにチャレンジしたのでコード晒し (〜分野クイズ編)

DevQuizへの挑戦


今年になって存在を知ったGDDとDevQuiz。
今年は是非参加したいと思いながら事前登録を忘れており、公開から遅れること数日、9/1に登録してチャレンジ開始です。

ウォームアップクイズ

ウォームアップクイズはググったりChrome拡張使ったりで、2回目でクリア。
Googleの画像検索って画像ファイルをもとに検索できるのね。こりゃ便利。
知人に教えたところ「長年の疑問が解消された」と感謝されてしまいました。
まんまとGoogleの策略にはまってる気がする…
Search by Image – Inside Search – Google


○参考ページ:
HTML5 Forms Status - The Chromium ProjectsChromeHTML5対応状況?


分野別クイズ

どのコードも言語の特徴を生かせていない、正直晒すと株が下がりそうなコードばかりですが、自分への戒めも込めて公開してみます。
次はもっと質やメンテナンス性、テストのしやすさも向上させたいです。


ソースコードは下記でも公開しています。
https://github.com/kokemono/GDD2011_DevQuiz

Web Game

まずは一番上にある「Web Game」からチャレンジ。
ひとまずヒントをダウンロードして動作させてみることにしました。


一昔前のFirefox拡張はいじったことあるのですが、Chromeは未体験です。
とりあえずChrome拡張機能をのぞいてみると「デベロッパーモード」→「パッケージ化されていない拡張機能を読み込む」というものが。
修正内容がすぐに反映されるし、開発中は助かる機能ですね。


上記機能でヒントを解凍したフォルダを選択すると、一枚目のカードをめくってその色を表示するサンプルが実行されました。
ヒントのスクリプトから要素の取得方法、カードのクリック(めくり)方法、 色の取得方法がわかります。
これらを参考に、一度全部のカードをめくって色を記憶し、その後同じ色のカードをめくっていくようにしました。
一発で最後まで解けたのでまあまあかと思っていたら、他の人はもっとスマートな回答してますね…反省
たしかに3回もループ回しちゃってるしムダだったな。


なお、manifest.json はノータッチです。

var elements = document.getElementsByClassName("card");
if (elements == null) {
  alert('Card element is not found. Check element id.');
} else {
  var res;
  var element;

  //クリックイベント作成
  var myevent = document.createEvent('MouseEvents');
  myevent.initEvent('click', false, true);

  var cardlist = [];
  //各Cardの背景色取得
  for( var j=0; j<elements.length; j++ ) {
    //res += elements.item(j).nodeName + ":" + elements.item(j).className + ":" + elements.item(j).id + "\n";
    element = elements.item(j);
    element.dispatchEvent(myevent);
    var cardinfo = {};
    cardinfo["color"] = element.style.backgroundColor;
    cardinfo["opened"] = false;
    cardlist[j] = cardinfo;
  }
  //Open済かどうかチェック
  for( var j=0; j<elements.length; j++ ) {
    element = elements.item(j);
    var style = element.style.backgroundColor;
    if(style == cardlist[j]["color"]) {
      cardlist[j]["opened"] = true;
    }
  }

  //色が同じCardを開けていく
  for( var j=0; j<elements.length; j++ ) {
    if(cardlist[j]["opened"] == false) {
      var temp = cardlist[j]["color"];
      for( var k=j; k<elements.length; k++ ) {
        if(cardlist[k]["color"] == temp) {
          elements.item(j).dispatchEvent(myevent);
          elements.item(k).dispatchEvent(myevent);
          cardlist[j]["opened"] = true;
          cardlist[k]["opened"] = true;
        }
      }
    }
  }
}


参考文献
特になし

Google Apps Script

次にチャレンジしたのがGoogle Apps Script。
javascriptで組めるというのと、VBAみたいなもんだろう、というのが選んだ理由です。


jsonの取得(HTTP通信)、セルへの書き込み方法、書式の設定方法が分かれば特に問題ありませんでした。
なお、もともとあったシートは手動で削除しました^_^;


書式については、手動で書式設定したセルに対して getNumberFormat して得た値を設定するようにしました。


他の人のコード見てて気づいたけど、jsonをパースするAPIGoogle Apps Script側で用意されていたようです。
WebAPIとの連携が意識されているんでしょうね。
http://www5d.biglobe.ne.jp/~pog/utilities_services/class_utilities.html#jsonParse

function myFunction() {

  //データ取得
  var response = UrlFetchApp.fetch("http://gdd-2011-quiz-japan.appspot.com/apps_script/data?param=-4693790266312240589");
  //Browser.msgBox(response.getContentText());
  if(response == null) {
    return;
  }

  //JSONデータを配列に変換
  var jsondata = eval("("+response.getContentText()+")");
  if(jsondata == null) {
    return;
  }

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SpreadsheetApp.getActiveSheet();
  //Browser.msgBox(sheet.getRange(2, 3).getNumberFormats());

  for( var i=0; i<jsondata.length; i++ ) {
  //for( var i=0; i<1; i++ ) {
    //都市名でシート作成し、作成したシートを取得
    ss.insertSheet(jsondata[i].city_name)
    sheet = ss.getSheetByName(jsondata[i].city_name);
    for( var j=0; j<jsondata[i].data.length; j++ ) {
    //for( var j=0; j<1; j++ ) {
      sheet.getRange(j+1, 1).setValue(jsondata[i].data[j].capacity);
      sheet.getRange(j+1, 2).setValue(jsondata[i].data[j].usage);
      //C列には計算式を記載
      sheet.getRange(j+1, 3).setValue("=" + sheet.getRange(j+1, 2).getValue() + "/" + sheet.getRange(j+1, 1).getValue());
      //sheet.getRange(j+1, 3).setNumberFormat("0.00%");
    }
    //サンプルを見ると、データは数値だったり式であったりしたが、
    //表示形式は"0.00%"に統一されているようなのでここで設定
    sheet.getRange("C1:C"+j).setNumberFormat("0.00%");
  }
}


○参考ページ:
JSONってなにもの? | Think IT(シンクイット)jsonの勉強
http://www5d.biglobe.ne.jp/~pog/index.htmlAPIリファレンスとして
→特にSpreadsheetrange
初心者のためのGoogle Apps Scriptプログラミング入門:サンプル


Android

分野別問題2つ解いたし次はチャレンジクイズだ!とも思ったんですが、他の分野別クイズが気になって集中できないので、先に分野別問題を片付けることにしました。


Androidは触ったことあるんですが、正直サンプル程度で本問題の回答はさっぱりです。


まずは、エミュレータGoogleが用意したアプリをインストールするところから。
エミュレータ起動した状態で下記コマンド実行します。

adb install "apkのパス"


無事インストールできたので、エミュレータ上でアプリ起動しメールアドレス等を登録。


あとはこのアプリ(サービス)にアクセスしてコードを取得するのですが、どうにもさっぱり…
そこで日経ソフトウェア2010年7,8月号でAndroidのサービスをざっくり勉強したあと、「他の人が作ったサービスを使うための手法」を検索しました。


結果的に、参考ページにあるような方法でAIDLを組み込んでやるとうまくいきました。
本問題のポイントは「AIDLを読み込ませてinterfaceを自動生成する」というところだと思います。
一応、interface自動生成後のソース晒しときます。

package com.kokemono.android.gdd2011;

import com.google.android.apps.gddquiz.IQuizService;

import android.app.Activity;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;



public class MainActivity extends Activity {

     private EditText mEditText;
     private Button mButton;

     private IQuizService mQuizService = null;

     private ServiceConnection svcConn = new ServiceConnection() {

          @Override
          public void onServiceDisconnected(ComponentName name) {
               mQuizService = null;
          }

          @Override
          public void onServiceConnected(ComponentName name, IBinder service) {
               mQuizService = IQuizService.Stub.asInterface(service);
          }
     };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mEditText = (EditText)findViewById(R.id.editText1);
        mButton = (Button)findViewById(R.id.button1);

        Intent intent = new Intent(IQuizService.class.getName());
        bindService(intent, svcConn, Context.BIND_AUTO_CREATE);

        mButton.setOnClickListener(new View.OnClickListener() {

               @Override
               public void onClick(View v) {
                    // TODO 自動生成されたメソッド・スタブ
                  try {
                         String devcode = mQuizService.getCode();
                         mEditText.setText(devcode);
                    } catch (RemoteException e) {
                         // TODO 自動生成された catch ブロック
                         e.printStackTrace();
                    }

               }
          });


   }
    public void onDestroy() {
        super.onDestroy();

        unbindService(svcConn);
    }

}

○参考ページ:
AndroidのRemote Serviceについて(+作り方) - adsaria mood
他のアプリ(パッケージ)からもアクセスできるServiceを作る - terurouメモ

Go

まずはWindowsに開発環境を整えることからスタートです。
Windows環境なのでwingo使用。VmWare上のCentOSでインストールしようとしたらうまくいきませんでした…


HelloWorldが表示できることを確認したあと、いよいよコード着手です。
今回も日経ソフトウェアの過去記事が参考になりました。
日経ソフトウェア 2010年11月号に、「sliceを駆使して画像処理プログラムを作ろう」というど真ん中な連載記事が。
これ見た瞬間に「楽勝!」と思ったんですが、使えるプロパティが記事と違うところがありすんなりとは行きませんでした。


まあちょっと調べながらなんとかクリアです。


意外と困ったのが、importしたimage/pngパッケージを使いたくても、仮引数ですでに「png」が使われていると言う点。
きっと出題者もあえてこのような名前にしているのでしょう。
自分の場合下記ページを参考に別の名前(限定付き識別子?エイリアス?)をつけてやることで解決しています。


Go言語仕様翻訳(part12) - golang.jp


もちろん、関数の仮引数名を変更しても正解のようです。


後から見直して大変カッコ悪いんですが、色の組み合わせをキーにして連想配列を作る際、「0埋めして文字列作らないと一意にならない」と思い込みから「よく分からんから10未満100未満でやっちゃえ」としてしまった点。
他の方の回答見た時、RGB各値の間に":"挟んだりしてるのをみて「そりゃそうか」と思わず納得してしまいました。


最終的な数も連想配列のlenではなくカウントで取得してるのがまたカッコ悪い。

package main

import (
     "fmt"
     "io"
     "strings"
     "image"
     p "image/png"
     "strconv"
     /* add more */
)


/* ----- これらの関数は提出時に自動挿入されます。----- */
func main() {
     png := GetPngBinary()
     cnt := CountColor(png)
     fmt.Println(cnt)
}

func GetPngBinary() io.Reader {
     // img_strの中身は提出するたびに変化します。
     img_str := "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x08\x08\x06\x00\x00\x00\xe3\xa1?c\x00\x00\x02\xeeiCCPICC Profile\x00\x00x\x01\x85T\xcfk\x13A\x14\xfe6n\xa9\xd0\"\x08Zk\x0e\xb2x\x90\"IY\xabhE\xd46\xfd\x11bk\x0c\xdb\x1f\xb6E\x90d3I\xd6n6\xeb\xee&\xb5\xa5\x88\xe4\xe2\xd1*\xdeE\xed\xa1\x07\xff\x80\x1ez\xf0d/J\x85ZE(\xde\xab(b\xa1\x17-\xf1\xcdnL\xb6\xa5\xea\xc0\xce~\xf3\xde7\xef}ov\xdf\x00\rr\xd24\xf5\x80\x04\xe4\r\xc7R\xa2\x11il|Bj\xfc\x88\x00\x8e\xa2\tA4%U\xdb\xecN$\x06A\x83s\xf9{\xe7\xd8z\x0f\x81[V\xc3{\xfbw\xb2w\xad\x9a\xd2\xb6\x9a\x07\x84\xfd@\xe0G\x9a\xd9*\xb0\xef\x17q\nY\x12\x02\x88<\xdf\xa1)\xc7t\x08\xdf\xe3\xd8\xf2\xec\x8f9Nyx\xc1\xb5\x0f+=\xc4Y\"|@5-\xce\x7fM\xb8S\xcd%\xd3@\x83H8\x94\xf5qR>\x9c\xd7\x8b\x94\xd7\x1d\x07inf\xc6\xc8\x10\xbdO\x90\xa6\xbb\xcc\xee\xabb\xa1\x9cN\xf6\x0e\x90\xbd\x9d\xf4~N\xb3\xde>\xc2!\xc2\x0b\x19\xad?F\xb8\x8d\x9e\xf5\x8c\xd5?\xe2a\xe1\xa4\xe6\xc4\x86=\x1c\x185\xf4\xf8`\x15\xb7\x1a\xa9\xf85\xc2\x14_\x10M'\xa2Tq\xd9.\r\xf1\x98\xae\xfdV\xf2J\x82p\x908\xcada\x80sZHO\xd7Ln\xf8\xba\x87\x05}&\xd7\x13\xaf\xe2wVQ\xe1y\x8f\x13g\xde\xd4\xdd\xefE\xda\x02\xaf0\x0e\x1d\x0c\x1a\x0c\x9a\rHP\x10E\x04a\x98\xb0P@\x86<\x1a14\xb2r?#\xab\x06\x1b\x93{2u$j\xbbtbD\xb1A{6\xdc=\xb7Q\xa4\xdd<\xfe(\"q\x94C\xb5\x08\x92\xfcA\xfe*\xaf\xc9O\xe5y\xf9\xcb\\\xb0\xd8V\xf7\x94\xad\x9b\x9a\xba\xf2\xe0;\xc5\xe5\x99\xb9\x1a\x1e\xd7\xd3\xc8\xe3sM^|\x95\xd4v\x93WG\x96\xacyz\xbc\x9a\xec\x1a?\xecW\x971\xe6\x825\x8f\xc4s\xb0\xfb\xf1-_\x95\xcc\x97)\x8c\x14\xc5\xe3U\xf3\xeaK\x84uZ17\xdf\x9fl\x7f;=\xe2.\xcf.\xb5\xd6s\xad\x89\x8b7V\x9b\x97g\xfdjH\xfb\xee\xaa\xbc\x93\xe6U\xf9O^\xf5\xf1\xfcg\xcd\xc4c\xe2)1&v\x8a\xe7!\x89\x97\xc5.\xf1\x92\xd8K\xab\x0b\xe2`m\xc7\x08\x9d\x95\x86)\xd2m\x91\xfa$\xd5``\x9a\xbc\xf5/]?[x\xbdF\x7f\x0c\xf5Q\x94\x19\xcc\xd2T\x89\xf7\x7f\xc2*d4\x9d\xb9\x0eo\xfa\x8f\xdb\xc7\xfc\x17\xe4\xf7\x8a\xe7\x9f(\x02/l\xe0\xc8\x99\xbamSq\xef\x10\xa1e\xa5ns\xae\x02\x17\xbf\xd1}\xf0\xb6nk\xa3~8\xfc\x04X<\xab\x16\xadR5\x9f \xbc\x01\x1cv\x87z\x1e\xe8)\x98\xd3\x96\x96\xcd9R\x87,\x9f\x93\xba\xe9\xcabR\xccP\xdbCRR\xd7%\xd7eK\x16\xb3\x99Ub\xe9v\xd8\x99\xd3\x1dn\x1c\xa19B\xf7\xc4\xa7Je\x93\xfa\xaf\xf1\x11\xb0\xfd\xb0R\xf9\xf9\xacR\xd9~N\x1a\xd6\x81\x97\xfao\xc0\xbc\xfdE\xc0x\x8b\x89\x00\x00\x00\x97IDAT(\x15\x9d\x92\x81\x0e\x80 \x08D\xa5\xf9m\xf5Y\xad\xcf\xaa\x9f#nz$\xba\xb9\xca\xad\x85\xc1\xbd\x03S\xd4\x96H\xf2\xa5\xea\xe1\xeb@\x8e\x02\xd0}\x14/\x80\x03\xca\xa75{\xeb0\x80\x01\xa9\xa0\xdcC|\x02:\xf1\xc3U\xc7\\K\x97}\xda9HPcq0pQ\x8aE\xe94y\x05'3\x92M[\x86\xc7\xc1\xa4n\x82\x01\x8ci\xe2\xc5\x7f\x02N`\xda\xdcCK\xaeqbqsD\xbd\x86=\xe0g\xdb\x9dy\xba\xb4Xp\x8bX\xf0\xe7\x8d\x89g\x84pD_\x0cx\x9438x7\xa4yC\r7\x04z\xae\x00\x00\x00\x00IEND\xaeB`\x82"
     return strings.NewReader(img_str)
}
/* ----- これらの関数は提出時に自動挿入されます。----- */


func CountColor(png io.Reader) int {
     var pic image.Image
     var color image.Color
    
     pic,e := p.Decode(png)
     if e != nil {
          fmt.Printf("Error %v\n", e)
          return 0
     }
    
     cnt := 0
    
     colormap := make(map[string] int)
     for y:= 0; y < pic.Bounds().Size().Y; y++ {
          for x:= 0; x < pic.Bounds().Size().X; x++ {
               color = pic.At(x,y)
               r,g,b,_ := color.RGBA()
               key := ""
               if uint8(r) < 10 {
                    key += "00"+ strconv.Uitoa(uint(uint8(r)))
               } else if uint8(r) < 100 {
                    key += "0"+ strconv.Uitoa(uint(uint8(r)))
               } else {
                    key += strconv.Uitoa(uint(uint8(r)))
               }
              
               if uint8(g) < 10 {
                    key += "00"+ strconv.Uitoa(uint(uint8(g)))
               } else if uint8(g) < 100 {
                    key += "0"+ strconv.Uitoa(uint(uint8(g)))
               } else {
                    key += strconv.Uitoa(uint(uint8(g)))
               }

               if uint8(b) < 10 {
                    key += "00"+ strconv.Uitoa(uint(uint8(b)))
               } else if uint8(b) < 100 {
                    key += "0"+ strconv.Uitoa(uint(uint8(b)))
               } else {
                    key += strconv.Uitoa(uint(uint8(b)))
               }
              
               if val, exist := colormap[key]; exist {
                    colormap[key] = val + 1
               } else {
                    colormap[key] = 1
                    cnt ++
               }
              
          }
     }
    
     return cnt
}


○参考ページ
WindowsでGo言語::インストールWindowsでGoコンパイル環境を整えるのに
Goプログラミング言語のチュートリアル - golang.jp:日本語チュートリアル。基本が詰まっています。
image/png パッケージ - golang.jp:image/pngパッケージのリファレンス。あとはimageとstrconvについて参照


一人ゲーム

分野別クイズではこれが一番苦労しました。


一般的なアルゴリズム詳しくない、「『二分木探索?』『幅優先探索?』なにそれおいしいの?」という状態からのスタートです。
プログラム歴=社会人歴で、これまで目の前の仕事片付けるのに精一杯だったことが悔やまれます。


言語は、最近勉強中のPythonを使うことにしました。
Python2.5、Python2.7での動作を確認しています。


とりあえず、適当な公式を考えだしてチャレンジするものの、さっぱり正解しません。
ちゃんと経路探索の手法を勉強してみることにしましょう。


その際に 広井 誠 氏のサイト、特にM.Hiroi's Home Page / Puzzle De ProgrammingAlgorithms with Pythonが大変参考になりました。
これはチャレンジクイズの「スライドパズル」でも同様で、こちらの解説がなければ100点止まりだったと思います。
この場を借りてお礼申し上げます。


閑話休題
今回は、この問題を「幅優先探索」で解いてみることにしました。
簡易的なQueueとしてリストを使用しています。


・処理の流れ
Queueから取り出す→すべて5の倍数であれば終了→そうでなければ取り出した値について「すべて2で割ったもの」と「5の倍数削除したもの」を追加しQueueに追加

# coding: utf-8
import os.path

#全て5の倍数、もしくは0であれば0を返す。そうでないなら-1
def isAllMultipleOf5(array):
     for x in array:
          if x % 5 != 0:
               return -1
     return 0

#与えられた数を半分にしていき、5の倍数がでるまでの回数を返す
def countDivToMultipleOf5(num):
     i = 0
     while num % 5 != 0:
          num = num /2
          i += 1
     return i

#与えられた数値を指定の回数だけ半分にする
def divideNum(num, count):
     for i in xrange(count):
          num = num /2
     return num

#5を含んでいれば0を返す。そうでないなら-1
def isContainMultipleOf5(array):
     for x in array:
          if x % 5 == 0:
               return 0
     return -1

#5 の倍数 (0 を含む) を全て取り除く
def clearMultipleOf5(array):
     i=0
     while i < len(array):
          if array[i] % 5 == 0:
               array.pop(i)
               i -= 1
          i += 1
     return array

#全ての数を半分にする(端数は切り捨て)
def divAllNum(array):
     return map((lambda x:x/2),array)
    
def solver(array):
     #文字列から数値に変換
     arrayint = map(int, array.split(' '))

     #メイン処理
     #とれる手段は以下の2つ
     # 1. 全ての数を半分にする(端数は切り捨て)
     # 2. 5 の倍数 (0 を含む) を全て取り除く
     cnt = 0
     q = [arrayint]
     while len(q) > 0:
          flg = False
          #dequeu
          arraypop = q.pop(0)
          arraylast = []          #探索中の最新手
          if isinstance(arraypop, list) == True:
               if isinstance(arraypop[0], list) == True:
                    arraylast = arraypop[len(arraypop)-1]     #二次元配列状態[[10,22,30],[5,11,15],[]]
               else:
                    flg = True
                    arraylast = arraypop[:]                         #数字の配列=一手目
          else:
               print "error"
         
          if isAllMultipleOf5(arraylast) == 0:
               #全ての数が5の倍数である場合
               if flg == True:
                    #一手目
                    cnt = 1
               else:
                    cnt = len(arraypop)
               return str(cnt)
          else:
               if flg == True:     #数字の配列
                    #queueから取得した状態に「全ての数を2で割った」手を追加する
                    div_array = []     #全てを2で割った配列
                    div_array.append(arraypop)
                    div_array.append(divAllNum(arraylast))
                    q.append(div_array)
                   
                    #queueから取得した状態に「5の倍数を削除した」手を追加する
                    if isContainMultipleOf5(arraylast) == 0:
                         #5の倍数を含む場合のみ
                         del_array = []     #5の倍数を除去した配列
                         del_array.append(arraypop)
                         new_array = arraylast[:]
                         del_array.append(clearMultipleOf5(new_array))
                         q.append(del_array)
               else:               #配列の配列
                    #queueから取得した状態に「全ての数を2で割った」手を追加する
                    div_array = arraypop[:]
                    div_array.append(divAllNum(arraylast))
                    q.append(div_array)
                   
                    #queueから取得した状態に「5の倍数を削除した」手を追加する
                    if isContainMultipleOf5(arraylast) == 0:
                         #5の倍数を含む場合のみ
                         del_array = arraypop[:]
                         new_array = arraylast[:]
                         del_array.append(clearMultipleOf5(new_array))
                         q.append(del_array)

#メイン処理

#入力データ取得
inputfile = "input.data"
if os.path.exists(inputfile):
     fi = open(inputfile, 'r')
else:
     exit()

#出力ファイル作成
outputfile = "answer.data"
fo =  open(outputfile, 'w')


#テストケース数
T = fi.readline()
i = 0
while i < int(T):
     N = fi.readline()
     a = fi.readline()
     print str(i+1) + u"問目"
     fo.write(solver(a) + '\n')
     i += 1

fi.close()
fo.close()

その後のIS04

これまでに、Android au IS04 (REGZA PHONE)の不満点を記事にしてきました。
《続》IS04を買ってから入れたアプリ、行った設定 その2 - kokemonoの日記


Wikiでも散々だったり価格.comなどでも酷評の連続だったのを覚えています。
そんな世間でもダメ端末のレッテルを貼られているIS04ですが、発売開始時と比べるといくつかの改善がみられているのをご存知でしょうか。


その大きなきっかけは2011年5月〜6月にかけて実施された「ケータイアップデート」と「OSバージョンアップ」でした。

au携帯電話「IS04」の「ソフトウェア更新」についてのお知らせ│製品アップデート情報│au
携帯電話(IS04) Android 2.2アップデート内容 - FMWORLD.NET(個人) : 富士通

改善点

ケータイアップデートによる改善点は以下のとおり

  • 最大通信速度144kbpsのエリア (CDMA 1Xエリア) でのデータ送受信機能の追加。
  • Eメール (xxx@ezweb.ne.jp) の各種改善。
    • 受信したEメールが文字化けする場合がある。
    • メールの全件削除に対応。
    • デコレーション絵文字の入力方式を改善。
  • アラームアプリ再起動後にアラームが鳴動しない場合がある。


OSバージョンアップでの改善点は以下のとおり

  • Flash〓 Player 10.1に対応
  • ワンセグの視聴予約・録画予約に対応
  • HD1080撮影モード対応
  • アプリのメモリカード保存に対応
  • 新フォントを追加
  • 画面消灯時のWi-Fi設定メニュー
  • ATOK for IS04のバージョンアップ
  • 連絡先のグループ登録に対応
  • E-Mailの横画面表示に対応

などなど…


ここで注目すべきは「メールの全件削除に対応」したという点です。


…もう一度言いましょう。
IS04はついに「メールの全件削除に対応」しました。


他の携帯を使っている人は分かりにくい感覚かもですが、IS04ではこれまでフォルダ内メールを全件削除するという当然のことができませんでした。
かと言って一つずつメール選ぼうとすると「メール選択していくとだんだん処理が遅くなる」「途中でメール受信すると選択状態解除される」と非常にやきもきさせられていました。


携帯電話ならできて当たり前の機能だとは思いますが、これだけのことがやけにうれしい。
ダメな子ほどその成長がうれしい、って感じですかね?

メール全件削除手順

1.削除対象のメールフォルダを開く。(ちなみに私の携帯は100通/日くらい迷惑メールきます)


2.[Menu]ボタンを押下し、表示されたメニューの「その他」をタップする。


3.「全件削除」をタップする。


4.削除確認画面で「OK」をタップする。


その他

ほかにも、Android2.2にバージョンアップしたことでアプリをSDカードにインストールできるようになったし、REGZA PHONEならではの追加機能も複数あります。
(こういう日本のメーカー独自の機能はユーザーのニーズとズレていることが多いのですが…)


IS04をお持ちの方は、「ケータイアップデート」「OSバージョンアップ」おすすめです。


IS04購入当初はどうなることかと思いましたが、その分改善する余地もあるということ。
これからますます使いやすい端末になっていくことを期待しましょう。


次は、端末再起動しないとwi-fi有効化できなくなる現象と、頻発する再起動をどうにかしてください!


→(参考)au REGZA Phone IS04 Iのキャリアメールトラブルを解決するたった一つの方法 - kokemonoの日記