Brainfuck インタプリタ
寝る前に OCaml でなんか書いてみるか、と思って書いてみた。
exception Unexpected_char let interpret str = (* バッファ *) let buf = Array.create 3000 0 in (* 対応する右括弧(])を探しに行く *) let rec rp idx n = match String.get str idx with | '[' -> rp (idx+1) (n+1) | ']' -> if n=0 then idx else rp (idx+1) (n-1) | _ -> rp (idx+1) n (* 対応する左括弧([)を探しに行く *) and lp idx n = match String.get str idx with | '[' -> if n=0 then idx else lp (idx-1) (n-1) | ']' -> lp (idx-1) (n+1) | _ -> lp (idx-1) n (* 1文字ずつ読み込んで処理 *) and loop idx p = match String.get str idx with | '>' -> loop (idx+1) (p+1) | '<' -> loop (idx+1) (p-1) | '+' -> buf.(p) <- buf.(p)+1; loop (idx+1) p | '-' -> buf.(p) <- buf.(p)-1; loop (idx+1) p | '.' -> print_char(char_of_int(buf.(p))); loop (idx+1) p | ',' -> buf.(p) <- int_of_char (input_char stdin); loop (idx+1) p | '[' -> loop (if buf.(p)=0 then (rp (idx+1) 0)+1 else idx+1) p | ']' -> loop (if buf.(p)<>0 then (lp (idx-1) 0)+1 else idx+1) p | '\n' -> () | _ -> raise Unexpected_char in loop 0 0 let _ = interpret (read_line()^"\n")
$ ocaml bf.ml +++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+. Hello, world!$
ゴルフを経験した後だと、 loop を ($) にすれば括弧が消せる!とか、if 式を消したい!とか、while 使った方がいいかも!とか、例外は無視してよくね!とか思ってしまう。
swc にリソースが埋め込めない
ボタンをいくつか縦に並べたメニューをライブラリに移したんだけど、うまく動かなかった。メニューにはそれぞれ違った背景画像を使うんだけど、その画像が表示されない。どうやら埋め込まれていないのが原因らしい。プロジェクトのプロパティで、swc に含めるように指定したはずなんだけど…。
メニュー項目は、背景画像とテキストだけが異なるがその他の設定は共通なので、 Repeater を使って次のように書いた。(関係ない属性は省略した)
<!-- メニューボタンを縦に並べる(画像が埋め込まれない) --> <mx:Repeater id="menuRepeater" dataProvider="{menuItemArray}"> <mx:Canvas backgroundImage="{menuRepeater.currentItem.imgpath}"> <mx:VBox width="100" height="100" click="(略)"> <mx:Text htmlText="{menuRepeater.currentItem.title}"/> </mx:VBox> </mx:Canvas> </mx:Repeater>
メニュー項目を1つずつ書いて背景画像を直接 "@Embed" 指定すると埋め込まれるんだけど、Repeater を使った場合にはその書き方は無理。
ちょっと調べたら、次のように書くと埋め込まれるという記述を発見した。
[Embed(source="assets/menu01.jpg")] [Bindable] private var menu01 : Class;
これも試したけどだめでした。なんでだ!
結局、以下のように画像を使うことを静的にわかるように(?)してやると、無事に埋め込まれました。
[Embed(source="assets/menu01.jpg")] [Bindable] private var menu01 : Class; [Embed(source="assets/menu02.jpg")] [Bindable] private var menu02 : Class; [Embed(source="assets/menu03.jpg")] [Bindable] private var menu03 : Class; [Embed(source="assets/menu04.jpg")] [Bindable] private var menu04 : Class; [Embed(source="assets/menu05.jpg")] [Bindable] private var menu05 : Class; [Embed(source="assets/menu06.jpg")] [Bindable] private var menu06 : Class; [Embed(source="assets/menu07.jpg")] [Bindable] private var menu07 : Class; private var imgArray : Array = [menu01, menu02, menu03, menu04, menu05, menu06, menu07]; private function selectImg(idx : int) : Class { return imgArray[idx]; }
<!-- メニューボタンを縦に並べる(画像が埋め込まれる) --> <mx:Repeater id="menuRepeater" dataProvider="{menuItemArray}"> <mx:Canvas backgroundImage="{selectImg(menuRepeater.currentIndex)}"> <mx:VBox width="100" height="100" click="(略)"> <mx:Text htmlText="{menuRepeater.currentItem.title}"/> </mx:VBox> </mx:Canvas> </mx:Repeater>
バロス!俺はなんか根本的な勘違いをしてるのか!?
ライブラリプロジェクト
FlexBuilder で開発していた某Eラーニングのサイトをシリーズ化することになったので、共通部分をライブラリ化することにした。
FlexBuilder で新しく"ライブラリプロジェクト"ってのを作って、そのライブラリを使うプロジェクトのプロパティから FlexBuilderPath -> LibraryPath -> AddProject で新しく作ったライブラリプロジェクトを指定する。
Eラーニングのサイトは構造が単純なので、共通のクラスやリソースファイルを移動していくだけの簡単なお仕事でした。
いろいろなサイトで書かれているけど、ライブラリプロジェクト内のクラスやリソースファイルはそのままでは外部からアクセスできないので、ライブラリプロジェクトのプロパティの FlexLibraryBuildPath で、ライブラリに含めるものを指定する必要がある。
選択されたテキストを alc で引く Firefox 拡張
予想外に5分でできた。というか選択されたテキストを wikipedia で引くサンプル(http://stupidbob307.eshlook.com/jetpacks/wikipedia.html)があったので、その URL を変えただけなんですけどね。予想以上に便利だったので Opera でも使いたい。(自画自賛)
jetpack.future.import("selection"); jetpack.future.import("slideBar"); jetpack.slideBar.append({ icon: "http://www.alc.co.jp/favicon.ico", width: 350, html: '<style>scrollbar * {display: none !important;}</style><iframe class="frame" height="99%" width="100%" src="http://www.alc.co.jp/"></frame>', onReady: function(slide) { jetpack.selection.onSelection(function() { $(".frame", slide.contentDocument).attr("src", "http://eow.alc.co.jp/" + jetpack.selection.text + "/UTF-8/?ref=sa"); }); } });
Flex 3 アプリケーションの国際化
ポルトガル語やら中国語やらフランス語を使うことになったので、http://d.hatena.ne.jp/kagamihoge/20090425/1240648033 を見ながら Flex の ResourceBundle を使ってみることにする。
ロケールの追加
まず、ディレクトリを以下のような感じで構成し、
project/bin-debug/... /html-template/... /locale/ja_JP /pt_BR /zh_CN /src/...
コンパイルオプションを以下のように指定してみた。
-locale=ja_JP,pt_BR -source-path=../locale/{locale} -allow-source-path-overlap=true -use-network=false
ポルトガル語のロケール pt_BR を追加すると、"pt_BR のロケールが見つかりません"みたいなエラーが出るので、FlexBuilder についてくる copylocale コマンドを使ってダミーのロケールを作る。僕の場合にはなぜか copylocale が2つあったのでちょっとはまった。
/usr/local/flexsdk/bin/copylocale /Applications/Adobe\ Flex\ Builder\ 3/sdks/3.2.0/bin/copylocale <- こっちを使う
ここも参照: http://livedocs.adobe.com/flex/3_jp/html/help.html?content=l10n_3.html
GUI アプリケーションのテスト
アルバイトをやっていて思ったことをつらつらと。
GUI アプリケーションのテストをする際に、どこが難しいのかというと、
- GUI は、ユーザの指定したレイアウトを記憶することが多い。ウィンドウの表示位置とか、スクロールバーの値とか、2ペインのウィンドウの大きさの比とか。これによりテスト対象のコンポーネントの位置が変化する
- GUI は表示されていないオブジェクトに対する入力が行えないし、ユーザからの入力系列をキャッシュするバッファという概念もない。そのため、アプリケーションがある特定の状態になってから操作する、というテストをうまく作れない
- GUI で表示されるデータは、ユーザという高機能なシステムが理解できればよく、他のアプリケーションから再利用される状況は想定していない。つまり、デバッガからうまく扱えるようになっていない
だと思う。expect でテストを一生懸命書く感じになる。
複数のテストを自動で実行する際にどこが難しいのかというと、
- 「初期化」が難しい
- 結果の判定が難しい
ことだと思う。どちらも「GUI アプリケーションの状態」がなんなのかよくわかっていないのが問題。
テスト対象アプリケーションにどんな機能があれば解決できるかというと
- 「GUI の状態」の定義
- GUI アプリケーションの状態のスナップショットを取り、いつでもそこに復帰できる機能
- 特定のイベントが起きるまで待機する機能
- 座標やコンポーネントの表示名以外の方法で、特定の GUI コンポーネントを普遍的に指定できる機能
- GUI アプリケーションの状態を他のアプリケーション(デバッガ)から取得できる機能
だと思う。
結論:これらの機能を実現する GUI フレームワークが必要だ!
デバッグモードでビルドすると、任意のタイミングで GUI の状態をシリアライズできるようなもの。ちなみに Plan9 ではプロセスをファイルで表現していて、プロセスファイルシステム以下のファイルにアクセスすることで、アプリケーションの状態を再利用可能な形で(テキストで)取得することができる(たぶん)。ただ、取得できるデータの形式はアプリケーションによる(たぶん)。
10分でコーディング
頑張ってブログを書こうキャンペーン中。理由は特にない。
http://ameblo.jp/programming/entry-10001721422.html のやつ。 then の中はもっと綺麗にかけるんじゃないかと思うんだけど。
deal :: Int -> [Int] -> [[Int]] deal num cards = let (h,t) = splitAt num cards in if length h == num then map (\(x,y) -> x:y) $ zip h (deal num t) else replicate num []