隠しコマンド

ゲーセンで見かけるゲームには、決められた順番にボタンを押すと隠しモードで遊べるようになっているものがある。 ファミコンだったかプレステだったかでは、「○○コマンド(←メーカー名)」などというメーカー固有の隠しモード移行コマンドなんてのもあったが、ゲーセンでも「通常モードより難しくしたい!」ということで導入されているのだろう。

ここで気になるのが、隠しモードへ移行するためのコマンド入力を受け付ける仕組みだ。 通常このようなコマンドは、コイン投入からスタートボタンを押すまでの間に入力される。 例えばそれが「(方向キーを)上上下下左右左右、Aボタン、Bボタン」だったとしよう。 もちろん人間が入力するようなものだから、間違ったときは最初のボタンから押し直せばオーケーということにしよう。 さて、どのようなプログラムになるだろうか。

まず思いつくのが、キー入力をバッファリングして、スタートボタンが押されたときにそれをチェックする方法だ。 押されたキーとその順番をすべて記憶しておき、最後にそのリストがコマンドと一致すればよいわけだ。 ではどのようにバッファリングすればよいのだろうか。 コマンドはたかだか10個の入力でできているのだから、バッファも10個分あれば十分だろう。 簡単にコードにしてみると、こんな感じだ。

int buf[10], key, i;
i = 0;
while ((key = input_from_controller()) != START_BUTTON) {
    buf[i] = key;
    i++;
}
これは単純にスタートボタンが押されるまでバッファリングしているだけだ。 間違ってもやり直しがきかないし、そもそも10個以上キーを押すとバッファが溢れてしまうという欠陥もある。 これを叩き台に、もう少し考えてみよう。

まず間違ったキーを押した時の処理をどうすればよいのかだ。 キー入力が間違っているかどうかは、実は入力を受け付けているこのループでは判定できない。 チェックはスタートボタンが押された後で行うことになっているからだ。 だから、間違ったらバッファの先頭に戻る(具体的には、i にゼロを代入する)ということはできない。 ではバッファを大きく取ったらどうだろう? buf の大きさを100ぐらいにして、最後から10個の要素を取り出してチェックすればいい。 まあそれも手だが、なんといっても90個の要素は無駄なのだし、何度も間違って100個のバッファも溢れさせるお客さんもいるかもしれない。 ここは10個のバッファを無駄なく使うようにしたい。

バッファの最後まで来てしまったら、要素を前へずらして、一番古いキー入力を捨ててしまうのはどうだろうか。 最後の10個さえ残っていればいいのだから、そんなもの捨てても問題はない。 試しに書いてみよう。

i = 0;
while ((key = input_from_controller()) != START_BUTTON) {
    if (i >= 9) {
        for (i = 0; i < 9; i++) {
            buf[i] = buf[i + 1];
        }
        buf[9] = key;
    } else {
        buf[i] = key;
        i++;
    }
}

ちょっと複雑になってしまったし、なんか分かりにくい。 コードも無駄な部分が多いように思う。 なんといってもキー入力が10個を超えた時点で、いちいちバッファをずらすのが嫌な感じだ。 たとえば「キー入力は常にバッファの最後に入れて、毎回バッファをずらす作業を行う」という手もある。 それならもう少しコードを整理できるが、毎回ずらす作業というのもいただけない。 もっとスマートに、リングバッファを使ったらどうだろう?

i = 0;
while ((key = input_from_controller()) != START_BUTTON) {
    buf[i % 10] = key;
    i++;
}
for (j = 0; j < 10; j++) {
    buf2[j] = buf[(i + j) % 10];
}

最初の while ループではバッファリングを行っている。 これは最初に書いたコードに似ているが、バッファが溢れたら(要素をずらさずに)先頭から再利用している点が異なる。 このままではコマンドの始まりがバッファのどこかへいってしまうので、入力が終わった時に正しい順番に並べかえる。 それが次の for ループの部分だ。 ここでは、要素をずらすのが面倒なので、別のバッファへコピーしている。 ちなみに % という演算子は、割算の余りを取るものだ。 「i % 10」は「変数 i を10で割った余り」ということになる。

最終的なチェックは簡単なので省略する。 たとえば様々な裏モードがあって、コマンドが何種類もあるときでも、同じルーチンがそのまま使えるだろう。 コマンドの長さが変わった場合は、数字の部分を変更すれば対応できる。

他にも、オートマトンを使うという手もあるのだが、それはいくらなんでも大げさすぎるのでやめておく。

Nov-29-1998


[prev] / [next]
[back to index]