完璧なプログラミングを目指して

 コードコンプリートを読んでいる。そのサブタイトルが「完璧なプログラミングを目指して」なので、完璧なプログラミングとは何かを考えてみる。何かを目指すにしても、その何かが何なのか分からないのでは目指しようがない。

 プログラミングとはソフトウェアを対象とした領域の活動と考えられることが多い。だいたいプログラミングを仕事としていると言ったら、コンピューター装置の前に座って、コーヒーとキーボードを携えて不可思議な文章を打ち込んでいたりする姿が想像させられることが多い。こうした典型的なイメージのプログラマが扱う領域は、ほぼソフトウェアに限定される。せいぜいハードウェアとのインターフェイスまでだったり、ハードウェアを制御するためのソフトウェアだったりして、直接ハードウェアを製造するものではない。それどころか、現代の最上位のレイヤーで作業するプログラミングは、一切ハードウェアに感知することがなかったりする。厳密には、コンピューターに命令を出していたり、ディスプレイモニターに表示させる画面イメージを制御しているという意味でハードウェアに接しているということができるので、完全に切り離されているというわけではない。しかし、コンピューターやディスプレイモニターの電気的な特性を考慮しながらWebサイトやスマホアプリをプログラミングすることは稀だろう。

 このように、ハードウェアから切り離して、ソフトウェアの領域だけでプログラミングをできるようになっていることは、 抽象化によってもたらされている。現代の複雑なソフトウェアが成り立っているのは、ハードウェアを直接扱わずに、その上に多段に構築されたレイヤーの上で、問題の領域だけを扱えるようになっているところが大きい。もし、今でも直接マシン命令しか扱うことでしかプログラミングができなかったら、現代社会を支えるの多くのソフトウェア基盤はもっと貧弱なものだっただろう。マシン語でプログラミングをするのは開発効率が悪すぎて、複雑な問題を扱うソフトウェアを構築するには時間がかかりすぎる。現実の複雑な問題を解決するだけの複雑さをもったソフトウェアを構築すること自体が困難だったりしただろう。 

 そういうわけで、今の時代、プログラミングとは主にソフトウェアの領域だけの活動を指して言うことが多い。しかし、ハードウェアだけでもプログラミングを行うことは可能だ。スイッチをたくさん取り付けた回路を組んで、手動でそのスイッチのONとOFFを切り替えることで、ソフトウェアなしでも機械の動作を制御することができる。現実に、天井についているライトや、電気スタンドなんかは物理的なスイッチで動作する、ハードウェアだけで構築されたプログラムのようなものと見ることもできる。他には針時計、レコードプレイヤー、エレキギターなどもプログラムのようなものだ。電気的な動力をしようしないものある。楽器はすべて自然界の音に関する性質を利用した一種のプログラムだ。ここまで解釈を広げると、あらゆるものがプログラムに見えてくる。机、椅子は、人間の体型に合わせてプログラムされている。衣類とそれをしまうクローゼット、靴と靴べら、食器と箸、 鉛筆と消しゴム、などだ。別にペアであることを強調したいわけではなくたまたま思いついたから書いただけだ。これらは、現実の問題を解決するために生み出されたという点で、ソフトウェアのプログラムと共通している。そして、人工的に生み出されたものであるという点も共通している。異論は当然あるだろうが、これらをすべてプログラミングによって生み出されたものとし、そして、その活動をプログラミングとしてみなすなら、人工的に自然界に手を加えて、本来の姿形に何らかの別の法則を適用して便利なものを生み出す行為をプログラミングと呼べる。 

 では、プログラミングは人工的な操作を行うものかというと、まだ解釈を広げることができる。 まずは生命だ。生命はコンピューターよりも遥かに高度なハードウェアとソフトウェアを備えている。生体をハードウェアに見立てるなら、遺伝子はソフトウェアといっていい。遺伝子は人工的にプログラムされたものでは、通常はない。しかし、何らかの法則にしたがって、生命単体から子孫を通してその種の生存を制御しようとしている。生命を持たないものでも、プログラムのようなものがある。気象、地形などは、何らかの要因があって、雨が降っているとか、川が流れているというような現象を観測できる。他には、空は青い、東から日がのぼり、西に沈む、夜には月が出る。これらにはすべてなぜそうなっているのかという理由があり、従っている法則がある。これらの法則をプログラムとみなすことにしてみよう。そうしたプログラムを開発することがプログラミングだとすると、プログラミングによって宇宙を創造することができる。こういう存在を神とか創造主とかいったりする。

 ここでようやく完璧なプログラミングとは何か、という問に戻ると、それは究極的には完璧な世界を作るということになる。しかし、そんなことは全く現実味がないし、不可能でもある。そこで、シミュレーションという現実的な選択を取ることができる。世界を完璧にしようなどというだいそれた考えを抱かなくても、自分の好きな形に世界をシミュレーションすることで代わりができる。世界のシミュレーションはコンピューターゲームで実現できる。現実世界と全く同一のゲームというのは、やはり実現不可能という意味で現実味がないのと、面白くもない。逆に、現実で不可能なことを可能とする世界の方が面白い。大部分が現実に近いような仮想世界で、現実で不可能なことができるというのが望ましい。そして、今のゲームはそういう風な方向に発展してきている。これは自分の作りたいものとも一致していて、だからゲームプログラミングの修行をしているというところがある。

 結論を出すと、自分にとって完璧なプログラミングとは面白いゲームのプログラミングだ。いかにコードが優れていても、ゲームが面白くなかったら完璧とは言えない。では、面白ければどんなひどいコードでもいいのかというとそれは違う。ひどいコードのゲームは完璧ではない。完璧なゲームは完璧なコードによって生み出される。ひどい変数名をつかっていたり、ひどい関数名をつかっていたりするコードからは面白いゲームは生まれない。最終的には、読みやすく、誤りがなく、効率的で、保守しやすいコードというありきたりのところに行き着く。そのためには高い技術と豊富な知識と長い経験が必要となる。そんなのは幻想に思えるところもある。実際にどこまで到達できるかよりも、このくらい理想を掲げていないとすぐに堕落してしまう。それくらい完璧なプログラミングというのは難しい。

つまらないゲームを作り続けること

 三並べを作った。しかもCPUなし。一人で二役やらないといけないこのゲームは、もうゲームとすら呼べないのではないだろうか。GUIライブラリのデモとして考えればそうひどいものではない。それにしてもつまらないゲームだ。プログラミング中には色々考えるところがあって、Rustの練習にはなっているように思える。並行してゲームプログラミングの経験値まで稼ごうというのはちょっと欲張り過ぎかもしれない。三並べのような原始的なゲームで一体何の経験値が得られるのかのと軽く見てしまうと良くない。CPUを用意するのはそこそこ良い経験値になりそうだ。今回はやらなかった。どうせつまらないゲームだからと割り切って、GUIライブラリの使い勝手をテストするだけのような形で終えた。一度に完全なものを作る必要はない。10分の動画に収めるには情報が多すぎる。少しずつ発展させていく形にするのもよいだろう。

 とにかく、今回のはGUIライブラリの使い方とRustの練習としてはそこそこ良い経験値が得られたものの、ゲームの方は全然だった。こんな初歩的なゲームを作ることに何の見返りを求めているのか、繰り返しになるけど、そんな風に侮るのは良くない。こういう初歩的なゲームであっても、完璧に仕上げていくことを繰り返すのと、形だけ取り繕った中途半端な完成度のもので満足してしまうのでは、後々、大きな差になって現れる。実利的な立場からすれば、三並べを完璧に完成させたとしても、誰にもプレイされない可能性が高く、中途半端であって完璧であっても大した違いはなく、微妙な部分に多くの時間を割くよりもさっさと次の、面白くなるかもしれないであろう新しいゲームに取り掛かるのが良い。本当に夢中になって継続して作り続けられるゲームをやる方が良い経験になる。

 今思うのは、まだ本格的なゲームの制作に取り掛かるような時間帯ではない。まだ慌てるような時間じゃない。Rustをこつこつやって、ついでにゲームの経験値もためて、いずれは塵も積もれば山となっていることだろう。そういうわけなので、中途半端な状態のゲームを作り続けるのはこの方針にあっていない。面白いゲームを作るというのはちょっとハードルが高い。つまらないゲームを作り続けることの弊害として、つまらないゲームを作ることに慣れてしまい、感覚が麻痺してしまうことも見逃せない。だから、YouTubeに継続的に投稿していきたいという気持ちがあっても、あまりハイペースでつまらないゲームを作り続けるのは褒められたものではない。つまらないならつまらないなりに、完成度を高めておきたい。細かいところをきちっと作り切るつもりでやるのが良い。大体つまらないゲームは完成度が低い。三並べに完成度なんて求めるもんではない、というのは、また繰り返しになるのでもう言わない。

 それっぽく動くだけのゲームというのは、つまらないならつまらないなりに、完成されたゲームに到達するまでのどれだけまで到達しているのだろう。今回の三並べについては、半分もいっていないのではないかと思う。良くて30%、悪ければ20%くらいだ。それどころか、今回作ったのはプロトタイプくらいの水準に到達していないとも考えられる。プログラミングの常識では、プロトタイプのコードは捨てるのが正しい。プロトタイプのコードをもったいないと思って使い続けて本番用に流用してしまうのは、陥りがちな罠だ。もう一度、なぜRustでゲームを作って動画にして投稿しているのかというと、最大の目的はRustの練習だ。ついでにゲームも作れるようになれれば、といったところなので、これもやはり練習の一貫といえる。したがって、その成果として出来上がったものは、本番用のプログラムとは言えない。本番の前段階の試作品、つまりプロトタイプの領域にすら達していない。そもそも具体的な成果を求めていない。経験値こそが最大の報酬だ。この視点に立つと、完璧な三並べのどの段階まで到達しているか、という質問自体が成り立たない。あえて答えるなら0%ということになる。

 目的は練習だけど、完成度は高めておきたい、というのは矛盾を抱えている。練習用に作ったものに、それ以上の意味をもたせるのは無理がある。プロトタイプを使いまわすようなものだ。完成度の高いゲームを作ろうというのなら、最初から目標をプレイして面白い、リリース目的のゲームに設定する必要がある。それをやってしまうと、今度はRustの練習という、どちらかというと実験的なプログラミングの経験ができなくなってしまう。考えられる対策としては、リリース目的のゲームの制作と並行して、練習目的のゲームを作っていくことになる。これはなかなか大変なことに思える。今、練習用にやっているだけでも、ほぼすべてのプライベートなプログラミング活動に対するエネルギーをそこにつぎ込んでいる。これに加えて本番のプロジェクトを稼働させることは不可能に思える。並行処理が苦手なのはプログラミングだけでなく、現実でも同じのようだ。

 無謀な計画を立てるのではなく、とりあえず目の前のことに集中しよう。これまで同じようにRustの練習目的でゲームを作るのは継続していく。ただし、完璧までとは言わないまでも、できるだけ、そこに近づけるようにがんばることにする。でも、出来上がったものはあくまで練習用なので、使い回しのできるものだとは考えてはいけない。あとはどこでRustが使えるようになったかと判断するかだ。時間も有効に使いたい。いつまでも練習ばかりしていられない。

行き詰まったときは

 昨日と今日は、RustのGUIライブラリであるicedを触っていた。なぜicedを選択したのか。しばらくSFMLを使ってきて、あまりRustらしいコードが書けていないことが気がかりだった。SFMLがC++のライブラリだということもあり、バインディングもオリジナルの使いやすさそのままにRustにポーティングされたようになっている。あまりRustらしい書き方を強制されることはない。これは良い面と悪い面がある。良い面は、C++での使い方を知っていれば、同じような使い方であまり迷うことなく始められるということ。悪い面は、良い面をそのまんま裏から見たもので、Rustらしい書き方をしなくても使えてしまうので、Rustらしいコードを書く機会を逃してしまうこと。今はRustらしいとはどんなものなのか分からない。Rustらしい書き方を身に付けたいにしても、どうやればいいのかわからない。SFMLを使うとどのようにも書けてしまうので、これまでC++で使ってきたのと同じように書いてしまうことが避けられない。今必要なのは、Rust流の書き方を強制することだ。SFMLは良いライブラリだけど、今は適切ではない。そう考えて、Rust製のライブラリを利用することにした。

 なぜゲーム用のライブラリで はなく、GUIライブラリにするのか。五目並べとかマインスイーパーのようなパズルゲームを作りたいと思っていて、それってGUIのウィジェット、例えばボタンなどを組み合わせてできそうだと思って、面白そうだと考えた。ちょっと息抜きに変なことがしたかった。RustでGUIプログラミングというのはなかなか新鮮で面白そうだった。ちょっとゲームとは別のことをしてみたいというのもあったかもしれない。ゲームプログラミングは比較的自由度が高い。そのため、どのような書き方でもできるとなると、Rust流の書き方をせずに、これまでの経験を引きずってしまう可能性が高い。GUIライブラリを利用したプログラミングというのは、最もライブラリに近いところでは、フレームワークが定めた範囲の中でプログラミングしないといけないところがある。そのフレームワークに従ったの書き方をしないといけない。通常はそのような制約は窮屈で、言語の可能性を下げることにもなるので、あまり良いものではない。しかし、Rust流の書き方を身につけるためという目的をもって見ると、何らかの制約がもたらされることはむしろプラスの方向に捉えられる。Rust製のライブラリなのだからRust流の使い方を強制されるだろう。そうすれば、どうしてもRust流の書き方をせざるを得ないことになる。これは願ってもないことだ。GUIのライブラリはおそらくゲームのライブラリよりも制約が多い。そこに目をつけた。

 ライブラリはいくつか選択肢がある。 GTKとFLTKが利用できて、使い勝手も良さそうだ。しかし、Rust製ではないので今回の目的にはそぐわないだろうからパスした。Rust製で人気がありそうなのは、icedとeguiだ。eguiはまだ試していない。icedはコンパクトで、割と簡単に覚えられそうな印象をもった。実際やってみると、ライブラリはコンパクトで大量に覚えることがあるというわけではないけど、基本動作が独特な感じになっていて、それを理解してしまわないといけない。Elmという言語のアーキテクチャに倣っていると書かれている。遠回りに思えるだろうけど、Elmのドキュメントを読んだほうが良さそうだ。

 icedを使用する上で困ったことは、ガイド的なドキュメントやチュートリアルがほぼないことだ。それなりの数のサンプルと、十分な量のAPIリファレンスはあるので、それを頼ることになる。今回はまず三並べを作ってみようとした。ボタンを3×3マスに並べて、それをクリックしたときにマスを選択したという風にしたいと考えていた。デフォルトのボタンはマスに見せるには無理がある見た目なので、変更したかった。参考になりそうなサンプルプログラムを探して、ボタンの見た目を変更するコードを発見したのだが、icedのリファレンスにある仕様と違っている。どうやらサンプルが使用しているicedのバージョンが古く、そのままでは利用できないようだった。しばらく時間を書けて、現在のバージョンのicedではどうやればいいかを調べた。その結果、ボタンの見た目を完全に変更することはできないという結論に達した。

 この結論は納得がいかない。ボタンの見た目を変更するなど、ありふれた要求に思える。こんなことすらできないGUIライブラリなどあるのだろうか。結論が間違っている可能性を捨てきれない。そこで行き詰まった。結論が正しいとして、ボタンの見た目を変更するのではなく、カスタムウィジェットがあるので、それを利用するか、結論が間違っているとして、また時間をかけて変更する方法を模索するか、板挟みになった。

 このように行き詰まったときに取ることのできるもう一つの方法は、しばらくその問題から完全に離れてしまうということだ。案外、割と単純なことを見落としていたり、勘違いしていたりすることもある。ちょっとリフレッシュすれば何か発見があるかもしれない。というのは楽観的すぎるだろうか。でも、やはりボタンの見た目が変えられないというのは受け入れがたいので、何かしら方法が見つかる可能性にかけてみたい。これを機にeguiを試してみるのもよいだろう。

面白いゲーム

 昨日は何を作るか長々と書いた末にブロック崩しを作った。Pongのコードの大部分がそのまま使えて楽ができた。今はまだ、とにかく動作するものを作るということに意識が持っていかれて、他のことにまで配慮ができていない。他のことってなんなのかと言うと、2つ無視できないことがある。

 1つ目は、コードの質について妥協していることだ。昨日書いたブロック崩しでは、明らかに問題なところがあったのを認識した上で、とりあえず動作するからこれでいいかと完了にした。練習だしRustに不慣れだからこんなもんでいいだろうという気持ちもあった。何が問題だったかと言うと、ひどく重複したコードがあって、本当なら共通の処理なので関数にまとめ上げるべきだったのを、そのままにしておいた。同じことを繰り返さないというのはプログラミングにおいて大切な姿勢だ。その姿勢はコードの中にも現れる。重複するコードが出現するというのは、典型的な改善するべきポイントとなる。Rustに不慣れだからだめなコードを書いてしまうのではなく、手持ちの能力でも改善できると認識していながら放置していってしまうと、良いプログラミングの習慣を身につけるチャンスをわざわざ逃していってしまうことになる。コードを良いものに作り変えるプロセスには、リファクタリングと呼ばれる名称がついている。リファクタリングについて学んだり練習したりしたことはないのだけど、おそらく今回のコードの重複を取り除くという改善作業は、リファクタリングに該当するのではないかと思う。せっかくプログラムを作ってリファクタリングを適用できる、訓練できる機会があったのに、むざむざとそれを手放してしまうというのはなんとももったいない話だ。コードの質の妥協についてはだいたいこんなところだ。 

 2つ目は、ゲームが面白いかどうかを気にかけていないということだ。既存のゲームのクローンを作るのだから、それが面白いかどうかなんて関係ないと思っていた。練習のために作ったゲームなので、誰も、自分自身ですらもそれで遊ぶことはないと割り切っている。ゲームプログラミングそのものを訓練しいるのであって、ゲームのデザインは自分の仕事ではないと思いこんでいる。確かに、ゲームデザインは自分の本業ではないかもしれない。将来的には、何かしらこういうのを作りたいという要求がどこからか湧いてきて、それを忠実にプログラムすれば面白いゲームができるのではないかという、夢の世界に生きている。現実ではそんなことはありえない。要求のとおりにプログラムするだけで面白いゲームになるわけでもない。これはゲームでないプログラミングについても同じで、要求のとおりにプログラムしたら使い勝手の良くないものが出来上がるというのはよく知られた悲劇で、プログラミングの失敗例だ。

 既存のゲームのクローンを作るというのは、ある意味、要求の分析を行う訓練を行うことを放棄していることでもある。プログラミングそのものを訓練しているのだから、それでいいというのはちょっと違う気がする。プログラミングと要求の分析というのは完全に切り離されたステージではない。プログラミングをどう定義するのかは置いておいて、もし完全に切り離してしまったら場合のコードを書くステージは、プログラミングと呼ぶより、コーディングと呼ぶほうがより適切になる。そう考えた場合、既存ゲームのクローンをとりあえず動作させるというだけの行為も同様に、プログラミングではなく、コーディングというのが適切だ。将来的に、忠実にコーディングだけを行うようなことを生業としたいかというとそんなことはない。面白いゲームをプログラミングすることを生業としたい。

 要求というのは安定しないものだ。特にゲームに置いては、ある程度形になってきてから、ここはこうした方がいいと分かって、コーディングよりも前の段階に戻ってやり直すなど日常茶飯事となる。前に戻るのがコストが高いから妥協するとなったりすると、つまらないゲームがになってしまう。つまらないゲームは、研究対象として興味があるかもしれないというのを置いておくと、使いにくいアプリケーションのような役に立たないプログラムと同じだ。アプリケーションの最大の存在価値化は、便利かどうかというところにある。ゲームの最大の存在価値は、面白いかどうかというところにある。だから、必ずしも実践できなくてもよいのだけど、今作っているゲームは面白いかどうか、というのは常に頭の片隅にでも置いて置かなければいけない。クローンの元となるゲームが面白くないのなら、どうやったらこれを面白くできるかということも検討するべきだ。どうやっても面白くならないのなら、そんなことはあまりないはずだけど、それはクローンする価値がない。そもそもの要求が間違っていたということだ。

 常に面白いゲームを作らなければいけないというのは、ちょっと理想が高すぎるかもしれない。 Rustの使い方がままならず、練習をしている段階でさえもゲームデザインについても考えながらやらないといけないとなると、前も書いたかもしれないけど、二兎を負うものは一兎も得ずの状態になってしまう。そんなたいしたことではない。ちょっとした意識の配分の仕方による。例えば、今回のブロック崩しを例に取ると、ボールの軌道にXとYが反転するだけ以外に変化がないのはいかにも退屈だ。パドルの当たり具合によってボールの軌道や速度に変化があるようにすると、ずっと良くなる。こんな感じで、気がついたことを直していく習慣をつけていくのが良い。その分プログラムはごちゃごちゃしてきて、見通しが悪くなる。これは必ずしも悪いことではない。現実の問題を解決するには、そういう状況に耐えうるようにプログラムを設計しなければいけない。ちょっとした変化をつけるだけで、何がなんだかわからなくなるようなのは、設計が不十分である、複雑さに耐えうるだけのしっかりしたものになっていないからだと考えられる。

 だんだんハードルが高くなってきている気がする。まだやっとこさブロック崩しを作った、という段階で要求やら設計やら考える必要があるだろうか。文字数を稼ぎたかったので、少し話を膨らませて書いたところが多い。本当の話は単純だ。面白いゲームにしたいという気持ちを持ち続けること、それだけ。プログラミングしながらそれを覚えておけば、あとはついて回るだろう。ここはこうした方が面白くなる、だからコードを書き換える、そうするとコードが煩雑になる、だから基本から設計をやり直す、と自然にそういう流れになるだろう。この練習を繰り返すことは、Rustの習得という点においても、そんなに効率が悪いとは思わない。

 そういう方向でやっていこう。

意外と作るものがない

 Rust練習のために丁度いいゲームがないか探している。1ファイルで収まるくらい小さくて、可能な限りシンプルなものが良い。ありそうでなかなか見つからない。よく挙げられるのが2Dのシューティングなんかだ。シューティングゲームはどの程度作り込むかによってプログラミングの規模に大きな幅がある。シューティングゲームに限ったわけではない。ただ、シューティングゲームは根底のゲームロジックはどれも同じだ。敵に弾を当てる、敵の弾を交わす、それだけなので、シンプルなゲームと言える。プレイして面白いかどうかなどは求めていない。ゲームを作ることが目的ではなく、プログラミングの練習ができれば良い。結果として何かを残したいだけだ。とりあえず動作すれば良い。

 シューティングゲームの名作だと、自分の中ではグラディウスが真っ先に思い浮かぶ。これのクローンを作るのはなかなか大変だ。練習のためのモチーフとしては複雑過ぎる。他に思いつく、もっとも有名なシューティングゲームはインベーダーゲームだろう。グラディウスに比べればシンプルだ。練習題材として十分にシンプルだろうか。少なくともPongよりは難易度に高いように見える。Pongは画面にパドルとボールという2つの要素しかない。インベーダーゲームは、自機、防壁、敵がたくさん、UFO、敵の弾、自機の弾、こんなにもたくさんある。必ずしもこれらを全部作らないといけないわけではない。Pongと同じくらいシンプルにするなら、敵が1体と自機で弾を打ち合うということもできる。なんなら敵は弾を撃ってこないようにして、1対1で、一方的に敵に弾を当てるだけとしてもよいだろう。これならPongより少しだけ要素が増えただけで、十分にシンプルといえるのではないか。ただ、これを作っても何かをやってやったという達成感が得られないのが残念なところでもある。PongはPongとして完成されている。インベーダーゲーム先に上げたような要素全部が入ってインベーダーゲームだ。一方的な1対1だともはやインベーダーゲームの名前で定着しているものとはまったく異なるので、完成されたゲームとは言えない。クローンを作ったとは言えなくなる。

 クローンを作ることにそれほど固執する必要はないだろう。絵のデッサンとは違う。絵の贋作を作ることにそれほど重きを置く必要もない。先日のPongも、オリジナルの特徴的な部分を抽出してそれっぽく見せたものに過ぎない。オリジナルのプレイ感やゲームを面白くするために工夫されている様々な調整が欠落していて、クローンであるとは言えない。目立つのは、パドルの操作にかかる慣性や、ボールを打ち返すときにパドルの状態によって軌道や速度に変化を与えるなど、ゲームに変則的な法則を取り込んで、プレイヤーにゲームの状態を予測させることで楽しみや快感をもたらす、そういったぱっと見は分からなくても、ゲームの面白さを決定する重要なところが欠落している。そういうのを作り込むのは、ゲームプログラミングの練習には重要とは言える。今はまだRustの基礎を練習しようとしていて、ゲームプログラミング自体にはに重きを置いていない。どうせ作るならゲームがいいかなという程度だ。なので、Pongあれで良かった。あのくらい簡単なものがちょうどいい。

 昨日書いたのだけど、ある程度の複雑さがないと、Rustの特徴を活かしたプログラミングをする必要性がなくなってしまう。1対1の一方的なシューティングゲームを作るとして、シンプル過ぎるのではないだろうか。たぶん、シンプルすぎるように思える。しかし、やってみないとわからないところでもある。一発で成果を得ようなどと考えず、何度か繰り返していって感触を掴んでいくのが良い。何度も繰り返していれば、だいたいどの程度の規模感なのかを予測できるようになって、Rustの練習としてどの程度有用かも把握できるようになっていくだろう。今はまだシンプルすぎることを懸念しすぎるような時間じゃない。とりあえず1対1のをつくって、次に敵を増やして、弾を撃ってくるようにして、と段階的に発展させていくとよい感じがする。Pongしたって、あれで完成とはせず、オリジナルはやったことないのだけど動画で確認できるような、それに近づけていくのも良い練習になりそうだ。

 だいたい1対1の一方的なシューティングが候補に見えてきた。他にもいくつかある。テトリスとか、ブロック崩しとかどうだろう。テトリスは原始的なバージョンであってもそれなりに複雑なプログラムになる。さらに面白くしようとすればいくらでもやることがある。現在でも活発にプレイされているような完成されたルールと拡張性を備えた奥の深いゲームだ。ブロック崩しは、対人戦がないからというのもあって、テトリスほど現役のゲームではない。その分、基本的なプログラムのシンプルさという点では軍配が上がる。複雑なゲームであると、完成させることからとりあえず動作させることに意識が持っていかれる。そしてRustの練習をするという目的から外れてしまうことがある。コードがとりあえず動かすためにやっつけ仕事になってしまうということがある。意識していればそんなことにはならないというのは当てにならない。長い時間コンピューターに向かっていると、早く終わらせて次に行きたいという気持ちが湧いてくるのは避けられないことだ。テトリスはそれなりに複雑なロジックがある。ブロック崩しはPongのちょっと複雑なバージョンといった程度でちょうどよい。テトリスの原始的なものはいろんな言語で作ったことがあるけど、そんなに成果が得られたという感じがしない。どうしてもとりあえず動作させることに意識が持っていかれてしまい。言語を注意深く観察することを降ろさかにしていたためと思われる。ブロック崩しはあまり作ってこなかった。テトリスとブロック崩しのどちらかにするとなったら、ブロック崩しが良いだろう。

 ここまでで、次の候補は、1対1の一方的なシューティングか、ブロック崩しとなった。当初考えていたのは三並べのようなパズルゲームだった。具体的には、Simon Tatham’s Portable Puzzle Collectionのクローンを作っていくことで練習にしようと思っていた。いたのだけど、こういうパズルゲームは、リアルタイム性がなくて、SFMLのようなライブラリとはあまり相性が良くない。典型的なメインループを中心にフレーム単位でゲームを回すという処理が必要とされない。不可能ではないし、特段難しくなるというわけでもない。そうなのだけど、これはGUIライブラリを使ってやってみたいと思っていた。GUIのフレームワークが想定する、おそらくイベントドリブン型のプログラムでやってみたい。なので、もう少しあとにとっておくことにする。

 もっとさくさく作りたいものが見つかるかと思っていた。意外と見つからない。Rustの練習のためという名目があるので、ちょうどよい感じになるかどうかを考えると、かなりの制約があることが分かった。一番良いのは楽しみながらやることだ。やらなければならないという負の感情を抱えたままやるよりも、楽しんでやったことのほうがずっと脳はよく記憶してくれそうな気がする。楽しむということでは、自分でオリジナルのゲームをデザインしてそれを作るというのがベストだ。まだそこの領域まで到達していないので、今はクローンをたくさん作って行くことで我慢しておこう。

Pongを作った感想

 Pongを作ってみた。Rustの動画を投稿したいと思って、何かしら作らないとネタがなかったのでとりあえずやってみたという感じだ。やってる最中は、こんな書き方でいいのだろうかと疑問がついて回った。そんなに難しいという感じではなく、CやC++で書くのとあまり違いはない。それもそのはずで、CやC++で書くときと同じ思考で書いている。結局の所、どの言語でも通用するような、公約数の部分だけを使って書いている。Pongのような単純なプログラムでは、熟練度が低いうちは、意図的にでもそのプログラミング言語の特性を強調しようとしないと、表に出てこない。どの言語でもかけるような解決法があるのなら、わざわざ専門的にならなくても、その方法を使えば良いというのは正しいやり方なのだろうか。

 Pongを単純なプログラムとみなすかどうかは微妙なところだ。とりあえず動くものなら簡単に作れるという意味では、単純であり簡単ともいえる。手の混んだ解決策を探さなくても、ストレートに書いていけば、とりあえず動くものは完成する。ライブラリが、今回はSFMLなのだが、低レベルな部分を吸収してくれて、高いレベルでプログラミングができるからそうなのだということは置いておいて、低レベルなところは無視する。SFMLの上に構築する基礎部分と純粋なゲームロジックだけに目を向けよう。そうしたとき、とりあえず動くものが作れるから、簡単だとなめてかかるよりも、どうやればよりRustらしいコードになるかを模索するのに、ちょうどいいくらいの複雑さを持っているように思う。しかし、Rustらしいとは何なのだろう。不必要に賢くなろうとすることは、良いプログラミングの姿勢とは言えない。しかし、Rustを全く知らない誰でも理解できる部分だけ使ったコードが、もっとも単純で良いコードになるのかというと、それは違うだろう。賢くなりすぎず、シンプルにしすぎない、この相反するような姿勢をバランスよく保つのがまず目指すところになる。もう少し具体的に言うことができればいいのだけど、思いつかない。シンプルという言葉はあまり適切でないかもしれない。プログラミングだけでなく、多くの分野でシンプルであることは好まれる。今言いたいのは、今回やったPongのように、多くの言語の公約数的な部分だけを使ってプログラミングすることを指している。反対に、賢くなりすぎるとは、使用する言語の秘伝のテクニックを多用するようなことを言う。シンプルすぎればコードは冗長になり、賢くなりすぎると冗長さは軽減されるが、理解するのに言語の詳細な知識を備えていることが条件になったり、直感的でなくなる場合がある。別の例えを使うと、最適化に対する警句が適用できるかもしれない。時期早々な最適化は諸悪の根源だという。時期早々な不最適化も避けるべきというのを聞いたことがあるけど、時期早々な最適化に比べればりは強くはない主張だった。これらの警句を賢くなりすぎることとシンプルすぎることに対応させると、ちょうどよい感じに思えなくもない。賢くなりすぎずに問題を解決できるならそれ以上はやらないほうがいい。しかし、あまりに非常識なRustにそぐわない方法を取るべきではない。

 だいたい目標が見えてきた。これから目指すところは、賢くなりすぎない程度にRustらしいプログラミングを身につけることだ。Rustらしいとは、漠然と思い浮かべているのは、トレイトを活用したジェネリックなプログラミングだったり、並行処理や非同期処理を活用したプログラミングだったりするのかもしれない。こういうのには憧れるが、Pongにはオーバースペックなので、出番はもともとなかったように思える。もし無理矢理にでも使っていたら、それは賢くなりすぎたという結果に終わっただろう。もしトレイトや並行処理を多用してRustを活用している気になりたいのであったなら、それに見合った問題に取り組むべきだ。この問題を自力で見つけ出すというのは、経験が不足しているうちはなかなか難しいことに思える。現段階ではそれらを身につけられていないからこそ、練習したいのでそういった問題に取り組みたいのだが、どういった場面に最も適合しているのか、例えば、この問題はトレイトを使えばうまく解決できるなどといった具合に判断ができない。取りうる手段は2つ思いつく。1つ目は最適な解決策なのかどうかに関係なく、無理やりにその手法を適用させてしまうことだ。これはさっき言っていた、賢くなりすぎることだ。目的は練習のためであると明確であり、事前に賢くなりすぎていると自覚しているのであれば、弊害はそれほどないだろう。練習であると割り切って数をこなしていけば、適用するべき場面のパターンのようなものが見えてくる可能性がある。ただし、これはあくまで練習であって、本来やるべきでないことをやっているということを常に忘れてはいけない。そうしないと、無意識に賢くなりすぎてしまう癖がついてしまう危険性がある。2つ目は、誰かが、Rustの達人たちが用意してくれたフレームワークで問題に取り組むことだ。例えば、Rust製のWeb開発のためのフレームワークや、GUIライブラリ、ゲーム用のライブラリなど、決められた枠組みの中で、型にはまったプログラミングを要求するものがある。その要求されるプログラミングはRustらしいものであると期待ができる。そういったものの利用して問題に取り組めば、問題の性質に関係なく、フレームワークが要求するやり方でやらなければならないので、否応なしにRustらしいプログラミングを体験することができる。思いついたのはこの2つだ。どちらか一つだけに絞らないというわけではなく、併用していくのが良さそうだ。

 Pongを作っただけにしては、こうして今後の心構えというか方針がはっきり見えてきたことは、大きな収穫だった。作っている最中にも作り終えたあとにもこんなことを考えていたわけではない。こうやって文章に書き出しているうちに出てきた。今の練習のサイクルは、①何か作る、②動画にして投稿する、③ブログに書き出す、となっている。時間はかかるけど、学習効果はそこそこな気がする。といってもまだ目的を取り違えているところは否めない。本来は、Rustを使いこなせるようになることや、プログラミングの学習をすること自体が目的というわけではない。ゲームを作ることが目的だ。しかし、1回だけの大作を作るのではなく、継続的にゲームを作り続けるというのが健全なあり方だろう。そのためにはどうしてもプログラミング自体が目的になったり、学習して熟練度を上げていくということ自体が目的になったりするものだ。したがって、学習することそのものに対して熱意を抱くことは恥じるべきものではない。かといって、誇るべきことでもない。学習の過程をスキップして直感だけでプログラミングができる人も稀にいるようで、そうした人と比較したときどちらが神に愛されているかといえば、後者かもしれない。そうした人に向かって、あなたは学習を実行しないから恥ずべきだと告げるのは滑稽だ。色んな方法がある。たかがPong、されどPong。

動画投稿について考える

 1ヶ月とちょっとぶりに動画を撮って投稿してみた。今日は書くことがないのでそれについて書いてみることにする。以前raylibを使ってみるというテーマで30本ほど撮った。どれも1時間超えのプログラミング実況といった内容だった。何も準備なしでやる自信はなかったので、予め、一度コードを書いてから、それをもう一度実況を交えながらやり直すといったものだった。raylibの機能に焦点を当てたかったのだが、成り行きでゲームを作る方向にシフトしていった。1回やったことをもう一度繰り返すのと、確実に何をやっているかを確かめながらコーディングするということで、学習効果はそこそこ高かったのではなかったかと思う。それで目的は達成できていた。そこそこの成果が得られたと思っている。

今回はRustでゲームを作るというテーマで撮っていく。すでに3本アップロードした。前回のように、すべてを実況するのではなく、その日その日の要点だけをアップしていくというものにするつもりだった。前回のは長すぎて、密度が低すぎると反省しているからだ。今日の3本のうち、最初の1本は良かった。15分で終われた。これはいける、と思ったのだけど、2本目は30分、3本目は1時間と、結局前と同じになってしまっている。これは良くない。明日から修正していかないといけない。どうやったら短時間で必要なポイントだけ記録することができるだろう。コーディングを実況というタイプの動画だから、どうしても長くなってしまうのだろう。コーディング実況は録画でやってもあまり面白みがない。やるならライブ配信の方が面白そうだ。しかし、ライブ配信は敷居が高い。まず、誰も見てないのにライブ配信するというのがちょっとしんどい。これまでの録画してきてアップロードしたものは、再生回数を稼ごうなどという気はまるっきりなかった。そのはずだったのだけど、あまりに再生されなさすぎなので、残念な気持ちがまったくないと言ったら嘘になる。自分でページを開いてしまうとカウントされてしまうので開かないようにしていたので正確な数がわかる。1本につき大体5回といったところだろう。再生時間は1分未満がほとんどだ。本音をいうと、100回とは言わないが、30回はほしいところだ。

不本意ではあるが、なぜ再生されないのかを考えてみよう。喋りが良くない、声が良くない、内容よくないといったところだろう。一言でいうとつまらないからだ。アイコンがデフォルトのままだしチャンネルページの見栄えも良くないし、タイトルや説明に情報が少なすぎて検索にもかからないだろう。不運にも動画を開いてしまった人はこいつは一体何がしたいのだろうと不審に思うに違いない。何をしたいか、自分でもよく分かっていない。動画として残すことで、そのために行ったプログラミングを定着させる効果が見込めると思っていたのだが、だんだん動画を完成させることの方に意識が持っていかれる。確かに多少の効果はあるだろう。しかし、もっとも良い手段とはかけ離れている。もっとも良い手段とは何だろう。現実のプログラムを書くことだ。ゲームを作ることがゲームプログラミングの能力を向上させる最高のプロセスではなかろうか。その過程を取り繕ったように動画に仕立て上げることに本当に価値はあるのか、疑問だ。前回のraylibの動画から得られた教訓は、そのようなことに時間をかけるくらいなら、さっさとゲームを作れ、技術をみにつけろ、ということだ。今回も同じようなことをやっていたら、まるで成長していないということになる。今日やってみてそれに気づけたことだけでも良かった。

実をいうとさっきまで、この投稿を書くまではそうは思っていなかった。これからしばらく、Rustが使えるようになるまで、同じようなサイクルでこつこつアップロードしていこうと考えていた。たった今、こうやって振り返ってみることで、それに気づけた。このブログは特に目的もなく始めたのだけど、かなり自省を促す効果があるようだ。 これは続ける価値がある。YouTubeはどうだろう。何か得るものがあるだろうか。さっきも書いたけど、その日行ったコーディングを繰り返すことによって、プログラミングを定着させるという効果は見込めるものの、もっと良い手段は他にもある。ゲームプログラミングができるようになりたいならゲームを作るのが一番良い。今日の動画をアップロードするまでに準備なども含めて費やした時間は、おおざっぱに5時間くらいではないかと思う。この間に何ができただろう。これからもこのように時間をかけていていいものだろうか。

だんだんと動画を投稿し続けることが否定的な方向に向いてきた。学習効果だけを期待すると、良いものとは言えないことが明らかになってきた。しかし、それだけが理由でやってきたわけではなかった。動画を取り終えてアップロードしたときの、やってやった感、達成感はなかなかのものだ。数時間の作業の見返りとして得られる達成感は中毒性がある。それにもし再生回数までついてきたらもうどハマリしてしまうだろう。もしかしてドハマりする前に気づけてよかったのかもしれない。もうちょっと冷静になってやるべきだ。動画を投稿するのは楽しいだろうかと言われると、そこそこ楽しいと思える。それは良いことだ。過酷なトレーニングの合間の僅かな楽しみとして、ちょっと趣味としてやるだけなら、悪くない。ただ、全力で、半日や1日かけてやるようなことではない。ゲームの完成を動画の投稿と同一にしてしまうべきではない。もし続けるならもう一度やり方を見直す必要がある。

完全にやめてしまうのはちょっと惜しい。せっかく見つけた密かな楽しみなので、も少しやってみたい。理想は、1日30分くらいの時間を確保して、その時間内にすべての作業を完了させることだ。30分ではその日の成果をリプレイすることは不可能だろう。また、そんなものの需要は皆無であることはもう前回のシリーズで身を持って知っている。動画の長さは重要で、10分程度でないといけない。その時間では実況コーディングは不可能なので、もうやらない。その日作ったゲームのコードに解説を加えて再考するというのはどうだろう。これなら10分程度で終わるのではないだろうか。振り返ってみることで定着を測るという目的にもあっているように思える。悪くない、しばらくこの方針でやってみよう。ライブ配信はどうだろう。今はやる価値がなさそうだ。もう少しうまく喋れるようになってからのほうがいいように思える。練習としてやるのはありだけど、それ以外の成果は期待しないほうがいい。まずRustがまだ全然馴染んでいないこの状態でやるのは、無謀に思える。ということでなしだ。学習過程をオープンにするというのは新鮮で試してみたい気もする。しかし、中毒性が高そうで、前と同じ罠にハマってしまいそうだ。危険なのでやめておこう。

だいたい方針が決まったので満足した。

 

急がば回れ

 Rustで少し書いてみた。やったことは、SFMLを使ったゲームプログラミングの本を読みながら、C++で書かれたコードをRustで書き直すといったことだ。まだRustでどのように書けばいいのかわからなかったので、何かしらガイドになるものが欲しかった。題材はゲームがいいだろうというのと、SFMLのRustのバインディングが公開されている、SFMLの本を選んだ。オリジナルのSFMLのAPIとは異なるところが多々あって、思うようには書けない。それはまだ想定内なので何も問題ではない。懸念しているのは、C++のコードをそのままRustに書き直すということで、間違ったRustの使い方をしてしまうのではないかということだ。読んでいる本は、C++のクラスをベースとした設計、要はオブジェクト指向のような設計になっている。継承を多用していないのであれば、データ型とメソッドでそのまんま書き直すことができる。それが問題に思える。まだ、Rustらしいといえばいいのだろうか、よいRustのコーディングスタイルを身につけていないので、こういうときはこう書くべきだというのが何もない。何もないからこそ、下敷きになるものが欲しくてC++のコードが手に入るSFMLを選んだのだけど、もしかしたら逆効果なのではないかという気がしてきた。SFMLのRustバインディングを使うことは、それほど悪い選択肢ではない。問題なのは、C++をそのまんま書き直すということでRustを身につけようとしていることだ。今はまだまっさらの白紙に色を塗るような、あるいは吸収力の高いスポンジのような状態であって、今からインストールする習慣は何の抵抗もなく受け入れてしまうことだろう。良い方向で考えれば、高効率で身につけることができる。悪い方向で考えれば、良いか悪いか判断ができず、間違った習慣までもすんなりと受け入れてしまう。また、間違った習慣のためを記憶してくために、空間を無駄に消費してしまう。

 プログラミングの学習は、反復と修正を繰り返すプロセスだ。かならずしも良い方法、グッドパーツだけを回収することだけで上達するものではない。間違った方法を経由することもあり、しばらくしてから間違っていることを認識して、これは間違いだったと身体と頭に刻むことで、同じ間違いを繰り返さないようになっていく。実験的なプロセスとも言える。だから、一度に正しい方法だけを選択するよりも、失敗も数多く経験することによって学習を繰り返しながら身につけていくのも有効な手段だと言える。通常はそうだ。しかし、今はちょっと状況が違う。

刷り込みというのがある。今はまだ卵から孵ったひな鳥のような状態だ。この状態で見たり触れたりしたものは、たとえ姿かたちがまったく違っていたとしても、同じ巣にいる親鳥を親として認識してしまう。これはもしかしたら危険かもしれない。SFMLを選択したのは、本があるからといのもあるが、もう一つはC++で慣れているからというのがある。まずRustそのものになれるために、練習として何も考えず書き直すということで、文法を身につけようという算段だ。文法だけを身につけることができるのならば、これは悪くないように思える。しかし、余計なものまでついてくる。C++でこう書くところはRustでこう書けばよいのか、という情報だ。これはC++とRustの公約数だけを使ってプログラミングすることを意味する。今は孵ったばかりのよちよち歩きの状態で、この状態でそのようなプログラミングをやり方を覚えてしまうと、まさに刷り込みの効果により、これからもそういうやり方から離れられなくなってしまう可能性がある。修正が難しくなってしまう。SFMLの資産を有効活用できないのは残念だが、諦めたほうがいい。初期投資をけちって、大きな機会を損失出してしまうことになりかねない。

SFMLを使うことに問題があるわけではない。SFMLのRustバインディングは、たぶんRustのイディオムに適合するように書き直されているだろうから、姿かたちのまったくことなる親に対する刷り込みが起こるということにはならないかもしれない。それでも、C++が頭にあるので、それを振り払うのを意識を持っていかれる点は無視できない。もしかしたら、それはまだ許容できるかもしれない。一番まずいのは、C++で書かれた本をRustに書き直すという学習方法だ。Rustの何の経験もない状態でこれを行ったら、確実に刷り込みが起こる。非常に残念だが、今回はこの方法は諦めざるを得ない。もう少し経験を積んで、良いか悪いかの判断くらいできるようになってからにした方がいい。

 今日はそういうことをやっていたのだけど、早い段階で気づけたのはラッキーだった。最初良さそうに見えた方法が、実はあまり良くなかったというのはプログラミングではよくあることだ。学習方法にも同じことが言える。もっというと、何かしらの方法を選択しなければいけないという状況においては、分野を問わず似たようなことが発生するのかもしれない。なので一度立ち止まって、本当にこの方法は正しいのだろうかと自問してみることは大切かもしれない。急がば回れ、とはこういうときに使うのかと学んだ。

それで、どうやってRustを身につけるかをもう一度考えてみよう。ベストはRustを使ったゲームの本があると良い。Packtのライブラリを見ると、一応あるにはある。ただ、それはWebAssemblyとタイトルがついている。これはちょっと手に負えない感じがする。難しいとかじゃなくて、むしろ、WebAssemblyはやりたいくらいなのだが、まだRustがままならないうちにWebAssemblyに手を出すのは時期尚早ということだ。一度小規模なプロジェクトを経由してから手を付けるのがいいだろう。それ以外にはゲームの本は見当たらない。ここは本かゲームかどちらかを諦めよう。二兎を追う者は一兎をも得ずという警句もある。本を選択する場合、言語解説中心のものは今は良いだろう。オライリーのを読み終えたばかりなので、まずはこれを血肉にするために、リファレンスとしてオライリーのを活用しながら、プログラムを書くのが良い。白紙状態からプログラムを書くというのは流石に効率が悪いので、プロジェクトベースで解説を行う本があると良い。Packtのライブラリに2冊ほど良さそうなのがあるので、それが選択できる。ゲームを選択する場合の方法は、Rust純正のゲーム用ライブラリを使って、その環境の中でゲームを作るというものだ。ライブラリはいくつか選択肢がある。そのライブラリの利用方法を学びながら、Rustのプログラミングスタイルを定着させようという狙いだ。まだ二兎を追っているような気がしないでもないが、大丈夫だろう。ゲーム専用のフレームワークでなくても良い。汎用的なGUIライブラリであれば、シンプルなパズルゲームなどは作ることができる。

大体今後の方針が固まってきた。本をベースにプログラムを書くのと、Rust純正のライブラリを利用してゲームを書くのどちらかだ。同時進行は可能だが、一緒くたんにしてはいけない、別々に進める必要がある。

OOP離れについて考える

 今後Rustに移行するにあたって、オブジェクト指向プログラミングの世界からどうやって離脱するかを考えておきたい。Rustはオブジェクト指向を採用していない。これは良い知らせだ。オブジェクト指向にはずっと馴染めないでいた。C++では、それが可能だからという理由でお付き合いをしていただけで、可能ならもっとシンプルな方法を取りたかった。C++にとってオブジェクト指向は重要な要素であり、また有用であることを否定することはできない。現実の問題を解決するときに、特に設計段階においては、強力なツールとなる。プログラミングを始めたばかりの頃は、これが唯一のC++の使い方だと思いこんでいて、必死になってその技法を身につけようとしていた。それを今でもずっと引きずっている。C++は別のプログラミング方法もサポートしている。現に標準ライブラリはオブジェクト指向をベースにしたものになっていない。オブジェクト指向は自分に合わないというのは割と早い段階で気づいていた。だから、バッサリと手を切ってしまって、別のプログラミングスタイルを身につけることにしても良かった。だけど、それはできなかった。C++がオブジェクト指向を全面的にサポートしている以上、何を書くにしても常につきまとう。何を書くにしても、例えばHello Worldを書くだけにしても、常に頭の片隅にはオブジェクト指向がある。これはもう強迫観念と言っても良い。もう10年くらい前になるだろうか、突然、少なくとも自分には突然に思えたのだが、関数型言語が注目浴びるようになった。このときは嬉しかった。もしかしたらオブジェクト指向をもうやらなくてもいいのかもしれない、と思った。今そのようなキャンペーンは終了したのか、さほど関数型言語が取り上げられることは少なくなってきたように思える。自分の中でも落ち着いてきた。しかし、今でもやはりHaskellのような言語を使えるようになりたいという思いは消えていないし、今も学習を継続している。本当は、関数型言語は突然現れたのではない。昔からずっとあったものだ。ただ、視界が狭かったから見えてなかっただけだった。もし、最初にオブジェクト指向に疑念を抱いたときに関数型言語が目に入っていたら、その時点で乗り換えることができていたかもしれない。そう話は単純でないかもしれない。C++をどうしてもやらなければいけない理由があった。ゲーム開発で利用される言語だったからということを真に受けて、それしか選択肢がないと思っていた。もし、ゲーム開発でもっとも利用される言語がHaskellだという情報があったら、とっくにHaskellに乗り換えていたことだろう。

 これは10年以上前の話だ。現代では、まだ圧倒的な優位にあるのは変わりないが、ゲームプログラミングならC++一択だというほどではなくなってきている。それでもC++を使い続けている理由の一つに、言語に対する執着や愛着というものがある。一方でオブジェクト指向に対する嫌悪感もある。その相反する感情が入り混じって、どうにもすっきりしない状態がずっと続いていた。C++ではオブジェクト指向を採用しなくてもいいという逃げ道がある。そこへ逃げればよかったのだけど、それもできなかった。オブジェクト指向を採用しないプログラミング技法についてのガイドラインがイマイチ不明であったため、なかなかものにできなかったからだ。簡単な方法がある以上、そちらの方へ流されてしまうのは仕方がないことだ。C++を使うけどオブジェクト指向は絶対採用しないという強い意思がないと、STLのような素晴らしいライブラリを発明するのは無理だろう。普通の人間にはなかなかできないことだ。良いガイドラインがないといったけど、Boostライブラリのような優れたライブラリのドキュメントは結構あるものだ。ただ、オブジェクト指向を採用しないアプリケーション開発についてのものはそんなに見つからない。ゲームプログラミングにおいては、書籍とかだとまず何かしらオブジェクト指向的な手法を使っている。そういったものをすべて無視して、独自の技法を編み出してやらないといけないというのは、自分の熟練度じゃちょっと厳しい。もしかしたら、そこを模索して考えだすのが楽しいのかもしれない。今から始めてもいいけど、今までやらなかったのだからこれからもやらない可能性がある。いや、きっとやらない。

 オブジェクト指向をやりたくないからC++をやめるというのは、極端な選択だ。それだけが理由ではないが、もしRustがオブジェクト指向を中心に据えた言語だったら、たぶんそれほど魅力を感じなかったのは間違いない。Rustがオブジェクト指向を完全に排除しているわけでもないように思える。先日、GTKのRustバインディングであるgtk-rsをいうのを触ってみたのだけど、それはオブジェクト指向をベースとしている。GTKはGObjectをベースにしたちょっと特殊なライブラリであるので、参考にはならないかもしれない。しかし、可能だということだ。ただ、これは、Cでオブジェクト指向が可能といっているのとさほど違いはなく、Cを使うときにオブジェクト指向を意識するかというと、通常はしない。それと同じことで、Rustを使うときにオブジェクト指向を意識するかというと、たぶんしなくて良いと踏んでいる。C++を使うときオブジェクト指向を意識するかというと、おそらく悟りでも開かなければ、どうしてもしてしまう。Rustも、データに関連付けられたメソッドを中心に何かを行うというのはあまり変わっていない。さらに、継承、多態、カプセル化といった要素も含まれているように思える。しかし、従来のオブジェクト指向とは随分異なっているように見える。何より、Rust自身がオブジェクト指向言語だと公言していないので、きっとそうなのだろう。

 オブジェクト指向から離脱したあとに何が残るか、まだ分からない。関数型言語であれば、きっと関数型言語のプログラミングスタイルを身につけることに没頭すれば良くて、分かりやすい。Rustの場合はどこへ向かえばいいのかまだ良くわかっていない。登場して10年と少しといったところで、最近急激に成長した言語で、ユーザー数も多く、そこそこのノウハウが蓄積されているだろうから、まずはそういったところを吸収していくのが良さそうだ。プログラミングスタイルを身につけるのはいいとして、もう一つ重要なのが、設計手法だ。オブジェクト指向による設計を諦めるということは、何かしら別の方法をまた身につけないといけないということになる。問題をクラスに分割して、サブルーチンに分割して、といった手法があまり通用しなくなるのではないか。もっとも、設計についてちゃんとした訓練をしてきたわけでもないので、それほど失うものはない。これからまたリフレッシュしてやっていけばいいだけだ。

Rustでなにか作る

 「プログラミングRust 第2版」を読み終えた。これでRustを使い始める準備はできた。スタート地点には立てたのではないだろうか。記憶は風化していくものなので、ここで満足せずに継続的にプログラムを書いていくことが求められる。どんなプログラムを書いていくのがいいのだろうか。Rustはシステムプログラミングの分野でCとC++を置き換えることを考えられて作られた言語だ。なので、システムプログラミングをやることがRustを知るには最も良い方法となるのだろう。最近の動向では、システムプログラミングとは呼べないような色んな分野で活用されているようだ。例えば、WebAssemblyやマイクロサービスによるWebアプリケーションとかでの活用だ。他にも、GTKは公式のバインディングが提供されていたりして、デスクトップアプリケーションでの活用も、実際にどれだけ利用されているのかは置いておいて、進んできている。ゲームもそうだ。「プログラミングRust」では、システムプログラミングとは何かというのが書かれていて、その中にゲームも含められている。ゲームは比較的速度が求められる。おそらく、どんなゲームというわけでもないだろう。ここで想定されているのは、最新のグラフィックスハードウェアの性能を限界ギリギリまで引き出そうとするような、一部のトップタイトルのことを指しているのだと思う。1日で書けるようなクラシックでシンプルなゲームをシステムプログラミングと呼ぶことはないのではないかと思う。今作りたいのはそういうシンプルな練習用のゲームだ。そういうゲームにRustの安全性は過剰だし、効率性はオーバースペックなように思える。本当にRustが必要とされるのは、やはりシステムプログラミングなのだろうから、システムプログラミングを題材としてトレーニングしないとRustの真の性能を引き出すことはできないかもしれないし、良いプログラミングのスタイルは身につかないかもしれない。でも、そんなに構えて、こうあるべきだ、とかならなくてもいいかもしれない。まずはシステムプログラミングにも、そうではない、普通のプログラミングにも当てはまる、公約数の部分のプログラミングを身につけることを目標にするといいだろう。ちょっと回りくどい。わかりやすく言うと、今までやってきたことをRustに置き換えてやっていって、徐々になれていくということだ。その一環として、シンプルなゲームを作っていきたい。

新しいことにもチャレンジしたい。さっき書いたWebAssemblyは興味がある。Rustじゃないとだめなのかどうかは知らない。ただ、Rustの本でそういうのを見かけたというだけ。今の時代、ゲームの最大のプラットフォームはスマホだろうけど、次点でWebが来るのではないだろうか。ゲームの規模や特徴にもよるけど、シンプルな練習用の2DゲームにPCやPlayStationなんかは大げさ過ぎる。そういうのが存在していても、あまりプレイしたいという気にはならないだろう。プレイしてもらうことが目的ではないのでそれはそれでいいかもしれない。しかし、誰にもプレイされないゲームというのは虚しいものがある。Webはそういう心配はあまりない。つまらないゲームでもページを開くだけでプレイできるというのは、考えられる最も手軽なプレイ環境ではないだろうか。積極的に面白いゲームを探している人でなくても、何かの弾みでついそのページにたどり着いてしまうということが考えられる。経緯はなんであれ、作ったものが使ってもらえることは嬉しいもので、次のステップへの弾みになる。今の時代、よっぽど目を引くようなルックスをしていて、プレイヤーを誘致するような仕掛けがされていないと、わざわざダウンロードしてきてPCの記憶領域の一部を専有するようなインストール手順を踏んでまでしてプレイしようという気にはならないものだ。それにWindowsもMacも持っていないので、Linuxユーザー向けのゲームとなるとさらにプレイしてもらえる可能性は低くなる。スマホもインストール手順をふまないといけないし、記憶領域を必要とする点ではPCと変わりないのだけど、圧倒的にユーザーが多い。老若男女問わず、多くの人が利用しているプラットフォームだということで、インストールの面倒さを帳消しにしてくれる。でも、スマホの開発をやりたいとは全く思えない。今の所Rustでやるのは無理だろうし、そうでなくても、予め決められた環境の中で、一定の手順を踏んで組み立てているだけのような感じで、プログラミングの占める割合が低い、という先入観がある。決められた枠内でというと、Rustも制約が多く、自由な環境を重視するならRustを選択する理由にはならないのではないかということも言える。Rustは安全性のために制約を課し、スマホは便利なデバイスを利用するために制約を課すという違いは同質なものとは言えない。プログラミング言語のほぼすべてが、プログラマーに何らかの制約を課す。ifはこう書かないといけないとか、そういう取り決めがなければ、何もすることができない。CPUのレベルに至ってもそうだ。このビット列はこのように解釈するという決まりがなければ、CPUは何もすることができない。Rustによってがんじがらめにされるというのは、その延長だと言える。プログラマーの自由な精神活動を妨げるようなものではない。なんか大げさなことを書いてしまったようだけど、 ただ単にスマホにはあまり興味がないというそれだけのことだ。

スマホをやらないとすると、PCかWebAssemblyなんだけど、どっちもやればいいだろう。まず基本はPCだろう。利用できるライブラリが豊富にあるので、学習にも向いている。このプラットフォームで十分に経験値をためてから、WebAssemblyに移るのが良さそうだ。PCはLinuxのマシンしかない。なので、プレイしてもらうという考えは捨てて、レベル上げのためだけにやるということになる。競技プログラミングとかやるのとあまり違いがない。モチベーションを維持できるかどうかが問題となるだろう。何かしら外部にアピールして自己欲求を満たす仕組みを用意しないと、継続するのは難しそうだ。単純なのはGitHubのようなところでソースを公開するとか、YouTubeでライブ配信するとかそういう手段がある。そういうのはPCでもWebでやるにしても同じことなので、早めに手段を確保してしまうのがいいだろう。しかし、目的を違えてはいけない。ゲームを作ることあるいはプログラミングそのもの目的であって、それ以外は付属的なものに過ぎない。