2022.09.28
Javaプログラミング
モンティ・ホール問題とは?
3つのドアA、B、Cの1つに車が入っていて、他の2つのドアにはヤギが入っています。車を入れるドアはランダムです。
ドアが閉まった状態で、司会者のモンティがプレイヤーに車が入っているドアを当てさせます。手順は以下のとおりです。
・プレイヤーが、ドアを1つ選んで司会者(モンティ)に伝えます。 ・司会者が、ヤギが入っているドアを1つ開きます。このとき、プレイヤーが選んだドアは開きません。 ・司会者が、最初に選んだドアを変更しても良いとプレイヤーに伝えます。
この質問の後、プレイヤーがドアを変更した方が良いか、変更しない方が良いか?
これが、モンティ・ホール問題です。
Javaのソースコード
上記のルールに従って、車が入っているドアが当たる回数、当たらない回数を確認するプログラムを作成しました。
このソースコードでは、最初に選んだドア番号を、必ず変えるようにしています。
MontyHallProblem.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 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048
public class MontyHallProblem { public static void main( String[] args ) { // 当たりの回数 int atari_num = 0; // ハズレの回数 int hazure_num = 0; // 10万回ゲームを実行する for ( int i = 1; i <= 100000; i++ ) { // 最初に当たりとしたドア番号を乱数で選択 int first = (int)( Math.random() * 3.0 ); // 当たりのドア番号atari(0~2)を乱数で発生 int atari = (int)( Math.random() * 3.0 ); // 開けるドア番号を選択 int open = 0; for ( int j = 0; j < 3; ++ j ) { // 最初に選択した番号と、当たり番号は選択しない if ( ( j != first ) && ( j != atari ) ) { open = j; break; } } // 変更するドア番号を取得 int changed = 0; for ( int j = 0; j < 3; ++ j ) { // 最初に選択した番号と、開けた番号は選択しない if ( ( j != first ) && ( j != open ) ) { changed = j; break; } } // 変更したドア番号が当たりのドア番号か判定 if ( changed == atari ) ++ atari_num; else ++ hazure_num; } // 結果をコンソール出力 System.out.println( "当たりの回数:" + atari_num ); System.out.println( "ハズレの回数:" + hazure_num ); } }
実行結果
コンパイル ソースコードが「ANSI」の場合
C:\talavax\javasample>javac -encoding sjis MontyHallProblem.java
コンパイル ソースコードが「UTF-8」の場合
C:\talavax\javasample>javac MontyHallProblem.java
実行
C:\talavax\javasample>java MontyHallProblem
出力結果(実行する毎に結果がかわります)
当たりの回数:67044 ハズレの回数:32956
この結果から、最初に選んだドアを変えた方が当たる確率が約2倍になることがわかります。
Javaソースコードの解説
001
public class MontyHallProblem {
クラス名を、MontyHallProblemとしています。
002
public static void main( String[] args ) {
このmainメソッドからプログラムを実行します。
003 004
// 当たりの回数 int atari_num = 0;
006 007
// ハズレの回数 int hazure_num = 0;
009 010
// 10万回ゲームを実行する for ( int i = 1; i <= 100000; i++ ) {
011 012
// 最初に当たりとしたドア番号を乱数で選択 int first = (int)( Math.random() * 3.0 );
014 015
// 当たりのドア番号atari(0~2)を乱数で発生 int atari = (int)( Math.random() * 3.0 );
Math.randomメソッド
public static double Math.random()
・乱数を返します。 パラメータ なし 戻り値 0.0以上、1.0未満の乱数
017 018 019 020 021 022 023 024 025
// 開けるドア番号を選択 int open = 0; for ( int j = 0; j < 3; ++ j ) { // 最初に選択した番号と、当たり番号は選択しない if ( ( j != first ) && ( j != atari ) ) { open = j; break; } }
司会者が開けるドアの番号を選んで変数openに代入しています。
for文で、変数jを0~2まで1ずつ増やしていくループを作成しています。
この変数jのうち、プレイヤーが選んだドア番号firstでもなく、当たりのドア番号atariでもない番号を変数openに代入しています。
027 028 029 030 031 032 033 034 035
// 変更するドア番号を取得 int changed = 0; for ( int j = 0; j < 3; ++ j ) { // 最初に選択した番号と、開けた番号は選択しない if ( ( j != first ) && ( j != open ) ) { changed = j; break; } }
プレイヤーが変更するドアの番号を選んで変数changedに代入しています。
for文で、変数jを0~2まで1ずつ増やしていくループを作成しています。
この変数jのうち、プレイヤーが最初に選んだドア番号firstでもなく、司会者が開けたドア番号openでもない番号を変数changedに代入しています。
037 038 039 040 041
// 変更したドア番号が当たりのドア番号か判定
if ( changed == atari )
++ atari_num;
else
++ hazure_num;
044 045 046
// 結果をコンソール出力 System.out.println( "当たりの回数:" + atari_num ); System.out.println( "ハズレの回数:" + hazure_num );
当たりの回数と、ハズレの回数をコンソール出力しています。
以上です。
次に読んでほしいコンテンツ
円の中心座標(0,0)、半径rで表される円の円周上のランダムな座標を求めるJavaのソースコードを紹介しています。ラジアンを乱数で発生して座標を計算しています。
円の中心座標(0,0)、半径rで表される円の円周上のランダムな座標を求めるJavaのソースコードを紹介しています。度単位の角度の乱数をラジアンに変換して座標を計算しています。