Tests first:
require './monty_hall' require 'test/unit' class TestMontyHall < Test::Unit::TestCase def test_either_goat_door_is_opened_when_you_choose_the_car_door check_either_goat([:car, :goat, :goat], { :chosen_door => 0, :goat_doors => [1, 2] }) check_either_goat([:goat, :car, :goat], { :chosen_door => 1, :goat_doors => [0, 2] }) check_either_goat([:goat, :goat, :car], { :chosen_door => 2, :goat_doors => [0, 1] }) end def test_other_goat_door_is_opened_when_you_choose_a_goat_door prizes = [:car, :goat, :goat] check_other_goat(prizes, { :chosen_door => 1, :opened_door => 2, :offered_door => 0 }) check_other_goat(prizes, { :chosen_door => 2, :opened_door => 1, :offered_door => 0 }) prizes = [:goat, :car, :goat] check_other_goat(prizes, { :chosen_door => 0, :opened_door => 2, :offered_door => 1 }) check_other_goat(prizes, { :chosen_door => 2, :opened_door => 0, :offered_door => 1 }) prizes = [:goat, :goat, :car] check_other_goat(prizes, { :chosen_door => 0, :opened_door => 1, :offered_door => 2 }) check_other_goat(prizes, { :chosen_door => 1, :opened_door => 0, :offered_door => 2 }) end def test_strategy_of_sticking_with_chosen_door wins = Array.new(big) { MontyHall.new() } .count { |game| game.chosen_door == game.car_door } puts "Win car(sticking with chosen door):#{wins}/#{big}" end def test_strategy_of_switching_to_offered_door wins = Array.new(big) { MontyHall.new() } .count { |game| game.offered_door == game.car_door } puts "Win car(switching to offered door):#{wins}/#{big}" end #- - - - - - - - - - - - - - - - - - - - - - - - def check_either_goat(prizes, expected) chosen_door = expected[:chosen_door] goat_doors = expected[:goat_doors] check_params(prizes, chosen_door, goat_doors[0], goat_doors[1]) goat_counts = [0,0] 100.times do |n| game = MontyHall.new(prizes,chosen_door) opened_door = game.opened_door offered_door = game.offered_door assert_equal chosen_door, game.chosen_door assert_equal goat_doors.sort, [opened_door,offered_door].sort assert_equal doors, [chosen_door,opened_door,offered_door].sort assert_equal :car , prizes[chosen_door] assert_equal :goat, prizes[opened_door] assert_equal :goat, prizes[offered_door] [0,1].each do |n| goat_counts[n] += (offered_door == goat_doors[n] ? 1 : 0) end end [0,1].each { |n| assert goat_counts[n] > 25 } end def check_other_goat(prizes, expected) chosen_door = expected[:chosen_door] opened_door = expected[:opened_door] offered_door = expected[:offered_door] check_params(prizes, chosen_door, opened_door, offered_door) game = MontyHall.new(prizes, chosen_door) assert_equal chosen_door, game.chosen_door assert_equal opened_door, game.opened_door assert_equal offered_door, game.offered_door assert_equal :goat, prizes[ chosen_door] assert_equal :goat, prizes[ opened_door] assert_equal :car , prizes[offered_door] end def check_params(prizes, door1, door2, door3) assert_equal 3, prizes.length prizes.each { |prize| assert [:goat,:car].include? prize } assert_equal doors, [door1,door2,door3].sort end def doors [0,1,2] end def big 1000 end endCode second:
class MontyHall def initialize(prizes = [:goat,:goat,:car].shuffle, chosen_door = doors.shuffle[0]) @prizes = prizes @chosen_door = chosen_door @car_door = prizes.find_index { |prize| prize == :car } if prizes[chosen_door] == :car @opened_door = goat_doors.shuffle[0] end if prizes[chosen_door] == :goat @opened_door = (goat_doors - [chosen_door])[0] end @offered_door = (doors - [chosen_door, opened_door])[0] end def chosen_door @chosen_door end def car_door @car_door end def opened_door @opened_door end def offered_door @offered_door end private def doors [0,1,2] end def goat_doors doors.select { |door| @prizes[door] == :goat } end endYou can replay my entire progression (warts and all) on Cyber-Dojo (naturally).