2020.05.07
Javaプログラミング
サイコロの出目確率
サイコロは、卓上ゲームなどに使われる道具で乱数を発生するときに使われます。一般的なものは正6面体で各面に1個から6個の点が記されています。さらに、対面の数字の和が7になるように記されています。具体的には1の裏は6、2の裏は5、3の裏は4です。
ここでは、乱数で1から6の数字を複数回発生し、それらの値をサイコロの出目(振って出た数字)としたときに、1から6の値が均等に現れるかどうかを確認します。
詳しい処理の内容は、以下のソースコードと解説を参照してください。
Javaソースコード
Dice.java
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028
public class Dice { public static void main(String[] args) { // サイコロを振る回数 int count = 100000; // 出目数 int deme_num[] = new int[ 6 ]; // 各出目数に0を格納 for ( int i = 1; i <= 6; ++ i ) deme_num[ i - 1 ] = 0; // 100000回乱数を発生(サイコロを振る) for ( int i = 1; i <= count; ++ i ) { // 1から6の乱数を発生 int deme = (int)( Math.random() * 6.0 ) + 1; // 出目(deme)の配列にに1を足す ++ deme_num[ deme - 1 ]; } // 結果を表示 for ( int i = 1; i <= 6; ++ i ) { System.out.println( "出目" + i + ":" + deme_num[ i - 1 ] + "回" + " 確率:" + (double)deme_num[ i - 1 ] / (double)count * 100.0 + "%" ); } } }
実行結果
コンパイル ソースコードが「ANSI」の場合
C:\talavax\javasample>javac -encoding sjis Dice.java
コンパイル ソースコードが「UTF-8」の場合
C:\talavax\javasample>javac Dice.java
実行
C:\talavax\javasample>java Dice
出力結果
出目1:16731回 確率:16.730999999999998% 出目2:16552回 確率:16.552% 出目3:16689回 確率:16.689% 出目4:16504回 確率:16.503999999999998% 出目5:16645回 確率:16.645% 出目6:16879回 確率:16.878999999999998%
実行結果は、毎回違います。
各出目(1~6)の確率が1/6≒0.166666...(16.6666...%)に近ければ均等に出現しているといえます。この出現確率はサイコロを振る回数によって変わります。一般的には、サイコロを振る回数が多いほど確率が均等になります。この実行結果では、出現確率が16.50~16.88%に収まっているので、ほぼ均等であるといえます。乱数を利用するゲーム(トランプ、麻雀、じゃんけん等)で使用するには問題ないレベルだと思います。
乱数を発生するプログラムを自作する場合、このようなプログラムによって出現確率を確認することができます。うまく自作できていない場合、出目の回数に偏りが出ます。
Javaソースコードの解説
ここからソースコードを順番に解説していきます。
001
public class Dice {
クラス名を、Diceとしています。
003 004
// サイコロを振る回数 int count = 100000;
サイコロを振る回数(count=100000)を宣言しています。
005 006
// 出目数 int deme_num[] = new int[ 6 ];
各出目の回数を格納する配列を宣言しています。
008 009
// 各出目数に0を格納 for ( int i = 1; i <= 6; ++ i ) deme_num[ i - 1 ] = 0;
各出目の回数に0を代入しています。
このプログラムでは、deme_num[ 0 ]は出目1の回数、deme_num[ 1 ]は出目2の回数、deme_num[ 2 ]は出目3の回数、deme_num[ 3 ]は出目4の回数、deme_num[ 4 ]は出目5の回数、deme_num[ 5 ]は出目6の回数を格納しています。
011 012
// 100000回乱数を発生(サイコロを振る) for ( int i = 1; i <= count; ++ i ) {
013 014
// 1から6の乱数を発生 int deme = (int)( Math.random() * 6.0 ) + 1;
1~6の乱数をMath.randomメソッドを使って発生し、int型の変数demeに格納しています。
Math.random()は0.0から1.0未満の値を発生するので、"Math.random()*6.0"は0.0~6.0未満の値を発生します。これをint型で型キャストすると0~5の整数値になります("(int)(Math.random()*6.0)"の部分)。型キャストした値の小数点以下は切り捨てになるので6に近い値5.9999でも5になります。最後に1を足すと1~6の乱数になります。
Math.randomメソッド
public static double Math.random()
・乱数を返します。 パラメータ なし 戻り値 0.0以上、1.0未満の乱数
016 017
// 出目(deme)の配列にに1を足す
++ deme_num[ deme - 1 ];
配列deme_numの添え字deme-1の値をインクリメント(1を足す)します。変数demeには1~6の値が格納されていますが、配列の添え字は0からなのでdeme_num[ deme - 1 ]をインクリメントします。
020 021 022 023 024 025 026
// 結果を表示 for ( int i = 1; i <= 6; ++ i ) { System.out.println( "出目" + i + ":" + deme_num[ i - 1 ] + "回" + " 確率:" + (double)deme_num[ i - 1 ] / (double)count * 100.0 + "%" ); }
結果をprintlnメソッドでコンソール出力しています。
以上です。