🎉
モンティ・ホール問題をGoでも実装してみた。
今回は、以前Pythonでモンティ・ホール問題を実装した記事を出したのですが、Goの勉強も兼ねて今回はGoでの実装を試してみました。モンティ・ホール問題って何?という方やPythonでの実装が気になる方はぜひこちらを参照ください。
それでは早速実装していく
プロジェクト初期化
今回もこちらの記事のようにmise
を使ってプロジェクトを初期化していきます。
mise use go@1.24.3
mkdir monty_golang
cd monty_golang
go mod init monty_golang
コード実装
早速コードを実装してみましょう。前回のPython実装を元に移植しています。ただし、以下のように条件を変えています。
package main
import (
"fmt"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
"math/rand"
)
const (
Car int = iota
Goat
)
type MontyHallProblem struct {
DoorPrize map[int]int
SelectedIndex *int
OpenedIndex *int
}
func GetPrize() map[int]int {
doorPrize := map[int]int{0: Goat, 1: Goat, 2: Goat}
prizeTargetIndex := rand.Intn(3)
doorPrize[prizeTargetIndex] = Car
return doorPrize
}
func InitializeProblem() MontyHallProblem {
problem := MontyHallProblem{}
problem.Reset()
return problem
}
func (p *MontyHallProblem) Reset() {
p.DoorPrize = GetPrize()
p.SelectedIndex = nil
p.OpenedIndex = nil
}
func (p *MontyHallProblem) SelectFirst(firstIndex int) {
p.SelectedIndex = IntPtr(firstIndex)
}
func IntPtr(i int) *int {
return &i
}
func (p *MontyHallProblem) ChangeCandidate() {
switch {
case *p.SelectedIndex == 0 && *p.OpenedIndex == 1:
p.SelectedIndex = IntPtr(2)
case *p.SelectedIndex == 0 && *p.OpenedIndex == 2:
p.SelectedIndex = IntPtr(1)
case *p.SelectedIndex == 1 && *p.OpenedIndex == 2:
p.SelectedIndex = IntPtr(0)
}
}
func (p MontyHallProblem) IsCorrect() bool {
return p.DoorPrize[*p.SelectedIndex] == Car
}
func (p *MontyHallProblem) OpenGoatDoor() {
for idx := range p.DoorPrize {
if idx == *p.SelectedIndex {
continue
}
if p.DoorPrize[idx] == Goat {
p.OpenedIndex = IntPtr(idx)
break
}
}
}
func main() {
ITERATION := 1000
problem := InitializeProblem()
changedResult := 0.0
unchangedResult := 0.0
changedResults := make(plotter.XYs, ITERATION)
unchangedResults := make(plotter.XYs, ITERATION)
for i := 0; i < ITERATION; i++ {
problem.Reset()
problem.SelectFirst(0)
problem.OpenGoatDoor()
if problem.IsCorrect() {
unchangedResult += 1
}
problem.ChangeCandidate()
if problem.IsCorrect() {
changedResult += 1
}
fmt.Println(unchangedResult, changedResult)
changedResults[i].X = float64(i)
changedResults[i].Y = changedResult / float64(i+1)
unchangedResults[i].X = float64(i)
unchangedResults[i].Y = unchangedResult / float64(i+1)
}
p := plot.New()
p.Title.Text = "Month-Hall Problem"
p.X.Label.Text = "Iteration"
p.Y.Label.Text = "Probability"
plotutil.AddLinePoints(p, "changed", changedResults, "unchanged", unchangedResults)
if err := p.Save(4*vg.Inch, 4*vg.Inch, "monty_hall_problem_result.png"); err != nil {
panic(err)
}
}
グラフを書くために、Gonum Plotを利用しました。Gonum Plotの使い方についてはこちらの記事を参照ください。
こちらを実行すると、以下のような結果を得ることができます。結果を確認すると、前回の検証と同じく、ドアを変更した場合がおよそ66%程度、そのままの場合が33%程度と予想していた通りの結果になりました。
まとめ
今回はモンティ・ホール問題をGoで実装してみました。個人的にGoを使い始めで構造体の使い方とか慣れないところではありますが、前回のPython実装と同様の結果が再現できてよかったです。また、昨日記事化したGonum Plotについても早速応用的に使うことができてよかったです。
今後はもっとGoを使った実装に挑戦していこうと思います。もし何か質問やコメントあればどんどん残してくれると嬉しいです。
Discussion