Casio Basic入門13
Casio Basic入門
誤字脱字・記載ミスや分かりにくい表現は随時追記・修正します
最終: 2015/05/08
修正: 2017/09/11
最終: 2015/05/08
修正: 2017/09/11
4. CasioBasicを使ってみる(続き)
Chapter 2 - 初級
◆ Chapter 2 の目標: 動きのあるプログラムを作る
簡単なアクションゲームを作る
前回: Casio Basic入門12
Chapter 2-7 で、予定していたゲーム仕様を作り込みました。
プログラム名 CH2-7
0→P:20→L:2→T
Locate 1,1,"P:0"
Locate 1,3,"L:"
Locate 10,10,"TRY:"
Locate 14,1,T
Lbl M
0→E
Locate 6,4,"<EXE>:START"◢
Locate 6,4," <(-)>:STOP"
Locate 1,2," "
RanInt#(2,50)→C
Do
If C-4Int(C÷4)≦1
Then
Locate 8,2,"×"
Else
Locate 8,2,"+"
IfEnd
Getkey=57⇒1→E
Dsz C
LpWhile E=0
Locate 8,2," "
0→C
Do
E=1⇒Break
C>L⇒Break
Isz C
LpWhile Getkey≠57
C>L⇒2→E
If E=2
Then
P-L→P:Dsz T
Locate 5,2,"TIME OUT"
Else If E=1
Then
P-L+C→P:Dsz T
Locate 3,2,"FALSE START"
Else If E=0
Then
P+J-C→P
IfEnd
IfEnd
IfEnd
Locate 3,1," "
Locate 3,1,P
Locate 14,1,T
T⇒Goto M
Locate 1,2," "
Locate 4,2,"GAME OVER"
Locate 6,4," <AC>:QUIT"
プログラム構造は、次のようになります。
[プログラム全体の初期化]
Lbl M
[繰り返し処理の初期化]
[アニメーション表示]
[反応速度の測定&表示]
[例外処理]
T⇒Goto M
[ゲームオーバー時の処理]
ゲーム仕様
1) ゲームスタート時、所定の試行回数が与えられる
2) アニメーションを表示する待ち時間がある(待ち時間はランダム)
3) アニメーションが終わったら、できるだけ速くキーを押す
4) 反応が速いほうが多くの得点が加算される
5) 表示が変わる前のお手つきや、反応が遅すぎる場合は、得点と試行回数が減る
6) 試行回数が0になるとゲーム終了し、その際の得点を競う
この仕様ではチョットモノ足らないので、ゲームを少しだけ面白くしてみます。
Chapter2-8
ゲーム進行に変化をつける
プログラム CH2-7 で遊んでみて、チョットつまらない理由を考えてみると、タイムアウト条件が必ず20カウント(Lが20に固定されている)ことではないかと思います。当初から予想していたことですが、やはりツマラナイ。
ツマラナイのはゲーム進行が単調なのが原因だ考え、タイムアウト条件をランダムに変化させるような変化を付けてみます。
そこで、20→L の代わりに RanInt#( ) 関数を使って、タイムアウト条件の L をランダムに変化させましょう。
20→L を [プログラム全体の初期化] ブロックに書いていました。
これを削除して、その代わりにRanInt#( ) 関数を使った L の初期化を [繰り返し処理の初期化] ブロックに追加します。
[プログラム全体の初期化] ブロックの変更
0→P:
Locate 1,1,"P:0"
Locate 1,3,"L:"
Locate 10,1,"TRY:"
Locate 14,1,T
(削除部分を赤文字で示した)
タイムオーバー条件の初期表示 Locate 3,3,L は、[繰り返し処理の初期化] ブロックへ移動させます。
[繰り返し処理の初期化] ブロックへの追加
0→E
RanInt#(7,25)→L
Locate 3,3," "
Locate 3,3,L
Locate 6,4,"<EXE>:START"◢
Locate 6,4," <(-)>:STOP"
Locate 1,2," "
(追加部分を赤文字で示した)
移動した Locate 3,3,L (タイムアウト条件 L の表示) は、表示のたびに表示するL の値が変化します(それが今回の狙い!)。L の値は、7~25 の範囲で変化するので、25の表示の後で 7 を表示させると、画面上では 75 となってしまいます(似たような事例は既に出てきていますね)。
そこで、一旦2文字文をスペースで上書き消去したあとで、Lを表示させると良いので、先に Locate 3,3," " を実行してから Locate 3,3,L を実行しています。
さて、ランダムに決める L の値の範囲は、自分で遊んでみて、私の反射神経では一番早い時でも8カウント程度の反応時間なので、それよりも少しだけ厳しい条件を盛り込んで、7~25としました。これは、後で最適化すでば良いので、当面はこのまま進みます。
もうチョット面白く...
今のゲームはペナルティーしか無いので、確実に試行回数が減ってゆきます。現在、試行回数として最初に3回与えているので、これを増やしたら面白くなるかと思ったのですが、そうでもない。ゲームオーバーまでの時間は長くなるだけで、単調でツマラナイ(-_-;)
頑張ったらご褒美が欲しい!!
と言うわけで、総得点が一定レベルになると、試行回数を増やすように変更してみます。これで頑張り甲斐が増して、ゲームが面白くなるでしょう。最初に与える試行回数は3のままにして、総得点が一定値になると試行回数が増えるようなボーナス機能を追加します。
自分で遊んだ感覚から、総得点が50点増えるたびに試行回数が1増えるのが良さそう...
総得点が増えるのは、タイムアウトでもフライングでもなく、得点が増える時です。これは、[例外処理]ブロック内の E=0 の時の処理ですから、ここに試行回数 T を増やす処理を追加します。
総得点が、50点、100点、150点...と50点アップするごとに、ボーナス(ご褒美)ポイント:B を増やすようにします。ゲーム開始時はB=0です。但し、一度50点になって試行回数が増えた後、総得点が一旦減ってからもう一度50点になったら、再び試行回数が増えるのでは、50点を行き来するだけでボーナスが貰えるのでは多分やる気が出ないしツマラナイので、一旦50点になったら、次は100点にならないとボーナスを貰えないようにします。
ボーナスポイント B は増えるだけで減らさないようにして、50×(B+1) を計算すれば、その答えが次のボーナス獲得の目標点数になります。ゲーム開始時の B は0(ゼロ)とします。
具体的には、「総得点 P」 と 「50×(B+1)」 を比較すると、うまくゆきそうです。
・ボーナスB=0の時: P≧50(B+1) ならば、B と T を1つ増やす
総合得点Pが初めて50を超えた時、ボーナスと試行回数を1つ増やします。
次に試行回数が増えるのは100点超えした時です。
・ボーナスB=1の時: P≧50(B+1)ならば、B と T を1つ増やす
総合得点Pが最初に100を超えた時、ボーナスと試行回数を1つ増やします。
次に試行回数が増えるのは150点超えをした時です。
・ボーナスB=2の時: P≧50(B+1)ならば、BとTを1つ増やす
総合得点Pが最初に150を超えた時、ボーナスと試行回数を1つ増やします。
次に試行回数が増えるのは200点超えをした時です。
・以降、同様に続く...
このように、ボーナスポイントBを使って P≧50(B+1) を条件にして If 文を利用すると、総合得点が最初に+50点された時だけ、試行回数を増やせます( ^o^)ノ
この処理は、通常に得点が得られた時に行う処理と同じところに追加します。つまり、E=0の時の [例外処理] 部分ですね。
P+L-C→P
If P≧50(B+1)
Then
Isz B:Isz T
Locate 3,4,B
IfEnd
IfEnd
長々と書きましたが、コードにすると5行で済みます。追加した5行を赤文字で示しました。
なお、[プログラム全体の初期化] ブロックに、ボーナスポイントに関して以下の初期化処理を追加する必要があります。
・ボーナスポイント B を 0 に初期化: 0→B
・ボーナスポイント表示の初期化: Locate 1,4,"B:0"
ボーナスポイントの表示は、画面の左下にしました。
プログラム開始時の画面

ゲームをしながら、目の端で総合得点(P)、タイムアウト条件(L)、ボーナスポイント(B)、試行回数(TRY)が分かります。
総合得点Pが50、100、150と増えるに従って、ボーナスBが増え、試行回数TRYも増えます。TRY残りが1に時、頑張って2に増えると、チョット嬉しい。
以下のプログラムを入力して、遊んでみてください。
プログラム名 CH2-8
0→P:3→T:0→B
Locate 1,1,"P:0"
Locate 1,3,"L:"
Locate 10,1,"TRY:"
Locate 14,1,T
Locate 1,4,"B:0"
Lbl M
0→E
RanInt#(7,25)→L
Locate 3,3," "
Locate 3,3,L
Locate 6,4,"<EXE>:START"◢
Locate 6,4," <(-)>:STOP"
Locate 1,2," "
RanInt#(2,50)→C
Do
If C-4Int(C÷4)≦1
Then
Locate 8,2,"×"
Else
Locate 8,2,"+"
IfEnd
Getkey=57⇒1→E
Dsz C
LpWhile E=0
Locate 8,2," "
0→C
Do
E=1⇒Break
C>L⇒Break
Isz C
LpWhile Getkey≠57
C>L⇒2→E
Locate 8,2,C
If E=2
Then
P-L→P:Dsz T
Locate 5,2,"TIME OUT"
Else If E=1
Then
P-L+C→P:Dsz T
Locate 3,2,"FALSE START"
Else If E=0
Then
P+L-C→P
If P≧50(B+1)
Then
Isz B:Isz T
Locate 3,4,B
IfEnd
IfEnd
IfEnd
IfEnd
Locate 3,1," "
Locate 3,1,P
Locate 14,1,T
T⇒Goto M
Locate 1,2," "
Locate 4,2,"GAME OVER"
Locate 6,4," <AC>:QUIT"
Chapter2-9
ゲームの仕上げ
これまで作った反射ゲームで遊んでみると、まだ物足りない。ゲームを繰り返しやりたい!
これを実現します。これまで作ったプログラムをループの中に入れると良い。簡単ですね。ここでは、While ループを使って無限ループを作ります。
無限ループは、以下のようにすればOK。
While 1
・
[プログラム全体]
・
WhileEnd
While [ループ継続条件] の継続条件が「真」の時、ループが継続します。「真」とは「0でない」と同じなので、1 にすれば[ループ継続条件] は常に「真」になり、無限ループとなります。
プログラムで使う無限ループについて
電卓プログラムは、[AC] キーを押せば強制終了できます。従ってプログラム全体をすっぽりと無限ループの中に入れることが出来ます。この点がパソコンのプログラムと大きな違いです。
ちなみに、CasioBasicには、STOP コマンドがあります。これを実行すると [AC] キーを押すのと同様に強制終了できます。何かキーを押した時に STOP コマンドを実行するようにしても良いわけです。
ただ、[AC] キーを押す時と同じ動作をさせるために、わざわざ Getkey などを使ってプログラムを作ることは意味がないと、私は思います。そこで、無限ループを用い、プログラム終了に [AC] キーを使うことにします。
そこで、画面表示で、<AC>:QUIT と表示しているわけです。
※ CasioBasicコマンドリファレンス
- Stop
なお、今回の無限ループ化は、ゲームを繰り返し愉しみたいのが目的なので、
<EXE>:RETRY
と言う画面表示を追加しようと思います。
RETRY とは 「もう一度トライする」と言う意味です。
<EXE>:RETRY の表示は、ゲームオーバーになった後の表示 <EXE>:START の場所に表示させることにします。これに伴い、これまで一番下の行(4行目)に表示していた <AC>:QUIT の表示位置を1行上に変更します。その際、<AC>:QUIT の前にスペースを1個いれていましたが、今回は不要です。
ゲーム終了時の処理は、以下のようになります。
Locate 4,2,"GAME OVER"
Locate 8,3,"<AC>:QUIT" (頭のスペースは不要)
Locate 6,4,"<EXE>:RETRY"◢
ここで、◢命令 を追加しています。この表示をさせたところで、プログラムを一時停止させ、[EXE] キーを押せば一時停止が解除するので、無限ループでプログラムの最初へ戻ります。
プログラムの最初へ戻るのですから、画面全体の表示を消去しておくのが楽です。
画面全体を消去するのは、Cls コマンドを使います。
※ CasioBasicコマンドリファレンス
- Cls
ゲーム終了時の処理は、以下のようになります。
Locate 4,2,"GAME OVER"
Locate 8,3,"<AC>:QUIT"◢
Cls
ゲームオーバーした時の画面

ここまでを、まとめます。
プログラム名 CH-9
While 1
0→P:3→T:0→B
Locate 1,1,"P:0"
Locate 1,3,"L:"
Locate 10,1,"TRY:"
Locate 14,1,T
Locate 1,4,"B:0"
Lbl M
0→E
TankInt#(7,25)→L
Locate 3,3," " (スペース4個)
Locate 3,3,L
Locate 6,4,"<EXE>:START"◢
Locate 6,4," <(-)>:STOP" (頭にスペース1個)
Locate 1,2," " (スペース16個)
RanInt#(2,50)→C
Do
If C-4Int(C÷4)≦1
Then
Locate 8,2,"×"
Else
Locate 8,2,"+"
IfEnd
Getkey=57⇒1→E
Dsz C
LpWhile E=0
Locate 8,2," " (スペース1個)
0→C
Do
E=1⇒Break
C>L⇒Break
Isz C
LpWhile Getkey≠57
C>L⇒2→E
Locate 8,2,C
If E=2
Then
P-L→P:Dsz T
Locate 5,2,"TIME OUT"
Else If E=1
Then
P-L+C→P:Dsz T
Locate 3,2,"FALSE START"
Else If E=0
Then
P+L-C→P
If P≧50(B+1)
Then
Isz B:Isz T
Locate 3,4,B
IfEnd
IfEnd
IfEnd
IfEnd
Locate 3,1," "
Locate 3,1,P
Locate 14,1,T
T⇒Goto M
Locate 1,2," " (スペース16個)
Locate 4,2,"GAME OVER"
Locate 8,3,"<AC>:QUIT" (頭のスペースはない)
Locate 6,4,"<EXE>:RETRY"◢
Cls
WhileEnd
(追加および変更したところを赤文字で示した)
プログラム構造
While 1 (大ループ)
[プログラム全体の初期化]
Lbl M
[繰り返し処理の初期化]
[アニメーション表示]
[反応速度の測定&表示]
[例外処理]
Goto M
[ゲームオーバー時の処理]
WhileEnd
これで、ゲーム機能の実装が終わりました。
Chapter 2 で作ったプログラムは、機能別に分けたブロック構成になっています。
プログラムを機能別にブロック化するメリットは、プログラムコードが見やすい、見やすいからバグが入りにくい、機能追加しやすい、などがあります。
これまでの機能追加で、このメリットを感じて貰えたでしょうか?
機能別のブロックを並べて作るプログラムの構造を作るには、1つコツがあります。極力Goto 文を使わないと言うことです。
このようなプログラミングを構造化プログラミングと言います。構造化プログラミングとは Goto文を使わないことだ、との見解を見聞きすることがありますが、Goto文を使わないのが構造化プログラミングではありません。
構造化プログラミングは、本来見やすいプログラムを書くことです。それによって、効率の良いプログラミングを行えるので、機能追加や変更、デバッグが楽になるメリットが得られます。ブロック構造にすることが構造化プログラミングの本質で、Goto文を使わないことはそのための手段にすぎないと、私は考えます。
構造化プログラミングについて [2015/05/08 更新]
構造化プログラミングについては、もう一度 こちら を参照ください。それを読んで頂いた上で、以下の話を続けます。
この裏話でも触れたように、プログラムのブロックを上から下へ1列に並ぶような構造(つまり「連結構造」)にするのが、構造化プログラミングの要件になります。ところが、これまで作ったプログラムのブロック構造は、Lbl M と Goto M によって、反復、つまりループ構造を作って、話が違います。
実は、構造化プログラミングでは、「階層化」と言う概念があります。後出しジャンケンではありません。Lbl M から Goto M までをまとめて1つのブロックと考えるわけです。つまり、この1まとめにしたブロックを [ゲーム1回分の処理] ブロックと考えます。
これを「階層化」と言います。
すると、プログラムのブロック構造は、
While 1
[プログラム全体の初期化] ブロック
[ゲーム1回分の処理] ブロック
[ゲームオーバー時の処理] ブロック
WhileEnd
と、階層化により、反復(=ループ)も含めたブロックの繋がり(連結)ができました。
待てよ、一番外側の While ループは、どうするんだ! という突っ込みは承知の上です。
通常のパソコンなどでのプログラムでは、必ず「終了処理」を作ります。なので、WhileEnd の次に「終了処理」が来ます。While ループを階層化により1つの [ゲーム本体] ブロック にまとめてみます。
[ゲーム本体] ブロック (While 1 ~ WhileEnd を1まとめに階層化したブロック)
[終了処理] ブロック
こうすると、[ゲーム本体] ブロックと [終了処理] ブロックが1点で繋がる連結構造になります。
階層化とは、このようにプログラムを機能別に抽象化することです。プログラム全体を2つのブロックに集約することは、実際には意味がありませんが、ブロックの連結構造でプログラム全体を表現できることを突き詰めれば、こうなると言う事例を示しただけです。
1点で連結できるブロック構造になるようにプログラムを作れば、機能追加が楽に行え、バグの特定が容易になり、生産性と品質を両立したプログラムが作れる...と言う理屈です。
但し、CasioBasic では [AC]キーによる強制終了を利用してプログラムを終了させると言う特殊技を使えるので、例外的にプログラム全体を無限ループにすることが許されると考えることにします。
電卓の[AC]キーを押してプログラムを終了させるのは、パソコンのプログラムを終了するのに、ウィンドウの右上にある[X] ボタンをクリックするのに近いと思います(実際は、[X] ボタンを押した時に必要な正常終了プロセスを書くことも多いので、必ずしも同じというわけでもないのですが...)。パソコンでは異常な操作、プログラムの異常時に強制終了する操作なのは、皆さんもご存じの通り。
なので、この例外は認めてやろうというわけです。
なお、[ゲーム本体] ブロックなんて言ってしまうと、肝心のプログラムの構造が分かりませんので、階層化し過ぎないことも重要です。
さて、Chapter 2 では、「動きのあるプログラムを作る」 がテーマです。
そこで、次回では幾つかの動きを追加して、反射ゲームを完成させます。
つづく...
⇒ CasioBasic入門14 / 目次
応援クリックをお願いします。励みになるので...