2019年07月15日

プチコンゲームプログラミング講座~第九回「予習・復習3:条件判断とジャンプ命令」

文 プチ太郎 氏
=-=-=-=-=-=-=-=-=-=-
 今回もサンプルゲームをお休みして、プログラム記述の話です。今回は、条件判断とジャンプ命令について説明していこうと思います。
 さてさて、プログラム処理の基本は一番簡単な回答なら

1.転送:値を別の所に動かし、出力装置に動かせば字や音を出す
2.比較:2つの数を比べてどっちが大きいか結果を出す
3.ジャンプ:プログラムの実行場所を他の場所に移す

 の三種類です。比較の結果ジャンプする事もあり、それがBASICで言うIF・THEN・GOTOです。使いやすくするため、FORやGOSUBなど微妙に改良を加えた命令も作られました。今回は内容の関係上、プチコン以外も一部紹介しています。

★ IFとTHENの基礎1:演算子 ★
 比較演算子について、昔の記述とプチコンの記述を並べてみましょう。

1907-ex1.jpg

 違いがあるのは、初代プチコンを出す時そのままでなく、後世に出た優れたプログラム技術も組み込んだためで、「==」「!=」はC言語の記述です。なぜ「両者が同じ」が「==」かというと、「A=B」では代入か比較か区別がつきにくいからです。
 また以内や以北など「以」が入るのは、以の直前の対象も含む(英語だと"equal"=イコール)」という意味です。「未満」「超える」は以が入らないので直前の対象は含まない、つまり英語だと"equal"の無いlessやmoreだけです。この辺をしっかり覚えておくと、プログラム以外でも厳密な区切りを書く時に役立ちます。
 それと演算子の無い「IF 変数 THEN…」もよく見ますね。これは「ゼロでない」つまり「IF 変数!=0 THEN…」と同じです。これまで時々出てきた「UNTIL BUTTON()」は「終了条件は、BUTTON()がゼロでない」つまりボタンが押されるまでという事です。

★ IFとTHENの基礎2:ELSEの登場 ★
 一番簡単かつ基礎となる条件判断文は「IF 比較内容 THEN 比較内容がYesだった時の処理…」で、BASICが生まれた時もこれだけでした。これではNoだった時の処理が書きにくいので、日本のホビーパソコンではPC-8001から「IF 比較内容 THEN Yesの処理… ELSE Noの処理…」が実装されました。これならYesとNoどちらも短い処理なら一行でまとまります。初代プチコンもELSEが計画されていましたが、命令を削減する事になり、LEFT$やRIGHT$と共に消えました。

★ IFとTHENの基礎3:ジャンプ命令  ★
 ELSEが出た所でジャンプ命令のおさらいです。普通にジャンプする時は「GOTO ジャンプ先」。では以下の違いは何だか答えられますか?
A.IF 条件判断 THEN GOTO ジャンプ先
B.IF 条件判断 THEN ジャンプ先
C.IF 条件判断 GOTO ジャンプ先
 答えは「どれも同じ」。元々Aだけでしたが、書きやすくするためBやCも認められました(三種類で処理速度に僅かな違いが出る言語もあります)どれを使うんだ?と迷う人もいますが、ここで目安を一つ紹介します。もし例1のような記述を書いたら、例2の方がスッキリしませんか?

1907-ex2.jpg

 スッキリした記述は見ただけでなく、修正しやすく、デバッグしやすく、書いた本人以外でも解析しやすい長所があります。こうした事を心掛けていると、後々で便利です。なお「ELSE GOTO ジャンプ先」に対して「ELSE ジャンプ先」も出来ますが、「IF…GOSUB ジャンプ先」は出来ません。ご注意!

★ IFとTHENの基礎4:ENDIFの登場 ★
 とは言え上記でも、THENの後に大量の内容が書けません。この問題の解決のため、「構造化プログラミング」が考えられました。これはFOR~NEXTやREPEAT~UNTILなど、二つの予約語で挟める命令をうまく配置し、スパゲッティ(GOTOであっちこっちに飛んでわかりにくくなるプログラムの事。中にはたった一行の処理で元に戻るものもある)を無くすというもので、IFに対し「ENDIF」が登場しました(言語によっては「END-IF」「END」「if … {…}」もあり)プチコンのENDIF追加はmkIIで検討されましたが、mkIIの処理では組み込めない事が判り、3号から登場しました。IFとENDIFで挟むとどれだけスッキリするかはここで書くより、皆さんがENDIFの例を探して、それを見る方がいいでしょう。

★ 多重分岐命令1:ON GOTO ★
 ある程度プログラムが組めると、どんな時にどんなIF命令を使ったらいいかが判るので、多少種類の多い判定をするとIF命令が増えてきます。IFが判ってきた初心者のリストを見ると
IF 変数==0 THEN…
IF 変数==1 THEN…
IF 変数==2 THEN…
 と並んで見にくいですね(^^;この原因はプログラムを書く人の能力だけでなく、言語自体にもあるため、一つの命令で複数の比較と実行先を並べる「多重分岐命令」が生まれました。プチコンでも初代から存在する「ON GOTO」「ON GOSUB」は、BASIC最古の多重分岐命令です。
 実際の使い方ですが、「ON A GOTO @ラベルA,@ラベルB,@ラベルC…」と書くと「変数Aが0なら@ラベルAに飛ぶ、1なら@ラベルBに飛ぶ、2なら@ラベルC…」という処理をするので、ツールやコマンド入力ゲームの様な、順に並んだ数字ごとに何をする?というプログラムに向いています。
 これだと変数が必ず0,1,2…と順になる場合しか使えませんが、「ON A+1 GOTO @ラベルA,@ラベルB…」と書けば「1なら@ラベルA、2なら@ラベルB、3なら…」、「ON A*2 GOTO @ラベルA,@ラベルB…」と書けば「0なら@ラベルA、2なら@ラベルB、4なら…」に変えられます。が「一つの変数が規則的に変わる時しか使えない」「記述が長すぎ」といった欠点はそのままです。

★ 多重分岐命令2:ラベルに文字列を使おう ★
 mkIIから追加された新機能で今回関係あるものに「ラベルに文字列が使える」があります。それのどこが便利か?「GOTO "@J"+STR$(A)」としたら、どうなると思いますか?「変数Aが0なら@J0に飛ぶ、1なら@J1に、2なら@J2…」となります。しかも記述がスッキリな上、GOTOやGOSUBのみならず、RESTOREやBGMSETDなどラベルを指定する全命令に使えます!
 しかし「命令分としては非常に小さくなるため、再度見つけにくく、バグが出るとデバッグしにくい」「ラベルにはアルファベットや数字が使えるが、符号が使えないので、変数から作ったラベルがマイナス符号になるとエラーになる」という欠点があります。またONもラベル文字列も、変数が大きくなりすぎて対応するラベルを作っていないと、エラーになります。

★ 多重分岐命令3:ELSEIFの応用 ★
 3号の途中からは、ELSEの変形バリエーションとして「ELSEIF」が追加されました。昔のプログラムは「とにかく短く詰めて、容量も速度も縮めろ」が美徳でしたので、「IF 条件1 THEN Yesの処理 ELSE IF 条件2 THEN Yesの処理」も「IF条件1THENYesの処理ELSEIF条件2THENYesの処理」と詰められ、ELSEとIFが合体してELSEIFとなったのです。ところがこれは以下のようにも使えます。既にこの連載で早くから出しており、以下は前回のプログラムです。

1907-k08.jpg

 最初の条件判断でYesならそれを処理し、Noなら次の条件判断でYesならそれを処理し、さらにNoならまた次の条件判断で…と、見た目も処理も上手いプログラムが組めます。最初のIFと条件の間のスペースを、1つでなく5つ開けると、下のELSEIIFと文字が並び、これまたスッキリしますね。こういう局面があったら、どんどん使いましょう!

★ 多重分岐命令4:多重分岐命令の完成 ★
 それでもまだ便利な多重分岐命令が足りず、一つの条件判断から複数処理を分岐させる命令が、いろんな言語で作られました。COBOLはEVALUATE、C言語はswitch(ゲーム機じゃないぞ)、VisualBASIC(VB)はSelect Caseと方言(機種やプログラム言語毎の違い)が大きいが、これはこの命令が比較的後世に作られたためです。プチコン4では新命令として「CASE~ENDCASE」が追加されました。例はプチコン4に載っているのですが、ここでも書いておくほか、よく似ているVBのSelect Caseも書いておきましょう。

1907-ex3.jpg

★ 評価関数 ★
 これは比較についての中級者テクニックです。関数というからにはRND()やDEF()と同じで、値が帰ってきます。どんな入出力か? 「変数==値」などの評価は今回多数書いてきましたが、ちょっと画面に「A=1:? (A==1)」と書いて、ENTERを押してみてください。1が出ましたね?では「A=2:? (A<3)」や「A=3:? (A==0)」はどうだったでしょう? それぞれ1と0が出たと思います。

1907-k09_0.jpg

 つまり条件判断の両側をカッコでくくると、条件がYesなら1(古い機種は-1もあり)・Noなら0を返します。これを上手く使うと、IFが無くても処理を変えることができます。「1しか出ないんじゃ、もっと大きな数はどうするのか」って? 次のプログラム「KOZA09-1」を実行してみましょう。数をFORで変化させて、5の時だけ大きな数を加えています。左の表示はIF、右は評価関数と掛け算を使っており、右はこんなにスッキリします。前回の数値バトルゲームの「S=(A<B)」は、これで先攻と後攻を決めています。

1907-k09_1.jpg

 もう一つの応用がプログラム「KOZA09-2」です。左の十字ボタンで赤いキャラが、右の丸ボタンで青いキャラが動きます(ボタンを複数同時に押すと動きません!本当はそこもクリア出来るが、記述が面倒になるのでこうしました)右は第五回で紹介したプログラム「K05_SPC」と同じですね。これを使うと第四回や第六回のようなアクションゲームは、動きの処理がよりスッキリします。

1907-k09_2.jpg

1907-k05spc.jpg

 ただこの裏技、KOZA09-2のようなキャラ移動はそうでもありませんが、KOZA09-1のような一部の数値を変える処理に使うと、前述の「ラベル+文字列」のようにリストに埋もれてしまい、目立たなくなるので、バグが見つけにくくなります。それに気を付けて使いましょう。評価関数まで普通に使える様になったら、上級者に手が届いた証拠です。

★ 条件が来るまで抜けない!1:WHILEとREPEAT ★
 次は3号以降の新命令。日本のホビーパソコンでは、PC-8001の後続機であるPC-8801から採用されました。どちらもFORのように一定回数繰り返すのでなく、条件を満たすまで繰り替えします。両者の違いは以下の通り。

・WHILE~WEND=繰り返し処理の最初で「条件がYesなら繰り返す」判定をする。最初に繰り返さない条件(No)が来ると、繰り返し処理を一度もせず抜ける。
・REPEAT~UNTIL=繰り返し処理の最後で「条件がNoなら繰り返す」判定をする。最初に繰り返さない条件(Yes)が来ると、繰り返し処理を最低一度して抜ける。

 この違いを並べてみたのが、サンプルプログラムKOZA09-3です。数の変化と条件判断だけなので、プログラムの説明は無し(え?)なぜこの4つの処理でこう違いが出るのか、上の説明をよく読んで考えてみましょう。

1907-k09_31.jpg

1907-k09_32.jpg

 何か複雑そうですが、実際の処理はREPEATがFORとよく似ているので、最初はREPEATだけ使い、WHILEの方がいいと把握できる様になったら、WHILEを使いましょう。
 前述のVBには、よく似たDo~Loop命令があります。終了条件の記述方法がWHILEやREPEATより判りやすいので、これも後学のために図でお見せします。

1907-ex4.jpg

★ 条件が来るまで抜けない!2:LOOP ★
 プチコン4では「LOOP~ENDLOOP」も追加されました。ではこの命令はどうやって抜け出すかというと…WHILEやUNTILに相当する抜け出し命令がありません!代わりに3号から「BREAK」命令が追加されており、これはFOR,WHILE,REPAETなどのループを強制的に抜ける命令なので、LOOP~ENDLOOPもこのBREAKで抜けます。

★ 条件が来るまで抜けない!3:FORを使う ★
 実は初期のBASIC命令を使った裏技で同じ事が出来ます。FOR~NEXTは規則的に数が変化していきますが、「FOR I=0 TO 1 STEP 0」とすると、STEPがゼロなのでずっと終わらず無限ループになります。この中でIFや評価関数を使いIを1にすると、「TO 1」の条件を満たすのでループを抜けます。条件つき終了命令の代用として、一画面プログラムなどで使われました。例としてhonoPさんが初代プチコン公式サイトに投稿した「Petit Ski」を見てみましょう→ https://smileboom.com/special/petitcom/pochette-petitski.html

★ その他の条件判断1:MZ-80の時代 ★
 他の機種から、上記のどれにも入らない例を少し紹介。PC-8001の名を何度か出しましたが、共にホビーマイコンの代表格だったMZ-80K/Cの初期は、条件判断をつなぐANDやORがありません!こんな書き方をしていました。
・ANDの例:「IF(A=1)*(B=2)THEN…」
・OR の例:「IF(A=1)+(B=2)THEN…」
 カッコがあるから評価関数ですね。上は*が掛け算つまり両方の評価関数が1の時だけ1を返し、下は+が足し算つまり片方でも1になれば1以上を返します。「IF 数値 THEN」は「IF 数値!=0 THEN」と説明した通りで、これによって変数AとBそれぞれがYesかによって、ANDやORと同じ処理が出来るのです。コンピュータの奥深くでは、こうした方法で計算しています。

★ その他の条件判断2:三項演算子 ★ 
 最後にCからまた一つ。CにはBASICにはない、短く便利な命令が沢山あり、X1やプチコン3号など、Cの処理を部分的に採用したBASICも存在します。三項演算子はIFと同じ判定をそのまま関数で使えるもので

a = (条件 ? Yesの値 : Noの値)

と書くと、条件によってYesかNoの値が左端の変数aに入ります。これもプチコンに欲しかったなぁ…

(第10回につづく 次回はまたサンプルゲーム。内容は未定です)

★今回の教材プログラムは、サーバにアップしてありますので、サーバからダウンロードしてご覧下さい。
公開キー  :2KL37KAE(連載が進んで新しい教材プログラムが追加されると、公開キーも変わります。この公開キーでダウンロード出来ない場合は、連載の一番新しい回の公開キーをご利用下さい)
プロジェクト:KOZA
ファイル名 :上の教材プログラムの見出しをご覧下さい。
=-=-=-=-=-=-=-=-=-=-
※次の更新は、フリーゲームレビューの予定です。お楽しみに!