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;

当たり(車を選ぶ)の回数を格納するint型変数atari_numを宣言して0を代入しています。

006
007
		// ハズレの回数
		int hazure_num = 0;

ハズレ(ヤギを選ぶ)の回数を格納するint型変数hazure_numを宣言して0を代入しています。

009
010
		// 10万回ゲームを実行する
		for ( int i = 1; i <= 100000; i++ ) {

for文で、変数iを1~100000まで1ずつ増やしていくループを作成しています。

このループの中にゲームを処理するプログラムを記述します。よって、10万回ゲームを繰り返します。

011
012
			// 最初に当たりとしたドア番号を乱数で選択
			int first =  (int)( Math.random() * 3.0 );

ここから、ゲーム開始です。

プレイヤーが選択するドアの番号を乱数で選んで変数firstに代入しています。選ぶドアの番号は0から2です。

014
015
			// 当たりのドア番号atari(0~2)を乱数で発生
			int atari =  (int)( Math.random() * 3.0 );

当たりのドア番号を乱数で選んで変数atariに代入しています。選ぶドアの番号は0から2です。

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;

プレイヤーが変更したドア番号changedがatariであれば変数atari_numに1を足しています。違えば、変数hazure_numに1を足しています。

044
045
046
		// 結果をコンソール出力
		System.out.println( "当たりの回数:" + atari_num );
		System.out.println( "ハズレの回数:" + hazure_num );

当たりの回数と、ハズレの回数をコンソール出力しています。

以上です。

次に読んでほしいコンテンツ

Javaの学習に役立つソースコードを多数紹介しています。是非、ご覧ください。

2022.09.10

処理を繰り返すために使用するfor文について解説しています。

2020.03.23

整数型の変数に1を足すインクリメント、1つ引くデクリメントについて詳しく説明しています。

2020.03.23

乱数の意味と、Math.randomメソッドの使い方をソースコードを使って詳しく解説しています。

2015.12.27

「Javaソースコード」から実行可能な「オブジェクトコード」に変換する方法をくわしく説明しています。

2020.03.23

乱数を使って指定サイズのノイズ画像を作る方法を解説します。Javaのソースコード付きです。

2016.05.26

乱数を使って指定の画像にノイズ画像を加える方法を解説します。

2016.06.14

乱数を使って指定サイズのノイズ画像を作る方法を解説します。ノイズが発生する割合はパーセントで指定します。

2020.11.11

円の中心座標(0,0)、半径rで表される円の円周上のランダムな座標を求めるJavaのソースコードを紹介しています。ラジアンを乱数で発生して座標を計算しています。

2019.09.27

円の中心座標(0,0)、半径rで表される円の円周上のランダムな座標を求めるJavaのソースコードを紹介しています。度単位の角度の乱数をラジアンに変換して座標を計算しています。

2019.09.27

円の中心座標(ox,oy)、半径rで表される円の円周上のランダムな座標を求めるJavaのソースコードを紹介しています。

2019.09.27

繰り返し処理を使ったJavaのソースコードサンプルを紹介しています。

2020.03.23

1から6のサイコロの目が出る確率を割り出すプログラムの作りかたを解説しています。

2020.05.07

2つのサイコロを振って同じ目が出る確率を割り出すプログラムの作り方を解説しています。

2020.08.25

条件式を判断して処理を分岐する方法を詳しく説明しています。

2023.03.20

変数やクラスに格納されている値をコンソール出力する方法は?

2020.03.23

プログラムの最初に実行されるメソッドは?

2022.12.13

プログラミングで使う変数って何?

2020.03.23

Javaのプログラムを書いてみませんか?プログラムの書き方をくわしく説明しています。

2020.03.23

関連コンテンツ

乱数の意味と、Math.randomメソッドの使い方をソースコードを使って詳しく解説しています。

2015.12.27

Javaのプログラムを書いてみませんか?プログラムの書き方をくわしく説明しています。

2020.03.23

Javaプログラムの構成について解説しています。詳しくは、こちらをご覧ください。

2020.03.23

プログラムの最初に実行されるメソッドは?

2022.12.13

プログラミングで使う変数って何?

2020.03.23

for文で変数名iがよく使われる理由について説明しています。興味のある方は是非。

2022.08.29

処理を繰り返すために使用するfor文について解説しています。

2020.03.23

繰り返し処理の作り方を解説しています。

2016.03.02

変数やクラスに格納されている値をコンソール出力する方法は?

2020.03.23

広告