[OSASK 4081] Re: 絶対音感ゲーム3.0

  こんばんは、川合です。


ZAKKI さんは 2002/07/17 18:34:11 の「[OSASK 4077] 絶対音感ゲーム
3.0」で書きました:

>絶対音感ゲームをバージョンアップしました。
>http://zslash.s5.xrea.com/onkan.zip
>
>[OSASK 4073]での川合さんのアドバイスを取り込んでいます。
>結果、サイズがかなり縮みました。
>3.19KB(1.1)->2.32KB(2.0)->1.90KB(3.0)
>1.1と比べるとかなりの差です。

  喜んでもらえて嬉しいです。でもまだまだです。

>今度こそ最終版になりそうです。

  ごめんなさい、先はまだ長いのです。ということで、テクニック紹介
第3弾です。

  まず、プログラムを見ると、

    lib_putstring_ASCII(0x0000, 0, 0, ****, 0, 0, ****);

というパターンが非常に多く出ていることに気が付きます。ということ
で、こんな関数を作りましょう。

void putstr(struct LIB_TEXTBOX *tbox, const char *str)
{
    lib_putstring_ASCII(0x0000, 0, 0, tbox, 0, 0, str);
    return;
}

そしてこいつを代わりに使うことにしましょう。・・・これで少し縮む
と思います。しかも読みやすくなるでしょう。そんでもって、start:前
後の

>    /*メッセージを表示(初回のみ)*/
>    putstr(textbox, "ONKAN 3.0");
>    putstr(textbox2, "SCORE:");
>    putstr(scorebox, "00000000");
>    /*判定の後ここに戻る*/
>    start:
>    putstr(helpbox, "Hit Space           ");

の7行を以下のように書き換えます。

    putstr(textbox2, "SCORE:");
restart:
    miss = score = 0;
    /* メッセージを表示 */
    putstr(textbox, "ONKAN 3.0   ");
    putstr(scorebox, "00000000");
start:
    putstr(helpbox, "Hit Space           ");

ここで、missとscoreの0の代入をやっているので、/*変数*/のところで
の代入はやめます。宣言だけにします。

  で、こうすると、gameover:のところで表示やmissなどの再代入を記
述することなく、goto restart;でOKになります。

  修正個所はあと少しです。プログラムを見ると、getsignal()を使う
ときはいつでも0以外のシグナルが来るまで待機していることが分かり
ます。それなら、getsignalを書き換えて、以下のような関数にしてし
まいましょう。

const int getsignalw()
/* 0が返されたら、シグナルなし */
{
    int signal;
    /* シグナルがなければ来るまでスリープ。シグナルがあればスリープしない */
    lib_waitsignal(0x0001, 0, 0);
    if (*sig_ptr == REWIND_CODE) {
        /* REWINDシグナルを受け取った */
        /* 直後の値の分だけシグナルを処理したことにして、ポインタを先頭に戻す */
        lib_waitsignal(0x0000, *(sig_ptr + 1), 0);
        sig_ptr = signalbox0;
    }
    signal = *sig_ptr;
    if (signal != 0) {
        sig_ptr++;
        /* 1シグナル受け取ったことをライブラリに通知 */
        lib_waitsignal(0x0000, 1, 0);
    }
    return signal;
}

  これを使えば、プログラムがすっきり書けます。たとえば、スペース
キーの入力を待つループは(start:とgameover:のところにありますね
)、

    while (getsignalw() != 9);

と書けます。だからgameover:のところは、こうなります。

    while (getsignalw() != 9);
    goto restart;

関数beep()のところでは、

    while (getsignalw() != 10);

になります。

/*キー操作受付*/のところは、

    do {
        num2 = getsignalw();
    } while (num2 > 8); /* num2が0や1になる事はないから */
    num2--;

  それと、ラベル「judge:」はもう不要なので、消しちゃいましょう。

  これだけ直すと、まあまあ変わるでしょう。ところで、直せるところ
はまだあります。だからまだ「最終版」って書かないでおいてください
(笑)。

  ええと、もしうんざりしちゃったらごめんなさい。今のレベルでもバ
イナリサイズとしては十分なので、面倒だからもう改良したくない、っ
ていうのはありです。でも、Cのソースとしては無駄が多いので、ZAKKI
さんに「普通はこういう風に書くのか」と知っておいてもらいたいと思
っただけなんです。おせっかいですみません。

  ちなみに僕がこういうレクチャーをするのは負担ではないか、とは思
わないでください。僕にとっては、こんなのは暇つぶしレベルです。休
憩です。だから負担になるどころかリフレッシュしています。楽しんで
やっていますので、心配なさらないでください。

  ついでに次回予告としては、start:やgoto start;をなくしたりgameo
ver:やgoto gameover;をなくしたりします(今回作ったrestartもなく
なります)。gotoをなくしたいとのことでしたので、これは楽しみにな
るんじゃないでしょうか?

  ちなみに最終的には、1.0KBくらいになると思われます。ゲームの内
容からすると、そんな感じです。もちろん、読みにくくなるような過激
な最適化はしません(そんなのはC言語の勉強にはなりませんから)の
で、ご安心ください。


  それでは。

--
    川合 秀実(KAWAI Hidemi)
OSASK計画代表 / システム設計開発担当
E-mail:kawai !Atmark! imasy.org
Homepage http://www.imasy.org/~kawai/


ML番号でジャンプ
ML単語検索