上のコードができるまで
ゴルフったところこんな感じになった。ファイルは更新しておいた。
#include/* s='''*/<stdio.h> main(){char*_;/*==;sub _:lvalue{$_}<<s;#';<<s#''' def printf(a,*b):print a%b, s #*/ _=" #include/*%cs='''*/<stdio.h>%cmain(){char*_;/*==;sub _:lvalue{%c_}<<s;#';<<s#'''%cdef printf(a,*b):print a%%b,%cs%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10);%c#/*%cs='''*/%c}//'''#==%c";printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10); #/* s='''*/ }//'''#==
まぁ Quine 作る方法は色々あるわけですが、メインの処理の部分は全く同じ形にしとかんと Quine にするのは大変だよなーと思ったので、一本化しやすいし短い printf で。以下の形。 Quine 自体の説明は略。
_="..."; printf(_, ..., _, ...);
全ての言語がこの部分を通るわけですが、各言語問題があります。
- C
- int main(){char*_; って内容を入れないといけない。
- Python
- printf が存在しないので自分で定義しないといけない。
- Perl
- 変数 _ は SIGIL が無いって怒られるので、代入可能な _ を用意しないといけない。
- Ruby
- このままで通る。
こういう下準備の部分とかは各言語別のパスに分けないといけません。順に。
#include/*
とりあえず最初の空白は一応 PHP のため。
で、まず C++ は一番毛色が違う言語なので分離しないといけない。とはいえ複数行コメントがあるので分離しやすい。最初の行で #include として他の言語はコメントにしておきつつ /* で C++ コメントスタート。
s='''*/<stdio.h>
前半部。 Perl と Ruby と Python で実行。これらの言語には複数行コメントはないので基本的に文字列リテラルで分離する。後で Perl と Ruby と Python をバラす必要があるので、それぞれの言語で別の方法でリテラルに突入しないといけない。色々考えた結果上記の形に。 Python は ''' による複数行文字列リテラル (Python はこれ以外に複数行処理から外す方法無い気がする) で、 Ruby は '' と '*/... っていう文字列が定数文字列の結合でくっついている。 Perl は定数文字列の結合ができないので諦めかけてたんだけど、正規表現 s/// を使うことを思いついた。つまり / のかわりに = にして s=== って形で正規表現リテラルにしている。 s= は右辺値を用意してやれば Ruby と Python でも問題が無い。
後半部。 C++ がコメントから戻って #include の続き。
main(){char*_;/*==;sub _:lvalue{$_}<<s;#';<<s#'''
まず C++ が下準備を終えて /* でコメントに突入。
次は Perl をコメントから戻す。 ==; はさっきの s= とくっついて、 s=...==; となるので何も変化しない置換になる。 sub _:lvalue{$_} はなんか左辺値になれる関数を Perl は定義できるらしいと今日調べて知った。で、ヒアドキュメント << s; で s だけの行が出るまでコメントアウト。この行の以降の部分を無視するために # も。
次は Ruby が戻ってくる。本当は Python を戻したいんだけど、 ''' とかすると Ruby も戻ってくるので先に小細工しないといけない。で Ruby だけ戻すために ' を一個だけ入れて、特に Ruby はやることないので << s でそのままヒアドキュメント突入。 Perl 同様 # で以降を無視。
Python が ''' でコメントから戻ってきてこの行は終了。
def printf(a,*b):print a%b, s
Python は printf が無いので適当に定義。ヒアドキュメントの終了を s にしたのは Python のため。 Python は既に s= で s は変数になってるので問題なく s 単体の行を抜けられる。
#*/
他の言語はコメントから出たので、 C++ もコメントから戻す。 # で一旦スクリプト言語達をコメントアウトして、 */ で C++ が戻る。これで次の行は全員集合。
後はまぁ、普通の Quine と C++ は } で閉じなきゃいけない、ってだけの話なので似たようなことをして終了。あえて言うなら # 単体の行は C++ で合法らしいと。
Polyglot Quine
http://shinh.skr.jp/dat_dir/poly_quine.txt
基本的には上記 4言語の Polyglot quine 。あとまぁ C と PHP でも Quine になる。あなごるだと m4 なんかもまぁ。 C++ が標準準拠してない気がするので気になるなら main に int をつけると良い。
実行は以下みたいな。
i@colinux ~/wrk/ag> diff poly_quine.txt =(gcc -xc =(php =(perl =(python =(ruby poly_quine.txt))));./a.out) i@colinux ~/wrk/ag>
はてなのシンタクスハイライト (vim のなんだっけ) を試してみる。
#include/* s='''*/<stdio.h> main(){char*_;/*==;sub _:lvalue{$_}<<_;#';<<_#''' _=0 def printf(a,*b): print a%b, _ #*/ _=" #include/*%cs='''*/<stdio.h>%cmain(){char*_;/*==;sub _:lvalue{%c_}<<_;#';<<_#'''%c_=0%cdef printf(a,*b):%c print a%%b,%c_%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10);%c#/*%cs='''==;%c__END__%c*/%c}//'''%c";printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10); #/* s='''==; __END__ */ }//'''
#include/* s='''*/<stdio.h> main(){char*_;/*==;sub _:lvalue{$_}<<_;#';<<_#''' _=0 def printf(a,*b): print a%b, _ #*/ _=" #include/*%cs='''*/<stdio.h>%cmain(){char*_;/*==;sub _:lvalue{%c_}<<_;#';<<_#'''%c_=0%cdef printf(a,*b):%c print a%%b,%c_%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10);%c#/*%cs='''==;%c__END__%c*/%c}//'''%c";printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10); #/* s='''==; __END__ */ }//'''
#include/* s='''*/<stdio.h> main(){char*_;/*==;sub _:lvalue{$_}<<_;#';<<_#''' _=0 def printf(a,*b): print a%b, _ #*/ _=" #include/*%cs='''*/<stdio.h>%cmain(){char*_;/*==;sub _:lvalue{%c_}<<_;#';<<_#'''%c_=0%cdef printf(a,*b):%c print a%%b,%c_%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10);%c#/*%cs='''==;%c__END__%c*/%c}//'''%c";printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10); #/* s='''==; __END__ */ }//'''
#include/* s='''*/<stdio.h> main(){char*_;/*==;sub _:lvalue{$_}<<_;#';<<_#''' _=0 def printf(a,*b): print a%b, _ #*/ _=" #include/*%cs='''*/<stdio.h>%cmain(){char*_;/*==;sub _:lvalue{%c_}<<_;#';<<_#'''%c_=0%cdef printf(a,*b):%c print a%%b,%c_%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10);%c#/*%cs='''==;%c__END__%c*/%c}//'''%c";printf(_,10,10,36,10,10,10,10,10,10,34,_,34,10,10,10,10,10,10); #/* s='''==; __END__ */ }//'''
なんか関係ないけど並列の話とか
http://www.igda.jp/modules/xeblog/?action_xeblog_details=1&blog_id=505
を見てて思い出したので書く。
Python のすばらしいものの一つとして generator があるとおもう。
中略。
で、たとえば、
pos_ary = ary.select do |x| x > 0 end
とかで正の数だけ抽出する時と
pos_sum = ary.select do |x| x > 0 end.inject do |r, v| r + v end
正の数だけ summation する時で、前者は Array が帰ってきて後者は generator チックに動作する Enumerable が自動的に選択されたらステキだなぁと。
もっと言うとこう select と inject が別スレッドで走ってくれたらそれは嬉しいなぁと。っていうか Erlang とかが微妙に流行ってるのとか Alef とか Limbo とかのチャンネルってこういう意味での並列だよねと。 CPU でいうところのパイプライン並列化というか。
で CPU でいうところのもう一個の並列化だけど、
ary.each do |x| f(x) end
みたいなループで(fに副作用が無い時)並列化させる、ってのはこう、 ary が少ない時はいらんし、ものすごい多い時は別マシンで走らせればいいじゃんって気がする。 ary が適度に大きい時、ってのは私はマルチメディア処理くらいしか思いつかないのだけど、まぁそれはマルチコアじゃなくて SIMD とかでやればいいじゃんって気がする。
でも select と inject が別スレッドで走るのはまぁ普通に嬉しいと思っていて、ループの中で a って変換と b って変換と c って変換をしたい時に、
ary.map do |x| x = a(x) x = b(x) x = c(x) end
とか書いてたとして、単一 CPU だと a と b と c を微妙に展開して a の計算途中のデータを b でも使ったりすると速くなったりとかするケースが結構あって、そいうことすると効率とコードの綺麗さが敵対関係になっちゃったりする。でも、
ary.map(:a).map(:b).map(:c)
って書くと (Symbol#to_proc あればこう書けるんだっけ) 3 つの map が適当に別スレッドで動いてくれる、っていうなら当然みんな a と b と c を分けて書くわけで、効率と綺麗さが仲良くできていいよなぁと。
あとなんか ary.map(:a) はこう、最初はなんかよくわからん Enumerator が帰ってて、時が満ちるか Array としての動作が必要になると Array になる(Array としての動作が必要になった場合は map の終了を待つ)、とかだと面白いよなぁと。
メッセージベースのオブジェクト指向言語ってこう、レシーバがなんだろうとインターフェイスさえ正しけりゃ問題ないわけで、いったんなんかのクラスだったオブジェクトが突然別クラスのオブジェクトに変わってくれたりしてもまぁ問題ないんじゃないかなぁ、って思う。
このあたり Io の Concurrency が面白かったと思うのでまた今度。
なんかよくわからんのでまとめると、まとめる気が起きない。
近況はイルブリードが面白い。と言ってもニコニコで見てるだけだけど。
イテレータの話とか
がこのへんとかで色々ありました。
http://mono.kmc.gr.jp/~yhara/d/?date=20070612#p04
私としてはこう、
- #each というインターフェイスは絶対変えたくない
each_with_index に変える時の精神的な圧迫に耐えられないし、 each_with_index はゴルフ的に略とか。
- 普段はなんも処理しない方がいい
なんか必要になった時だけ #each のループで回りが取りたいなぁという。
ary.each do |i| i + $LOOP.prev[-1] + $LOOP.succ[1] end
とかまぁ Ruby だとこうまともな解決法なさげなのでまぁ。
それは良くないけどまぁいいとして。
ABA style で pixel shader とか
なんか長らくシェーダとか触ってみたかったのに触ってなかったので触ってみた。
http://shinh.skr.jp/tmp/pbg_ps.tar.bz2
ABA style ってのは id:ABA さんが偉大すぎてプリミティブと半透明だけでデザインがんばってゲーム作るとそう呼ばれるらしい。で、こう shader とかって基本的にはリアル絵出すためのものだけど、まぁそいうの興味無いっていうか絵かけないしモデリングとかよくわかんないしーってこと(興味はあるけどいじけてるというか)でそっち方向でもシェーダって使えないのかなとかそんなことを思って勉強してみることに。うーん日本語になってないがまぁそんな感じ。
中身は pbg.exe を実行すると動く。左と右でピクセルシェーダ変更 (PS 0 ってなってるところが変わるはず) 、 r で PS のリロード、 s で現在の PS を一番最後のシェーダ番号のところに保存 (配布物には ps/7.fp まで入ってるから保存すると 8.fp になる)。 0.fp を適当にいじって気に入った絵が出たら s してまた書く、ってのが想定された使い方。
ARB_vertex_program 拡張が入ってない GPU では動かない。特にチェックしてないからたぶん落ちたりイヤなことが起きると思います。珍しいことに Windows 以外ではチェックされてない。というのは今 Linux が coLinux でしか動いてないので、 Linux から WINE でビルドしてる。クロスコンパイラで GLee とかたぶん結構めんどいので。
時代に乗り遅れまくりの子が数日触っただけの素人雑感。
基本的にはシェーダってややこしいモデルを処理する時に見栄えを調整するって感じなはずなので、全ての出力が手のうちにある ABA style にはあんまり向いたもんじゃないとは思う。で、何に使えるか、ってこと考えると演出のメインの要素として使う、ってよりは、画面全体に手軽にエフェクトをかける、ってシーンに良いと思う。
特に 3.fp や 4.fp みたいな画面全体の色を変える、なんてのは問題なく CPU 側の処理でできるわけだけど、 PS でやった方がラクができるかなぁと思う。要はファミコンとかの時によくあったようなカラーパレット切り替えるような感じというか。
でもそれだけじゃ PS 使うメリット無さすぎなので、 5.fp, 6.fp, 7.fp みたいな感じでピクセルの点の位置情報使ってエフェクトか書けるのはまぁシェーダ特有かもしれない。
エフェクトに使うだけならシェーダの無い環境なら別のエフェクトを使う…とかもまぁしやすいし。
で環境なんだけど、テストに使ってるのは Thinkpad X60 とかで、これ nVidia とか ATI じゃなくてインテルのチップセットなんだけど ARB_vertex_program や ARB_fragment_program くらいは入ってたので、あーそろそろ初代シェーダは存在してると仮定してもそんなにポタビリチー落ちないのかなぁとか思う。
開発は fp/ 以下のファイルを適当にいじってガンガンリロードして動的に動作チェック、ってのは GL のわけわからんパラメータをあちこちいじるよりはラクなように思える。ただまぁ 6.fp や 7.fp は時間情報を使いたかったのでプログラム側からパラメータを渡していて、こういうことする時は元のソースもいじらにゃならんのだけど、理想的にはこのへんの部分こそ Lua とかそいうのに分離できるといいんじゃないかな、やらないけど。
ARB_*_program でコードを書く場合問題になるのはアセンブリで書かにゃならんのでめんどい&保守しにくい、ってこと。特にエラー出た時にどこでエラー出てるかさっぱりわからないのは結構きびしいかも。ただまぁアセンブリって言ってもインストラクションの数少ないしそんなに大変じゃないとは思う。
まぁもちろん Cg を使う、ってのは間違いなく正しい解だと思う。たぶん Cg を使う方法は二種類あって、コンパイラを静的に走らせて fp ファイルを生成する方法が一つ。この方法だと書き換えて即実行のお手軽感がちょっと落ちるかもしれない。もう一つは libcg をリンクして動的にコンパイルしてもらう方法。この方法はお手軽感は損わないけどたいしたことしないのに libcg をリンクするってのもなぁ、とは思う。まぁ開発時は libcg でリリース時は静的にコンパイル、っていう態勢を整えればいいだけの話じゃないかな。
偉そうに色々書いたけど素人もいいところなので、まだまだ機能把握してないし、応用はいくらでもあると思うし、もっとセンスのいいもの書きたいものだと思うけどまぁそのへんはセンスのある人が。
あとまぁ vertex shader の方もやってみたいことはあるので地道にやってみたいと。
ARB_fragment_program 書く時は、ぐぐって出てきた適当なサンプルを ARB の仕様見ながらいじる、って感じでやった。以下の 3.11.4 の項目を見るとまぁだいたいどんな命令があるのかはアタリがつく。 reciprocal が逆数って意味だと知らなくて割り算どうやってやるんだーとしばし悩んだのは秘密。
http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_program.txt
あとは日本語のリソースだとやはり t-pot さんとこが色々ためになった。
http://tpot.jpn.ph/t-pot/program/
あとライセンスは GPLv2 or later 。 fp/ 以下にピクセルシェーダは入ってるけど勉強しながら書き散らかしたものだし汚なすぎるので注意。
あとビルドは以下のコマンドでやってます。
dmd.exe -O -g -Isdl -Iopengl -Iglee *.d sdl/*.lib opengl/*.lib GLee.lib SDL_pad.lib -ofpbg.exe || exit