サンプルプログラム3(後)

プログラマーからひとこと

サンプルプログラム3を見ていくのも後半になりました。
と言っても、前回までで難しいところはだいたいおさえたので、今回はわりとスルスルいくような気がします。

中にはかなりおおざっぱな説明も出てきますが、リクツ付けはそのうち、レベルが上がってきたころにやるので、それまでは「こーゆーもんなんだな」という感じでおぼえてください。
ないしょですが、プログラマーでもそうやっておぼえた事というのは、けっこうあります。
ちなみに私も前回ここで指摘されるまで、「フォールス」または「フォルス」と読む「False」を「ファルス」と間違って読みつづけていました。あんがいそういうものです。

ビット演算子

博士
さて、メインループの話からダイブずれてしまったようじゃな。そろそろLOAD”SAMPLE3”でサンプルプログラムにモドるとするかの。

ワンパク
それにしたってよォ、ここで出てくるIF文はケッキョクまだココまででオボエたやり方じゃセツメイつかねェぞ!

インテリ
いちばん多く使われてるのは、このタイプの文だね。
0058#. IF B AND 1 THEN BEEP 52

神崎
今まで習ったことのフンイキから、「上ボタンを押したら52番の音色でBEEP」ということはわかるけど……

ワンパク
IF B AND 1 THEN」ってナンだよコンチクショー! おかしいにもホドがあるじゃねえか!

インテリ
これはリクツは気にせず丸ごとおぼえた方が早いかなあ。BUTTON()したバアイ、「IF B AND 1」と書くと、「Bの中に1がまじっている」というイミになるんだ。

神崎
「まじっている」?

インテリ
とくに十字ボタンの入力なんかにベンリな使いかただね。たとえば押されたボタンが右上だったとしよう。すると変数に入る数字は1+8でだよね。
十字ボタン↑1
十字ボタン↓2
十字ボタン←4
十字ボタン→8
そうなるとコマるのは、「IF B==1」じゃヒットしないことだね。
ところが「IF B AND 1」や「IF B AND 8」と書くと、ちゃんとヒットするんだ。フシギだね。

博士
これをセツメイするには、まず「ビット演算」についてセツメイせねばならん。ならんのじゃが、あんまりムズカしいのでヒトにオシエづらいのじゃあああああ

ワンパク
ショシンシャ向きのサンプルプログラムなのに、ちょくちょくフクザツなコトをしようとするよな。セツメイできねェなら、サイショからやるなよ!

インテリ
まあまあ。こういうベンリな使いかたがあるんだから、ふかく考えずに使えばいいのさ。

ワンパク
テメーのワリキリもなんだかスゲエな……。


連続入力を止めるために

神崎
まだ57行目が残ってるね。
0057#. IF OLDB!=0 GOTO @DSKIP
IFGOTO」っていうカタチも初めてだけど……

インテリ
IFTHEN」のGOTOバージョンだと考えていいよ。そんなに違いはないよね。

ワンパク
それにしたって、イミがワカらねえぜ! 変数OLDBがゼロじゃなければ@DSKIPのある行に飛ぶ。そりゃナンのタメだ?

博士
ソレならちょっと前までモドって55行を見るのじゃ。
0055#. OLDB=B
変数はもちろん押されているボタンの番号じゃな。もしも十字ボタン上が押されておれば、変数はスナワチというコトになる。

神崎
ということは変数OLDBにも、変数と同じが入るということですね。

博士
さよう! 変数のナマエOLDBは、「OLDオールド(古い)」というイミで付けたのじゃよ。

インテリ
今までは「変数数字」のカタチを使っていたけど、「変数変数」というように書いてもいいってコトだね。

ワンパク
フーム、変数もオクがフカいぜ……。
イヤ、ちょっと待て! 57行のイミがまだワカるようでワカらねえままだぜ!

インテリ
そうだね、たとえば上ボタンを押したときで考えてみようよ。
はじめに55行に来たときには変数はまだゼロだから変数OLDBもゼロのままだね。
そして56行のB=BUTTON()で初めて変数が入ることになる。

ワンパク
オウ。ナンドもやったコトだから、ソコはまあワカるぜ。

インテリ
OLDBがゼロだから57行は飛ばしていい。58行でIF B AND 1になってるから、BEEP 52と音を鳴らすよね。

ワンパク
まあトウゼンだな。アトのIF文はひっかからねェからドンドンすっトバすぜ。

インテリ
途中ははぶくけど、79行でGOTO @LOOPしているから、また52行からのループになるね。

ワンパク
フム……? すると55行でOLDB=Bするから、変数OLDBになるな。

インテリ
まだ上ボタンをはなさずに押しっぱなしだと考えるよ。56行でB=BUTTON()してもやっぱり変数だね。

ワンパク
で、57行のIF OLDB!=0がキいて、GOTO @DSKIPするワケだ……オイオイ、58行を飛ばしちまうってのか?

博士
ソコじゃ! もしこのまま58行に行くと、またもやBEEP 52するコトになるのう。ソレでは「ドン」と鳴る音がレンゾクして「ドドン」と鳴りっぱなしになってしまうじゃろ。

ワンパク
ソレはソレでロックじゃねェか?

神崎
そ……そういうモンダイじゃないんじゃないかな。

インテリ
ためしに57行の先頭に「」をつけてみよう。
0057#. ’IF OLDB!=0 GOTO @DSKIP
これでこの行は使われなくなったよね。RUNしてドラムを鳴らしてごらん。

ワンパク
ウ……ウォオー! コレはコレでロックだとしても、このプログラムでやりたかったのはこういうコトじゃねー!

インテリ
そういうコトさ。カクニンできたらさっきの「」は消しておこうね。

博士
先頭に「」をつけてとりあえずテストしてみる、というのはタンジュンじゃが、ダイジなテクニックじゃな。
プログラム用語では「コメントアウト」と言うのじゃが、このキカイにおぼえておくといいぞい。


INKEY$()命令

神崎
66行から、気になることが書いてあるね。
0066#. ’--- FOR-NEXT テ゛
0067#. ’--- トチュウカラヌケルト
0068#. ’--- ナイフ゛メモリカ゛ヘルノテ゛
0069#. ’--- GOTO ヲツカッタル-フ゜

博士
う、うむ。ソコはちょっとヤッカイなモンダイなのじゃが、ひとまずその先の72行から片づけてもらおうかの。
0072#. K$=INKEY$()

神崎
カタチはなんとなくBUTTON()命令と似ているね。

インテリ
そう! INKEY$()命令は、BUTTON()命令のキーボードバージョンだと考えていいだろうね。「IN KEYイン・キー」つまりキー入力というコトだね。

ワンパク
ツマリ、72行だと変数K$に押したキーの……ナニが入るんだ?

インテリ
あ、それはBUTTON()命令よりカンタンだね。押した文字がそのまま変数に入るんだ。Aキーを押していたら、K$にはという文字が入るよ。

ワンパク
チッ、フカヨミしすぎたか! しかし、おかげで73行目のやってるコトはよくワカッたぜ。
0073#. IF K$==”” GOTO @LOOP
変数K$がカラ……つまりキーが押されてなければ、おなじみの@LOOPに飛んでくり返しってことだな!


FOR~NEXT文からの脱出とスタック溜まり

神崎
このあたりまではBUTTON()命令と本当によく似ているね。問題はこの後だけど……

博士
ゴホン。ここはヒトアシさきに、カンタンに書き直したプログラムの方を見てもらおうかの。
0074#. FOR I=0 TO KCNT-1
0075#.  IF K$==N$(I) GOTO @PLAY
0077#. NEXT
これを読めば、ナニをしとる行かはワカるはずじゃの?

ワンパク
……たしか配列変数N$()には(0)(19)まで、ケンバンに使う字が入ってたハズだな。

神崎
変数KCNT-1はケンバンの数をコンピューター風に数えて、19のはずだよね。

ワンパク
変数K$に入ってるのは押されたキー。つまり……20回ブンN$()を変えながらくり返しチェックして、どこかで押されたキーがケンバンのキーと同じだったら@PLAYに飛ぶ、ってコトだな!

博士
おお……ワンパク君、すっかりリッパになったのう……。

ワンパク
そりゃいいんだけどよォ、ジッサイのサンプルはこうじゃねェよな。マズいコトでもやったのか?

博士
おお……ズバズバ言うトコは変わっとらんのう……。
0074#. I=0
0075#. @KLOOP
0076#.  IF K$==N$(I) GOTO @PLAY
0077#.  I=I+1
0078#. IF I<KCNT GOTO @KLOOP
0079#. GOTO @LOOP
よーく見なおしてもらえばワカると思うが、ココで書いているコトはFOR~NEXT文で書いたコトと同じなのじゃ。

ワンパク
77行目の「I=I+1」てのが初めて見るパターンだが……

神崎
変数のルールにそって考えると、なんとなく分かるね。バケツに、それまでのの中身プラスを入れるってことでしょ?

インテリ
そういうこと。こういうふうに変数の中では、同じ変数を使った計算もできるんだけど、なれないとピンとこないかもね。
もしも変数のナカミがだったときにI=I+1すると、0+1が変数のナカミになるね。

ワンパク
FOR~NEXT文も、変数に1ずつプラスしてくワケだしな。
よし、このブブンがFOR~NEXTと同じコトをやってるのはワカッた。で、なんでそんなコトすんだ? FOR~NEXTの方がカンタンじゃねェか!

博士
ココがムズカしいトコロでのう……。
押されたキーとケンバンのデータがマッチすれば@PLAYに飛ぶのはワカッとるな?
じゃがFOR~NEXTのくり返しが終わらないウチにトチュウで飛び出して、またFOR~NEXTをゼロからくり返しはじめて……、とやっておると、プログラムの中に「トチュウで止まったままのFOR文」がドンドンたまっていくのじゃよ。

インテリ
つまり、いわゆるスタックがたまってメモリをアッパクするんですね。

ワンパク
???

博士
まあモノはためしじゃ、サンプルをFOR~NEXT方式に書きかえて、ジャンジャンキーボードをたたいてみい。

ワンパク
ウオォー! オレのレンシャが火をふくゼェー!

Out of memory (74, FOR)
OK
ワンパク
ゼエ、ゼエ……た、タシカにエラーが出たな。

博士
メッタにないコトではあるんじゃが……。とにかくFOR~NEXTをトチュウで抜け出すのはあまりコンピューターにやさしくないというコトと、もし自作のプログラムでOut of memoryエラーが出たらコレをうたがってもいい、とはココロのスミでおぼえておいていいかもしれんのう。


BEEP命令で再生

インテリ
さあ、ここまで来たらもうあとはキーボードどおりに音を鳴らすだけだね!

神崎
なんだかんだで、けっこう長かったなあ。
0082#. @PLAY
0083#. P=F*(I)-4096
0084#. BEEP V,P
0085#. GOTO @LOOP
84行で使っている変数は最初のほうで出てきたBEEP命令の音色、変数BEEP命令の「ピッチ」だね。

ワンパク
その変数を決めてるのが83行目ってワケだな。もうずいぶんサカノボるが、変数は46行目で決めてたんだったか。
0046#. F=4096/12

インテリ
1音ずらす数字が「4096/12」なんだったね。そして変数がキーボードの「」、がキーボードの「」、……と対応してるから……

ワンパク
キーを押せばF*1、つまりフダンより1音上のピッチになるってコトだ!

神崎
……あれ? -4096って何だろう?
0083#. P=F*(I)-4096

博士
ウム。P=F*(I)のままじゃと、ちょっと音がカルいかと思ってのう。-4096してちょうど1オクターブだけ下げておいたのじゃ。

ワンパク
重低音……ってホドじゃねェが、そこはワカるぜ。いっそ-40960くらいにしたらどうなるんだ?

Out of range (84, BEEP)
OK
博士
ウウ……BEEP命令のピッチは-8192~8192までがゲンカイなのじゃよ……。

インテリ
Out of rangeアウト・オブ・レンジ」というのは「ハンイからはずれた」という意味のエラーメッセージだね。

博士
インテリ君のすばやい進行は、ときにザンコクじゃ……。


ループ脱出とEND命令

神崎
88行目からは、ラベル@EXITだね。
0088#. @EXIT
0089#. SYSBEEP=TRUE
0090#. END

ワンパク
@EXIT……。そんなラベル、どっかで見たような……見てねェような……

インテリ
ははは。BUTTON()命令を使ったところで、ボタン判定をしていたじゃないか。
0062#. IF B==64 GOTO @EXIT

ワンパク
オゥ、これだ! そういやあの時はドラムのコトばっかり考えてて、このGOTOのコトはすっかり忘れてたぜ! オレとしたことが!

神崎
BUTTON()命令で64が入ったということは、たしかXボタンを押したってことだったよね。

博士
さよう。このプログラムでは、Xボタンでプログラム終了じゃったな。と言えばあとはワカるじゃろう?

ワンパク
さすがにラクショーだぜ! 89行でSYSBEEP=TRUEして音を元にモドして、90行でENDだな!

神崎
ポイントは、Xボタンを押すことで、50~80行目の間をグルグル回っていたメインループからぬけ出しているコトだね。

インテリ
そういうコト! ハッキリ言えば90行目のENDはなくてもいいんだけど、ループから飛びだしてプログラムを終わらせるにはピッタリだね。

博士
それはモチロンじゃし、この後にラベルを増やして新しいキノウを増やすときにはますますENDがダイジになるじゃろうな。
0088#. @EXIT
0089#. SYSBEEP=TRUE
0090#. END
0091#. @USO
0092#. SYSBEEP=FALSE
たとえばこういうプログラムじゃと、90行目にENDがなければ91行から先まで勝手に進んでしまうわい。

ワンパク
フーム……。ラベルでループを使ったプログラムじゃ、ループを抜け出すのと、そこでENDするのがダイジになるワケだな……。

博士
ワ、ワンパク君! どうしたんじゃそのリッパなまとめぶりは……!

ワンパク
さすがに長びいたからよォ、このヘンでENDっぽく終わらせるのがイイ気がしたんだゼ。ノーフューチャー!

神崎
いつも通りだったね。


今回のまとめ

コメントアウト
行の先頭に「」と書くだけで(あたりまえですが)その行がなかったことになります。プログラムの動作テストのときなどに便利です。
INKEY$()命令
(文字変数)=INKEY$()
変数に押されたキーが入ります。
ビット演算子
むずかしいので、使い方だけおぼえましょう。BUTTON()命令で使う変数なら、この形が使えます。
IF (変数) AND (数) THEN (命令)
変数がボタンに対応した数を含んでいるときだけ、命令を実行します。
BUTTON()命令以外でもこれが使えると思ったら大まちがいです。
FOR~NEXT文からの脱出とスタック溜まり
くわしいことをはぶくと、FOR~NEXT文の中からGOTOで飛び出して、またFOR~NEXT文の中から……とくり返すのは、あんまりコンピューターに優しくなく、激しくやりすぎると「Out of memory」エラーが出ることもあります。めったにないことですが、このサンプルプログラムの方法で回避はできますよ。