As Sloth As Possible

可能な限りナマケモノでありたい

カテゴリ: 趣味

アリシアちゃんを動かしてみた話が途中で止まってるけど、先週末第3回Oculus Game Jam@n_mattunと一緒に参加してきたのでその話を。

どんなゲーム作ったの?

こんなの。

どういうゲームかというと、「どうやら軍人らしい人になって何らかの力で手から焔を出して、不死身のマスクマンの軍団を燃やし尽くす体験をする」というものです。企画会議では「この人は何らかの国家資格を持っている上にきっと大佐くらいの高い地位にある」「なんか多分手袋に仕掛けがある」みたいなことが囁かれていたとかいないとか、どっかで見たことがあるような気がするのはきっと気のせいだと思いますよ。君もそう思うだろう?鋼の。

操作方法は、右手にあるものを持って「親指で弾くと指先から火球が飛んでって着弾地点で大爆発を起こす」「人差し指を引くと前進」「中指を引くと後退」「Oculusなのでキョロキョロすると画面内でも視界が変わる」みたいな感じです。右手だけで操作出来るので簡単。

右手に持ってるものは何?

こんなの。

これは何かというと、@n_mattunと一緒に秋葉原であれこれ物色していたときに見付けた、「机に置いてるときは普通のマウス、持ち上げた状態だとトラックボールとして機能する2wayマウス」。

Oculusのゲームを作るにあたってみんな試行錯誤してるのがインターフェースで、Oculus Riftとキーボードやマウスはなにしろ非常に相性が悪い。視界が全部覆われているからどこに何があるか分からないのももちろんのこと、「今自分の見ている世界の中に無いものを使って世界を動かす」ってのをやってしまうと若干夢から覚めるように没入感が損なわれるんだよね、ってのを常々思ってて、それが故にLeap MotionやKinectなんかのモーションコントローラを使ったり、バランスWiiボードに乗ってみたり、Oculusの傾きだけで操作したり、なんてことをやってる人が多い。

んでこれを見付けた時に、「これだったら握ったまま手を自由に動かせるよね」「手触りだけでボタンの位置とか把握できるし見えてなくても操作し易いよね」と言うことで即買い。冒頭のゲームの内容もこいつを活かすにはどういうゲームが良いだろうという風に考えての逆算で出てきたアイディア。こいつを握って手を前に突き出した状態と画面の中での手の位置がリンクして、親指でトラックボールを弾くという動作と画面内の指先から火の球が出るというエフェクトともリンクする、そしたら自分が見てる世界と自分がやってることの違和感が少なくなるかな、というこだわりポイントだったのです。プレゼンでちゃんと説明できなかったけど!

実際に遊んでみてもらった感触は上々で、みんな1回説明すればすぐ覚えてくれたみたいだし、「これはなかなか自然ですね!」って言ってもらえたので、もうちょいブラッシュアップして他のゲームでも使ってみたいと思ってる。

出来なかったこと

本当はこれにさらにLeap Motionを組み合わせて、実際の手の位置と画面内の手の位置を連動させて、ちゃんと手の向いてる方に火球が出るようにしたかったのだけど、残念ながら間に合わずオミット。大体みんな色んな方向に手を向けてみては「あ、腕の向きは固定なんですね…」ってなってた。これがあっちこっち向けられたら楽しいだろうなーと思ってたのでここが一番残念だった。

あと、ちゃんとゲームの体をなす、という意味で、なんらかのクリア目標を設定するとか、マスクマンに襲われたらダメージを受けるとかも作り込みたかったのだけど、これもそこまで到達出来なかった。今現時点では単に「無尽蔵に湧いてくるものの鬱陶しいだけで無害なマスクマンを大火力でひたすら蹴散らす」という謎のデモになっている。折角なのでどっかの体験会とかには出してみたいので、その時までには最低限ゲームとして成立するものにはしたいところ。

他、細かいところだと、本当は「魔法陣は手の甲にデカール、親指シュッと連動して画面上の指先もアニメーション、"稲光のような、見えない導火線のような"エフェクトが走って、任意の”空間”で発火、爆発後も燃え残りのパーティクルが散らばる」みたいな演出にしたかったんだけど、これも実装上の都合で普通に火球を飛ばして当たり判定取って爆発させるにとどまった。

ゲームジャム初体験の感想

周りみんなすごい人だらけだしなんとかゲームらしきものも作れたし、何もかもが超楽しかった、という感想が全てなんだけど、強いて付け加えるならアラサーのおっさんかつド素人が事前準備もせずいきなり30時間耐久ゲーム開発とかするとどうなるかというとこんな感じになるというのを当日の発言から察していただきたい。

UE4とOculus Rift DK2を使ってニコニ立体ちゃんと戯れるデモを作ってみた話の続き、今度はAIを作ってみる前編。

プレイヤーについてくる

まずはアリシアちゃんがプレイヤーについてくるようにする。なんでついてくるのかは分からん。アリシアちゃんはプレイヤーが大好きなので片時も離れたくないのかもしれないし、不倶戴天の敵なので見付け次第抹殺しようとしてるのかもしれない。その辺は適当に脳内で補ってください。

とりあえずおいかけっこ

ただ単にプレイヤーを追尾するだけならめちゃくちゃ簡単。

まずはマップにNav Mesh Bounds Volumeを配置する。ビューポート上でP押すか、「表示」から「Navigation」のチェックを入れてやるとAIが歩ける範囲が確認できるので、地面が黄緑色になってるのを確認する。

黄緑色

次はアリシアちゃんのCharacterとAIControllerを作る。キャラクターが親のBP作ってコンポーネントにアリシアちゃんのメッシュを設定し、AIControllerが親のBP作ってCharacterのBPのAIController Classにそれを指定してやる。

AIControllerのEvent GraphにAIの処理を書いてやるんだけど、TickイベントでGet Player ControllerしてSimple Move ToでGoalに設定してあげればいい。こんな感じ。

簡易プレイヤー追跡ロジック

これであとはスケルタルメッシュではなくキャラクターの方をマップ上に配置してプレイしてみると、アリシアちゃんがついてくるようになる。ルートの探索とかはAIControllerが勝手にやってくれるので便利。これだけでも案外楽しい。デフォのMax Walk Speedだと早すぎて一瞬で距離を詰めてくるので、200くらいに設定してみた。

一定の範囲に入ったときだけプレイヤーを発見する

取り敢えず追いかけっこは出来るようになったものの、常についてくるのではなくて条件次第で別の動作もさせてみたい。そのままBPでゴリゴリ書いていってもいいんだけど、どうやらAIの制御をするのにはそれ用にビヘイビアツリーというのがあるようなのでそれも使ってみることにする。

何の事はない、ビヘイビアツリーのクイックスタートガイドにまんまプレイヤーの追跡をするビヘイビアツリーの作り方が書いてあるのでそれをそのまま実装してみる。何か色々やってるように見えるけど読んでみると結構簡単。

まずMultiSphere Trace for Objectで一定範囲内に何らかのActorがあるかチェック。ObjectTypesにはPawnを指定しておくと、WorldStaticに設定されてる床とか壁とかは拾わずプレイヤーとかだけ拾う。

その後、AIがコントロールしてるActor(この場合はアリシアちゃん)の位置からさっき見つけたActorまでLine Traceする(ドキュメントだとSingle Line Traceって書いてあったけど4.5だとノード名がLine Traceになってる模様)。これはUnityだとRaycastってのに相当するみたい。

こちらはfor Objectではなくby Channelになってる。さっきは指定したObject Typeのものを引っ掛けていたのでPawnを指定していればPawnだけ拾ってたけど、今度はコリジョン応答>トレース応答>Cameraのブロックにチェックされてる奴はなんでも拾う。MultiじゃなくてSingleの方を使ってるのが肝で、最初に見つけたのがSphere Traceの時に見つけたのと違う、この場合はプレイヤーとアリシアちゃんの間に遮蔽物がある場合は「見つからなかった」ことにしてる。無事見つけたらブラックボードにプレイヤーActorをTargetToFollowに登録。見つからなかったら削除。

TargetToFollowが設定されてたらツリー上の左側の方の処理が実行される。RapidMoveToタスクは大分大雑把に言うとさっきのAIControllerに直接書いたやつと大体一緒で、AIControllerが制御してるActorをTargetToFollowのActorまで移動させている。

1個戻ってCloseEnoughデコレーターを見てみると、ターゲットと自分との距離を測って指定した距離より近くにいるならfalseでCondition Checkを終えるので、その先の移動処理は実行されない。十分に近付いてるならAI Move Toしないので無駄にAIにルート探索させないし、さっきのだと常にアリシアちゃんがこっち向いてくるので出来なかった「後ろに回りこむ」が出来るようになるし、Acceptable Distanceを長めに取ると一歩下がって遠くから眺めるとかも出来るようになる。

プレイヤーを追いかけていないときは…?

ツリーの左側の処理がプレイヤーを見つけて追いかけている時に実行されるので、プレイヤーを追跡中じゃない時の処理を作りたければ右側の方に書けばよさそうだ。こっちはサンプルとは違う動きを作って行くことにしたのだけど、長くなってきたので一旦切って後編に続きます。

UE4とOculus Rift DK2を使ってニコニ立体ちゃんと戯れるデモを作ってみた話の続き、今度はモーションを付けてみる編。

アニメーションリターゲットを使う

前回インポートするときに一緒にアニメーションを取り込めなくてどうしたものかと困っていたら、UE4.5から、異なるスケルトン間でアニメーションを使い回せるアニメーションリターゲットの機能が入っていたらしい。つまりあの人の動きをアリシアちゃんにも付けられるわけだ!素敵機能だ!

blueman2

泣く子も黙る我らがブルーマンさん…のアニメーションは「ライフルを構えて走る」とか「撃たれて死ぬ」とかなので、アリシアちゃんに適用するにはちょっと…。ということでマーケットプレイスから入手出来るMixamo Animation Packから待機モーションと歩きモーションを貰うことにする。

基本、ドキュメントに書いてある通りにやればいいんだけど、まずハマったのがアニメーションをリターゲットしようとした瞬間の突然のUEのクラッシュ。何回やってもクラッシュするんだけど、クラッシュログがAssertion Errorとかで情報量無くて何が原因だか分からない。

色々試してたらlowerbodyとupperbodyの両方のボーンがノードに割り当てられてるときにクラッシュする様子(片方ずつならクラッシュしなかった)なので、upperbody外してみる。これでアリシアちゃんも歩けるように…

motion

…ならなーい。はい。こうなることはある程度予想してたので慌てちゃだめです。スケルトンツリーからupperbody01を選んで平行移動のリターゲティングを「スケルトン」にしてやると無事上半身と下半身が繋がった。

これで調子にのって走りモーションもリターゲットしてみたんだけど、こっちはいまひとつ。というのも、アリシアちゃんのheadのボーンとリターゲット元のそれの高さが違うので、元は前傾姿勢で走ってるモーションなんだけどアリシアちゃんにあてると頭が微動だにしないまま体は全力疾走みたいになってしまう。あと、そもそも割と走り方がいかつい感じなので、上手く調整してもあんまり似合ってない感じだった。

マーケットプレイスにいかにも日本人が喜びそうな可愛らしい走り方やダンスのモーションを含んだアニメーションパックが出てくれないかな、と願うところである。

アリシアちゃんが動き出すようになって楽しくなってきたので、その3、追いかけっこをしてみる編に続きます。

先月Oculus Rift DK2が届いたので折角だしゲーム制作に挑戦してみよう、ということでニコニ立体ちゃんことアリシア・ソリッドの3DモデルをUE4で取り込んでOculusで戯れてみることにした。

Oculusを使って、と書いたけど別にOculusが無くても戯れられます。というか、Oculus表示が出来るというだけでOculusならではなことは特にしてません。

マップを用意する

いきなり自分で1からマップ作ってくとなると結構ハードルが高いので、今回はマーケットプレイスから入手できるブループリントオフィスのマップをそのまま使わせてもらう。

Epic Gamesが提供しているサンプルプロジェクトはちょっと尋常じゃないクオリティなんだけど、サンプルプロジェクトで使われているアセットは自作のゲームにも流用可能なので、取り敢えず何か作ってみようみたいなときにそこから始めるといきなりなんかかっこいい感じになってテンションが上がります。まだ何もしてないのになんかすごいの出来ちゃった感が出る。まだ何もしていない。

それはそれとして、見てるだけでもかなり勉強になるので積極的にサンプルプロジェクトを弄ってみると良さそう。あれどうやるんだろう、みたいのがContent Examplesに大体あったりする。

モデルを読み込む

Alicia_solid_Unity.FBXをインポートする。取り敢えず何も考えないでインポートしてみたけど、よくある「モデルが寝てる!」とかもなく普通に読み込めた。ちなみに開発時点では配布開始直後だったのでVer.1のを使ってるけど、記事書いてる時点ではVer.3まで出てました。

が、哀しいことにモーションはちょっと大変なことになってます。頭の中で「ゲッダンんーふふんーふふんーふふんーふふーふふふー」みたいなBGMが流れました。

インポートのオプション良くわかってなくて間違えたかなーとか思ったけど、他の3Dモデリングツールで開いてもアニメーション上手く見れないみたいな話を聞いたので、結局諦めてアニメーションのインポートのチェックは外してメッシュだけ読み込んだ。

見た目の調整

勇んでインポートしたままのスケルタルメッシュをポンと配置すると、(特にアニメ調のキャラクターのモデルだと)あ、あれ??なんか思ってたのと違う…みたいな気持ちになる。

default

…まずは見た目を調整しよう。こっから試行錯誤。

とりあえずUnlitにしてみる

こんな感じ

unlit

スケルタルメッシュをダブルクリックして表示してみて、ライティングなしの表示に変えてみると、元々のテクスチャそのままの表示になるのでそれっぽく見える(当たり前)。ようしそれならとすべてのマテリアルのShading ModelをUnlit(ライティングなし)に変えてみる。置いてみます。超、浮いてます。

真っ暗闇のマップにアリシアちゃんだけを配置して眺める分にはいいんだけど、なまじマップがサンプルプロジェクトのおかげでやたらリアルなので、一人だけ全くライティングの影響を受けてないアリシアちゃんがものすごい異物感出る。

真面目にマテリアルを弄ってみる

ちゃんと質感を考慮してないままリアルなライティングが効くところに置いてるからフィギュアっぽい感じになってしまってるので、それぞれマテリアルを調整する。

マテリアルのドキュメントを読むと、どうやらラフネスとかスペキュラとかを調整してやると良さそうだ。

あとそれから、例えば肌や髪、目なんかは石とか壁とかとは光の反射の仕方が違うので、そういう設定をする。Shading Modelのドキュメント読むと肌とかにはちゃんとそれ用の設定があるらしい。このあたりでアリシアちゃんが血色良くなって生き物っぽくなってきました。

それから服、これも布っぽい感じが欲しいところ。なんかそういうのの例ありそうだなと思ってContent Examplesを見に行くとそのままずばりCloth.umapがある。開いてみると、すごい布だ!布感ある!ってなります。でもこれは上手く取り入れられたかというと微妙なところ。もうちょい試行錯誤が必要そう。

調整済み

んで最終的にこんな感じ。

セルシェーディング

リアルさを追求していく方向性ではなくて、アニメっぽいキャラなんだからアニメっぽくレンダリングしてあげれば良いのでは、の方向性。というより、あれ?って思ってニコニ立体の配布ページに見に行くとそう(セル画風のレンダリングに)なってるし、モデラーさんの製作過程見ても「トゥーンシェーダー作って適用」みたいに書いてあるので、ならばUE上でもそうしてあげればよいのではということに気付く。

UE4だとポストプロセスでやるやり方があるようで、シモダジュンヤさんのそれを参考にやってみる。

Cell Shading in Postprocess セルシェーディングのポストプロセス

これも一発では上手く行かなくて、影になってるとこに入ると真っ黒になる、みたいなのが起きたりしてかなり試行錯誤した。したけど何したか思い出せないんだ…。いきなり手を出すにはちょっと難易度高いやつだった。

結果多少はそれっぽい感じにはなったんだけど元の見た目に忠実ってとこまではなってないし、一方マテリアル調整してそれっぽくなった版のアリシアちゃんもこれはこれで悪くないよなぁ、と悩んだ末Alicialusでは動的に切り替えられるようにした。セルシェーディングするかしないかはRender Custom Bufferのチェックで決めてるので、Cキー押すとBPでメッシュのRender Custom Bufferをトグルするようにしてある。口で説明するより見た方が早いのでデモで試してみてください。

ライティング

モデル自体のマテリアルやレンダリングの仕方もそうなんだけど、そもそもの話としてライディングがどぎついというのもある。実は、弱めのポイントライトが配置された室内とか、反射光で照らされる木陰とかだと、取り込んだそのままでも思ったよりそれっぽく見えるし、マテリアル調整後やセルシェーディング有効にしてても直射光が当たってるとこだと眩しくて微妙な感じになる。

んじゃライティング調整すればって話なんだけど、今回マップが自分で1からセットアップしたやつじゃなくてサンプルプロジェクトのやつを使わせてもらってるので、ディレクショナルライトの光自体を弱めちゃうと全体が暗くなって雰囲気が変わってしまうのでやらなかった。同じくポストプロセスで色々と弄っても調整可能なのも分かってるけど、それも全体に影響するのでちょっと悩み中。

長くなってきたので一旦切ろう、その2、モーションを付けてみた編に続きます。

なんでなのかと聞かれても「なんか暇だったから…」としか。

いや元々はこう周期的に来る「なんか仕事と全然関係ないコード書きたい」期だっただけなんだけど、Goとかで遊んでる最中にひょんなことからRustを見付けてしまってへー面白そうとか手を出してみることになり、「慣れない言語を使うときはとりあえずWhitespaceの処理系を作ってみるとなんか慣れたような気分になる」という癖でですね。なんか出来ちゃった。

記事書いてる時点の最新のnightly(v0.12.0-pre)ではコンパイル通るのを確認済み(というか多分0.12.0でしかビルドできない。流石いつβが出るとも分からないα言語、0.10.0と0.11.0と0.12.0で互換性無いし、ドキュメント見に行ったら標準ライブラリを含むほとんどのAPIがexperimentalだった)。rust-albinoの方をcloneしたら最新のrustcと対応するcargoをrustupかなんかで入れて、

cargo build
するとビルドできる。homebrewでも入れられるけどバイナリだと0.11.0、ソースからのビルドだとかなり時間かかるので大人しくnightlyのバイナリ使うがよろし。

Albinoがコマンドラインツールで、こいつがWhitespaceを実行したり逆アセンブルしたりしてくれる。最初は普通にインタプリタ作ってたんだけど、例のごとくWhitespace読めないし書けないからアセンブリ言語でもでっちあげよう、あとその昔書いたDTとかも動かしたいよねー、とかやってたらいつの間にかVMとパーサが分離して副産物として何故かライブラリになっちゃったのがWhitebase

厳密に言うと本体はWhitebaceの方でAlbinoはただのインターフェースだったりするけど細かいことは気にしない。先に名前が決まったのはWhitebaseの方で、Whitespaceの命令セットを持ったVMとパーサのライブラリなので「白地」というのが由来であって決して某19歳に見えない艦長率いる連邦の戦艦ではない。合わせてツールの方はWhitedevilにしようかなーとか一瞬考えたけどコマンド名としては長すぎるしrx78とかエイリアスするはめになるのでアルビノにした。VMとパーサが分離した結果どういうわけかBrainf*ck派生の言語をWhitespaceの命令セットに変換できるようになったので、「本来白くないものまで白くなっている」からアルビノなんです。

得られたもの。Rustがなかなか触っていて楽しいということが分かった。いまどきっぽいサブコマンド型のコマンドどうやって作ってるのかなーってのが分かった。WhitespaceもしくはBrainf*ckのトークンの内部表現を返すイテレータさえ実装できれば簡単にオレオレ言語が作れるライブラリが出来たので、今後さっと言語を作ってドヤリングしたいときは一瞬で出来るようになった。Brainf*ckの任意のプログラムからWhitespaceのコードが生成できるようになった。

失なったもの。時間。結構な無駄な時間。

写真を撮るのが大分楽しくなってきた今日この頃、このまま行くとプログラミングの話とか一切しないでどんな鳥を撮ってきたとかそういう話でここを埋めてしまいそうだったから、年単位で寝かせっぱなしにしてたサブブログを写真貼るようのブログに変えてみた。ちなみに撮った写真はPICSにも貯めてあるので、まだまだ練習中だけど見てもらえたら、それはとっても嬉しいなって。

本当は一番撮りたいのは生ナマケモノなんだけどナマケモノさん意外と国内には少なくて、自分のアイコンを自分で撮ったナマケモノ写真にできるのはいつの日になるのやら。どっかの動物園から脱走してうちまで来てくれればいいのに、と思うけどどう考えてもそんなアクティブな連中じゃないのは知ってる。

せっかくカメラを買ったのでなにかこうモフモフしたものを撮りたい、というわけで早速動物園に行ってきた。行ったのは公園の片隅にありながら何故かブチハイエナがいたりウォークインバードケージがあったりする大宮公園小動物園

檻の消し方

先週は買ったばかりでろくに説明書も読まずに「おまかせモード」でパシャパシャしてただけなので、今回は事前に動物園での撮影テクニックと言うのを調べてから行く。

レンズには絞り値という設定があって、絞りを開くと被写界深度は浅くなり背景のボケは大きくなる。逆に絞っていくと被写体深度は深くなり背景のボケは少なくなる。 これは長い焦点距離を持った望遠レンズほど、また、開放時のF値が少ない、明るいレンズほど効果は大きい。
動物園での写真撮影の基本 〜オリの消し方と背景をボカすテクニック
動物園の撮影では、この関係を覚えておくと、檻を消したり、人工物だらけの背景を単純化したり、被写体の目など体の一部を強調したりする時に非常に役立つだろう。
動物園での写真撮影の基本 〜オリの消し方と背景をボカすテクニック

なるほどなるほど。ということで設定を弄ってみて、撮り易そうなバードケージの方で試してみる。

ウスユキバト

本当だ…消えてる…!ちなみにこの子はウスユキバト。小学校の飼育小屋みたいな金網の中にいたのだけど、ちゃんと金網が消えて背景もボケて鳥だけにフォーカスが当っている。

ただ、大型の動物の方は、檻が太くて頑丈なやつで、檻までの距離も若干遠くて、でもそんなに広い檻でもないので被写体と檻の距離が近く、消すのはちょっと難しかった。

仔ニホンザル

この小猿は割と奇跡の一枚で、ハイエナとかツキノワグマとかも撮ってみたのだけどウロウロしててなかなか上手く撮れなかった。難しいなー。小動物や鳥の方も、何枚かは上手く撮れてはいるんだけど、半分以上は微妙な感じだったので、もうちょい設定弄るのと練習が必要そう。

カラス天国

動物園自体とはあんま関係ないんだけど、大宮公園内にはカラスが沢山いて、もうどの方向を見てもカラス、くらいのカラス天国。カラス好きとしてはたまらないので、動物園行ったはずなのに家帰って画像取り込んだら1/3くらいカラスの写真で埋まってた。

まず、こっちが家の近所で撮った方のカラス。一応ベランダからすぐ見える距離の電柱にいるのだけど、それでも若干遠い。

青空とカラス

そんでこっちが今日大宮公園で撮った方のカラス。同じレンズ、同じカメラなのにこの距離感。つか、カラスもカラスで、埼玉のカラスは東京のカラスよりも若干油断してる気がしてならない。暑かったからか。暑かったからなのか。

今年暑すぎんだろ…

ということでモフモフ分とカラス分は十分補給できた。レンズ越しにみる公園とか動物園の風景って目で見てるのとはまたちょっと違ってすごく楽しかった。とりあえず次は上野動物園か、どっかの水族館に行ってみようかな。危ないなーこのまま行くと沼にはまりそう。

タイトル通り。なんでそんなことになったのかという経緯はこう。

  1. TOKYO JUNGLEにハマる
  2. TOKYO JUNGLE熱が動物熱に発展する
  3. なんと地元の超小規模な動物園が日本でも数少ないブチハイエナのいる動物園であることを知る
  4. ちょくちょく通ううちに、俺はiPhoneのカメラでパシャパシャやっているというのに、最近の幼児はデジタル一眼レフを使いこなしていることを知る
  5. うらやましい
  6. それなりにちゃんとしたカメラ欲しい

…という、子供よりも子供っぽい理屈によりカメラ欲が高まった結果、大人気ない大人の経済力を発揮(夏のボーナス万歳)してカメラ買ってきました。買ったのはSONY α NEX-5N ダブルズームレンズキット。あんま良く分かんないのでどれがいいのーって同僚に聞いたところ、「NEXだったら液晶がパカパカ動いて便利」「鳥とか撮るんならズームレンズは必須」「SONYのEマウントはレンズそんなに種類出てないから沼にはまる危険性が低い」という話だったので。殆ど何の知識も技術も無いのでぶっちゃけどれでも良かったのだけど、初めて買ったミラーレス一眼というのはなかなか素敵な代物だったので大変に満足しています。

その辺のハト

まぁまだこんなの撮って遊んでる段階なのでどやこや言えることは特にないです。動物園通ったりその辺の猫とか撮ったりしてHDDのモフモフ度合いを高めていく所存。

あ、ちょっと気になったのは、NEX-5Nの「ズームレンズキット」「Wレンズキット」に付いてくる"ズームレンズ"は「E 18-55mm F3.5-5.6 OSS」だったのだけど、これ想像してたより「ズームじゃない」感じしたので、「ビルの上のカラスとか、荒川を泳いでるカモとか撮りたい」と思ってた俺にとってはもう少し遠くまで撮れる「E 55-210mm F4.5-6.3 OSS」が付いてくる「Wズームレンズキット」の方にしといて正解だったなーと。逆に普段使う分には「E 18-55mm F3.5-5.6 OSS」の方で別段困ってないし。きっとまぁこういうのを買う人は数字見てちゃんと分かるんだろうけども、参考までに。

ゴールデンウィークを利用して久々にろくでもないものができたので晒しておく。

「ごっこじゃないよ、兄ちゃん!」「才能の無駄遣いじゃなくて、無駄そのものだよ、お兄ちゃん。」

前のと何が違うの?

そもそもの発端についてはプログラミング言語「DT」という記事を、実際の言語仕様についてはREADMEでも読んでもらうとして、何で再実装したのかという話。

3年前に作ったのは「Whitespaceのトークンを置換した処理系をインタプリタとしてRubyで実装」したものなんだけど、何を思ったかコンパイルしてみたいと思い立ってしまい、んでそれ自体はLLVMが良く分かんなかったとか、llvmruby自体がプロジェクトとして大分アレな感じになってしまっていたとか、そういう事情で挫折してたんだけど、時は流れ、なんか見返してみたら普通にLLVMアセンブリ読み書きできるようになってたし、ruby-llvmがちゃんと動くようになってるみたいだし、ということで再実装してみることにした。

そんで作り直す過程で「Whitespaceの置換ってのもなんだか面白くないな」と思ってVMのアーキテクチャと言語仕様を見直すことにした(ぱっと見だと全然分かんないけど、旧DTと新DTの間に互換性は無い)。そのせいで実際にはチューリング完全じゃなくなってると思うし、そもそもちゃんと出来てるのかどうか怪しいものだけど、とりあえず「Hi!」って出力するのとフィボナッチ数を出すのは動いたので良しとする。

当初の目標だった「DTコードをネイティブのバイナリにまでコンパイルして高速に実行」ってのも実現して、DTインタプリタで250msくらいかかるfib.dtをコンパイルすると4msくらいで結果が出るようになった。似たようなRubyのコードだと大体100msくらいだったので素敵に速い。まぁ、コンパイル自体はLLVMとコンパイラに任せているので大して威張れるあれでもないのだけども。そして高速に動いたからなんだという話なのだけども。

ぶっちゃけDTよりLLVMアセンブリの方が遥かに記述力高いし書きやすい。当たり前のように構造体とか関数ポインタとか使えるのな。Cの関数呼べるし。最初Cで書いてたVMを途中でLLVMアセンブリ直接書くようにしたけど、大して変わらない。DTで書くくらいならLLVMアセンブリ書いた方がいいです。LLVMの無駄遣いタグを付けていただきたい。

DTの存在意義については疑問を差し挟む余地もなく皆無だと言っていいけど、その過程でレジスタマシンについて色々調べて、はー、こんぴゅーたーってこうやってうごいてるのかー、と勉強になったのでそれはそれで良かった。よくこんなの考えられるよなぁ。CPUとかコンパイラとか作ってる人達、本当に俺と同じ種類の生き物なのだろうか。凄い。

件の「ニュー速実験」ことOPERA実験のニュースがなかなか面白そうで気になる。ここんとこシュタゲにハマりまくってたタイミングで「CERNが!光速を!超えた!」なんてニュースが来たら、これはwktkせざるを得ませんなドゥフフ、なんだけど、まぁそれを差し引いても驚くべき話ではある。

OPERA実験ってなんだったのかなーと思って色々見てみたのだけど、ええと、「スイスからイタリアに向けて素粒子ニュートリノを打ったら、どうやら光速を超える速度で到達しているらしい。精密に測定してるはずだけど、計測誤差の範囲を超える数値で"速い"ようだし、統計的に十分な回数試行しても再現する。なんぞこれ」っていう話だったという理解でいいのだろうか。ふむ、なんか凄そうだ。もうちょっとキーワードを追ってみる。

  • ニュートリノ、と言えば、小柴先生が史上初めて自然に発生したニュートリノを観測してノーベル物理学賞を受賞しているわけだけれど、その小柴先生のチームは超新星爆発の際発生したニュートリノは可視光とほぼ同じ速さで到達していることを観測していて、今回のOPERA実験とは矛盾する。
  • 正の質量を持つ物質をどれだけ加速させても、理論上光速を超える速度は出ないとされている。今までにそういう物質や現象は確認されていない。
  • 特殊相対論に反しない形で、虚数の質量を持ち、エネルギーを失なえば失なうほど減速し、どんなに減速しても常に超光速であり光速以下にならないタキオンの存在は理論上仮定されているが、実験によって観測された例はいまのところ無い。
  • ニュートリノは質量を持つことが実証されているので、質量0や虚数質量の粒子ではない。件のOPERA実験チームもニュートリノ振動を観測するための研究をしているらしい。

みたいな。うーん。「とりあえず他の研究機関が同様の実験をしてみるまでは結論保留で、あと他の方法でこの現象を確認する良いアイディアあったらよろ」って段階っぽい。そりゃそうだよなぁ。素人目にも、少なくとも「アインシュタインの相対論は間違っていた!」とか「CERNはタイムマシンを開発しようとしている!」みたいな報道は早計すぎんだろと思う。「これでタイムマシンも作れちゃいますねー」なんて、コメント求められた専門家が言ったんだとしても冗談半分のリップサービスか、聞いてきた記者が理解できなくてセンセーショナルなところだけ抜き出して書いちゃった感。もちろんそれでも面白そうな話題であることに違いは無いんだけども。

それにしても折角面白そうな話題なのに解説読んでも半分も理解できないの寂しい。一体どこから勉強しなおせばちゃんと理解できるんだろ。それこそタイムマシンでも使って高校生くらいからやり直さないとだめかしら。誰か相対論とか場の量子論が何言ってるか分かるようになるまでに何が必要か教えてくだしあ。

あと全然関係ないけど「Operaは光速より速いブラウザ」って誰かが言い出す、あるいはもう言ってるに76円28銭賭ける。

ニンテンドー3DSの体験会があるから行かないかと友達に誘われたので、今日は朝から幕張メッセまで行ってきた。恐しく混んでてろくに遊べないんじゃないかと不安だったんだけど、タイミングが良かったのか案外しっかり触ってこれた。体験したのはSTEEL DIVERとARゲームズとnintendogs+cats。ゼルダやMGSはまぁ、流石に長蛇の列で映像を見るだけに留めた。パルテナの鏡かパイロットウイングスかどっちかは試しておけばよかったなぁとちょっと後悔。んでまぁ、総合的な感想としては、予想してたより面白いデバイスで好感触。

裸眼立体視ディスプレイ

3DSというくらいなので目玉機能なわけだけど、思ったことは二つ。「かなりちゃんと3Dしてるし、綺麗」「んでもまぁ、面白い映像だなーっていうくらい」。

実はこないだ誘惑に負けてLYNX 3Dを買ってしまったんだけど、個人的にはこれよりも立体感あるなぁと思ったし、ディスプレイそのものも現行のDSより大きく綺麗になってるので映像は良かった。

一方で、3Dテレビや3D Androidのときも思ったんだけど、「おおすげー、3Dだ!…確かに凄いけど、凄いんだけど、それで?って感じだなぁ…」という印象は拭えなかった。面白い演出は出来るようになるんだろうけど、ゲームそのものには(今までとまるで違うというほどには)影響しなさそうというか。見え方にも個人差があるし(ガチャ目や乱視持ちにはちょいキツい)、結構目や脳にかかる負荷もあるし、映像展示の方で色々見てたらソフトによって大分差が出てたし、3Dオフにしてもちゃんとゲームできないといけないし、というわけで、まぁぶっちゃけオマケ感は否めない。本当に立体映像でゲームががらっと変わるとしたら、やっぱり本当に立体投影できるようになるまで待たないとなんだろうなぁと思った。

モーションセンサー、ジャイロセンサー

個人的におっと思ったのはこっちの方。STEEL DIVERの潜望鏡モードやARゲームズでは「3DS自体を動かす」というのがゲームの操作の一部になってて、これがかなり良かった。これとあとスライドパッド(アナログスティック)が追加されて、タッチパネルやフロント/リアカメラと合わせれば携帯ゲーム機としては「入力手段」がかなり多いデバイスになるので、それこそゲーム性にかなり影響してくると思う。

特にARゲームズ!twitterとかでも行ってる人が口を揃えて「ARゲームズ面白い!」って言ってたのが分かると思うけど、実際これが大分良かった。ゲーム自体は他愛のないもので、机の上に置いたマーカを3DSのカメラで認識すると、そこに的やらドラゴンやらが出てきてそれを撃ったりして遊ぶ(体験版なのでそれだけだったけど、実際にはもっと色んなミニゲームが入るとのこと)というものなのだけど、マーカを置いてる机ごとぼよんぼよん波打つのを上から横から狙いを付けるとか、ドラゴンの背後に回り込んで背中を攻撃するとか、「ゲームの演出として」ARとモーションセンサーをしっかり組み込んでて、拡張現実で遊ぶってのはこういうことだよなーと思わせるものだった。

ていうか、一応スマートフォンアプリの開発者のはしくれとしては、「何でこれをiPhoneやAndroidで先に"ちゃんと"やらなかったんだろう…」と大分反省した。モーションセンサーとカメラが付いててOpenCVやARToolKitを使えてある程度の処理性能があるデバイス、もうあるのに、ね。

ステージイベント

ゲームミュージックライブがとても良かった。ジャズアレンジのマリオやゼルダがすごく素敵で、もし明日明後日行く人がいたら、12:30からライブなのでそれに間に合うように行くことをおすすめする。並んで待ってる間に演奏を聴けたので、退屈せずに待ってられた。ちなみにステージイベントの様子はインターネット中継されてるようなので、ストIVやバイオのソフト紹介とかを見たい人は時間を確認して見てみるといいですよ。

全然関係ない話

隣でペット博をやってたらしく、会場付近にはそこかしこにnintendogsじゃない本物のdogsが走り回っていて、一旦外出て休憩してる間に凄く和んだ。うん、本当に全然関係ない話。

「RubyKaigiが終わったら真面目にやろう」とか言ってたくせに、中々やる暇無くて放置してたら大変に分かりやすい作り方講座が出てしまった上、弾さんまで乗ってきてしまって完全にタイミングを逃したfaultierですこんばんは。

悔しいので対抗してみる

うどんげが出たならてゐもいてもいいだろう、ということでてゐ。AAは上記の記事同様こちらを使わせてもらった。初春もいいなーと思ったんだけど表示してみたら大き過ぎて自分のターミナルで表示できなかったのでやめといた。コードはこんな感じ。

# tewi.rb
eval$s=%w't=true;e="eval($s=join("<<34<<34<<",qw{$t=1;$s=~/"<<92<<"[[0-9,]+"<<92<
<"]/;$n=eval($&);$e=          "<<39<<"eval$s=%w"<<39<<    ".chr(39)."<<39<<($s+(
($s.length>1756)?"   ":"#"<<$    s.gsub(/[^0-9a-zA-   Z]/,      "")[0,(1755-$s.l
ength)]));e[-312,  311]=""<<39<<   ";$e.=          ("<<39<<"#"<   <39<<".substr(
join("<<39<<39<<  ",split(/[^0-9a-z              A-Z]/,$s)),0,(200  9-length($s)
))).chr(39)."<<  39<<".join"<<39<<";@o   =       map{$t=!$t;split(//  ,((!$t)?su
bstr($e,0,$_,"< <39<<39<<"):chr(32)x$_)         )}@$n;for(1..34){spli  ce(@o,$_*
81,0,chr(10))}  ;print(join("<<39<<39<<         ",@o).chr(10      )    )}))";o=[
101,10,24,4,40 ,3,8,4,18,3,4,6,33,2,13           ,3,6,10,1            2,3,30,2,1
7,14,17,2,27,  2,21,3,1,7,19    ,2                     ,              25,1,23,9,
21,2,23,2,23,  9,12,6,1,                           4                   ,23,1,23,
11,9,12,23,2, 13,4,2,2                   1                             ,1,14,23,
2,9,27,1,19   ,22,1,8         ,                  1    9   ,             1,29,20,
3,7,9,1,      18,1,4      ,         1        ,          3           ,    1,13,16
,6,6,6,      1,9,1,8                          ,1           ,    1    0,    1,11,
1,4,14,      6,7,26,                   2,1     1,1,4   ,1              ,4,   2,4
,12,6,7     ,19,3,5,             5,  3,2,14,3  ,3,1   0,5               ,8,13  ,
2,2,8,    2,4,3,3,15,          5,2    ,7    ,  4,11 ,10,3,              4,2,4,1,
2,4,    1,6,14,12,4,1      3  ,   6,1,     2,1,3,4,5,18,3,1,3   ,   1   ,3,12,3,
12,1   3,5,1,2,4,15             ,1,1, 11    ,10,3,14,12,6,1 ,           2,5,13,2
,1   ,1,1,6,12,2,16            ,11,7, 8,     13,2,1,7,13,1  , 1      8,10,8,6,14
,  1,2,10,10,1,20,1           2,5,3,1        2,1,6,13,7,2,  1       9,13,26,14,7
, 2,16,16,11,1,13,14          ,8,2,14,      16,13,7,5,15,1 0,          3,8,10,1,
8 ,25,10,1,4,13,27,23,            12,4,   2,12,5,1,1,1 ,8,1,1             3,17,1
0  ,1,3,5,1,12,14,4,8,             4,10,2,13,25,2,3,9,4,2,1,3              ,15,1
3,  33,4,5,1,4,3,20,                8,182].map{ |i|t=!t;((!t)              ?e.sl
ice  !(0,i):32.chr*                i)}.join;1.up       to(35               ){|i|
o[(i*   81)-1,0]          =        10.chr};puts(o)#ttrueeeva          l    sjoin
3434qwt1                           s920992nevale39evalsw39            chr3  939s
slength1     7 5        6             sgsub09azAZ01755s          l   ength e3123
1139e39              39su        bstr          jo             #t1s09nevaleevalsw
chr39tt  rue         eeva  l   sjoin3434qwt1s9             20992nevale39evalsw39
chr3939sslen    gth17 56sg   sub09azAZ01755slengt        he31231139e3939substrjo
in3939split09azAZs02009lengthschr3939join39omapttsplittsubstre03939chr32xnfor134
spliceo810chr10printjoin3939ochr10o10110244403841834633213361012330217141'.join

Gistにも置いてあります。はい。

Quineじゃない件

上のコードをコピペしてRubyに実行させると何やらコードを吐くので、それをさらにRubyに流し込んで実行させてやると…なんということでしょう!エラーを吐くではありませんか!Quineになってねぇじゃねーか、このド低能が!

# tewi.pl(tewi.rbの出力結果)
eval($s=join("",qw{$t=1;$s=~/\[[0-9,]+\]/;$n=eval($&);$e='eval$s=%w'.chr(39).'t=
true;e="eval($s=join(          "<<34<<34<<",qw{$t=1;$s=    ~/"<<92<<"[[0-9,]+"<<
92<<"]/;$n=eval($&)   ;$e="<<3    9<<"eval$s=%w"<<39   <<".      chr(39)."<<39<<
($s+(($s.length>17  56)?"":"#"<<$   s.gsub          (/[^0-9a-zA-   Z]/,"")[0,(17
55-$s.length)]));  e[-312,311]=""<<3              9<<";$e.=("<<39<<  "#"<<39<<".
substr(join("<<3  9<<39<<",split(/[^0-9   a       -zA-Z]/,$s)),0,(200  9-length(
$s)))).chr(39)." <<39<<".join"<<39<<";@o         =map{$t=!$t;split(//,  ((!$t)?s
ubstr($e,0,$_,"  <<39<<39<<"):chr(32)x$_         ))}@$n;for(1      .    .34){spl
ice(@o,$_*81,0, chr(10))};print(join("<           <39<<39<<            ",@o).chr
(10))}))";o=[1  01,10,24,4,40    ,3                     ,              8,4,18,3,
4,6,33,2,13,3,  6,10,12,3                           ,                   30,2,17,
14,17,2,27,2,2 1,3,1,7,                   1                             9,2,25,1
,23,9,21,2,2   3,2,23,         9                  ,    1   2             ,6,1,4,
23,1,23,1      1,9,12      ,         2        3          ,           2    ,13,4,
2,21,1,1      4,23,2,                          9,           2    7    ,1    ,19,
22,1,8,1      9,1,29,                   20,     3,7,9   ,1              ,18   ,1
,4,1,3,1     ,13,16,6             ,6  ,6,1,9,1  ,8,1   ,10               ,1,11  
,1,4,14    ,6,7,26,2,1          1,1    ,4    ,  1,4, 2,4,12              ,6,7,19
,3,5,    5,3,2,14,3,3,      1  0   ,5,8     ,13,2,2,8,2,4,3,3,   1   5   ,5,2,7,
4,11,   10,3,4,2,4,1             ,2,4, 1,    6,14,12,4,13,6, 1           ,2,1,3,
4,5   ,18,3,1,3,1,3,            12,3,1 2,     13,5,1,2,4,15  , 1      ,1,11,10,3
,1  4,12,6,1,2,5,13,           2,1,1,1        ,6,12,2,16,11  ,       7,8,13,2,1,
7, 13,1,18,10,8,6,14,          1,2,10,1      0,1,20,12,5,3, 12          ,1,6,13,
7, 2,19,13,26,14,7,2,16            ,16,1   1,1,13,14,8, 2,14,1             6,13,
7,  5,15,10,3,8,10,1,8,             25,10,1,4,13,27,23,12,4,2,              12,5
,1,  1,1,8,1,13,17,10                ,1,3,5,1,12 ,14,4,8,4,10,              2,13
,25,  2,3,9,4,2,1,3,                15,13,33,4,5,       1,4,3               ,20,
8,182]   .map{|i|          t        =!t;((!t)?e.slice!(0,i):3          2    .chr
*i)}.join                           ;1.upto(35){|i|o[(i*81)            -1,0  ]=1
0.chr};pu     t s        (             o)#ttrueeevalsjoi          n   3434q wt1s
920992ne              vale        39ev          al             sw39chr3939ssleng
th1756sg  sub         09az  A   Z01755slengthe3             1231139e3939substrjo
';$e.=('#'.su    bstr( join   ('',split(/[^0-9a-zA        -Z]/,$s)),0,(2009-leng
th($s)))).chr(39).'.join';@o=map{$t=!$t;split(//,((!$t)?substr($e,0,$_,''):chr(3
2)x$_))}@$n;for(1..34){splice(@o,$_*81,0,chr(10))};print(join('',@o).chr(10))}))

ええはい。良く見てもらえると分かると思うけど、実はこのコードは自分自身を出力してない。何を出力してるかと言うと、Perlのコードを出力している。んで、そのPerlのコードは何をするかというと、最初のRubyのコードを出力する。つまり、最初のコードは「『このRubyのコードを出力するPerlのコード』を出力するRubyのコード」で、後のコードは「『このPerlのコードを出力するRubyのコード』を出力するPerl」のコードになっていて、お互いがお互いの自分自身を相手に出力させるという、「人は一人では生きて行けないんだ」というメッセージ性を持った難読コードなわけです。まぁ嘘です。RubyもPerlもやられちゃったので、そのまま真似してもつまらなかっただけです。こんな感じで遊んでみるといいよ!

$ cat tewi.rb | ruby | perl | ruby | perl | ruby

何をしたの?

実のところ別になんということはなくて、やってることは基本的にはうどんげQuineと一緒。配列リテラルとjoinとevalを使ったQuineはPerlでもRubyでも全く同じ要領でできるので、自分自身を吐く代わりに相手のコードを吐くように書き換えると簡単に行ったり来たりできるようになる。

# 任意に加工できるRubyコードを出力する、
# 任意に加工できるPerlコードを出力する、
# 任意に加工できるRubyコードの例
eval$s=%w'puts("eval(join("<<39<<39<<",qw{print("<
<39<<"eval$s=%w"<<
39<<".chr(39)."<<39<
<$s<<39<<".chr(39)."<<39<<".join"<<39<
<")}))")'.join

あとは、二言語分のコードが一つのAAの中に入ることになるし、PerlとRubyだとリテラルがそっくりなのでデータ部は共有したいので生のデータを書きたい、となると流石に元のAAデータだと文字数の制限がキツいから、反転して白抜きのAAにした。ちなみに、てゐの方はうどんげのとはAAデータ持ち方は換えてる(元記事のロジックをPerlで実装するのが面倒だっただけ)。

あとはまぁ、出力時に尻尾に適当なゴミを付けて文字数調整してるんだけど、文字列リテラルの入れ子が簡単に崩れるので面倒臭いとかそんな程度。chr(39)濫用しまくり。あとドットがRubyのドットなのかPerlのドットなのか良くわかんなくなったりします。

まとめ

途中で「俺は一体何をやってるんだ」と思ったら多分負けなんだと思います。一度ベースができちゃうと後はデバッグと文字数の調整が面倒なだけで、割と簡単にできます。あと段々哲学的な気分になります。

こんにちは、「それは一体誰得なんだ」でお馴染みのfaultierお兄さんだよ!今日はみんな大好きMacRubyをどれだけ無駄遣いできるかを考えてて例のごとく失敗したので、その顛末を教えてあげるよ!

MacRubyでDTを動かしたい

まぁ冒頭書いた通りなんだけど、「Objective-CからMacRubyを利用する - Watsonのメモ」を読んでなんか変なことできないかなーと考えてて、そういや俺ってば見た目に面白い以外は全く使い道のないものを以前作ってたじゃん、と思い出したんだけど、上手くいかなったという話。あ、全く使い道の無いものってのは、もちろん言うまでもなくあいつのことですね。

esotericは構成としては、ソースコードをパースしてSexpにするParserと、それをRuby2Rubyを使ってRubyのコードにトランスレートしてから実行するRunnerでできているので、MacRuby Frameworkを使ってesotericをObjCから呼び出せば、アプリケーションにDTやてってってーでプラグインを書ける仕組みを比較的容易に導入できるかと思います。導入したところで誰が使うのかわかりませんが。少なくとも俺は絶対に使わない。

まずは小手調べのコンパイルエラー

とりあえずMacRubyをDownloadしてくる。最新版の0.5はSnow Leopardにしかインストールできないけどこないだクリーンインストールしたばっかりだから全然問題ないもんね!と勝ち誇ってみせたけど、一体誰に勝ったのかはよくわからない。ちなみにソースからのビルドも時々試みてるけど大体こけるので今回は無難にバイナリをインストール。macgemは0.4のときはまともに使えたもんじゃなかったのでちょっと不安だったけど、Ruby2Rubyも特に問題なく入った様子。なに、こんな拍子抜けするくらいさらっと入っちゃっていいの?とニヤニヤしながら次のコマンドを実行。

$ pwd
/Users/taro/Projects/esoteric
$ echo $RUBYLIB
lib:
$ macruby -v 
MacRuby version 0.5 (ruby 1.9.0) [universal-darwin10.0, x86_64]
$ macruby bin/dt -v
/Users/taro/Projects/esoteric/lib/esoteric/dt/parser.rb:13: end pattern with unmatched parenthesis: /((?:\xE3\x81\xA9|\xE7\xAB\xA5\xE8\xB2\x9E\xE3\x81\xA1\xE3/
/Users/taro/Projects/esoteric/lib/esoteric/dt/parser.rb:74: end pattern with unmatched parenthesis: /(\xE3\x81\xA9|\xE7\xAB\xA5\xE8\xB2\x9E\xE3\x81\xA1/
dt.rb:3:in `<main>': compile error (SyntaxError)
    from dt:4:in `<main>'

オゥフ。言われたところを見てみたら、parser.rbの13行目には/((?:ど|童貞ちゃうわっ!)+)…/という正規表現が書いてあった。念のため試してみたけど、Ruby 1.9.1ではちゃんと動いてる。どうも、()の中にASCII以外の文字が含まれてるとMacRubyさんは閉括弧を見つけられなくて正規表現として不正だと言ってくる様子。ソースコードはutf-8で書いてあって、magic commentにもutf-8って指定してて、文字列リテラルだと問題ないのに、正規表現だと駄目。仕方ないのでベタに日本語書いてたところを全部Unicodeリテラルにしてみた。"ど"だったら"\u3069"とか。とりあえずそれでコンパイルできないというエラーは出なくなった。CRubyの方でももちろんちゃんと動く。なんだよ、やればできるんじゃないか、ツンデレか?などと思いつつhi.dtを実行させてみる。

$ macruby bin/dt -v
esoteric 0.0.2, DT 0.0.2
$ macruby bin/dt examples/hi.dt
parser.rb:160:in `numeric:': ArgumentError (ArgumentError)
from parser.rb:80:in `process'
from parser.rb:58:in `block'
from parser.rb:51:in `parse'
from parser.rb:11:in `parse:'
from runner.rb:25:in `run:'

ぬぅ。まだツンツンしてやがる。ちょっと勢い込んでしまったけど、どうもまだMacRubyと打ち解けきれてないみたい。ちなみに、CRubyの方でやるとこんな感じになる。

$ ruby -v
ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-darwin10.0.0]
$ ruby bin/dt -v
esoteric 0.0.2, DT 0.0.2
$ ruby bin/dt examples/hi.dt
$stack = []
$heap = {  }
$stack.push(72)
$stdout.print($stack.pop.chr)
$stack.push(105)
$stdout.print($stack.pop.chr)
$stack.push(33)
$stdout.print($stack.pop.chr)
$stack.push(10)
$stdout.print($stack.pop.chr)
exit(0)
Hi!

うーん、ちゃんと動いてるよなぁ。該当の箇所を調べたら、本来encodingがUTF-8のStringが来てなきゃいけないところで、MacRubyの場合はUS-ASCIIなStringが来てしまっている。あるぇ?その文字列がどっから来てるかを辿って行くとARGF.readしてるとこなんだけど、MacRubyでは既にその時点でUS-ASCIIとして読み込んでしまっている。CRubyでやったらちゃんと動くのだから、$stdin.external_encodingはちゃんとUTF-8になるはずなんだけど、そもそもそこがnilだし、opneとかset_encodingとかで指定しても変化なし。force_encodingとかしても上手くいかない。と、このあたりでもっと色々なことがおかしいということに気付く。

MacRubyでStringが期待した挙動をしてない件

いまいち良くわからないので、試しにこんなことをしてみた。

$ cat test_string.rb
# coding: utf-8
a = "ど"
b = "\u3069"
puts "\"ど\".encoding        #=> #{a.encoding}"
puts "\"\\u3069\".encoding    #=> #{b.encoding}"
puts "\"ど\" == \"\\u3069\"     #=> #{a == b}"
puts "\"\\u3069\" == \"\\u0069\" #=> #{b == "\u0069"}"
puts "\"ど\" =~ /\\u3069/     #=> #{a =~ /\u3069/}"
puts "\"i\" =~ /\\u3069/      #=> #{"i" =~ /\u3069/}"
puts "\"i\" =~ /\\u0069/      #=> #{"i" =~ /\u0069/}"
$ ruby testb_string.rb
"ど".encoding        #=> UTF-8
"\u3069".encoding    #=> UTF-8
"ど" == "\u3069"     #=> true
"\u3069" == "\u0069" #=> false
"ど" =~ /\u3069/     #=> 0
"i" =~ /\u3069/      #=> 
"i" =~ /\u0069/      #=> 0
$ macruby test_string.rb
"ど".encoding        #=> UTF-16
"\u3069".encoding    #=> US-ASCII
"ど" == "\u3069"     #=> false
"\u3069" == "\u0069" #=> true
"ど" =~ /\u3069/     #=> 
"i" =~ /\u3069/      #=> 
"i" =~ /\u0069/      #=> 0

おぉう…どういうことなの…なんでこんなに違うの…。ちゃんとわかってないんだけど、こんな感じなのかしら。

  • MacRubyはソースコードがUTF-8で書かれているものと想定して、それをUTF-16に変換している?あと、magic commentを見てないようで、試しにeuc-jpで書いてみたらバイト列をそのままUTF-16の文字列だと解釈してStringクラスにしていて、化ける。
  • IOからの読み込みはASCIIとして扱っている。ARGFでもopenでも同じだった。こちらも環境変数、コードのencoding、magic comment、読まれるファイルのencodingに関わらず同じ。
  • String#encodeやString#force_encodingが何もしないでselfを返してるように見える。NSStringのメソッドを使って変換してやれば変わるんだろうか?
  • Unicodeリテラルを解釈するときに、\uXXXXの後ろ二桁しか見てないっぽい。"\u3069" == "\u0069"がtrueって何の冗談かと思った。
  • Unicodeリテラルの扱いが、文字列リテラルの中なのか正規表現リテラルの中なのかで違っている。"i" == "\u3069"はtrueだけど"i" =~ /\u3069/はfalse。そう言えば、"(ど)"は正しくパースできるのに/(ど)/はSyntaxErrorになるところを見ると、Unicodeリテラルに限らずそもそもそこのパースのロジックが微妙に統一されてない感じ。

さてどうしたもんかな…。日本語を正規表現でマッチさせてるところがまずい(ちなみにBrainf*ckは完全に、Whitespaceは不完全ではあるけど一応動いたので、ソースコードと入力にNON-ASCIIな文字列が含まれてなければ問題ないらしい)なら、完全にバイト列だと思って扱ってやるとか、正規表現じゃなくて==しか使わないとか(もちろんバイト単位で比較)、ObjCでまず入力を正規化してやった上でMacRubyに渡すとか(本末転倒!)、そういう風にすれば動かないでもないかもしんないけど、そういう文字列処理みたいなObjCであんまり書きたくないところをRubyでさらっと書けるから良いんであって、それ以外のところはそもそもObjCで書いたって大して難しくない。performSelectorとかランタイムAPIとか使いまくればいいんだよ!というわけでちょっと残念な感じ。

余談

esotericに付属のesocコマンドを使うとDTやBrainf*ckのコードをRubyのコードに変換できるので、出来たコードをmacrubycにかけてやれば最終的にMacOSXで動作するバイナリができます。DTのコードがなんと高速で動作するネイティブのバイナリに!…と思ったけど結構遅かった。なんかこう、色々読み込むののオーバーヘッドが馬鹿にならない感じ。でも、普通にRubyを使うとstack level too deepで動かないような深い再帰のコードでも動いたりする。ていうかexamples/fact.*、macrubycでコンパイルしないと動かないんですけど。何でこんなコード入れてんだ俺。

今日は秋らしいよいお天気だったので、それとは特に関係なく今日も今日とてぼーっとディスプレイに向かっていたところ、こんな記事を見付けた。

勇気を出して告白! その返事で覚えるHTTPステータス・コード

あらあらまあまあ。なんだか俺、この記者の方にシンパシーを覚えるよ。

この手のネタは大好物なのだけど、404はお断りの返事ちゃうやん、てか断り方だけでも何パターンもあるんやで、とうずうずしてきたので便乗して考えてみることにした。例によって400系レスポンスに偏ってるのはお約束。しかたないよねー。告白のレスポンスなんて受けとる方でも返す方でも400系しか知らないもん。ごめん嘘だ。503(「お前本当にタイミング悪いな」)返したことある。再リクエストはありませんでした。200?ああ、そんなステータスコードもありましたね。おいしいのかな。使ってみたいです。

(予想外に反響があったので追記)見ての通り全部のステータスコードについては書いてないです。100系一切書いてないし、201とか下ネタしか思い付かなかったし、300とか305とかも結構面白いなと今気付いたりしたし、400系はWebDAVとかでしか使ってないようなマニアックなステータスコードとか一杯あるんだけどスルーしてるし、500系は元記事のネタで個人的には満足してたので良いかなと思ったりしました。や、思い付きで書いてるから、これ割と適当なんでちゃんとみんなRFCとか読むといいよ。

200系レスポンス

200 OK
「好きです、付き合ってください」「はい…」だって。よかったね。あーほんとよかったね。なんだよ。別に羨しくないし。
202 Accepted
「好きです、付き合ってください」「…受理されました」「え、あの…」「只今処理中です。お待ち下さい」。とりあえず、告白は聞いてはもらえたらしい。待てばいいんだろうか。

300系レスポンス

303 See Other
「好きです」に対して「…あなたには、もっとふさわしい人がいると思うの…」と返すときに使う。ちなみに、この返事をするときに、多くの人が302(「今は私じゃなくて、あの子の方が素敵だと思うの」)を返すが、実は正しくないことがある。302を返されたら(一時的ではあるが)基本的には誰であれその人とは付き合えず、紹介された別な人に行くべきであるが、303の場合は「あなたにはもっとふさわしい人がいると思うの」なので、誰からのどんな要求かによってはOKが返っている可能性がある。
304 Not Modified
「まだあなたに対する気持ちは変わってないの」。最初に断わられたのかOKだったのかによって全然意味が違ってくるが、要するに「この前言ったのと同じだから、もう一度答えるまでもない」ということ。違う返事が欲しければしばらく待つ必要がある。
305 Use Proxy
「話ならマネージャーを通して聞きます」。その連絡先では直接会話することが許されていないので、しかるべき人に伝言をお願いすることになる。

400系レスポンス

400 Bad Request
「好きです」に対して「何言ってるかわかんない」「理解に苦しむ」という返事をするときに使う。告白の仕方が遠回しすぎて伝わらない、何か手順を間違えた、言語や文化の壁で相手に意図が通じてない、等の可能性がある。あるいは、「お前が告白してくる、ということ自体が不正なリクエストである」ということを婉曲に表現している可能性も考慮した方がいい。
401 Unauthorized
交際を要求されたが、「そもそも私とあなたは知り合いですらないんですけど」「誰が話しかけていいって言ったよ」などの返事をするときに使う。告白するまえにまずは会話する許可を貰いましょう。
402 Payment Required
「付き合ってもいいけど、お金払って下さい」
403 Forbidden
「半径1km以内に近付いてはいけないと、裁判所で言われたのをお忘れですか?」
404 Not Found
文字通りに受けとるならば「その人はいない」。家に行ったら留守だった、実家にかけたら「そんな子はうちにはいません」って言われた、などのときにはこのステータスが返っていると思われる。ただ、拒否したいんだけど、丁度いい理由がない、あるいは理由を言いたくない場合に使うことも多いので、居留守である可能性もある。
406 Not Acceptable
交際の要求に対し、相手が求めているものと違うものしか返せない場合に使う。拒否ではなく一応レスポンスが返ってくることもある。「そう言ってくれるのは嬉しいけど、私、多分あなたの思ってるような子じゃないよ…?本当の私、見てくれる…?」と言われた場合、受け入れる側に覚悟が求められる。実際は好みの子じゃなかった、程度であればいいが、異性だと思ったら同性だった、そもそも人間じゃなかった、などの可能性も考慮する必要がある。
408 Request Timeout
「もーーーー、トロい!言いたいことがあるんならさっさと言ってくれない!?」という言葉とともに返す。言われた通りもう一回繰り返しても構わないが、さっさと言わないと怒られる。
410 Gone
「その人はいない、そして二度と戻ってはこない」。404と似ているが、こっちのがより強く「もう、いくら望んでも手に入らない」ことを意味する。いいですか、いい加減忘れて下さい。もうあの人はいないんです。新しい恋を探して下さい。
413 Request Entity Too Large
「長編小説一本分になるほどの超大作のラブレターを送ってこないで下さい、重すぎます」
418 I'm a teapot
「私は人間ではなくティーポットです」。ティーポットに対して交際を要求するあらゆる行為は、このステータスコードで終わる。なお、RFCとして定義されてはいるものの、これは正式なHTTP Status Codeではなく基本的にはエイプリルフールの冗談である。
423 Locked
ちょっと束縛してしまう癖のある恋人と付き合っている人に対して告白してしまったときに返される。恋人の束縛が解けるまでは何度リクエストしても付き合ってくれる可能性はないと思う。

500系レスポンス

500 Internal Server Error
告白された側が予期せぬ事態にテンパってしまっている時に返す。思考回路はショート寸前、だって純情どうしよう。
501 Not Implemented
「付き合うってなんですか?」「多分、私それ、できないし、よくわからない」などの返事とともに使われる。要求している側は、「相手が幼児でないか」「相手がロボットでないか」などを確認する必要がある。
502 Bad Gateway
ああ、お前に頼んだ俺が馬鹿だったよ。余計なことしやがって。お前のせいで台無しだ。
503 Service Unavailable
「ちょっと今…返事できないの」。沢山の人に言い寄られていてすぐには返事すらできない場合や、前回の失恋からまだ立ち直れずそういう話をする気分ではないときに使う。ちなみに、このステータスだからと言って必ずしも過負荷であったり立ち直る最中とは限らない。単純に告白に対して返答する気がないだけの場合もあり、とにかく分かることは「今聞いても返事が返ってこない」ということである。親切な相手であれば「ちょっと今」が「いつまで」なのかを教えてくれることもあるが、そうでなければ告白した側にから見れば500の場合と大差ない。

400系多くない?

やっぱり人間断わるときの方があれこれ考えるものなんだろうか。色々理由付けられても「ダメ」なことに変わりはないんだけど、ダメと返されたときに「諦める」「何度でも言う」以外にパターン毎に適切な対応をした方が相手の態度も変わってくるんじゃないかと思うんだ。なんだそのまとめ。

追記

400系のネタだけでにするつもりだったけど結局他のも入れたので、「告白を断わるときの…」ってタイトルは変えた。

あと、400系は基本的にクライアントからのリクエストに問題があるときに使うものなのに、告白された方の問題のような書き方をしてるとこは直した。告白される方や仲介してくれる人に問題があるのは500系。まぁ、幼児や機械に交際を求めるリクエストはどっちかというと403 Forbiddenな気もしないでもないけども。

この間から「イヴの時間」にハマっている。

映像が綺麗とか音楽が好きとかナギさんのウインクとか諸々全部ツボに入ったので勢いでDVD全部買ってしまってああ俺もうドリ系でいいやとか思い始めてるんだけどそれはひとまず置いといて、このテーマ。もの凄く精巧なアンドロイド、「当店内では人間とロボットとロボットを区別しません」という「イヴの時間のルール」、何度も流れる倫理委員会の公共広告、そして「ドリ系」こと"Android Holic"。「人間」と「人間でないもの」が共存する世界においての、互いの関係。

劇中でも象徴的に出てくる、アシモフのロボット工学三原則とかブレードランナーを持ち出すまでもなく、SFでは何度も語られてるテーマだ。そう言えば昔哲学書か何かでも読んだことがある気がする。その辺は別にあんまり詳しいわけでもないので、さぶかるちゃん辺りで誰か取り上げてくれたりしないかなーとか、適当に呟いてみる。

それはそうと、これを観ててふと面白いことに気付いた。俺は、このレベルのアンドロイドが実用化されたとして、それを人と同列に扱うことに多分何の疑問も抱かない。むしろ、そもそも劇中でアンドロイドに人格を見出すことが危険視されていることすら違和感があった。

…想像力。ペットに話しかける人がいる。何か像に特別な意味を見出す人がいる。フィクションの世界の登場人物に恋をする人がいる。自分の愛用の道具を労わったりする人がいる。気に入らない動きをする道具を怒鳴りつける人がいる。文字と画像だけでも実際に会ったこともない人と会話が出来る。どっかのパソコンで動いてるプログラムと会話が出来る。死んで肉になったものも人として扱う。その肉すら無くなっても人として扱う。人は人を感じる要素があるものに対してはなんであれ人を感じることができるし、人でないものに対してすら人を見出してしまうし、そこに何も無くたって人を作り出してしまう。とんでもないな、人って。

だったら「人の姿をして、人の様に思考し、人と会話ができるように見える」ものなんて余裕で人の範疇じゃないの。チューリングテストじゃないけど、中身が何であれどうやら自分と同じように振る舞うものは人だと思っていいんじゃないの。だって目の前にいる「本物の人間」だって中身が何なのか本当に自分と同じなのか俺は知らないけど、多分人だし。

とか取りとめ無く考えてたら、昔AIを作ろうとしてたことをふと思い出した。プログラミングに二度目くらいに熱中してたとき、生物の授業をやたらとわくわくしながら聞いてたとき、大学で言語学の勉強をしようと決めたとき、哲学の講義で居眠りをしてたとき、心理学の実験室に遊びに行ったとき。確か俺はその度にAIを作ろうとしてた。何度か書いたあのプログラムはどこ行ったんだろう。そんで俺は何を作ろうとしてたんだろう。

とくにオチは無い。またAIを作りたくなった。

内容が内容なのでぼかしつつ書くけど、今朝「最後に出されたアイスコーヒーに付いてきたガムシロップの味がとにかく気に入らなかったので、ここのフルコースは100点満点中5点でした」とかいう種類の「感想」を見た。アイスコーヒーとフルコースは比喩。実際は別な何かの話だと思って欲しい。Amazonの本でもAppStoreのアプリでも何でもいいけど。

俺自身はそこのレストランがかなり好きで、一週間と待たずにもう一度行くくらいのリピーターだから、カチンと来たのは隠さない。ただ、フルコースなんだからアイスコーヒーのガムシロップ以外にも他にいくらでも言及するとこあるだろ、と思うんだよなぁ。

その程度のことで料理全体が否定されるんなら、いっそ「アイスコーヒーへのこだわり以外見るべきところが何もない店だが、そのアイスコーヒーを安物のガムシロップが台無しにしている。ということでクソレストランだった」くらい言い切ってくれれば、味の好みが違うんだなぁ、くらいで流せるんだけど。

いやそりゃ俺もあれはガムシロ抜いて飲みたいと思ったし、この料理はくどいけどこっちは味薄いなぁ、みたいなのはあったけど。でも一個一個の料理は丁寧で手も込んでたし、全体のバランスも悪くないし、ぶっちゃけ75点くらいの出来だと思うけどなー。ガムシロが無かったら80点、もう一品多かったら90点、でも店員さんが好みの顔っていうボーナスを抜いたらやっぱり80点、くらいの評価。

いや、別にいいけど。「感想」だし。「批判」だったら怒るとこですが。

日々着実にバカな方にバカな方に向かってるのを実感してるfaultierです、みなさんお久しぶり。

一昨日あたりに見かけた「彼女がいないことをステータスコード404で表わす」ってのが大変ツボに入ったので、今日はせっかくだから実際にそれを実装してみたよ。なんと以下のURLをGETすると「faultierの彼女」ってリソースがいまどんなステータスなのか返してくれるんだ。

http://faultier.jp/resource/kanojo

…まぁ俺に彼女がいるかどうかなんて瑣末なことはどうでも良くて、一応これGET/POST/PUT/DELETEに対応してて、それぞれ違うレスポンスを返すように作ってあるので、生まれついてのHTTPクライアントな感じの少年少女紳士淑女な方々はいろんなリクエストを送って「リソース:faultierの彼女」をいじってみるといいと思うんだ。まぁどう操作しようが何も起きませんが。何、あんま使わないからってサボってGETとPOSTしか実装してない?しょうがないやつだな、GETするときにURLの末尾に/putとか/deleteとか入れてみなよ。それっぽい動きするから。

みごとに400系のステータスコードばっかりになっちゃったけど、せっかく作ったので、そのうち「418 I'm a teapot」とかも実装する予定。ってそれも400系か。あ、あとちなみに、GETするときにmode=prevとかmode=nextってクエリを付けると「前の彼女」「未来の彼女」についての情報も返ってくる。どうでもいいですね。

追記:418も実装した。ついでに多少ステータスコードをいじった。そのリクエストにそのレスポンスは普通無いだろ、みたいのがあるとあれなので。あと、HEADを忘れてたのでHEADも対応した。

Rack可愛いよRack

ネタはネタとして置いとくとして、今回はこれをRackHamlを使って作ってみた。何でかというと、今Ruby版Atompub::Serverみたいの作ってて、RailsやMerbのプラグインもそのうち書くつもりではいるんだけど、まず単体でサクっと動くの作りたいなと思っていろいろいじってるところだったから。Hamlは興味はあったんだけど中々触る機会がなかったので、ついで。

なんというか、Rackは素敵だなぁ。この程度のものを作るのにちゃんとしたWAFを使うのもなんだかゴキブリ退治に対戦車ミサイル持ち出すみたいで気がひけるんだけど、かといってCGIってのもねぇ、みたいなときにもとても良い。簡単な認証とかロギングとかセッションとかは添付のミドルウェア使えば実現できちゃうし、WEBrickとかで簡単にローカル環境で開発サーバ作れちゃうのも魅力的。そんでもって深く考えなくてもWEBrik、thin、mongrel、fcgi、Passengerと色んな環境に対応できちゃうのも素敵だ(というかそれは話が逆で、そのためのインターフェースライブラリなんだけども)。なによりRack::Testが便利すぎる。こんなしょうもないアプリでもちゃんとSpec書いたんだぜ、あんまり簡単だったから。

ハムは食べたいけども

Hamlの方は、なんというか、結構微妙。いやまぁ、確かにすっきりシンプルなテンプレートが書けるんだけど、普段見なれてるHTMLから乖離しすぎててちょっと抵抗あるかも。正直学習コスト考えたら素のHTMLとRubyをそのまま書けるerbやその派生/改善版のテンプレートエンジンのがよっぽどとっつきやすい気がする。一人でやってるときはともかく、デザイナーやマークアッパーとの分業で仕事してると、これ出力がどうなるか想像しながらやんなきゃならなくて作業しづらいんじゃないのかなーとか思ってしまう。

とは言え不思議な魅力もあるのも確かで、文句言いながら書いてたけど数分後にはなんとなく慣れてしまった。趣味でなんか作るときにはしばらく使ってみようかなと思ってたりする。

ところで

一応言っとくけど、あそこからエントリーしても別にデータとか保存してないしメール送ったりもしないので、安心して彼女の名乗りを上げるといいよ!まぁ本当に名乗りたければあんなとこで慎しやかに名乗られても困るけど、いないよねそんな人。

こないだ作ったesotericがあろうことか0.0.2にバージョンアップしました。主な変更点は以下の通り。

  • 各言語をコンパイルしてできる中間コードが、前のバージョンでは似非アセンブラ的な何かだったものを、ParseTreeなんかで作るようなRubyの抽象構文木(AST)的な何かに変わった。VMでの実行前に生成されたコードを最適化するとかできるようになるとか、他のRubyライブラリにEsoteric Languageパーサが埋め込めるようになるとか、無駄に夢が広がる感じで。
  • もちろん似非VMでは動かなくなったので、作り直さなきゃいけないんだけど、ちょっと時間かかりそうなので似非VM殺した。そのかわり、ASTはRuby2RubyとかでRubyコードに変換できるように作ってあるので、とりあえずRuby2Rubyを使うようにして誤魔化すことにした。
  • 副産物としてDTやWhitespaceのコードを実行可能なRubyスクリプトに変換するコンパイラもどきのツールが出来た。Cへのトランスレータもあるみたいだし、そういうの使えば本当にコンパイルしてバイナリも作れたりしますね。DTでコマンドとか作れるようになるね。まったくやりたくないけどね。
  • Brainf*ckのパーサを追加
  • てってってーのパーサを追加。一応一通りの仕様は満たしてると思うけど、「「\xAB」「\uABCD」「\d00000」:エスケープシーケンスとして、それ全体で1文字と扱われる。(予定)」ってのはまだ実装してない。あと「ててー」と「てっー」が微妙な動きをするのを解決してないけど、まぁそのうちなんとかする。

とまぁ、そんな感じ。次はまず、VMの再実装と、あとSpec書く。それ終わったらRubyで作る奇妙なプログラミング言語 ~Esoteric Language~に載ってたStarryやBolicでも実装しようかな。あとはとかやってみようかしら。

大分楽しくなってきたところだけどアイマスSP買ってきてしまったので、一回休み。そしたら来月ぐらいから仕事が忙しくなるに違いないのでまた一回休み。一段落ついたら多分飽きてるだろうからまた(ry。まぁまったりもったりやりますかねぇ。

プログラミング言語DTを作ったところ「いいからソースを晒せコラ」と言われたので、DT処理系のソースコードをgithubに上げてみた。

faultier's esoteric at master - GitHub

正確に言うと、DTの処理系と言うか、似非VMとそれで実行できる中間言語を吐くコンパイラ群のセット。その中にDTコンパイラとサンプルも入ってます。構成整理して無駄にgemspecを作ってあるので、

$ sudo gem install faultier-esoteric --source http://gems.github.com

とかやるとesotericがインストールできる…はず。なにしろgem作るのも初めてだしそれをgithubで自動ビルドさせるのも初めてなので、なんかしくじったかもしれない。てか、初めてのgemがこれか。それでいいのか、俺。まぁいいや。あ、できた。ちゃんとできてた。一応1.8.6-p287、1.8.7-p72、1.9.1-p0では動作確認済み。大したことやってないのでまぁ動くはず。

ちなみに、esotericに含まれてるコンパイラはWhitespaceとDTだけです。HRKは白紙に戻して、Nonowaと改称した上で言語仕様から考え直すため、Decadeはfaultierが某特撮番組を観てないので、ファンの人から怒られそうなため、今バージョンでのリリースは見送りました。今バージョン、てことは、esotericはバージョンアップするものらしい。何のために。誰が得するんだ。多分次のリリースあたりではBrainf*ckとかてってってーとかが取り込まれてて、その次のリリースあたりではNonowaが実装されたりしてるんだと思う。気が向いたら。飽きてなかったら。

あ、で、使い方だけど、インストールするとesm、whitespace、dtの三つのコマンドが使えるようになるので、

$ dt -v
esoteric 0.0.1, dt 0.0.1
$ dt hi.dt
Hi!

などとすると前の記事のコードが実行できたりする。これであなたも今日からDTer。

まさかそんな馬鹿いないとは思うけど、これ一緒にいじりたい、って人がいたら「べ、別にあなたのために手伝ってあげるんじゃないんだから、ただの興味よ、興味」とかメールで送ってください。別になにもしないけど。俺がニヤニヤします。…まぁ、githubにあるものなので好きにいじってください。あ、あとVMのこととか教えてくれる人がいたらすごく喜びます。

最近「Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~」を読んで、ついカッとなって言語処理系を作ってみた。それも、チューリング完全な、本物の(ry まぁ、Whitespaceのトークンを置き換えただけだけど。

一応、上記の本に習って、ソースコードをWhitespaceの命令セットを持つ中間言語にコンパイルしてVMで実行する形にしてみた。あとはパースする部分を適当に置き換えたコンパイラを作ればそれっぽいのが簡単に作れる。んで、いくつかネタ言語を作ってみたんだけど、その中でも一番しょーもないのがDT。DTでは次のようなソースを実行することができます。("Hi!\n"を出力する)

「○○くんて、もしかして童貞?」
「どどど童貞ちゃうわっ!どど童貞ちゃうわっ!どどど…童貞ちゃうわっ!」
「えー。その慌てっぷりが余計怪しなぁw」
「…どどどどど童貞ちゃうわっ!童貞ちゃうわっ!ど童貞ちゃうわっ!どど童貞ちゃうわっ!…童貞ちゃうわっ!」
「はいはい、わ、わかったってば。そんなにムキになんないでよ。」
「…どどどどど童貞ちゃうわっ!どどどど童貞ちゃうわっ!…童貞ちゃうわっ!」
「だから、わかったってば。もう言わないから。」
「…どどどどど童貞ちゃうわっ!ど童貞ちゃうわっ!ど…童貞ちゃうわっ!」
「いやその、なんか、ほんとごめんね。そんなに気にしてると思わなかったから、あの…」
「どど…」
「(ほんとキモいなぁ…)」
「…」

バレンタインだと言うのに一体何をしてるんですかね、僕は。ちなみに「ど」「童貞ちゃうわっ!」「…」以外の文字は全て無視するので、それらの順番と数さえあってればどんなコメントを挟んでも問題ない。コメント記法とかも特にない。ちなみに上記のコードから有効な部分を抜き出すとこんな感じ。一応読みやすくするために改行は入れてある。

どどど童貞ちゃうわっ!どど童貞ちゃうわっ!どどど…
童貞ちゃうわっ!…どど
どどど童貞ちゃうわっ!童貞ちゃうわっ!ど童貞ちゃうわっ!どど童貞ちゃうわっ!…
童貞ちゃうわっ!…どど
どどど童貞ちゃうわっ!どどどど童貞ちゃうわっ!…
童貞ちゃうわっ!…どど
どどど童貞ちゃうわっ!ど童貞ちゃうわっ!ど…
童貞ちゃうわっ!…どど
………

あと他に「アイドルが機嫌良さげに踊るののワ型言語HRK」とか、「9つの世界を巡る変身ヒーロー型言語Decade」とか作ったけど、どれも今のところただのWhitespaceなのでどんなソースになるかは想像つきますね。てことで割愛。もちろんどれも入出力や四則演算やジャンプ命令を備えてますので、フィボナッチ数列を無限に出力するとか余裕だし、その気になればきっとWebアプリぐらい書けますね。やりたかないけど。ていうかどれも書くことを全く考慮してないので、俺もうざくなって似非中間言語書いてそれを置換してソースコードにするっていう本末転倒なことしないと書けない。まぁそんなもん。

そろそろWhitespaceにも飽きたので、次は何しよう。Ruby分は十分補充できたので、Objective-CでVM書くとか、Parrotの上で処理系作るとかしようかな、とか。関数型言語もまだやってないので、それを実装するのもいいし、処理系をHaskelで書いてみるとかもしたい。しょーもない見た目の「まともな」言語仕様を考えるとかもしたいなー。やってみると結構面白い。ハマる。十分脳味噌ほぐれたらちゃんとした言語処理系のソースでも読んでみよう。

と、そんな現実逃避をして過した休日。うーん、充実した土日だった。え?何?何でDTなんか作ったのって?もしかしてfaultierって童…いいいいいやいやいや。どどどどど童貞ちゃうわっ!

注意

上の言語はほんとしょーもないですが、Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~の方はちゃんと面白い本なので誤解のなきよう。変な言語も色々紹介されてるし、Rubyでサクっと言語処理系つくるやりかたも書いてあるので、オススメです。

Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~
著者:原 悠
販売元:毎日コミュニケーションズ
発売日:2008-12-20
おすすめ度:4.0
クチコミを見る

追記

これ書いた後にクチコミを見たら弾さんがてってってーとかやってて、その記事のさらに元記事が結構なブクマ数だったりして、今頃それに気付いてなんか負けた気分。ぬぅ…。いいもん、ちゃんとののワさん言語完成させるから。もうなんかiPhoneで動くようにしちゃうから。配布できないけど(インタプリタは規約でAppStoreに登録できなかったはず)。

↑このページのトップヘ