Skip to content

Instantly share code, notes, and snippets.

@dangerous
Last active July 14, 2016 04:19
Show Gist options
  • Save dangerous/28a4a031778cafa6be1b8100626abd2b to your computer and use it in GitHub Desktop.
Save dangerous/28a4a031778cafa6be1b8100626abd2b to your computer and use it in GitHub Desktop.
Monty Hall problem where host picks randomly - based on https://gist.github.com/alexaandru/1926859
#
# This class creates a model of the Monty Hall problem.
# It simulates arranging the set with prize/goats, both guest
# and Monty picking a door and then the decision to switch
# or not to switch (and of course, the outcome).
#
# Each instance of the class (MontyHall.new) runs a new
# show. Sample usage code is at the bottom.
#
class MontyHall
attr_accessor :doors, :result
#
# We start with three doors, randomly sorted.
# Then we run through the entire scenario as
# outlined below.
#
def initialize(do_switch = true, show_backstage = false)
@doors = [0, 1, 2].sort_by { rand }
@doors_content = Array.new(3)
@do_switch = do_switch
@show_backstage = show_backstage
set_the_stage
guest_pick
monty_pick
guest_decide_to_switch_or_not
determine_outcome
end
#
# Set the stage: put a prize behind one door,
# a goat behind the two remaining doors.
#
def set_the_stage
# put a prize at a random door
@doors_content[rand(3)] = :prize
# put a goat on all other doors
3.times { |i| @doors_content[i] ||= :goat }
end
#
# Guest takes his pick.
#
def guest_pick
# The doors are already randomly sorted, so we just
# pop out a door from the top of the stack.
@guest_pick = @doors.pop
end
#
# Monty takes his pick, always picking a :goat
# door.
#
def monty_pick
# always pick d1
# comment these three lines to use original MH problem
@monty_pick = @doors.first
@remaining_door = @doors.last
return
d1, d2 = @doors.sort_by { rand }
# And we also make sure that we have a goat
# behind the door Monty opens.
if @doors_content[d1].eql?(:goat)
@monty_pick = d1
@remaining_door = d2
else
@monty_pick = d2
@remaining_door = d1
end
end
def guest_decide_to_switch_or_not(_do_switch = @do_switch)
@guest_pick, @remaining_door = @remaining_door, @guest_pick if @do_switch
end
def determine_outcome
@result = if @doors_content[@monty_pick].eql? :prize
nil
elsif @doors_content[@guest_pick].eql?(:prize)
true
else
false
end
end
end
# This controls the number of shows we play
no_of_shows = 100_000
# This controls the switching decision, can be set to: true or false
# It will be used for ALL shows we run at once.
do_switch = false
# Show backstage tips. Don't set it unless you run really small loops.
show_backstage = false
# This counts the success/failure of all shows we played
success = 0
failure = 0
# This runs all the shows we asked for
no_of_shows.times do
result = MontyHall.new(do_switch, show_backstage).result
success += 1 if result === true
failure += 1 if result === false
end
# And finally, we compute & display the rate
puts 'Success rate when we %s switch is: %.2f%' % [do_switch ? 'do' : "don't", ((success * 100.0) / (success + failure))]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment