ポリモーフィック構造体

2020年1月19日

私がパチンコの開発をしていたのはもう10年以上前ですから、今も同じかはわかりませんが、当時は厳しい納期を迫られつつ仕様変更が波のように押し寄せるという、過酷極まりない状況でした。若かった私は自分の技量不足を労働時間で補う方法しか知らず、今思うと入院しなかったのが奇跡と思えるような働き方をしていました。

そんな中、何の気なしに思いついたソフトウェア実装のある一つのパターンが、状況を一変しました。そのアイデアの採用後は、労働時間がそれ以前と比べて誇張抜きで半分になりました。このパターンには一般名称がないようなので、私はそれを「ポリモーフィック構造体」と呼んでいます。

パチンコのプログラムを非効率に書いていた私にしか刺さらない、ごくごく狭いアイデアですから、期待はしないでください。ただ、アイデアの中身はともかく「プログラミングの世界では、働き方を変えるのはあなただ」というメッセージは伝えたいです。

アニメーションの作り方

当時私は、パチンコの液晶画面のアニメーションを制作する仕事をしていました。とはいっても、絵を描いたり、それに動きをつけたりするのはデザイナーの役目で、プログラマーはそうして出来上がった最終データをいかに効率よくプログラムの形に落とし込むかが、腕の見せ所でした。ここでいう効率とは、データ効率と開発効率の両方を指します。

アニメーションの編集には Adobe Director というツールが使われていました。考え方は簡単で、任意の画像を、描画の重ね順を気にしながら、ただ時間軸上に並べていくだけです。これはその編集画面のイメージです。

横軸が時間、縦軸が描画の重ね順です。ここに並べたものはすぐにパソコンの画面上でアニメーションとして確認できますから、パチンコの制作にうってつけだったのです。

アニメーションというのは、いわば超高速の紙芝居です。この紙芝居の一枚をフレームといいますが、全フレームにおける全画像の座標と描画順さえわかれば、アニメーションは成立します。というわけで、特製のスクリプトを使ってこの全データを CSV 形式で吐き出させ、あとはプログラマーがそれをどう料理するか、というワークフローはすでに出来上がっていました。

問題点

ここで少し困ったことがあります。パソコン画面に映っているものをそっくりそのまま液晶に移植するのは非常にたやすいのですが、時折そうでないものが混じっています。たとえば画面上にでかでかと映っている数字がそうです。

この数字は画面上を縦方向にぐるぐると循環するので、その動きをつけるのはツールの力を借りなければ大変です。しかし、表示する数字自体はランダムでなければなりません。このジレンマがありました。

私はこのジレンマを解消するのに、当初どのような手段を使っていたのか、思い出すことができません。ただ少なくとも、とてつもなく醜いコードを書いていたことは確かです。というのも、このデータがひとたび編集されると、そのせいで徹夜になっていたことだけは覚えているからです。

解決策

この仕事を始めて数年たった頃でした。きっかけは忘れましたが、あるアイデアが浮かびます。構造体の先頭に、データの種類を表す番号を置けばいいのではないか。そして、画像をそのまま描画するか、ランダムに描画するかは、その番号で表現すればいいのではないかと。コードで書けば、こういうことです。

const Direct     sky    = { 0, /* 略:画像 */ };
const Direct     moon   = { 0, /* 略:画像 */ };
const Direct     castle = { 0, /* 略:画像 */ };
const Randomized left   = { 1, /* 略:変数ポインタ, 画像テーブル */ };
const Randomized center = { 1, /* 略:変数ポインタ, 画像テーブル */ };
const Randomized right  = { 1, /* 略:変数ポインタ, 画像テーブル */ };

型と番号の関係を必ず一致させるように徹底すれば、これらはすべて次のような関数で統一的に扱えます。

void draw(const void *p)
{
  switch (*(const int *)p)
  {
  case 0:
    {
      const Direct *q = (const Direct *)p;
      /* 画像をそのまま描画する */
    }
    break;
  case 1:
    {
      const Randomized *q = (const Randomized *)p;
      /* 変数の値に応じて画像テーブルを引用して描画する */
    }
    break;
  }
}

このアイデアは天啓でした。コードの量が圧倒的に減っただけでなく、数字をランダムに表示することにまつわる一切のバグがなくなったのです。データが途中で編集されることも、もう怖くなくなりました。

それだけではありません。このパターンは、データの定義方法を工夫すれば、本当に何でもできるのです。たとえば音。それまではアニメーションに合わせて音を鳴らすことは別領域の仕事でしたが、このパターンなら、音としての番号を振っておいて、あとは Adobe Director に音のタイミングを示すダミー画像を埋め込むだけです。これは本当に画期的でした。

ポリモーフィズムとの違い

ここまで読んで、オブジェクト指向に詳しい方はお気づきになったかもしれません。これはポリモーフィズムを回りくどく書いているだけだと。

その通りです。当時の私はオブジェクト指向の知識も C++ の知識もありませんでしたから、何かを発明した気分でいましたが、結局これは俗にいうポリモーフィズムの一表現に過ぎません。C++ で継承を使って書けば、同じコードがもっとスマートに書けるでしょう。

ただ今でもなお、こちらのパターンに軍配が上がる点があります。それは RAM を消費しないという点です。C++ のクラスインスタンスは、どうやっても RAM に配置されてしまうからです。その理由もあって、このパターンは以降もう一度だけ、私のキャリアの中で生かされることになりました。

まとめ

私はこのアイデアに救われたのと同時に、プログラミングという仕事の醍醐味を見た気がします。この仕事では、泥臭くやるか賢くやるかは、結局自分次第なのだと。実際に私はこれ以来、自分の仕事に独自のアイデアをどんどん盛り込んでいき、残業時間をがんがん減らしていきました。たとえ誰もほめてくれなくても、その工夫は自分を助けるという事実だけで、十分にお釣りが来ます。そして、それに対する執着だけが、プログラマーを成長させるのです。