乱数を発生させる

 数当てゲームを作ろうでフライングして使用してしまいましたが、.NET Frameworkを使った乱数発生することを試してみましょう。

 Randomクラスを使う

 .NET Frameworkで乱数を発生させるにはSystem.Randomクラスを使います。Randomクラスの使い方はいくつかあります。

   Random.Next() ・・・・・・・・・ 0〜2,147,483,647 の整数を返します。
   Random.Next(100) ・・・・・・ 0〜99の整数を返します。
   Random.Next(Min,Max) ・・・ Min〜Max-1の整数を返します。
   Random.NextDouble() ・・・・・ 0.0〜1.0の浮動小数を返します。

試してみましょう。

from System import *

rnd = Random()
for i in range(5):
print 'rnd.Next()=', rnd.Next()

for i in range(5):
print 'rnd.Next(5)=', rnd.Next(5)

for i in range(5):
print 'rnd.Next(1,3)=', rnd.Next(1,3)

for i in range(5):
print 'rnd.NextDouble()=', rnd.NextDouble()

raw_input()

出力画面:
 rnd.Next()= 441264980
 rnd.Next()= 2135130701
 rnd.Next()= 1607536483
 rnd.Next()= 488662129
 rnd.Next()= 786828923
 rnd.Next(5)= 1
 rnd.Next(5)= 2
 rnd.Next(5)= 0
 rnd.Next(5)= 2
 rnd.Next(5)= 3
 rnd.Next(1,3)= 2
 rnd.Next(1,3)= 1
 rnd.Next(1,3)= 1
 rnd.Next(1,3)= 1
 rnd.Next(1,3)= 2
 rnd.NextDouble()= 0.137232247804
 rnd.NextDouble()= 0.62444855395
 rnd.NextDouble()= 0.93179809392
 rnd.NextDouble()= 0.928610644736
 rnd.NextDouble()= 0.915255263408
まあこんな感じですかね。

 Randomクラスの欠点

 そもそも"乱数"とは、ある数字があり、次にくる数字はその前の数字とは何ら関係なく、まったく予想不可能な数字のことをいいます。では次のScriptを試してみましょう。

from System import *

rnd1 = Random()
rnd2 = Random()
rnd3 = Random()

for i in range(5):
  print 'rnd1.Next(10,100)=', rnd1.Next(10,100)

print
for i in range(5):
  print 'rnd2.Next(10,100)=', rnd2.Next(10,100)

print
for i in range(5):
  print 'rnd3.Next(10,100)=', rnd3.Next(10,100)

raw_input()

出力画面
 rnd1.Next(10,100)= 78
 rnd1.Next(10,100)= 11
 rnd1.Next(10,100)= 20
 rnd1.Next(10,100)= 68
 rnd1.Next(10,100)= 21

 rnd2.Next(10,100)= 78
 rnd2.Next(10,100)= 11
 rnd2.Next(10,100)= 20
 rnd2.Next(10,100)= 68
 rnd2.Next(10,100)= 21

 rnd3.Next(10,100)= 78
 rnd3.Next(10,100)= 11
 rnd3.Next(10,100)= 20
 rnd3.Next(10,100)= 68
 rnd3.Next(10,100)= 21
 全く予想不可能なはずなのにおかしいですよね。一回Randomクラスを動かしてしまえば、2回目以降のRandomクラスが何を出してくるか予想できてしまいます。これはまずいですね乱数ではなくなってしまいます。

 原因はRandomクラスの生成を3つ一編にやっているところにあります。Randomクラスは生成したタイミングである数字(System.Environment.TickCount)を受け取ります。Randomクラスはこの数字を使って乱数を発生させています。

ではSystem.Environment.TickCountというと1ミリ秒ごとに数字が変わっていく整数です。
なので刻々変わっていくので、Randonクラスを連続で生成しても問題ないと、人間の感覚では思えますが、それはあくまで人間の感覚です。コンピュータは1ミリ秒の間に、数千の命令を実行しています。なのでコンピュータからすれば、1ミリ秒は非常に長いで連続で生成されたRandomクラスは同じ数字を受け取る可能性が高くなります。

 そこで解決させる方法として、Randomクラスが生成する際に与える数字自体を乱数にしてみます。

from System import *
rnd = Random() ←Randomクラス生成時に使うRandomクラス

rnd1 = Random(rnd.Next()) ←Randomクラスの生成時に引数を与えると
rnd2 = Random(rnd.Next())  引数を元に乱数を発生させます。
rnd3 = Random(rnd.Next())

for i in range(5):
  print 'rnd1.Next(10,100)=', rnd1.Next(10,100)

print
for i in range(5):
  print 'rnd2.Next(10,100)=', rnd2.Next(10,100)

print
for i in range(5):
  print 'rnd3.Next(10,100)=', rnd3.Next(10,100)

raw_input()

出力画面:
 rnd1.Next(10,100)= 68
 rnd1.Next(10,100)= 63
 rnd1.Next(10,100)= 83
 rnd1.Next(10,100)= 13
 rnd1.Next(10,100)= 41

 rnd2.Next(10,100)= 44
 rnd2.Next(10,100)= 81
 rnd2.Next(10,100)= 56
 rnd2.Next(10,100)= 61
 rnd2.Next(10,100)= 27

 rnd3.Next(10,100)= 40
 rnd3.Next(10,100)= 13
 rnd3.Next(10,100)= 48
 rnd3.Next(10,100)= 29
 rnd3.Next(10,100)= 88
今度はうまくいきました。