読んでおきたい記事メモ
http://android-developers.blogspot.jp/2011/06/new-editing-features-in-eclipse-plug-in.html
http://android-developers.blogspot.jp/2011/05/introducing-viewpropertyanimator.html
http://android-developers.blogspot.jp/2011/03/identifying-app-installations.html
http://android-developers.blogspot.jp/2011/02/android-30-fragments-api.html
http://android-developers.blogspot.jp/2011/03/renderscript.html
http://android-developers.blogspot.jp/2011/07/custom-class-loading-in-dalvik.html
http://android-developers.blogspot.jp/2011/07/debugging-android-jni-with-checkjni.html
http://android-developers.blogspot.jp/2011/06/things-that-cannot-change.html
http://android-developers.blogspot.jp/2011/01/processing-ordered-broadcasts.html
http://android-developers.blogspot.jp/2010/12/its-not-rooting-its-openness.html
http://android-developers.blogspot.jp/2010/12/analytics-for-android-apps.html
http://android-developers.blogspot.jp/2010/12/new-gingerbread-api-strictmode.html
http://android-developers.blogspot.jp/2010/12/saving-data-safely.html
http://android-developers.blogspot.jp/2010/10/improving-app-quality.html
http://android-developers.blogspot.jp/2010/10/traceview-war-story.html
http://android-developers.blogspot.jp/2010/09/proguard-android-and-licensing-server.html
http://android-developers.blogspot.jp/2010/07/multithreading-for-performance.html
http://android-developers.blogspot.jp/2010/07/apps-on-sd-card-details.html
http://android-developers.blogspot.jp/2010/06/game-development-for-android-quick.html
http://android-developers.blogspot.jp/2010/05/dalvik-jit.html
http://android-developers.blogspot.jp/2010/05/be-careful-with-content-providers.html
http://android-developers.blogspot.jp/2010/04/multitasking-android-way.html
http://android-developers.blogspot.jp/2009/11/optimize-your-layouts.html
http://android-developers.blogspot.jp/2009/11/integrating-application-with-intents.html
http://android-developers.blogspot.jp/2009/05/drawable-mutations.html
http://android-developers.blogspot.jp/2009/02/android-layout-tricks-1.html
http://android-developers.blogspot.jp/2009/02/android-layout-tricks-2-reusing-layouts.html
http://android-developers.blogspot.jp/2009/03/android-layout-tricks-3-optimize-by.html
http://android-developers.blogspot.jp/2009/02/faster-screen-orientation-change.html
http://android-developers.blogspot.jp/2009/01/why-is-my-list-black-android.html
まとめ系ニュースを、さらにまとめて眺める系アプリ作った
https://play.google.com/store/apps/details?id=com.komamitsu.newstream
ちょっとした暇なときに、カジュアルなニュースを流し読みできるアプリです。 発言小町、知恵袋、はてなブックマーク、NAVERまとめの最新情報をまとめて読めます。 元々、AppStoreのNewsStormっぽいものを探していたのですがAndroidアプリで良さげなものがなかったので、 自分好みのものを作りました。機能を絞ってシンプルにしてあります。 各ニュースをクリックすると、普段使い慣れているWebブラウザで詳細を閲覧できるので、URLの共有等はそちらから行ってください。 また、電波が届かない場所でも、前回閲覧したニュースを楽しめるようにしてあります。
もともと個人用でやっつけで作ってあったのだけど、折角なので少し手直ししてリリース。
テトリスっぽいけどテトリスじゃないアプリを作った
https://play.google.com/store/apps/details?id=com.komamitsu.pentaris
以前作ってみたテトリスアプリは
This is a notification that your application, Ketris (Tetris clone), with package ID com.komamitsu.ketris, has been removed from the Google Play Store. REASON FOR REMOVAL: Alleged copyright infringement (according to the terms of the Digital Millenium Copyright Act). All violations are tracked. Serious or repeated violations of any nature will result in the termination of your developer account, and investigation and possible termination of related Google accounts. Please review the Developer Distribution Agreement and Content Policy to ensure that your applications are compliant with our policies.
ということでremoveされてしまったので、テトリスのテトリスたる四つのブロックを使わないように五つのブロック中心のゲームに変更して作り直してみた。
ゲームバランスは微妙... テトリスよりも悩みどころが多いのでやりごたえはあるけど、テトリス好きにそのままお勧めできるかどうか....
まぁ、ちょっと様子みる感じで。
[ocaml] OCamlでLispのサブセットっぽいのを作ってみた
https://github.com/komamitsu/OCaml-minilisp
先日、仕事が一区切りついてボーッとしていたところ、「そういえばLisp系の言語に疎いなぁ自分」とふと思ったので、簡単なLispのサブセットを作ってみた。いま見ると文法的にはSchemeぽい。
こんな感じでREPLしたり、
$ ./minilisp minilisp> (define (fib n x1 x2) (if (<= n 0) x1 (fib (- n 1) x2 (+ x1 x2)))) Func(fib, [n, x1, x2], Cond(Apply(<=, Var(n), Num(0)), Var(x1), Apply(fib, Apply(-, Var(n), Num(1)), Var(x2), Apply(+, Var(x1), Var(x2))))) minilisp> (fib 100 0 1) Num(3736710778780434371)
ソースファイルを読んで評価したりできる。
$ cat sample.minilisp (define (fib n x1 x2) (if (<= n 0) x1 (fib (- n 1) x2 (+ x1 x2)))) (print (fib 100 0 1)) $ ./minilisp sample.minilisp Num(3736710778780434371)
フィボナッチ数列でも計算できれば良いか、くらいの感じだったので、気がついたらcarもcdrも実装してなかった(シンボルもない)という何だかやる気のない感じが... 気が向いたらlambdaとかprognとかも一緒に実装しようかなぁ。気が向いたら。
OPAMでインストールしたパッケージがocamlfindで見つからない件
OPAMいいですね。
http://d.hatena.ne.jp/wistery_k/20120909/1347164530 の記事を見て使い始めましたが、道具としてのOCamlが何かの壁を乗り越えそうな感じがしてます。
で、使っていて、たまにocamlfind -listの中にopamでインストールしたパッケージが出てこないことに気がつきました。
eval `opam config -env` でパス周りの設定を通しているので、こいつは .xxshrc辺りに書いておいてあげる必要がありそうです。
あと本題と関係ないけど、shell/opam_completion.sh とかを読み込んでおくと auto-completeが効くのでさらに便利。
追記(2012-10-08)
https://github.com/OCamlPro/opam に普通に載ってたわ...
sendBroadcast()のコスト
極端な話、普通のメソッド呼び出しとどの程度違うのか、と気になったので試してみた。
package com.komamitsu.bench; import java.util.concurrent.Executors; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; public class BenchActivity extends Activity { private static final String ACTION_HOGE = "hogehoge"; private static final int LOOP_COUNT = 10000; private volatile int countForIntent; private final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Log.d("#####", "intent onReceive"); countForIntent++; } }; private volatile int countForThread; void onRecieveFromThread(String label) { countForThread++; } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.intent).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Executors.newSingleThreadExecutor().execute(new Runnable() { @Override public void run() { IntentFilter intentFilter = new IntentFilter(ACTION_HOGE); registerReceiver(receiver, intentFilter); Intent intent = new Intent(ACTION_HOGE); intent.putExtra("hoge", "hogehoge"); long start = System.currentTimeMillis(); Log.d("#####", "intent start: count=" + countForIntent); for (int i = 0; i < LOOP_COUNT; i++) { sendBroadcast(intent); } long end = System.currentTimeMillis(); Log.d("#####", "intent end: count=" + countForIntent + ", time=" + (end - start)); unregisterReceiver(receiver); } }); } }); findViewById(R.id.methodcall).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Executors.newSingleThreadExecutor().execute(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); Log.d("#####", "methodcall start: count=" + countForThread); for (int i = 0; i < LOOP_COUNT; i++) { onRecieveFromThread("hogehoge"); } long end = System.currentTimeMillis(); Log.d("#####", "methodcall end: count=" + countForThread + ", time=" + (end - start)); } }); } }); } }
こんな感じで、10000回、メソッド呼び出しをしたり、ブロードキャストインテントを投げたりして時間を計ってみた。
結果、
09-19 01:22:08.264 D/##### (16201): intent start: count=0 09-19 01:22:22.984 D/##### (16201): intent end: count=10000, time=14728 09-19 01:22:25.325 D/##### (16201): methodcall start: count=0 09-19 01:22:25.335 D/##### (16201): methodcall end: count=10000, time=3
メソッド呼び出しはまぁ置いといて、ブロードキャストインテントを投げると一回辺り1.5msec近くかかる。
vmstat見てたら、freeが減ってanonが増えてた. swap outが必要な領域が増えたぽい。
リクルートコミュニケーションズの採用情報のところにあった問題
http://rikunabi-next.yahoo.co.jp/company/cmi0089954001/nx1_rq0008861224/
「相手の思考を推理する」過程をプログラムで表現する問題です。 開発言語は問いませんので、慣れ親しんだ開発環境をご用意ください。 A, B, C の3人が 1〜5の5枚のカードを使ってインディアンポーカーをします。 3人は、ランダムに1枚のカードを引いて額にかざします。 相手のカードは見えますが、自分のカードは見えません。 この状態で、A->B->Cの順番に、 ■自分が1番大きい(MAX) ■自分は2番目に大きい(MID) ■自分が1番小さい(MIN) ■わからない(?) を答えます。 一人でも答えがわかった場合、そこで終了となります。 「わからない」と答えた場合、回答権が次の人に移ります。 Cもわからない場合、再度Aに回答権が移ります。 3人ともウソを言ったり、適当に答えてはいけません。 例1「A=1 B=4 C=5」だった場合、 「A => MIN」で終了します。 例2「A=1 B=2 C=4」だった場合、 「A => ?, B => MID」で終了します。 Bは「Aがわからないなら、自分は5ではない」と考えるからです。 以上を踏まえて、 引数で「A=1 B=4 C=5」で実行すると「A => MIN」を出力 引数で「A=1 B=2 C=4」で実行すると「A => ?, B => MID」を出力 するようなコマンドラインのプログラムを作成してください。 なお、人数やカードの枚数がパラメーター化されていて、 さまざまなケースがシミュレーションできるコードが望ましいです。 ※ヒント: 今回のケースでは、 「全員がわからない(無限ループ)」という結果にはなりません。
三連休の最終日、ちょっと面白そうだったので暇つぶしに挑戦してみた。ちなみに書いたコードは公開してOKと許可頂き済み。
class Resolver def initialize(num_of_members, num_of_cards) @num_of_cards = num_of_cards @members = 'A'.upto('Z').to_a[0, num_of_members] @all_card_nums = 1.upto(num_of_cards).to_a end def resolve(cards, members_hist = []) @members.each do |member| if member_and_result = trackback_members_hist(cards, members_hist + [member]) return members_hist.map{|m| {m => nil}} + [member_and_result] end members_hist << member end if members_hist.size > @members.size * 3 nil else resolve(cards, members_hist) end end def get_visible_cards(cards, member) visible_cards = cards.clone visible_cards.delete(member) visible_cards end def trackback_members_hist(cards, members_hist) # puts "#{'-' * 40} cards:#{cards}, members:#{members_hist} #{'-' * 40}" members_hist = members_hist.clone member = members_hist.pop visible_cards = get_visible_cards(cards, member) result = answer(visible_cards.values) return {member => result} if result return nil if members_hist.empty? undecidable_nums = [] visible_nums = @all_card_nums - visible_cards.values visible_nums.each do |visible_num| assumed_cards = visible_cards.clone assumed_cards[member] = visible_num member_and_result = trackback_members_hist(assumed_cards, members_hist) undecidable_nums << visible_num unless member_and_result end visible_cards_min = visible_cards.values.min visible_cards_max = visible_cards.values.max result = case when undecidable_nums.all?{|x| x < visible_cards_min} :min when undecidable_nums.all?{|x| x > visible_cards_max} :max when undecidable_nums.all?{|x| visible_cards_min < x && x < visible_cards_max} :mid else return end return {member => result} end def answer(other_nums) min_start = nil min_end = nil mid_start = nil mid_end = nil max_start = nil max_end = nil 1.upto(@num_of_cards).each do |i| if max_start max_end = i - 1 unless other_nums.include? i elsif mid_start if other_nums.include? i mid_end = i - 1 max_start = i end elsif min_start unless other_nums.include? i min_end = i - 1 mid_start = i end else min_start = i if other_nums.include? i end end min_end = @num_of_cards if min_start && min_end.nil? mid_end = @num_of_cards if mid_start && mid_end.nil? max_end = @num_of_cards if max_start && max_end.nil? case when min_start == 1 && max_end == @num_of_cards :mid when min_start == 1 && mid_end == @num_of_cards :max when min_end == @num_of_cards :min else nil end end end if __FILE__ == $0 resolver = Resolver.new(4, 6) raise unless resolver.answer([1, 2, 3]) == :max raise unless resolver.answer([4, 5, 6]) == :min raise unless resolver.answer([1, 2, 6]) == :mid raise unless resolver.answer([1, 5, 6]) == :mid raise unless resolver.answer([3, 4, 5]).nil? raise unless resolver.answer([1, 3, 6]).nil? raise unless resolver.answer([1, 4, 6]).nil? raise unless resolver.answer([1, 4, 5]).nil? raise unless resolver.answer([2, 3, 6]).nil? raise unless resolver.resolve('A' => 1, 'B' => 2, 'C' => 5, 'D' => 6) == [{'A' => nil}, {'B' => :mid}] # p resolver.resolve('A' => 3, 'B' => 4, 'C' => 5, 'D' => 2) resolver = Resolver.new(3, 5) raise unless resolver.resolve('A' => 1, 'B' => 4, 'C' => 5) == [{'A' => :min}] raise unless resolver.resolve('A' => 1, 'B' => 2, 'C' => 4) == [{'A' => nil}, {'B' => :mid}] raise unless resolver.resolve('A' => 2, 'B' => 3, 'C' => 4) == [{'A' => nil}, {'B' => nil}, {'C' => :max}] exit if ARGV.size < 2 print_result = proc do |x| case x when :min then 'MIN' when :max then 'MAX' when :mid then 'MID' when nil then '?' end end num_of_members = Integer(ARGV.shift) num_of_cards = Integer(ARGV.shift) cards = ARGV.inject({}){|a, kv| kvs = kv.split('='); a[kvs[0]] = Integer(kvs[1]); a} resolver = Resolver.new(num_of_members, num_of_cards) answer = resolver.resolve(cards) puts answer.map{|kv| k = kv.keys.first; "#{k} => #{print_result.call(kv[k])}"}.join(', ') end
ちなみに今現在、会社の飲み会から帰宅して酔っ払ってるのでコピペミスがあるかも。