「rubyでモンティホール問題に挑戦」の記事を見て、自分なりにやってみたくなりました。ここでは Go でやってみます。
「モンティ・ホール問題」とは
三つの扉があり、その向こうのひとつにだけ当たりがあります。
挑戦者はまず三つの扉の中からひとつを選びます。
司会者(モンティ・ホール)は当たりの扉を知っています。そして二つあるハズレの扉のひとつ(挑戦者が選択していないそれ)を開けます。
挑戦者はそこで前に選んだ扉をもういちどそのまま選択してもよいし、二つの扉の別の方を選択してもよい。
さて、挑戦者はここで扉をもうひとつのそれに替えた方がよいのか、そのままにした方がよいのか、それともいずれでも当たる確率は一緒なのか。
どうなのでしょうか?
実際のところは?
先に答えを言っておくと、これは「扉を替えた方」が当たる確率は高くなるのです。扉を替えない場合、当たる確率は 1/3 で、扉を替えると 2/3 になります1。
不思議ですか? ただ扉を開けただけなのに?
シミュレートしてみる
コードはこんな具合になりました。
package main
import "fmt"
import "math/rand"
import "time"
const n = 1000000
//一回の試行
func trial(is_reselection bool) (result bool) {
doors := [3]bool{true, false, false}
select_of_challenger := rand.Intn(3)
if is_reselection {
remained_doors := doors[0:2]
reselect_of_challenger := 0
if select_of_challenger == 0 { reselect_of_challenger = 1 }
result = remained_doors[reselect_of_challenger]
} else {
result = doors[select_of_challenger]
}
return
}
//n回試行して確率の計算
func calc(is_reselection bool) float32 {
co := 0
for i := 0; i < n; i++ {
if trial(is_reselection) { co++ }
}
return float32(co) / float32(n)
}
func main() {
rand.Seed(time.Now().UnixNano())
//扉を替えない場合
fmt.Println(calc(false)) //=>0.333683
//扉を替える場合
fmt.Println(calc(true)) //=>0.666448
}
確かにそうなります。
説明が必要でしょう。まず、扉 0, 1, 2 があって、当たりは必ず扉 0 にあるとします。挑戦者は何も知らないので、この仮定で問題ありません。これがdoors := [3]bool{true, false, false}
で表されます。
挑戦者が最初にどれを選んでも、モンティがひとつ開けて(それは挑戦者の選んだ扉ではなく、また当たりでもありません)残った扉は「当たり、ハズレ」の二つになります。とにかくモンティは、ハズレの扉を開けるしかないのですから。それがremained_doors := doors[0:2]
の表わすところです。
あとはさほど問題はないと思います。
なお、これのRuby版がここにあります。
追記
何だか不思議ですね。最初はおもいっ切りまちがえていました2。