乱数を作るクラスを改良した

乱数を作るクラス

ランダムに並べ替える作業というのは滅多にないのだけれど、絶妙に忘れかけた頃に発生するので、

akashi-keirin.hatenablog.com

このときにクラスまで作っていた。

んで、改めて見直してみたら、イマイチやなあ、と(笑)。

そんなわけで、作り直してみた。

乱数を作るクラスの改良

前に作ったやつは、あくまでも「1~最大数」をランダムに並べ替えるというだけだった。

そこで、今回は、

  1. 最小値と最小値を指定できるようにする
  2. 素数を指定できるようにする

の2点を追加することにした。

あと、クラス名とか変数名、プロパティ名も大幅に見直した。

コード

さっそく、クラスモジュールのコードを示す。

クラス名は「RandomNumbers」に変えた。

リスト1 クラスモジュール
Option Explicit

'Variables'
Private Item_() As Long
'Properties'
Public Property Get Item(ByVal i As Long) As Long
  Item = Item_(i)
End Property
Public Property Get Count() As Long
  Count = UBound(Item_) + 1
End Property
'Constructor'
Private Sub Class_Initialize()
  ReDim Item_(0)
  Item_(0) = 1
End Sub
'Methods'
Public Sub setRandomNumbers(ByVal maxNum As Long, _
                            ByVal countOfElements As Long, _
                   Optional ByVal minNum As Long = 1, _
                   Optional ByVal hasDuplicate As Boolean = False)
'///minNum~maxNumまでの整数をランダムに並べて配列に格納する。'
'///引数maxNum:最大数'
'///引数countOfElements:出来上がりの要素数'
'///引数minNum:最小数'
'///引数hasDuplicate:重複を許可するならTrue'
'///ただし、要素数が数値の種類数(maxNum-minNum+1)より大きいときは、'
'///Falseが渡されてもTrueに変える。'
  If countOfElements > maxNum - minNum + 1 Then _
    hasDuplicate = True
  Dim isUsed() As Boolean
  ReDim isUsed(countOfElements - 1)
  Dim i As Long
  ReDim Item_(countOfElements - 1)
  Randomize
  Dim tmp As Long
  For i = 0 To countOfElements - 1
    Do
      tmp = Int((maxNum - minNum + 1) * Rnd + minNum)
    '///乱数:Int((最大値 - 最小値 + 1) * Rnd + 最小値)'
    Loop Until isUsed(tmp - minNum) = False
    Item_(i) = tmp
    If Not hasDuplicate Then isUsed(tmp - minNum) = True
  Next
End Sub

まあ、大枠では変えていないので、説明は省略w

使ってみる

次のコードで実験。

スト2 標準モジュール
Public Sub testRandomNumbers()
  Dim rndNums As New RandomNumbers
  With rndNums
    Call .setRandomNumbers(10, 10, 1, False)  '……(1)'
    Dim i As Long
    For i = 0 To .Count - 1
      Debug.Print .Item(i)
    Next
    Debug.Print String(5, "=")
    Call .setRandomNumbers(20, 20, 11, True)  '……(2)'
    For i = 0 To .Count - 1
      Debug.Print .Item(i)
    Next
  End With
End Sub

setRandomNumbersメソッドを2回呼び出して、それぞれ取得したランダムな数列をイミディエイトに書き出すだけのコード。

(1)の

Call .setRandomNumbers(10, 10, 1, False)

では、

最大値10(第1引数)、最小値1(第3引数)で、重複を許さず(第4引数)に、ランダムに並べた10個(第2引数)の数字を得ることになる。

同様に、(2)の

Call .setRandomNumbers(20, 20, 11, True)

では、

最大値20(第1引数)、最小値11(第3引数)で、重複を許して(第4引数)、ランダムに並べた20個(第2引数)の数字を得ることになる。

ちなみに、(2)で

Call .setRandomNumbers(20, 20, 11, False)

と、第4引数をFalseにしたとしても、setRandomNumbersメソッド内部でTrueに変えるようにしてある。(リスト1参照)

これは、たとえば「15を重複しないようにランダムに10個並べろ!」とか言われても、

そんなの、デキッコナイス

となるに決まっているからである。

実行結果

f:id:akashi_keirin:20190113221436j:plain

この通り。

うまくいっている。

おわりに

これに、あとひと工夫すれば、

f:id:akashi_keirin:20190113221507j:plain

こんなふうに、記号をランダムに散らす、といったことに使えます。

学校の先生なんかが、記号式のテスト問題の解答をテキトーに散らすのに使えるんじゃないですかね。

あとは、競輪の出目予想とかw