Skip to content

Instantly share code, notes, and snippets.

@alexaandru
Created February 27, 2012 20:35
Show Gist options
  • Save alexaandru/1926859 to your computer and use it in GitHub Desktop.
Save alexaandru/1926859 to your computer and use it in GitHub Desktop.
Monty Hall model in Ruby
#
# 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
# We randomly sort the remaining doors so that
# Monty doesn't get to always pick the first
# door (or the last).
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, @remaining_door = d1, d2
else
@monty_pick, @remaining_door = d2, 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 = @doors_content[@guest_pick].eql?(:prize)
if @show_backstage
puts <<BACKSTAGE
-----------------------------------------------------------------------------------------
Prizes were : door #1 #{@doors_content[0]}, door #2 #{@doors_content[1]}, door #3 #{@doors_content[2]}
Guest picked : door ##{@guest_pick + 1} (#{@doors_content[@guest_pick]})
Monty picked : door ##{@monty_pick + 1} (#{@doors_content[@monty_pick]})
Remaining : door ##{@remaining_door + 1} (#{@doors_content[@remaining_door]})
The quest #{@do_switch ? 'did' : 'did not'} switch the door.
-----------------------------------------------------------------------------------------
BACKSTAGE
end
@result
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, failure = 0, 0
# This runs all the shows we asked for
no_of_shows.times { MontyHall.new(do_switch, show_backstage).result ? success += 1 : failure += 1 }
# And finally, we compute & display the rate
puts "Success rate when we %s switch is: %.2f%" % [do_switch ? "do" : "don't", ((success * 100.0)/no_of_shows)]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment