25マスの手書きビンゴをもう浴びるほどやり狂いたい!
きっかけはもうこの一点だけ、でした。25ビンゴは、縦5マス、横5マスに1から25までの数字を適当に書いた紙をそれぞれ用意し、数字を交互に言い合いながらビンゴ(縦列・横列・ナナメ列)を完成させるゲームです。
エクセルVBAで1~25までの数字をランダムに発生させる処理を考えてみた
目次
25ビンゴのルールに関しては人や地域によって様々みたいなので、あくまでも個人的なアレですけど、代表的なものをふたつ紹介します。
25ビンゴルール
細かいアレはあるかもしれませんが、大きく分けると25ビンゴには2つの方式があります。
ビンゴルール1
自分が言った数字にバツ、相手が言った数字にマルをつけて、マルで1列ビンゴをつくる。
詳しい説明はコチラにあります
ゲームの特徴
相手が言った数字でビンゴを作るので、ビンゴ特有のドキドキ感が演出されます。さらに、自分がバツをつける位置も考えなくてはならないので、より戦略的、知的な戦いになります。
ビンゴルール2
自分が言った数字と相手が言った数字、両方マルをつけて、マルで数列(2列~5列くらい)ビンゴをつくる。
ゲームの特徴
自分が言う数字でもビンゴが作れるので特に何も考えずにビンゴが楽しめます。あまり深くまで考えられない子供向き、といった感じです。
完成イメージ A4版
完成イメージは以下のような感じです。
完成イメージ(25ビンゴシート)
実際のエクセル上にはボタンが配置されてあり、そのボタンをポチポチ押すたびにマスの数字がランダムで入れ替わるという仕様になってます。マクロのセキュリティでマクロを有効にしてお使いください。
ひとり1枚で15回の対戦が楽しめるので、もう嫌になるほど対戦が楽しめます。完成したシートを使ってみたいという方は以下のリンクからダウンロードできますので使ってみてください。
25ビンゴシート ダウンロード(ファイル名 25_bingo.xls)
(Excel 2003,2007,2010,2013 で動作を確認)
1~25の数字をランダムに発生させるマクロについて
ネットでちょっと調べてみると、別シート上で関数を使って乱数を発生させて、それに順位をつけて、みたいなやり方が一例として紹介されていました。
場合によりけり、かもしれませんが、個人的には別シートを使うやり方はどうもスマートではない気がします。VBAで書けば小難しい処理部分はすべて裏に隠し、ボタンひとつで表現できるので今回はこちらの方法でやることにします。
マクロに必要と思われる処理は主に以下の2点です。
- 1~25までのランダムな数字を自動で発生させる
- 1~25までの数字で同じ数字が出てはいけない
ランダムな数字の自動生成は単純ですが、問題は2の同じ数字が出ない、という点です。ここに悩まされましたが、ネットで調べながらあれこれ試行錯誤してみた結果、ブーリアン型を使ったフラグを使って実装する方法でうまくいきました。1から25までのフラグ用の配列を用意し、一度使われた数字かどうかをTrueとFalseで判断します。
以下は実際に作成した1から25までの数字をランダムに発生させるマクロです。
[vb]
Sub random25()
Const MIN =1
Const MAX =25
Dim num As Integer
Dim a_num(MIN To MAX) As Integer
Dim flag(MIN To MAX) As Boolean
Dim cnt As Integer
‘乱数の初期化
Randomize
For cnt = MIN To MAX
Do
num = Int(MAX * Rnd + 1)
Loop While flag(num)
a_num(cnt) = num
flag(num) = True
Next cnt
End Sub
[/vb]
マクロの解説的なもの
- まず最終的に25コの数字が必要になることからFor文を使用して25回繰り返しを宣言します。
- 次に変数numにランダムに発生させた1~25までの数字を格納し、flagの確認をしています。Do~Loop Whileはflag(num)がFalseを引くまで(まだ出ていない数字が出るまで)延々と処理を繰り返します。(ブーリアン型の宣言時の初期値はFalseです)
- ループを抜けると、その時の数字numを1~25までの配列であるa_num()へと格納し、numに対応するflag(num)をTrueに変えます。これで次の回のループ(2の処理)でこの数字が呼ばれても無視されることになります。
- For文が全て終わった時には、a_num(1)からa_num(25)には重複しないランダムな1~25までの数字が格納されていることになります。あとは25個の数字を順番にマス目に配置していくような処理を別で書いて連携させれば完成です。
乱数に関するサンプルコード、ありがとうございます。
一つだけ補足します「Excel2016でも動作確認しました」
私も良く見たの隠しシートの数字を持ってくるものですが、
>個人的には別シートを使うやり方はどうもスマートではない気がします。VBAで書けば小難しい処理部分はすべて裏に隠し、ボタンひとつで表現できる
確かにその通りだと思っていました。Rnd関数で「0から1」を求めたのを平易に
シートの値に変換する事は簡単ですが、こういう場合難解になります。
・データ格納用に隠しシートを持ってそこに乱数を元にしたテーブルを作成
・乱数格納用データと隠し値テーブルが併存する
・更にテーブル行が動的な場合、単純に乱数を置けない=これが一番の問題
(ここはサンプルの静的配列から改修しました)
VBA知識が深い訳ではありませんのでやや理解するまでに時間がかかりましたが、
コードに注釈をつけ、問題なく運用できました。
改修したのはConstで決め打つのではなく、最終行を取得して
動的配列を生成する部分です。
<サンプルコード>
Sub test()
Dim i, j As Integer
Dim a() As Integer
‘最終行を求める
j = Cells(Rows.Count, 1).End(xlUp).Row
ReDim a(j)
Call rnd_set(a(), j)
For i = 1 To j
Cells(i, 2).Value = a(i)
Next i
Range(Cells(1, 1), Cells(j, 2)) _
.Sort Key1:=Cells(1, 2), order1:=xlAscending
End Sub
Sub rnd_set(ByRef item_a() As Integer, item_max As Integer)
Dim myflag() As Boolean
Dim i As Integer
ReDim myflag(item_max)
Randomize
For i = 1 To item_max
Do
‘乱数=Int((最大値 – 最小値 +1 ) * Rnd + 最小値)
num = Int(item_max * Rnd + 1)
Loop While myflag(num)
item_a(i) = num
myflag(num) = True
Next i
End Sub
また機会がありましたら、宜しくお願いします。