前回の記事では演習問題7(アニメーション)、デバッグ、関数、セルの書式設定について学習しました今回は、ExcelVBAの最後の演習問題8(hit&blow)に挑戦しましょう
まずはExcelを開いて「開発」タブのリボン左端の「Visual Basic」ボタンをクリックし「Microsoft Visual Basic for Applications」画面を起動して、その画面の「挿入」タブの「標準モジュール」を選択してプログラミングの準備をしましょう

演習問題8(hit&blow)
hit&blow(ヒットアンドブロー)というゲームを知っていますか?
0~9の重複しないバラバラな3つの数字で構成された3桁の正解の数を当てるゲームです
(ルールによっては3桁ではなく4桁の場合もありますが今回は3桁にします)
hitは数字と桁の両方一致している、blowは数字は一致しているが桁は一致していないという意味で、プレイヤーは3桁の数字を答えると、その結果としてhit数とblow数を出題者から伝えられるので、hit数とblow数から正解の数を推理して、なるべく少ない回答数で正解の数を当てるというゲームです
言葉で説明するより実際のゲームの様子を見た方が分かりやすいと思うので以下をご覧ください
HitandBlow例.gif)
上記のゲーム内容の解説をします
【1ゲーム目】
1回目 「012」 = 「hit:0 blow:1」 → 0か1か2のどれかが桁は違うが使われている
2回目 「597」 = 「hit:0 blow:2」 → 5か9か7のうち2つが桁は違うが使われている
※ここまでその他の数字(3 , 4 , 6 , 8)は正解の数に使われていないことが判明
※1回目のblow:1の数字が1、2回目のblow:2の数字が9と7と仮定して桁を変えて次を回答
3回目 「179」 = 「hit:0 blow:1」 → 2回目がblow:2だったことから今回のblow:1は9か7のどちらか、さらに5は使われていて1は使われていない
※3回目のblow:1の数字が7、1回目のblow:1の数字が2と仮定して桁を変えて次を回答
4回目 「725」 = 「hit:2 blow:0」 → hit:2のうち5は確実で、もう1つのhitが7の場合は705、もう1つのhitが2の場合は925の2択
5回目 「925」 = 「hit:1 blow:0」 → 4回目で2択まで絞り込めていたので正解は705
6回目 「705」 = 「hit:3 blow:0」
【2ゲーム目】
1回目 「364」 = 「hit:0 blow:3」 → 3と6と4の桁が違うだけで全て使われている
※3と6と4の桁を変えて次を回答
2回目 「643」 = 「hit:0 blow:3」 → 1回目と2回目の結果から正解は436
3回目 「436」 = 「hit:3 blow:0」
hit&blowのゲーム内容について分かったと思うので、これまで学習した知識を使って以下のプログラムを作ってみましょう
ルール1)0~9の重複しないバラバラな3つの数字で構成された3桁の正解の数を決める
ルール2)MsgBoxにて 「3桁のヒットアンドブローをしましょう」「0~9の重複しないバラバラな3つの数字で構成された3桁の正解の数を当ててください」「なるべく少ない回数で正解の数を当ててください」と表示する
ルール3)InputBoxにて「答えを入力してください」と尋ね、入力された3桁の数字とルール1で決めた正解の数を比較し、hit数とblow数をMsggBoxで「hit:〇 blow:□」と表示する(〇と□は結果の数字)
ルール4)ルール3で入力した3桁の数字をA列に、hit数とblow数の結果「hit:〇 blow:□」をB列に上から順番に表示する(A列にはゼロで始まる数字も入力できるようにする)
ルール5)正解(hit:3 blow:0)するまでルール3とルール4をずっと繰り返す
ルール6)正解(hit:3 blow:0)したらMsgBoxにて「正解おめでとう」「●回で正解しました」と表示しゲームを終了する(●は回答した回数)
ルール7)ゲームのスタート時に前回の結果が残らないようにセルを全て消す
演習問題8(hit&blow)ヒント:プログラムの流れ
① セルの値を全て消す
② ゼロで始まる数字を記録できるようセルの書式設定を文字列にする
③ MsgBox関数でルール説明のメッセージ(ルール2の内容)を表示する
④ 回答した回数を数える変数countを用意し最初は0にしておく
⑤ 正解の数の3桁を1桁ずつ分けて変数a , b , cとして0~9のランダムな数にする
⑥ ⑤で決めたa , b , c が重複している場合は、重複しなくなるまで⑤を繰り返す
⑦ hit数を数える変数hitとblow数を数える変数blowを用意しどちらも0にする
⑧ 回答の3桁を変数answerとしてInputBox関数で入力された値を代入する
⑨ ⑧で入力された変数answerを1桁ずつ分けて変数x , y , z に代入する
⑩ hit数とblow数を数えるため正解の数(a , b , c)と回答(x , y , z)を1桁ずつ比べる
⑪ hit数とblow数の結果をMsgBoxで表示する
⑫ 変数count を1増やし、A列に回答、B列にhit数とblow数を入力する
⑬ 正解(hit3)になるまで⑦~⑫を繰り返す(⑦はhit数とblow数を0にする処理のみ繰り返す)
⑭ MsgBoxで正解した際のメッセージ(ルール6の内容)を表示する
※ただし、②~⑥は順番を入れ替えても問題なし
演習問題8(hit&blow)ヒント:プログラムの流れ⑤~⑬イメージ

※正解の数が「238」だった想定
演習問題8(hit&blow)ヒント:各プログラムの具体的な内容
① Cells.Clear
② Cells.NumberFormatLocal = “@”
③ MsgBox “3桁のヒットアンドブローをしましょう”
MsgBox “0~9の重複しないバラバラな3つの数字で構成された3桁の正解の数を当ててください”
MsgBox “なるべく少ない回数で正解の数を当ててください”
④ Dim count As Long: count = 0
⑤ Dim a As Long: a = Rnd * 9
Dim b As Long: b = Rnd * 9
Dim c As Long: c = Rnd * 9
⑥ While a = b Or b = c Or c = a
a = Rnd * 9
b = Rnd * 9
c = Rnd * 9
Wend
⑦ Dim hit As Long: hit = 0
Dim blow As Long: blow = 0
–⑬で繰り返すのは以下の2行のみ–
hit = 0
blow = 0
⑧ Dim answer As Long: answer = InputBox(“答えを入力してください”)
⑨ Dim x As Long: x = Application.WorksheetFunction.RoundDown(answer / 100, 0)
Dim y As Long: y = Application.WorksheetFunction.RoundDown((answer Mod 100) / 10, 0)
Dim z As Long: z = answer Mod 10
⑩ If a = x Then
hit = hit + 1
End If
If a = y Then
blow = blow + 1
End If
If a = z Then
blow = blow + 1
End If
If b = x Then
blow = blow + 1
End If
If b = y Then
hit = hit + 1
End If
If b = z Then
blow = blow + 1
End If
If c = x Then
blow = blow + 1
End If
If c = y Then
blow = blow + 1
End If
If c = z Then
hit = hit + 1
End If
⑪ MsgBox “hit:” & hit & ” blow:” & blow
⑫ count = count + 1
Cells(count, 1).Value = x & y & z
Cells(count, 2).Value = “hit:” & hit & ” blow:” & blow
⑬ While Not hit = 3
⑦~⑫
Wend
※While文のループ継続条件(Not hit = 3)を判定するために変数hitはWhileより上の行で宣言および0で初期化していなければならないため⑦の「Dim hit As Long: hit = 0」はWhile文より上にする
⑭ MsgBox “正解おめでとう”
count & “回目で正解しました”
演習問題8(hit&blow)ポイント:効率的にプログラミングを進めるコツ
プログラムを書いている途中で変数「正解の数」が分からないとhit数やblow数が正しいか分からずプログラムをテストするのに不便なので、⑥と⑦の間に「MsgBox a & b & c」を1行追加して変数「正解の数」の中身を表示すると効率的に進められます(完成したら削除します)
演習問題8(hit&blow)ポイント:⑬を実行する前に
⑬のプログラムが間違っていていつまでも正解(hit3)にならず無限ループになってしまうと最悪な場合はExcelが強制終了になり折角書いたプログラムが消えてしまう恐れがありますので⑬のプログラムを動かす前にバックアップとしてプログラムの中身をWindowsの「メモ帳」などにコピーして置くことをおすすめします
演習問題8(hit&blow)解答
Sub ヒットアンドブロー()
Cells.Clear 'セルの値を全て消す
Cells.NumberFormatLocal = "@" 'ゼロで始まる数字を記録できるようにセルの書式設定を文字列にする
MsgBox "3桁のヒットアンドブローをしましょう"
MsgBox "0~9の重複しないバラバラな3つの数字で構成された3桁の正解の数を当ててください"
MsgBox "なるべく少ない回数で正解の数を当ててください"
Dim count As Long: count = 0 '答えた回数をカウントするための変数をゼロにする
Dim a As Long: a = Rnd * 9 '正解の数の百の位の値を0~9のランダムな数にする
Dim b As Long: b = Rnd * 9 '正解の数の十の位の値を0~9のランダムな数にする
Dim c As Long: c = Rnd * 9 '正解の数の一の位の値を0~9のランダムな数にする
While a = b Or b = c Or c = a 'aとbとcのどれか一つでも重複していたらやり直し
a = Rnd * 9
b = Rnd * 9
c = Rnd * 9
Wend
Dim hit As Long: hit = 0 'hitの数を数える変数をゼロにする
Dim blow As Long: blow = 0 'blowの数を数える変数をゼロにする
While Not hit = 3 'hitが3じゃなかったら繰り返す
hit = 0
blow = 0
Dim answer As Long: answer = InputBox("答えを入力してください")
Dim x As Long: x = Application.WorksheetFunction.RoundDown(answer / 100, 0) 'answerの百の位の値だけを残す
Dim y As Long: y = Application.WorksheetFunction.RoundDown((answer Mod 100) / 10, 0) 'answerの十の位の値だけを残す
Dim z As Long: z = answer Mod 10 'answerの一の位の値だけを残す
If a = x Then
hit = hit + 1
End If
If a = y Then
blow = blow + 1
End If
If a = z Then
blow = blow + 1
End If
If b = x Then
blow = blow + 1
End If
If b = y Then
hit = hit + 1
End If
If b = z Then
blow = blow + 1
End If
If c = x Then
blow = blow + 1
End If
If c = y Then
blow = blow + 1
End If
If c = z Then
hit = hit + 1
End If
MsgBox "hit:" & hit & " blow:" & blow
count = count + 1 'カウントを1増やす
Cells(count, 1).Value = x & y & z
Cells(count, 2).Value = "hit:" & hit & " blow:" & blow
Wend
MsgBox "正解おめでとう"
MsgBox count & "回目で正解しました"
End Sub
以上でExcelVBAのプログラムは終了です、お疲れさまでした
最後の演習問題8はなかなか難しかったのではないかと思います
実践1~実践8までかなり色々なことを学習したのでVBAのプログラミングについてだいぶ力がついたと思いますが、ExcelVBAはまだまだ奥が深いので学習していないこともたくさんあります
もし、リクエストがあれば続編の記事もいつか書きたいと思いますのでリクエストお待ちしております
コメント