モンティ・ホール問題

ドアの選び方であなたの賢さが分かる!?——モンティ・ホール問題とは

すっきりしないのでシミュレーションしてみました。


ゲームのルール

1. 3つのドア (A, B, C) に(景品、ヤギ、ヤギ)がランダムに入っている。
2. プレイヤーはドアを1つ選ぶ。
3. プレイヤーがどのドアを選んだかにかかわらず、ホストは残りのドアの
うち1つを必ず開ける。
4. ホストは景品のあるドアを知っていて、必ずヤギの入っているドアを開ける。
もし、両方ともヤギだった場合はプレイヤーの見えないところでコインを投げ
て決める。

class Door
attr_accessor :present, :player_open, :hint, :new_open

def initialize
@present = :goat
@player_open = false
@hint = false
@new_open = false
end

def invest
["present=",@present,"player_open=",@player_open,"hint=",@hint,"new_open=",@new_open]
end
end

class Doors
def initialize
@d = []
3.times{ @d.push(Door.new) }
end

def setPresent(pos)
@d[pos].present= :car
end

def doMark(pos)
@mark=pos
@d[pos].player_open= true
end

def win?
if ( @d[@mark].player_open == true && @d[@mark].present== :car)
true
else
false
end
end

def lastWin?
@d.each do |door|
return true if ( (door.present == :car)
&& (door.new_open == true))
end
false
end

# 当たっていたので乱数によりどちらかのヤギを開ける。
def openRnadom
# puts "当たった"
cnt = rand(2)
pos = 0
@d.each do |door|
if ( not (door.present == :car))
if ( pos == cnt) then door.hint = true end
pos += 1
end
end
end

# はずれのときは、選ばれていない方のヤギを開ける。
def openGoat
# puts "はずれ"
@d.each do |door|
if( (not (door.present == :car)) && (door.player_open == false))
door.hint = true
end
end
end

# もう1つの閉じているドアに変更する
def anotherMark
@d.each do |door|
# 最初に選択したものでも、ホストが開いたものでもないものにマーク
if( ( door.player_open == false) && (door.hint == false))
door.new_open = true
end
end
end

def invest
@d.each{|door| p door.invest}
end
end

class Hsot
def setPresent(doors)
doors.setPresent(rand(3))
end

def setHint(doors)
# 当たっていれば乱数によりどちらかのヤギを開ける。
if doors.win? then
doors.openRnadom
# はずれのときは、選ばれていない方のヤギを開ける。
else
doors.openGoat
end
end
end

class Player
def mark(doors)
doors.doMark(rand(3))
end
# もう1つの閉じているドアに変更する
def anotherMark(doors)
doors.anotherMark
end
end

host = Hsot.new
player= Player.new

EXEC = 10000
cnt = 0
EXEC.times do
doors = Doors.new
host.setPresent(doors)
player.mark(doors)
cnt +=1 if doors.win?
end
puts "変 更 な し : #{ cnt.to_f / EXEC} #{cnt}/#{EXEC}"

cnt = 0
EXEC.times do
doors = Doors.new
host.setPresent(doors)
player.mark(doors)
host.setHint(doors)
player.anotherMark(doors)
cnt +=1 if doors.lastWin?
end
puts "変更した場合: #{ cnt.to_f / EXEC} #{cnt}/#{EXEC}"

変更しない場合は1/3で当たるけれども、変更すると2/3になる。


> $ ruby MontyHallProblem.rb
変 更 な し :0.3317 3317/10000
変更した場合:0.6692 6692/10000