ルール
・4枚のカードに0~9までのいずれかの数字が入っている。
・複数のカードに同じ数字は入っていない。
・数字だけが合っている場合は△、数字と場所の両方合っている場合は〇を表示する。
(数字も場所も違っている場合は×を表示する。)
・4枚全てのカードの数字と場所を当てることができればクリア
下準備
まずは図のように数字を入力するための枠を作りましょう。
そして各枠のセルをクリックした状態で『データ』タブ→『データの入力規則』を選択します。
入力値の種類に『リスト』を設定し、『元の値』に0~9までの数値をカンマ区切りで入力します。
4枚のカードに0~9までの数字を指定できるようになりました。
4つのカードに数をセット
それでは、いよいよ新規のプロシージャ『Number_Game_Start』を作成してコードを書いていきます。
<コード①>
Sub Number_Game_Start() '***変数の定義***' Dim Base_No As Collection '0~9までの数字を格納' Set Base_No = New Collection Dim myNo(3) As Integer '4つの数字を格納' Dim i As Integer, j As Integer '汎用 Dim int_MAX As Integer 'コレクションのインデックスの最大値を取得' End Sub
<解説>
最初にBase_Noという名称でコレクションオブジェクトを定義します。
コレクションは複数のデータを管理できるので配列と非常に似ていますが、要素数を必要に応じて
追加したり削除したりできるという便利な機能を持っています。
また、カードの数字を格納する配列やインデックスを取得する配列も準備しておきます。
<コード②(コード①の続き)>
For i = 0 To 9 'コレクションに0~9までの数字を格納' Base_No.Add i Next i
<解説>
ループ処理でコレクションに0~9までの数字を入力します。
要素の追加はAddメソッドで行い、半角スペースを開けて設定したいデータの値を指定します。
<コード③(コード②の続き)>
'配列の各要素にランダムに重複しない値を格納' int_MAX = 10 For i = LBound(myNo) To UBound(myNo) j = Int((int_MAX - 1 + 1) * Rnd + 1) 'jに1~コレクションのインデックスの最大値までの整数値を格納' myNo(i) = Base_No(j) Base_No.Remove j int_MAX = int_MAX - 1 'コレクションのインデックス数が1つ減少' Next i
<解説>
最初にint_MAXにコレクションのインデックス数を格納します。
そしてループ処理で4枚のカードの値となる配列に順番にコレクションの値を入れていきます。
この時Rndを使用してランダムにコレクションの要素を指定するインデックスを取得しています。
(コレクションのインデックスは1から始まる点にもご注意ください。)
そして、配列に格納し終えた要素はRemoveメソッドでコレクションから削除しています。
この処理により4枚のカードに0~9までの数をランダムに、重複することなく取得することができました。
<コード④(コード③の続き)>
'取得した値をセルに記録 Range("E9") = myNo(0) Range("G9") = myNo(1) Range("I9") = myNo(2) Range("K9") = myNo(3)
<解説>
それでは、配列に取得した値をセルに書き出してみましょう。
コード①~④を記述したプロシージャをボタンに登録して実行すると
指定したセルに4つの数字がランダムに設定されることが確認できるでしょうか。
<実行結果>
クリア判定
新しいプロシージャ『Number_Check』を作成してクリア判定機能を追加します。
<コード①>
Sub Number_Check() '***変数の定義***' Dim target_Col As Integer 'チェック対象となるセルの列数を記録' Dim answer_Col As Integer '答えのセルの列数を記録' Dim i As Integer For target_Col = 5 To 11 Step 2 'カードの数値をチェック' Cells(11, target_Col) = "×" '初期値として×を設定' For answer_Col = 5 To 11 Step 2 '答えの数値をチェック' 'ここにコード②(後述)を記述' Next answer_Col Next target_Col End Sub
<解説>
変数target_Colにカードの列数を、answer_Colに解答の列数を設定して
ループ処理でチェックを行います。
レイアウト上各セルの間に1列空白の列が入っているので、Step2で2列ごとにチェックを行います。
また、ヒントの初期値は“×”とします。
ここまで記述したらCheckボタンに上記コードを登録して結果を確認してみましょう。
続けてコード①のループ処理の内部にチェック処理を記述していきます。
<コード②>
'***変数の定義***' Dim target_Col As Integer 'チェック対象となるセルの列数を記録' Dim answer_Col As Integer '答えのセルの列数を記録' Dim i As Integer For target_Col = 5 To 11 Step 2 'カードの数値をチェック' Cells(11, target_Col) = "×" '初期値として×を設定' For answer_Col = 5 To 11 Step 2 '答えの数値をチェック' If Cells(5, target_Col) = Cells(9, answer_Col) Then If target_Col = answer_Col Then Cells(11, target_Col) = "〇" '場所・数字共に正解' Else Cells(11, target_Col) = "△" '数字のみ正解' End If Exit For 'ループ処理を抜ける End If Next answer_Col Next target_Col
<解説>
まずはIF文でカードの番号と解答の番号が一致しているかをチェックします。
一致している場合、さらに内部のIF文で列番号が一致している場合は〇を、
数字が一致しているが場所は一致していないという場合は△を表示するようにします。
不具合を入力チェックで排除
ところで、ここまでのコードには1つ問題点があります。
カードを全て未入力にしてCheckボタンを押すとヒントには全て×が表示されるはずですが、
解答に0が含まれている場合は下記の様に〇や△が表示されてしまうのです。
これは、VBAではセルが空白の場合は0と判定されてしまうことによる現象です。
この場合はカードが未入力のままチェックが行われることを防ぐ処理を入れることにより
不具合を解消することができます。
<コード④:変数定義の直後に記述>
'***変数の定義***' Dim target_Col As Integer 'チェック対象となるセルの列数を記録' Dim answer_Col As Integer '答えのセルの列数を記録' Dim i As Integer '未入力のカードがある場合はエラーメッセージを表示して処理を中断' If Range("E5") = "" Or Range("G5") = "" Or _ Range("I5") = "" Or Range("K5") = "" Then MsgBox "未入力のカードがあります。" Exit Sub End If
<実行結果>
様々な数字を入力し、チェック機能が問題なく組み込まれていることを確認したら
解答が見えている行は非表示にしておきましょう。
最後に、プロシージャの終端にクリア判定の処理を入れると数当てゲームの完成です。
<コード⑤>
'クリア判定 If Range("E11") = "〇" And Range("G11") = "〇" And _ Range("I11") = "〇" And Range("K11") = "〇" Then MsgBox "正解です!" End If
<実行結果>
まとめ
数当てゲームは数字と場所のチェック機能を組み込むことと、思わぬ不具合を防止するために
入力チェックを入れることがポイントです。
また、カードの枚数を増やしていくとより難度の高いゲームを作ることができるので
ぜひコードをアレンジして試してみてください。