wxHaskell (その5)

tanakh2004-07-14


前回のでゲームを作るための基盤はおおよそ固まっていたので、
とりあえず何か作ってみることにした。
何か、といってもあれなので、この前コメントをいただいたテトリスを作ることにした。
HaskellGUIテトリス。半年ほど前、Haskellというものを知ったころからは
考えもつかぬことであった。参照透明なのにゲームなんか作れるのかと。


結局のところHaskellでもIOモナドを羅列しだすと何でも出来るし、
また、IOモナドを羅列しだすとHaskellHaskellらしさというものも
あまり感じられなくなってくるのだが、
(たとえばIOが本質じゃないけどIOモナドになってるやつ、
たとえばvarCrate :: a -> IO (Var a) など、
はっきりいってIOなどという胡散臭い?ものを持ち出さずとも
見た目書き換え可能な変数は純関数的に構築できる。
詳しくはStateモナドあたりを調べていただくとして、
実際のところ、後ろに副作用が見え隠れする云々ではなくて
今現在の私にはモナディックなやり方がどうも
関数型っぽく感じられていないのかもしれない。
個人的にはStreamなやり方がまさしく純粋関数的に感じられる。
いやまぁ、モナドなやり方は便利だし、
高階プログラミングの技法としてすばらしいと思うけど、
そのたどり着く先が私の書いたようなコードだとするとちょっと悲しい)
そのせいかどうかは知らないが、当初思っていたほどの達成感は無いような。


…で、なんかよくわからん余談が長くなったけど、
とりあえずテトリスを作りました。
実装はとりあえず前回作ったやつのonProcessとonDrawを書き換えた感じ。
細かい部分でちょこっと書き換えたけど、昨日の時点での思惑は
そんなに外れていなかった模様。
テトリスの処理自体は普通にIOに侵食されずに記述できた。
描画も適当にビットマップ描画するだけなので適当に並べ立て。
昨日のプログラム、あそこまで書けていれば、今日は特に困ることは無かった。
なんというか、すんなり過ぎてあまり話題が無いのだが…
とりあえず、作ってて思ったことなど。

  • 設計技法・シーンなど

C++で作ってたころは適当にシーンクラスを作って、
実行すべきシーンクラスを差し替えながらいろいろやっていた。
Haskellでも、そのようなディスパッチャを作るのは簡単であるが、
もっとHaskellならではの良い方法があるのではないだろうか?

  • 実行ループ

これもC++で作ったときと同様に
ループごとに状態を書き換えという感じになるが、
(要するにFinite State Automaotnを実装するような感じに)
継続を用いればこのような気苦労がいらないのは周知の事実である。
(直接継続を扱えないC++などの言語では
MicroThreadとかFiberなどと呼ばれるコルーチンという形で同様の処理を行える)
Haskellで継続を扱うためにはContinuationモナドを使えるが、
継続を使うプログラムは難解になり易い。
それに、遅延言語はその遅延評価のために
同等の処理を継続を扱うことなしに可能である場合が多い。
要するに、遅延評価を生かして直接的に分断される計算のコンテキストを
管理することが出来るのでは無かろうかということである。

  • 実行速度

今使ってるマシン(PentiumM 1Ghz)でも今回作ったテトリス程度ならば
とくに問題なく60フレーム出る。
(なんかちょっとだけ足りてないような気がしないでもない…
しかし、なんだかCPUパワーを使い切っていない。
使い切っていないのにスキップしてしまっているということは
速度調節ルーチンがどこか間違えているのか、あるいはライブラリのバグか)


説明・考察はこの辺で。
成果物を公開しておきます。
http://fxp.infoseek.ne.jp/haskell/wxTetlis.zip
このプログラム音声が無いのでコロブチカあたりを
自前で用意して鳴らしながらプレイしてもらえれば…
ブロックの絵とか、http://www.linkfever.net/game/tetris.html このページから
ちょっと使わせてもらったんだけど…。まずかったら書き直します。
というか、このページほとんど誰も見てないから大丈夫だよね。


結局、ゲームのシステムの周りはコマンドの羅列になってしまったような
感じがするのだが、一つ特筆すべき点があった。
このプログラム、ほとんどバグが出なかったのである。
GHCにはソースレベルデバッガが無い(と思う)のだが、
そもそもデバッグの必要が無かった。
なんだか今まですっかり忘れていたが、
この点だけでもHaskellを使う大きな利点ではないかと思った。