fx-5800P【ゲーム】:Hit&Blow
追記 2018/10/30
※ CcLinker で fx-5800P に転送できるCCLファイルをダウンロードできるようにした [2018/10/31]
Hit&Blow と言うゲームをご存知だろうか?
フジテレビのNumer0nでの元になるもので、古くからある数当てゲームだ。
最初に、互いにN桁の数を決める。数の決め方には決まりがある。
・0から9までの数を使い、
・各桁は異なる数とする
・一番左の桁を0として良い
あなたが推測した数を相手に伝える。そして相手は、「2ヒット1ブロー」といったように、ヒット数とブロー数を答える。
・桁と数の両方が一致すれはヒット
・桁は違うが数だけ一致しればブロー
そこで、fx-5800Pで Hit&Blow を作ってみた
ところで、fx-5800Pで素因数分解プログラムを作った時、処理速度の遅いことが骨身にしみている。そこで、電卓が出題した3桁の数を当てるゲームとした。
プログラム作成時に、主に以下の2点を考えた:
・16桁x4行の画面内で遊べるように、全てをうまく配置できるか?
私なりのガイドライン(使いやすいプログラム参照)に従って、うまく配置してみた。
・HIT数とBLOW数の判定をどうするか?
ここが、多分一番肝心なところ。2通りのロジックを試してみた。
プログラムの仕様
1) 試行10回以下で正解すればOKとする。
・この時、「VERY GOOD」と褒めてあげる。
2) 試行11回目以降でも、ゲーム継続を可能とする。
・但し、「QUIT?」(止めるか?)と表示する。
・ここで止めたら、「YOU GAVE UP」と釘をさして、正解を表示する。
3) 試行11回目以降で正解すれば、一応ねぎらう。
・「Good」と言葉をかける。
4) 正解を出した時は、試行回数を表示する。
・一応「YOU WIN」と認定してあげる。
4) デバッグ目的で、ゲーム開始時に正解を見られるようにする
・秘密のキー入力で正解が分かるようにする。
プログラムファイルのダウンロード [2018/10/30:追記]
▶ CcLinker で fx-5800P に転送してスグ使える CCLファイルのダウンロード
※ CcLinkerの紹介
ここには、配列変数を使わない高速版(下記参照)を収録している。
ゲームの実行画面
こんな感じで完成した。
先ずは、メニューリストから、「HITBLOW」を選ぶ。

ゲームが起動した時の画面:

ガイドラインに従って、メニュー表示をした。
< ? >は秘密のキーだ(ここでは、まだナイショ)。
ここで、[EXE]キーを押して、ゲーム開始。

ゲーム開始早々、405 で 2HIT だ!
右上の :1 は試行回数を示す。
さらに [EXE] キーを押すと...

試行2回目、ここまでくれは、こっちのものだ!!
[EXE]キーを押して...次は決まるか?
ぶぅ~~(´д`)

あとは、組み合わせの問題....もうちょい...
で...

試行6回目で、当たり!!\(^_^)/
さらに [EXE]キーを押すと...

試行6回で YOU WIN の表示。
ここで、[0]キーを押すと、最初の画面へ戻って、新たに出題される。
ところで、最初の画面で秘密のキーを押すと...

こんな感じで、正解がわかる...
プログラムの構造
メインルーチンと4つのサブルーチンを作った。
・メインルーチン:
プログラム全体の流れを記述する。細かい作業はサブルーチンに任せる。
fx-5800P専用プログラム
プログラム名: HITBLOW
====================
Lbl 0
0→C:0→D:→E :初期化と初期画面表示
Cls
Locate 2,1,"Hit And BLOW"
Locate 2,3,"
Locate 2,4,"< ? >:ANSWER"
Do :秘密のキーを押した時
Getkey→F ⇒
If F>0 And F<10
Then 1→D
Break:IfEnd
LpWhile Getkey≠47
:この2行が肝心
Prog "S2HB3" :正解出題ルーチン
Prog "S3HB3" :ゲームの中心部分
Cls :結果表示
If D=1:Then
" YOU GAVE UP" :正解できなかった時 D=1
"THE ANSWER ="
Locate 14,2,A
Else
Locate 5,1,"YOU WIN" :正解時の処理
Locate 3,2,"IN"
Locate 6,2,C
Locate 8+Int(log(C)),2,"TRIES" :関数電卓ならではの処理
IfEnd ⇒ 別記事で紹介予定
Locate 1,4,"<0>:TRY AGAIN"
Whle Getkey≠25 :もう一度遊ぶ
WhleEnd
Goto 0
====================
・サブルーチン(1):
入力された3桁数を、各桁の数字に分解する。
fx-5800P専用プログラム
サブルーチン: S1HB3
入力された数字を各桁に分解し
変数 K、L、M に格納する
====================
Int(N÷100)→X ⇒ 別記事で紹介するかも...
Int((N-100X)÷10)→Y
N-100X-10Y→Z
If X=Y Or Y=Z Or Z=X
Then 1→E:IfENd
====================
・サブルーチン(2)
各桁の数字が同じにならないように、3桁数を作る。
fx-5800P専用プログラム
サブルーチン: S2HB3
各桁を重複しないように作り、
正解の変数、K、L、Mへ格納し、
正解の3桁数を変数Aに格納する
====================
RanInt#(0,9)→K
Do
RanInt#(0,9)→L
LpWhile L=K
Do
RanInt#(0,9)→M
LpWhile M=K Or M=L
100K+10L+M→A
If D=1:Then
"THE ANSWER = "
Locate 14,1,A◢
IfEnd
====================
・サブルーチン(3)
ゲームの核心の流れを記述する。
fx-5800P専用プログラム
サブルーチン: S3HB3
正解するか、諦めると
メインルーチンへ戻る
====================
10→DimZ
Do
0→E:Isz C
Lbl 0
Cls
Locate 12,1,":"
Locate 13,1,C
"3 DIGITS"?→N
Prog "S1HB3"
If E=1:Then
Locate 12,2,"ERROR"
Locate 6,3,"SAME NUMBER"
Locate 2,4,"FOUND IN DIGITS"◢
0→E:Goto 0
IfEnd
Prog "S4HB3"
If D=1:Then
Break:IfEnd
LpWhile H≠3
0→DimZ
Return
====================
・サブルーチン(4)
回答を判定して、△HIT、◇BLOW を表示する
2つの異なるロジックで作ってみた。
サブルーチン(4-1):桁数の拡張性を考えたロジック
For 文と配列変数Z[ ]を利用した。
fx-5800P専用プログラム
サブルーチン: S4HB3
ヒット数を Hへ、ブロー数をBへ
格納してサブルーチン S3HB3へ戻る
====================
0→S:0→T
0→H:0→B:0→D
X→Z[1]:Y→Z[2]
Z→Z[3]:K→Z[6}
L→Z[7]:M→Z[8]
For 1→S To 3
If Z[S]=Z[S+5]
Then Isz H
IfEnd:Next
For 1→S To 3
For 1→T To 3
If Z[S]=Z[T+5]
Then Isz B
IfEnd:Next:Next
Locate1,3,H
Locate 3,3,"HIT"
Locate 1,4,B-H
Locate 3,4,"BLOW"
If H≠3 And C>10
Then
Locate 12,3,"QUIT?"
Locate 12,4,""
IfEnd
If H=3:Then
If C>10:Then
Locate 13.3."GOOD"
Else
Locate 8,3,"VERY GOOD"
IfEnd:IfEnd
Do
Getkey→F
If F=34:Then
1→D:Break:IfEnd
LpWhilr F≠47
====================
処理速度が少し遅いように思われた。 For 文の実行分と、配列変数へのアクセスに多少余計に時間がかかるのかも知れない。配列変数に関しては単なる思い込みの可能性もあるが...
[2014/03/09:追記]
速度低下の主要因は配列変数へのアクセスが非常に遅いためである。通常変数に比べてアクセス速度が3倍近くかかるようだ。
[2018/10/30:追記]
桁数を拡張して3~5桁を選べるようにした Hit & Blow を作成している。
⇒ プログラムライブラリ - Hit & Blow
※ 拡張版 Hit & Blow ではメインルーチンは HitBlow と同じファイル名。そこで私は、3桁固定で配列変数を使わない高速オリジナル版のメインルーチンを HB に変更して、拡張版と一緒に fx-5800P に入れて遊んでいる。
サブルーチン(4-2):処理速度向上を狙って、If 文のみのロジック
2者択一の If文 は処理が速いと考え、それでも桁数拡張がしやすいロジックにしてみた。
fx-5800P専用プログラム
サブルーチン: S4HB
ヒット数を Hへ、ブロー数をBへ
格納してサブルーチン S3HB3へ戻る
====================
0→S:0→T:0→U
0→H:0→B:0→D
If X=K:Then
Isz H:1→S:IfEnd
If X=L:Then
Isz H:1→T:IfEnd
If Z=M:Then
Isz H:1→U:IfEnd
If X=L And T=0
Then Isz B:IfEnd
If X=M And U=0
Then Isz D:IfEnd
If Y≠X:Then
If Y=K And S=0
Then Isz B:IfEnd
If Y=M And U=0
Then Isz B:IfEnd
IfEnd
If Z≠X And Z≠Y:IfEnd
If Z=K And S=0
Then Isz B:IfEnd
If Z=L And T=0
Then Isz B:IfEnd
IfEnd
Locate 1,4," "
Locate1,3,H
Locate 3,3,"HIT"
Locate 1,4,B
Locate 3,4,"BLOW"
If H≠3 And C>10
Then
Locate 12,3,"QUIT?"
Locate 12,4,""
IfEnd
If H=3:Then
If C>10:Then
Locate 13.3."GOOD"
Else
Locate 8,3,"VERY GOOD"
IfEnd:IfEnd
Do
Getkey→F
If F=34:Then
1→D:Break:IfEnd
LpWhilr F≠47
====================
思った通り、配列変数とFor文で作ったサブルーチン(4-1)よりも、If 文だけで作ったサブルーチン(4-2)の方が、処理が速かった。
ちなみに、if 文が実行される回数を比較してみた:
(4-1):12回 (おそい)
(4-2):10回 (はやい)
if文が2回多いだけだ。
あきらかに体感できる範囲で、確実に速度差を感じる。If分の実行回数に違いがないとすると、
fx-5800Pで素因数分解プログラムを作った時、Doループの実行速度を簡易的に計測して、ループが1回だけ回るのに45m秒程度かかっていることが分かっている。処理時間は、当然ループ内の処理内容に依存するわけだが、それでもパソコンに比べると恐ろしく遅い。
fx-5800Pは、単4電池1本で、1日に1時間使用したとして1年の寿命と仕様に記載されている。消費電力を抑えることをかなり高い優先度としていると思われる。消費電力抑制の効果的な方策の1つに、MPUのクロックを落とすことがある。つまりその分処理速度は遅くなるわけだ。
いずれ、検証してみたいと思う。 [2014/12/14 追記]: For 文と Lbl / Goto ループの速度差は無視できるほど小さい。非常に遅い配列変数を使ったことが主要因だと判明している。
また、ソースコードの詳細については、プログラミング入門向けに別の記事で取り上げる予定だ。
応援クリックをお願いします。励みになるので...