LoginSignup
0
0

More than 5 years have passed since last update.

モンティ・ホール問題を Ruby で解いてみた

Posted at

Ruby の勉強も兼ねてモンティ・ホール問題をシミュレートしてみた。

モンティ・ホール問題

アメリカのテレビ番組で実際に行われていたゲームで、概要は次のようなもの

  • 3つのドアがあり、1つのドアの後ろには景品の車、その他2つのドアの後ろにははずれを意味するヤギがいる。
  • プレーヤーは1つドアを選び、車のドアを選ぶ事ができればそのまま車をもらうことができる。
  • ただし、ドアを選んだ後に司会者(景品の位置を知っている)がはずれのドア1つを開け、プレーヤーにはドアを選びなおすチャンスが与えられる。
  • このとき、プレーヤーはドアを選びなおすべきか???

直感的にはどちらも変わらず $\frac{1}{2}$ の確率になりそうなんですが、
実はドアを選びなおすと $\frac{2}{3}$ の確率で当たりを引くことになり2倍も有利になるというある種の心理的なパラドックス。

コード

monty_hall.rb
module MontyHall
  class Simulator
    CAR = "car"   # あたり
    GOAT = "goat" # はずれ

    # Initialize counter to zero.
    # @param [Integer] sample_size number of trials
    def initialize(sample_size)
      @sample_size = sample_size
      @cnt_winning_the_car = 0
    end

    # Execute <sample_size> times
    def execute
      @sample_size.times do
        doors = [CAR, GOAT, GOAT].shuffle
        your_choice = choose_door

        # The host opens the door which has a goat.
        host_choice = choose_door exclude: [your_choice, doors.find_index(CAR)]

        # Switch your choice to the remaining door.
        your_choice = choose_door exclude: [your_choice, host_choice]

        @cnt_winning_the_car += 1 if doors[your_choice].eql? CAR
      end
    end

    # Show simulation results.
    def show_result
      percentage = (100.0 * @cnt_winning_the_car.to_f / @sample_size.to_f).round(1)
      puts "------------------------"
      puts "N = #{@sample_size}"
      puts "------------------------"
      puts "WIN : #{@cnt_winning_the_car} times."
      puts "LOSE: #{@sample_size - @cnt_winning_the_car} times."
      puts "------------------------"
      puts "By switching your choice to the remaining door, "
      puts "you got a #{percentage} percent winning rate!"
    end


    private

    # Randomly choose a door No. within 0 to 2. 
    # @param [Array] exclude A list to be excluded.
    # @return 0, 1, or 2.
    def choose_door(exclude: [])
      ([0, 1, 2] - exclude).sample
    end
  end
end
main.rb
require './monty_hall'

simulator = MontyHall::Simulator.new(100_000)
simulator.execute
simulator.show_result

実行結果

------------------------
N = 100000
------------------------
WIN : 66675 times.
LOSE: 33325 times.
------------------------
By switching your choice to the remaining door,
you got a 66.7 percent winning rate!

ほぼ $\frac{2}{3}$ の確率で理論値通りの結果となりました。

参考

Wikipedia - モンティ・ホール問題
Wikipedia - Monty Hall problem 英語版の方が情報量が多くてより正確な解説があります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0