サンプルプログラム3(後)
プログラマーからひとこと
サンプルプログラム3を見ていくのも後半になりました。と言っても、前回までで難しいところはだいたいおさえたので、今回はわりとスルスルいくような気がします。
中にはかなりおおざっぱな説明も出てきますが、リクツ付けはそのうち、レベルが上がってきたころにやるので、それまでは「こーゆーもんなんだな」という感じでおぼえてください。
ないしょですが、プログラマーでもそうやっておぼえた事というのは、けっこうあります。
ちなみに私も前回ここで指摘されるまで、「フォールス」または「フォルス」と読む「False」を「ファルス」と間違って読みつづけていました。あんがいそういうものです。
ビット演算子
ハカセ「さて、メインループの話からダイブずれてしまったようじゃな。そろそろLOAD”SAMPLE3”でサンプルプログラムにモドるとするかの。
前回は、ドラムを鳴らすこのあたりで止まっていたんじゃったな。
前回は、ドラムを鳴らすこのあたりで止まっていたんじゃったな。
0054#. ’--- ト゛ラム
0055#. B=BTRIG()
0056#. IF B AND 1 THEN BEEP 52
0057#. IF B AND 2 THEN BEEP 53
0058#. IF B AND 4 THEN BEEP 62
0059#. IF B AND 8 THEN BEEP 25
0060#. IF B==64 GOTO @EXIT
」0055#. B=BTRIG()
0056#. IF B AND 1 THEN BEEP 52
0057#. IF B AND 2 THEN BEEP 53
0058#. IF B AND 4 THEN BEEP 62
0059#. IF B AND 8 THEN BEEP 25
0060#. IF B==64 GOTO @EXIT
ワンパク「ケッキョク、ここに出てくる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で9だよね。
そうなるとコマるのは、「IF B==1」じゃヒットしないことだね。
ところが「IF B AND 1」や「IF B AND 8」と書くと、ちゃんとヒットするんだ。フシギだね。」
十字ボタン↑ | 1 |
---|---|
十字ボタン↓ | 2 |
十字ボタン← | 4 |
十字ボタン→ | 8 |
ところが「IF B AND 1」や「IF B AND 8」と書くと、ちゃんとヒットするんだ。フシギだね。」
ハカセ「これをセツメイするには、まず「ビット演算」についてセツメイせねばならん。ならんのじゃが、あんまりムズカしいので人に教えづらいのじゃあああああ」
ワンパク「初心者向きのサンプルプログラムなのに、ちょくちょくフクザツなコトをしようとするよな。セツメイできねェなら、サイショからやるなよ!」
インテリ「まあまあ。こういうベンリな使いかたがあるんだから、ふかく考えずに使えばいいのさ。」
ワンパク「テメーのワリキリもなんだかスゲエな……。」
連続入力を止めるために
神崎「まだ61行目が残ってるね。
0061#. VSYNC 1
前の章でおぼえた命令だね。」ワンパク「ツマリ、BTRIG()命令をマトモに動かすために……エート……60分の1秒だけプログラムを止めてるんだったか。」
インテリ「もっとくわしく言うと、VSYNCで止まっている間でも、BEEPの音は鳴りつづけるのがポイントだね。」
神崎「ということは、VSYNCの直前で鳴らしたBEEPの音が、60分の1秒間は何があっても鳴りつづける……?」
ワンパク「言い方はスゴそうでも、イマイチたいしたことが起きてねえぞ?」
インテリ「実際にためしてみるのが早いかな。ためしに61行の先頭に「’」をつけてみよう。
」
0060#. ’VSYNC 1
これでVSYNC命令は使われなくなったよね。RUNしてドラムを一度に鳴らしてごらん。」
ワンパク「ウォオー! 鳴らしまくってやるゼェー!」
インテリ「みんなもワンパク君と一緒にためしてみてね!」
神崎「ワンパク君のロックはデタラメに音をならせばとにかくロックだからなあ。……あれ? なんだか今までより音が大きいような……?」
インテリ「そうなんだよね。VSYNCがないと、BTRIG()が「何度もボタンを押してる」ようなことになるのはおぼえてるかな? つまり、人間に出せないようなスピードで何度もBEEPが鳴ってるってコトさ。」
ワンパク「格闘ゲームっぽく言うと技を出した瞬間に、同じ技でキャンセルしてるってコトか。ナルホド……「ドカーン」の「ド」だけくり返し聞こえると、なんだか大きな音に感じるワケだな。」
インテリ「ワンパク君らしいけど、ナカナカわかりやすいたとえだね。じゃあ、さっきの「’」は消して、フツウに鳴るようにしておこう。」
ハカセ「先頭に「’」をつけてとりあえずテストしてみる、というのはタンジュンじゃが、ダイジなテクニックじゃな。
プログラム用語では「コメントアウト」と言うのじゃが、このキカイにおぼえておくといいぞい。」
プログラム用語では「コメントアウト」と言うのじゃが、このキカイにおぼえておくといいぞい。」
INKEY$()命令
神崎「64行から、気になることが書いてあるね。
0064#. ’--- FOR-NEXT テ゛
0065#. ’--- トチュウカラヌケルト
0066#. ’--- ナイフ゛メモリカ゛ヘルノテ゛
0067#. ’--- GOTO ヲツカッタル-フ゜
」0065#. ’--- トチュウカラヌケルト
0066#. ’--- ナイフ゛メモリカ゛ヘルノテ゛
0067#. ’--- GOTO ヲツカッタル-フ゜
ハカセ「う、うむ。ソコはちょっとヤッカイなモンダイなのじゃが、ひとまずその先の70行から片づけてもらおうかの。
0070#. K$=INKEY$()
」神崎「カタチはなんとなくBUTTON()命令と似ているね。」
インテリ「そう! INKEY$()命令は、BUTTON()命令のキーボードバージョンだと考えていいだろうね。「IN KEY 」つまりキー入力というコトだね。」
ワンパク「ツマリ、70行だと変数K$に押したキーの……ナニが入るんだ?」
インテリ「あ、それはBUTTON()命令よりカンタンだね。押した文字がそのまま変数に入るんだ。キーボードの「A」を押していたら、K$にはAという文字が入るよ。」
ワンパク「チッ、フカヨミしすぎたか! しかし、おかげで71行目のやってるコトはよくワカッたぜ。
」
0071#. IF K$==”” GOTO @LOOP
変数K$がカラ……つまりキーが押されてなければ、おなじみの@LOOPに飛んでくり返しってことだな!」
FOR~NEXT文からの脱出とスタック溜まり
神崎「このあたりまではBUTTON()命令と本当によく似ているね。問題はこの後だけど……」
ハカセ「ゴホン。ここはヒトアシさきに、カンタンに書き直したプログラムの方を見てもらおうかの。
」
0072#. FOR I=0 TO KCNT-1
0073#. IF K$==N$(I) GOTO @PLAY
0074#. NEXT
これを読めば、ナニをしとる行かはワカるはずじゃの?0073#. IF K$==N$(I) GOTO @PLAY
0074#. NEXT
」
ワンパク「……たしか配列変数N$()には(0)~(19)まで、ケンバンに使う字が入ってたハズだな。」
神崎「変数KCNT-1はケンバンの数をコンピューター風に数えて、19のはずだよね。」
ワンパク「変数K$に入ってるのは押されたキー。つまり……20回ブンN$()を変えながらくり返しチェックして、どこかで押されたキーがケンバンのキーと同じだったら@PLAYに飛ぶ、ってコトだな!」
ハカセ「おお……ワンパク君、すっかりリッパになったのう……。」
ワンパク「そりゃいいんだけどよォ、ジッサイのサンプルはこうじゃねェよな。またしくじったのか?」
ハカセ「おお……ズバズバ言うトコは変わっとらんのう……。
」
0072#. I=0
0073#. @KLOOP
0074#. IF K$==N$(I) GOTO @PLAY
0075#. I=I+1
0076#. IF I<KCNT GOTO @KLOOP
0077#. GOTO @LOOP
よーく見なおしてもらえばワカると思うが、ココで書いているコトはFOR~NEXT文で書いたコトと同じなのじゃ。0073#. @KLOOP
0074#. IF K$==N$(I) GOTO @PLAY
0075#. I=I+1
0076#. IF I<KCNT GOTO @KLOOP
0077#. GOTO @LOOP
」
ワンパク「75行目の「I=I+1」てのが初めて見るパターンだが……」
神崎「変数のルールにそって考えると、なんとなく分かるね。バケツIに、それまでのIの中身プラス1を入れるってことでしょ?」
インテリ「そういうこと。こういうふうに変数の中では、同じ変数を使った計算もできるんだけど、なれないとピンとこないかもね。
もしも変数Iのナカミが2だったときにI=I+1すると、I=2+1というわけで、3が変数Iのナカミになるね。」
もしも変数Iのナカミが2だったときにI=I+1すると、I=2+1というわけで、3が変数Iのナカミになるね。」
ワンパク「FOR~NEXT文も、変数に1ずつプラスしてくワケだしな。
よし、このブブンがFOR~NEXTと同じコトをやってるのはワカッた。で、なんでそんなコトすんだ? FOR~NEXTの方がカンタンじゃねェか!」
よし、このブブンがFOR~NEXTと同じコトをやってるのはワカッた。で、なんでそんなコトすんだ? FOR~NEXTの方がカンタンじゃねェか!」
ハカセ「ココがムズカしいトコロでのう……。
押されたキーとケンバンのデータがマッチすれば@PLAYに飛ぶのはワカッとるな?
じゃがFOR~NEXTのくり返しが終わらないウチにトチュウで飛び出して、またFOR~NEXTをゼロからくり返しはじめて……、とやっておると、プログラムの中に「トチュウで止まったままのFOR文」がドンドンたまっていくのじゃよ。」
押されたキーとケンバンのデータがマッチすれば@PLAYに飛ぶのはワカッとるな?
じゃがFOR~NEXTのくり返しが終わらないウチにトチュウで飛び出して、またFOR~NEXTをゼロからくり返しはじめて……、とやっておると、プログラムの中に「トチュウで止まったままのFOR文」がドンドンたまっていくのじゃよ。」
インテリ「つまり、いわゆるスタックがたまってメモリをアッパクするんですね。」
ワンパク「???」
ハカセ「まあモノはためしじゃ、サンプルをFOR~NEXT方式に書きかえて、ジャンジャンキーボードをたたいてみい。」
ワンパク「ウオォー! オレのレンシャが火をふくゼェー!」
Out of memory (72, FOR)
OK
OK
ワンパク「ゼエ、ゼエ……た、タシカにエラーが出たな。」
ハカセ「メッタにないコトではあるんじゃが……。とにかくFOR~NEXTをトチュウで抜け出すのはあまりコンピューターにやさしくないというコトと、もし自作のプログラムでOut of memoryエラーが出たらコレをうたがってもいい、とはココロのスミでおぼえておいていいかもしれんのう。」
BEEP命令で再生
インテリ「さあ、ここまで来たらもうあとはキーボードどおりに音を鳴らすだけだね!」
神崎「なんだかんだで、けっこう長かったなあ。
」
0080#. @PLAY
0081#. P=F*(I)-4096
0082#. BEEP V,P
0083#. GOTO @LOOP
82行で使っている変数Vは最初のほうで出てきたBEEP命令の音色、変数PはBEEP命令の「ピッチ」だね。0081#. P=F*(I)-4096
0082#. BEEP V,P
0083#. GOTO @LOOP
」
ワンパク「その変数Pを決めてるのが81行目ってワケだな。もうずいぶんサカノボるが、変数Fは46行目で決めてたんだったか。
0046#. F=4096/12
」インテリ「1音ずらす数字が「4096/12」なんだったね。そして変数Iは0がキーボードの「’」、1がキーボードの「A」、……と対応してるから……」
ワンパク「Aキーを押せばF*1、つまりフダンより1音上のピッチになるってコトだ!」
神崎「……あれ? -4096って何だろう?
0081#. P=F*(I)-4096
」ハカセ「ウム。P=F*(I)のままじゃと、ちょっと音がカルいかと思ってのう。-4096してちょうど1オクターブだけ下げておいたのじゃ。」
ワンパク「重低音……ってホドじゃねェが、そこはワカるぜ。いっそ-40000くらいにしたらどうなるんだ?」
Out of range (82, BEEP)
OK
OK
ハカセ「ウウ……BEEP命令のピッチは-8192~8192までがゲンカイなのじゃよ……。」
インテリ「「Out of range 」というのは「ハンイからはずれた」という意味のエラーメッセージだね。」
ハカセ「インテリ君のすばやい進行は、ときにザンコクじゃ……。」
ループ脱出とEND命令
神崎「86行目からは、ラベル@EXITだね。
0086#. @EXIT
0087#. SYSBEEP=TRUE
0088#. END
」0087#. SYSBEEP=TRUE
0088#. END
ワンパク「@EXIT……。そんなラベル、どっかで見たような……見てねェような……」
インテリ「ははは。BUTTON()命令を使ったところで、ボタン判定をしていたじゃないか。
0060#. IF B==64 GOTO @EXIT
」ワンパク「オゥ、これだ! そういやあの時はドラムのコトばっかり考えてて、このGOTOのコトはすっかり忘れてたぜ! オレとしたことが!」
神崎「BUTTON()命令で64が入ったということは、たしかXボタンを押したってことだったよね。」
ハカセ「さよう。このプログラムでは、Xボタンでプログラム終了じゃったな。と言えばあとはワカるじゃろう?」
ワンパク「さすがにラクショーだぜ! 87行でSYSBEEP=TRUEして音を元にモドして、88行でENDだな!」
神崎「ポイントは、Xボタンを押すことで、50~77行目の間をグルグル回っていたメインループからぬけ出しているコトだね。」
インテリ「そういうコト! ハッキリ言えば88行目のENDはなくてもいいんだけど、ループから飛びだしてプログラムを終わらせるにはピッタリだね。」
ハカセ「それはモチロンじゃし、この後にラベルを増やして新しいキノウを増やすときにはますますENDがダイジになるじゃろうな。
」
0086#. @EXIT
0087#. SYSBEEP=TRUE
0088#. END
0089#. @USO
0090#. SYSBEEP=FALSE
たとえばこういうプログラムじゃと、88行目にENDがなければ89行から先まで勝手に進んでしまうわい。0087#. SYSBEEP=TRUE
0088#. END
0089#. @USO
0090#. SYSBEEP=FALSE
」
ワンパク「フーム……。ラベルでループを使ったプログラムじゃ、ループを抜け出すのと、そこでENDするのがダイジになるワケだな……。」
ハカセ「ワ、ワンパク君! どうしたんじゃそのリッパなまとめぶりは……!」
ワンパク「さすがに長びいたからよォ、このヘンでENDっぽく終わらせるのがイイ気がしたんだゼ。ノーフューチャー!」
神崎「いつも通りだったね。」
- コメントアウト
- 行の先頭に「’」と書くだけで(あたりまえですが)その行がなかったことになります。プログラムの動作テストのときなどに便利です。
- INKEY$()命令
- (文字変数)=INKEY$()
変数に押されたキーが入ります。 - ビット演算子
- むずかしいので、使い方だけおぼえましょう。BTRIG()命令やBUTTON()命令で使う変数なら、この形が使えます。
IF (変数) AND (数) THEN (命令)
変数がボタンに対応した数を含んでいるときだけ、命令を実行します。
BTRIG()命令やBUTTON()命令以外でもこれが使えると思ったら大まちがいです。 - FOR~NEXT文からの脱出とスタック溜まり
- くわしいことをはぶくと、FOR~NEXT文の中からGOTOで飛び出して、またFOR~NEXT文の中から……とくり返すのは、あんまりコンピューターに優しくなく、激しくやりすぎると「Out of memory」エラーが出ることもあります。めったにないことですが、このサンプルプログラムの方法で回避はできますよ。