Casio Basic入門10

Casio Basic入門
<目次>

誤字脱字・記載ミスや分かりにくい表現は随時追記・修正します
最終: 2015/01/07

 4. CasioBasicを使ってみる(続き)


Chapter 2 - 初級

◆ Chapter 2 の目標: 動きのあるプログラムを作る
簡単なアクションゲームを作る

前回: Casio Basic入門9


Chapter 2-1 で羽根が回るアニメーションを作りました。

プログラム名 CH2-1
50→C
Lbl 0
If C-4Int(C÷4)≦1
Then
Locate 8,2,"X"
Else
Locate 8,2,"+"
IfEnd
Dsz C
Goto 0
Locate 8,2," "


羽根が回る時間は、カウンターCで決まり、今はCが50に固定されています。反射ゲームでは、羽根が回る時間をランダムにします。



Chapter 2-2
ランダム関数を使う

fx-5800Pには、Ran#RanInt# の2つのランダム関数が用意されています。

Ran#
0~1の間のランダムな小数を返します。
羽根を回す時間は、整数のカウンタC をランダムに設定する必要があります。そのためにはRan#が返す小数から整数を作る必要があります。例えば、2桁の整数を得るには、Int(100Ran#) とします。

RanInt#(L,H)
整数 L 以上、整数 H 以下の範囲でランダムな整数を返します。
羽根を回す時間は、整数のカウンタC をランダムに設定したいので、整数を返す RanInt#( ) 関数を用いる方がシンプルです。そこで、2~50の間の整数をランダムに得て、それをカウンタC に使うことにします。

そこで、50→C を RanInt#(2,50)→C  に置き換えます。

RanInt#(2,50)→C
Lbl 0
If C-4Int(C÷4)≦1
Then
Locate 8,2,"X"
Else
Locate 8,2,"+"
IfEnd
Dsz C
Goto 0
Locate 8,2," "



ところで、ここで 0~50 の間の整数を得ようとして、RanInt#(0,50) とすると、たまに問題が発生します。つまりバグです。

RanInt#(0,50) は、0を返すことがあります。すると、カウンタ C が0になります。

この場合、Locate 8,2,"×" に続いて Dsz C が実行されると、Cが1つ減って-1になります。ループが回るに従ってC はどんどん減ってゆき、0になることが決してありません。ループを脱出するのはC が0になる時です。つまり、いつまでたってもループが回り続けるので、ゲームになりません。

では、RanInt#(1,50) はどうでしょうか?
1を返すときは早過ぎて、表示と同時に消えてしまい、ゲームとしては鬼仕様。実際に実行すると分かります。

そこで、RanInt#(2,50) としました。

これで、アニメーションを表示し、ランダムな時間が経過すると消える部分(ゲームの前半)ができました。

プログラム名 CH2-2
RanInt#(2,50)→C
Lbl 0

If C-4Int(C÷4)≦1
Then
Locate 8,2,"X"
Else
Locate 8,2,"+"
IfEnd
Dsz C
Goto 0
Locate 8,2," "


続いてプログラムの後半部分を作ります。



Chapter 2-3
再びGetkeyDoループでカウンタ計測

プログラムの後半部分は、アニメーションが消えた後、キーを押すまでの反応時間を計測して、その結果を表示する機能です。

そのためには、何かキーが押されるまでループをまわし、ループの中でカウンタを増やしてゆく....これで反応時間を測定できます。キーが押されてループから抜けた時、カウンタの値を表示すれば、後半部分ができそうです。

今回は特定のキー、fx-5800P の [EXE] キーの隣にある [(-)] キーを押すことにして、このキーが押されたことの検出は Getkey を使います。そして、このキーが押されたらループから抜けて、その時のカウンタの数を表示するにコードを書いてゆきます。

さて、[(-)] キーのキーコードは、......Chapter 1 で作った Get Keycode プログラムで調べてみてください。DoループとGetkeyの使いこなしを、Chapter 1 で紹介しています。

或いは、プログラムライブラリ - キーコード取得 を参照してください。


先ずは、Do ループ:

Do
[処理]
LpWhile
[ループ継続条件]


ここで、ループ継続条件は、「押されたキーが [(-)] でないこと」 となります。従って、

Do
[処理]

LpWhile Getkey≠57

となります。


次に、このループ内でカウンタを増やす処理を追加します。

Chapter 2-2 で作った部分でもカウンタC を使っています。カウンタは0からスタートさせる必要があり、0→Cで初期化しておくのが常道です。

ところで、アニメーションが終わった時は、このカウンタC は必ず0(ゼロ)になります。そして、今作るループでは、カウンタを0からスタートすれば良いので、そのままカウンタCを使えば良さそうですが、今後のプログラム変更でどうなるか分かりません。

もし、Cがゼロから始まらないようなプログラム変更を行い、その時、ゼロに初期化していないことを忘れていると、バグに悩むことになります。そこで、明示的に 0→C で初期化しておきましょう。

ループがまわるたびにカウンターを1づつ増やせば良いので、Isz C を使います。

[(-)] キーを押すとループから抜けるので、ループから抜けた直後にカウンターCの値を表示します。

これで、今回の追加部分がきそうです。

プログラム名 CH2-3
RanInt#(2,50)→C
Lbl 0
If C-4Int(C÷4)≦1
Then
Locate 8,2,"×"
Else
Locate 8,2,"+"
IfEnd
Dsz C
Goto 0
Locate 8,2," "

0→C
Do
Isz C
LpWhile Getkey≠57
Locate 8,2,C


今回追加した部分は、赤文字で示しています。

実際にプログラムを走らせてみてください。ゲームの基本的動作を確認できます。



Chapter 2-4
例外処理・例外フラグ・Breakコマンド

これまでに作ったプログラムを走らせて遊んでみます。

すると、アニメーションが表示されている時から、[(-)] キーを連打し続けると、1 を表示させることができてしまいます。フライングができるわけです。これではマズイ。ゲームになりません。

フライングしたらペナルティーを与えるとゲームらしくなります。

そこで、今回はフライングしたことを検知するようにします。具体的なペナルティーについては、点数の付け方やゲーム全体のルールをに即して、あとで考えることにします。

アニメーションを表示するループを抜き出します。

Lbl 0
If C-4Int(C÷4)≦1
Then
Locate 8,2,"×"
Else
Locate 8,2,"+"
IfEnd
Dsz C
Goto 0


このループの中で、[(-)] キーが押されたら、それはフライングです。

フライングを検出したら、直ちにループから抜け出し、さらに「フライング」と表示するように、プログラムを変更しようと思います。

[(-)] キーのキーコードは、57なので、Getkeyの戻り値を監視して、57になればループを抜けるようにすれはOKですね。

このループは、カウンタC がゼロになればループから抜けるようになっています。これら2つの条件でループを抜けるように変更しなければなりません。

そこで、Lbl/Goto + Dsz ループとは別に、Doループ + Dsz を使うと、2つの条件でループを抜ける方法が、簡単に実現できるので、ループ自体を Doループに変更します。

Do
If C-4Int(C÷4)≦1
Then
Locate 8,2,"×"
Else
Locate 8,2,"+"
IfEnd
Dsz C
LpWhile Getkey≠57


Lbl 0 / Goto 0Do / LpWhile Getkey≠57 に置き換えただけですが、Cがゼロになる時とキーコード57になる時の2つの条件でループを抜けられます。とても簡単に変更できました。



では次に、ループを抜けた後、フライングがあったことをを表示する方法を考えます

本来のプログラムの流れとは別に、例外的なことが発生した時に対処することを「例外処理」と言います。今回のフライングを「例外処理」として扱うことにします。


例外処理は、本来のプログラムの流れとは別に、一括して処理するのが良い方法です。プログラムの構造を単純化し、流れを明確にするために役立ち、バグの発生を抑える効果があります。

複数の異なる例外に対しても、一カ所でまとめて処理するようにします(ゲームを完成させるためには、他の例外処理も必要になりそうです)。

そこで、例外が発生した時に、その例外の種類を「例外フラグ」という変数に記録し、例外1、例外2、例外3,といったように区別します。こうしておくと、例外を一括処理する時に、フラグの内容に応じて、場合分けをして処理を行います。

本来のルートからちょっと寄り道して例外処理を行って、それが終われば元のルートに戻る、これが例外処理です。



例外検知と例外フラグ

フライングは、ループで構成されるプログラムの流れを壊す例外事象なので、「フライングだゾ!」と表示し、さらにゲーム進行上の変数(点数など)を変更するのは、一括して 「例外処理」として扱うことにします。なお、例外が発生したことを記録しておく例外フラグの「フラグ」とは旗のことです。「例外が発生したゾ!」と旗を揚げるイメージですね。フラグの最初の概念は、0 か 1、つまり旗を下げるか挙げるかのどちらかでした。

しかし、例外フラグに整数を割り当てる方が便利です。例外が発生していない時は、フラグは0(ゼロ)、例外発生時には0以外の整数値を割り当てることで、例外の種類を区別して記録できます。

ここでは、変数 E を例外フラグとします。例外 = Exception (イクセプション )の頭文字をとって E としました。

・例外フラグ E は、例外が発生していない時はゼロと決めます。つまり最初はゼロに初期化します: 0→E

・フライングが発生した時は例外フラグ E の値を 1 とします:
1→E



すると、以下のように変更できます。

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


※ 重要: 例外フラグ E は、プログラムの先頭部分で0に初期化しておく必要があります。

変更した部分を赤文字で示しています。Getkeyの戻り値が57の時、例外フラグ E に 1 を代入します。
ここで、If を使っても良いのでですが、より動作の速い ⇒(ジャンプ命令) を使いました。

LpWhile [ループ継続条件] の部分を、E=0 としました。例外が発生しなければ、例外フラグ E はゼロなので、この時はDoループを継続します。フライングと言う例外が発生して、例外フラグ E が 1 になると Doループを抜けます。

同時に、カウンタC がゼロになると、Dsz C のおかげで、LpWhile E=0 をジャンプして、次へ進んでループを抜けられます。


今後、フライング以外に新たな例外に対応する必要になれば、例外フラグ E に、2、3...と別の整数を割り当てます。その場合でも、Eは 0 以外ですから、ループを抜けられます。

以上をまとめます。

0→E
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
Isz C
LpWhile Getkey≠57
Locate 8,2,C



さて、フライングをした場合は、反応時間の計測は不要で、直ちにこのブロックを通り抜けて欲しい。

そこで、フライングした時、つまり例外フラグEが1の時に、直ちにDoループを抜けるようにします。そこで、CasioBasicに備わっているBreakコマンドを使います。Breakコマンドはループから抜けだすコマンドです。


※ CasioBasicコマンドリファレンス
      - Break



そこで、以下のようにプログラムを変更します(赤文字が変更部分)。

0→C
Do
E=1⇒Break
Isz C
LpWhile Getkey≠57
Locate 8,2,C

If E=1
Then
Locate 3,2,"FALSE START"
IfEnd

Doループの中では、Eが1 ならば Break を実行して、ループから抜けます。

Doループが終われば、例外処理を一括して行う部分です。Eが1ならは「フライング」と表示を行います。

※ フライングは和製英語なので英語としては通じません。そこで FALSE START (不正スタート)と表示することにします。


これで、フライング検知と表示を盛り込むことができました。

プログラム名 CH2-4

0→E

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
Isz C
LpWhile Getkey≠57
Locate 8,2,C

If E=1
Then
Locate 3,2,"FALSE START"
IfEnd


改行を使って機能ブロックに分けています。CasioBasicでは、このように改行を入れてもエラーになりません。

1ブロック: 初期化
2ブロック: アニメーション表示(フライング検出)
3ブロック: 反応時間計測と表示
4ブロック: 例外処理(フライング表示)



次回は、これまで作ったプログラムを繰り返すようにし、さらに得点を計算させて、ゲーム仕様に近づけてゆきます。



つづく...


CasioBasic入門11 / 目次



応援クリックをお願いします。励みになるので...
にほんブログ村 IT技術ブログ 開発言語へ


 



keywords: fx-5800PCasioBasicプログラミング入門プログラム関数電卓

リンク集 | ブログ内マップ
関連記事

テーマ : プログラム関数電卓
ジャンル : コンピュータ

コメントの投稿

非公開コメント

無事解決して良かったです。(^^)

ツル様、こんにちは!

プログラム上の問題と気が付かずに安易にリセットを勧めてしまいすみませんでした。
今回の場合だと、もしオールリセットされていても、相変わらず解決しないということになっていたわけで、本当に良かったです。(^^)

fx-5800Pは10年選手ですが、今年に入ってからtakumako様のCcLinkerにてついにPCとのリンクも出来るようになりましたし、まだまだ息の長い機種になりそうです。(^^)
http://www.geocities.co.jp/SiliconValley/1946/index.html



管理人様、こんにちは!

Locateの表示による問題はCasioBasic全体での重要なFAQでしたね。
Cのプログラムでも同様の事象が発生して?ということになってしまうことがたまにありますが、これは常に頭の隅に置いておかねばなりません。
迅速かつ的確なサポートはさすが管理人様です!(^^)

>ところで、ようやく仕事の余裕できそうです。C.Basic
>の件ぼちぼちとりかかります。

1.00以降、機能拡大が一気に進んでバグ出しが細かなところまで出来てない状態が続いております。(^^;
よろしくお願いたします。(^^)

思い込みの罠

ツル様

今回のようなケースはよくあることで、Casio Basic入門の中でも取りあげているくらいです。私は思い込みの罠と称しています。慣れているほどハマる罠、というわけです。

よろしければ、是非またご質問下さい。

ありがとうございます。

サポート感謝

sentaro様

サポートありがとうございます。
以前ピタゴラス数を見つけるプログラム記事で、Locate の表示による問題を指摘下さったのをおもいだして、今回の解決に繋がったわけです。

いつもありがとうございます。

ところで、ようやく仕事の余裕できそうです。C.Basic
の件ぼちぼちとりかかります。

No title

やす様!

ありがとうございました。解決いたしました。
ご教示の通りでした! RanInt#は正常でした。
何年もやってきておきながらどうして気が付かなかったのか、
老いを痛感いたします。
いやあ、この感謝をどう表せばよいものか。
さすがブログ主様!本当に助かりました。ありがとうございました!

ひょっとして Locate が悪さをしているかも...

ツル様

コードを教えて頂き、ありがとうございます。

ひょっとして、RanInt#自体は正常に動作していて、Locate による表示の関係で、意図しない結果になっているかも知れません。


Cls:ClrMemory⏎
Lbl 0⏎
RanInt#(1,100)→X⏎
Locate 1,1,X▲
Goto 0


例えば、X として 100 が表示された後、

今度は X が 2 だとすると

既に 100 と表示された上から、一番左の1桁のみが 2 になって、続き 00 がそのまま表示されたままになります。

すると、本当は X = 2 なのに、X = 200 になったかのようになってしまいます。


Locate は、指令された位置 (1, 1) から、x の実際の桁数のみを表示する仕様になっています。


そこで、下から2行目の Locate 1,1,x◢
の1つ上に、

Locate 1,1,"  " (スペース3つ)


を追加してみてください。

これで、問題が解消されるなら、上の推測が正しいことになると思います。

私も同じ問題にハマったことが何度か有ります。お試しください。


> (当方、宮城県仙台市です。まさか福島原発の放射線が機器内に作用を?なんて色々悩んでおります。)

確かに、2台とも誤動作する理由になりそうですね。
あながち冗談でないかも知れないので、微妙です。
本当だとすれば、半導体に異常が出るくらいの放射線を浴びてしまっているツル様には、直ちに検診をお勧めするところです。

昔筑波の高エネルギー研究所で1年仕事していたことがあって、放射線防護は嫌になるほど言われたので、個人的には洒落にならなかったりします...

No title

管理人様

ふと思ったのですが、過去にRanIntでトラブルは記憶がありません。
もしかして、RanInt#とLblとが相性の悪い組み合わせなのではないか?
と思いました。RanIntをFor-Next文でいくら回しても問題が起こらないからです。指示範囲で戻ります。

No title

管理人様

お付き合いくださりとても恐縮しております。

これから少し長いプログラムをゆっくり始めようかと構想を考え、まとまりかけたので打ち始めた出だしでつまづいた次第です(笑)

Cls:ClrMemory⏎
Lbl 0⏎
RanInt#(1,100)→X⏎
Locate 1,1,X▲
Goto 0

要するに、たったのこれだけです。
初めの内は正常に動き、数十回目のEXEで範囲外の数値が戻ることが多いです。EXEが面倒な時は▲を外してLbl-Goto間の自動実行をさせますが、同じ結果、範囲外の表示が始まります。何なのでしょうね。
(当方、宮城県仙台市です。まさか福島原発の放射線が機器内に作用を?なんて色々悩んでおります。)

LANINT#の問題

ツル様

2台とも同じ問題が再現すると言うことから、ひょっとしてプログラム上で他のコマンドや関数との組み合わせで問題が発生している可能性があるかも知れません。以前組み合わせで問題が発生したときにカシオお客様センターに問い合わせた結果、その問題を認めてくれたこともあります。

そこで、問題が起きるプログラムから、少しずつ関係なさそうなコードを消して、LANINT#の問題動作が再現するように、プログラムをシンプルになさってはどうでしょうか?

私が掲載したコードに何か問題が見つかれば修正したいと思います。

今のところ、手元で問題が再現していないので、よくわからない状態なんです。

電卓の画面に表示されている通りに、書き出したコードをコメント欄にお書き頂ければ、こちらでも試してみたいと思いますm、お手数でなければですが...

No title

わざわざお返事頂き、ありがとうございました。
多くのプログラムデータが入っているためにそのリセット操作はまだです。
が、手持ちの未使用のもう1台でもRanInt#の動作を試したところ同じでした。やはり範囲外の数値が戻ります。様々なプログラムの計算結果が不安になりました。 明日にでもカシオ相談室に聞いてみます。
ありがとうございました。

メニューからのリセットを試してみて下さい。

ツル様、はじめまして。

私の手持ちのfx-5800Pで試してみたところ、範囲外の数値が出てくることは確認できませんでした。
仕様上はそれで正解なので、範囲外の値が返ってくるのは何かしら内部がおかしな状態になっていると考えられます。
おそらく、他の演算でも変な値になることがあるかもしれません。

裏面のリセットでは無く、メニューの2ページめのSYSTEMの、
Reset Setup
もしくは
Reset All
は試されましたでしょうか?

もしそれで直らないということであれば故障ということが考えられます。

No title

こんにちは。
とても参考になり有難く読ませて頂いております。
久し振りにfx-5800Pでプログラミングをして、ちょっと障害に当たり困っています。
アドバイスを頂けますと助かります。

RanInt#ですが、続く()に指定する範囲を超えた数値が戻り、困っています。
例えば、(1,100)としても最大値が800とか範囲を越える数値が良く出てしまい
エラーになります。どう頑張っても解決できません。
裏面のリセットしても直りません。故障でしょうか?
最新記事
検索フォーム
最新コメント
カテゴリ
C# (3)
Online Counter
現在の閲覧者数:
プロフィール

やす (Krtyski)

Author:やす (Krtyski)
since Oct 30, 2013


プログラム電卓は、プログラムを作って、使ってナンボ!

プログラム電卓を実際に使って気づいたこと、自作プログラム、電卓での Casio Basic, C.Basic そして Casio Python プログラミングについて書いています。

なお管理人はカシオ計算機の関係者ではありません。いつでもどこでもプログラミングができるプログラム電卓が好きな1ユーザーです。


写真: 「4駆で泥んこ遊び@オックスフォード郊外」

リンク
月別アーカイブ
Sitemap

全ての記事を表示する

ブロとも申請フォーム

この人とブロともになる

QRコード
QR